Files
next.orly.dev/pkg/policy/kind_whitelist_test.go
mleku 869006c4c3
Some checks failed
Go / build-and-release (push) Has been cancelled
Add comprehensive tests for new policy fields and combinations
Introduce tests to validate functionality for new policy fields, including `max_expiry_duration`, `protected_required`, `identifier_regex`, and `follows_whitelist_admins`. Also, cover combinations of new and existing fields to ensure compatibility and precedence rules are correctly enforced.

bump to v0.31.2
2025-12-01 18:21:38 +00:00

318 lines
9.4 KiB
Go

package policy
import (
"testing"
"git.mleku.dev/mleku/nostr/encoders/hex"
)
// TestKindWhitelistComprehensive verifies that kind whitelisting properly rejects
// unlisted kinds in all scenarios: explicit whitelist, implicit whitelist (rules), and combinations
func TestKindWhitelistComprehensive(t *testing.T) {
testSigner, testPubkey := generateTestKeypair(t)
t.Run("Explicit Whitelist - kind IN whitelist, HAS rule", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow", // Changed to allow so rules without constraints allow by default
Kind: Kinds{
Whitelist: []int{1, 3, 5}, // Explicit whitelist
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
3: {Description: "Rule for kind 3"},
5: {Description: "Rule for kind 5"},
},
}
event := createTestEvent(t, testSigner, "test", 1)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Kind 1 should be ALLOWED (in whitelist, has rule, passes rule check)")
}
})
t.Run("Explicit Whitelist - kind IN whitelist, NO rule", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Whitelist: []int{1, 3, 5}, // Explicit whitelist
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
// Kind 3 has no rule
},
}
event := createTestEvent(t, testSigner, "test", 3)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Kind 3 should be ALLOWED (in whitelist, no rule, default policy is allow)")
}
})
t.Run("Explicit Whitelist - kind NOT in whitelist, HAS rule", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Whitelist: []int{1, 3, 5}, // Explicit whitelist - kind 10 NOT included
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
10: {Description: "Rule for kind 10"}, // Has rule but not in whitelist!
},
}
event := createTestEvent(t, testSigner, "test", 10)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 10 should be REJECTED (NOT in whitelist, even though it has a rule)")
}
})
t.Run("Explicit Whitelist - kind NOT in whitelist, NO rule", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Whitelist: []int{1, 3, 5}, // Explicit whitelist
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
},
}
event := createTestEvent(t, testSigner, "test", 99)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 99 should be REJECTED (NOT in whitelist)")
}
})
t.Run("Implicit Whitelist (rules) - kind HAS rule", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow", // Changed to allow so rules without constraints allow by default
// No explicit whitelist
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
3: {Description: "Rule for kind 3"},
},
}
event := createTestEvent(t, testSigner, "test", 1)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Kind 1 should be ALLOWED (has rule, implicit whitelist)")
}
})
t.Run("Implicit Whitelist (rules) - kind NO rule", func(t *testing.T) {
policy := &P{
// DefaultPolicy not set (empty) - uses implicit whitelist when rules exist
// No explicit whitelist
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
3: {Description: "Rule for kind 3"},
},
}
event := createTestEvent(t, testSigner, "test", 99)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 99 should be REJECTED (no rule, implicit whitelist mode)")
}
})
t.Run("Explicit Whitelist + Global Rule - kind NOT in whitelist", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Whitelist: []int{1, 3, 5}, // Explicit whitelist
},
Global: Rule{
Description: "Global rule applies to all kinds",
WriteAllow: []string{hex.Enc(testPubkey)},
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
},
}
// Even with global rule, kind not in whitelist should be rejected
event := createTestEvent(t, testSigner, "test", 99)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 99 should be REJECTED (NOT in whitelist, even with global rule)")
}
})
t.Run("Blacklist + Rules - kind in blacklist but has rule", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Blacklist: []int{10, 20}, // Blacklist
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
10: {Description: "Rule for kind 10"}, // Has rule but blacklisted!
},
}
// Kind 10 is blacklisted, should be rejected
event := createTestEvent(t, testSigner, "test", 10)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 10 should be REJECTED (in blacklist)")
}
})
t.Run("Blacklist + Rules - kind NOT in blacklist but NO rule (implicit whitelist)", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Blacklist: []int{10, 20}, // Blacklist
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
3: {Description: "Rule for kind 3"},
},
}
// Kind 99 is not blacklisted but has no rule
// With blacklist present + rules, implicit whitelist applies
event := createTestEvent(t, testSigner, "test", 99)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 99 should be REJECTED (not in blacklist but no rule, implicit whitelist)")
}
})
t.Run("Whitelist takes precedence over Blacklist", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow",
Kind: Kinds{
Whitelist: []int{1, 3, 5, 10}, // Whitelist includes 10
Blacklist: []int{10, 20}, // Blacklist also includes 10
},
rules: map[int]Rule{
1: {Description: "Rule for kind 1"},
10: {Description: "Rule for kind 10"},
},
}
// Kind 10 is in BOTH whitelist and blacklist - whitelist should win
event := createTestEvent(t, testSigner, "test", 10)
allowed, err := policy.CheckPolicy("write", event, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Kind 10 should be ALLOWED (whitelist takes precedence over blacklist)")
}
})
}
// TestKindWhitelistRealWorld tests real-world scenarios from the documentation
func TestKindWhitelistRealWorld(t *testing.T) {
testSigner, testPubkey := generateTestKeypair(t)
_, otherPubkey := generateTestKeypair(t)
t.Run("Real World: Only allow kinds 1, 3, 30023", func(t *testing.T) {
policy := &P{
DefaultPolicy: "allow", // Allow by default for kinds in whitelist
Kind: Kinds{
Whitelist: []int{1, 3, 30023},
},
rules: map[int]Rule{
1: {
Description: "Text notes",
// No WriteAllow = anyone authenticated can write
},
3: {
Description: "Contact lists",
// No WriteAllow = anyone authenticated can write
},
30023: {
Description: "Long-form content",
WriteAllow: []string{hex.Enc(testPubkey)}, // Only specific user can write
},
},
}
// Test kind 1 (allowed)
event1 := createTestEvent(t, testSigner, "Hello world", 1)
allowed, err := policy.CheckPolicy("write", event1, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Kind 1 should be ALLOWED")
}
// Test kind 4 (NOT in whitelist, should be rejected)
event4 := createTestEvent(t, testSigner, "DM", 4)
allowed, err = policy.CheckPolicy("write", event4, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 4 should be REJECTED (not in whitelist)")
}
// Test kind 30023 by authorized user (allowed)
event30023Auth := createTestEvent(t, testSigner, "Article", 30023)
allowed, err = policy.CheckPolicy("write", event30023Auth, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Kind 30023 should be ALLOWED for authorized user")
}
// Test kind 30023 by unauthorized user (should fail rule check)
event30023Unauth := createTestEvent(t, testSigner, "Article", 30023)
allowed, err = policy.CheckPolicy("write", event30023Unauth, otherPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 30023 should be REJECTED for unauthorized user")
}
// Test kind 9735 (NOT in whitelist, should be rejected even with valid signature)
event9735 := createTestEvent(t, testSigner, "Zap", 9735)
allowed, err = policy.CheckPolicy("write", event9735, testPubkey, "127.0.0.1")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if allowed {
t.Error("Kind 9735 should be REJECTED (not in whitelist)")
}
})
}