Some checks failed
Go / build-and-release (push) Has been cancelled
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
318 lines
9.4 KiB
Go
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)")
|
|
}
|
|
})
|
|
}
|