Implement policy-based event filtering and add integration tests
Some checks failed
Go / build (push) Has been cancelled
Go / release (push) Has been cancelled

- Enhanced the HandleReq function to incorporate policy checks for privileged events, ensuring only authorized users can access sensitive data.
- Introduced a new integration test suite for policy filtering, validating the behavior of event access based on user authentication and policy rules.
- Added a script to automate the policy filter integration tests, improving testing efficiency and reliability.
- Updated version to v0.20.2 to reflect the new features and improvements.
This commit is contained in:
2025-10-30 17:51:15 +00:00
parent 62f244d114
commit 80ab3caa5f
17 changed files with 1445 additions and 2 deletions

View File

@@ -357,6 +357,57 @@ func (l *Listener) HandleReq(msg []byte) (err error) {
)
}
} else {
// Check if policy defines this event as privileged (even if not in hardcoded list)
// Policy check will handle this later, but we can skip it here if not authenticated
// to avoid unnecessary processing
if l.policyManager != nil && l.policyManager.Manager != nil && l.policyManager.Manager.IsEnabled() {
rule, hasRule := l.policyManager.Rules[int(ev.Kind)]
if hasRule && rule.Privileged && accessLevel != "admin" {
pk := l.authedPubkey.Load()
if pk == nil {
// Not authenticated - cannot see policy-privileged events
log.T.C(
func() string {
return fmt.Sprintf(
"policy-privileged event %s denied - not authenticated",
ev.ID,
)
},
)
continue
}
// Policy check will verify authorization later, but we need to check
// if user is party to the event here
authorized := false
if utils.FastEqual(ev.Pubkey, pk) {
authorized = true
} else {
// Check p tags
pTags := ev.Tags.GetAll([]byte("p"))
for _, pTag := range pTags {
var pt []byte
if pt, err = hexenc.Dec(string(pTag.Value())); chk.E(err) {
continue
}
if utils.FastEqual(pt, pk) {
authorized = true
break
}
}
}
if !authorized {
log.T.C(
func() string {
return fmt.Sprintf(
"policy-privileged event %s does not contain the logged in pubkey %0x",
ev.ID, pk,
)
},
)
continue
}
}
}
tmp = append(tmp, ev)
}
}

View File

@@ -0,0 +1,319 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"strings"
"time"
"lol.mleku.dev/chk"
"lol.mleku.dev/log"
"next.orly.dev/pkg/crypto/p256k"
"next.orly.dev/pkg/encoders/event"
"next.orly.dev/pkg/encoders/filter"
"next.orly.dev/pkg/encoders/hex"
"next.orly.dev/pkg/encoders/kind"
"next.orly.dev/pkg/encoders/tag"
"next.orly.dev/pkg/protocol/ws"
)
func main() {
var err error
url := flag.String("url", "ws://127.0.0.1:34568", "relay websocket URL")
allowedPubkeyHex := flag.String("allowed-pubkey", "", "hex-encoded allowed pubkey")
allowedSecHex := flag.String("allowed-sec", "", "hex-encoded allowed secret key")
unauthorizedPubkeyHex := flag.String("unauthorized-pubkey", "", "hex-encoded unauthorized pubkey")
unauthorizedSecHex := flag.String("unauthorized-sec", "", "hex-encoded unauthorized secret key")
timeout := flag.Duration("timeout", 10*time.Second, "operation timeout")
flag.Parse()
if *allowedPubkeyHex == "" || *allowedSecHex == "" {
log.E.F("required flags: -allowed-pubkey and -allowed-sec")
os.Exit(1)
}
if *unauthorizedPubkeyHex == "" || *unauthorizedSecHex == "" {
log.E.F("required flags: -unauthorized-pubkey and -unauthorized-sec")
os.Exit(1)
}
// Decode keys
allowedSecBytes, err := hex.Dec(*allowedSecHex)
if err != nil {
log.E.F("failed to decode allowed secret key: %v", err)
os.Exit(1)
}
allowedSigner := &p256k.Signer{}
if err = allowedSigner.InitSec(allowedSecBytes); chk.E(err) {
log.E.F("failed to initialize allowed signer: %v", err)
os.Exit(1)
}
unauthorizedSecBytes, err := hex.Dec(*unauthorizedSecHex)
if err != nil {
log.E.F("failed to decode unauthorized secret key: %v", err)
os.Exit(1)
}
unauthorizedSigner := &p256k.Signer{}
if err = unauthorizedSigner.InitSec(unauthorizedSecBytes); chk.E(err) {
log.E.F("failed to initialize unauthorized signer: %v", err)
os.Exit(1)
}
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
// Test 1: Authenticated as allowed pubkey - should work
fmt.Println("Test 1: Publishing event 30520 with allowed pubkey (authenticated)...")
if err := testWriteEvent(ctx, *url, 30520, allowedSigner, allowedSigner); err != nil {
fmt.Printf("❌ FAILED: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ PASSED: Event published successfully")
// Test 2: Authenticated as allowed pubkey, then read event 10306 - should work
// First publish an event, then read it
fmt.Println("\nTest 2: Publishing and reading event 10306 with allowed pubkey (authenticated)...")
if err := testWriteEvent(ctx, *url, 10306, allowedSigner, allowedSigner); err != nil {
fmt.Printf("❌ FAILED to publish: %v\n", err)
os.Exit(1)
}
if err := testReadEvent(ctx, *url, 10306, allowedSigner); err != nil {
fmt.Printf("❌ FAILED to read: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ PASSED: Event readable by allowed user")
// Test 3: Unauthenticated request - should be blocked
fmt.Println("\nTest 3: Publishing event 30520 without authentication...")
if err := testWriteEventUnauthenticated(ctx, *url, 30520, allowedSigner); err != nil {
fmt.Printf("✅ PASSED: Event correctly blocked (expected): %v\n", err)
} else {
fmt.Println("❌ FAILED: Event was allowed when it should have been blocked")
os.Exit(1)
}
// Test 4: Authenticated as unauthorized pubkey - should be blocked
fmt.Println("\nTest 4: Publishing event 30520 with unauthorized pubkey...")
if err := testWriteEvent(ctx, *url, 30520, unauthorizedSigner, unauthorizedSigner); err != nil {
fmt.Printf("✅ PASSED: Event correctly blocked (expected): %v\n", err)
} else {
fmt.Println("❌ FAILED: Event was allowed when it should have been blocked")
os.Exit(1)
}
// Test 5: Read event 10306 without authentication - should be blocked
// Event was published in test 2, so it exists in the database
fmt.Println("\nTest 5: Reading event 10306 without authentication (should be blocked)...")
// Wait a bit to ensure event is stored
time.Sleep(500 * time.Millisecond)
// If no error is returned, that means no events were received (which is correct)
// If an error is returned, it means an event was received (which is wrong)
if err := testReadEventUnauthenticated(ctx, *url, 10306); err != nil {
// If we got an error about receiving an event, that's a failure
if strings.Contains(err.Error(), "unexpected event received") {
fmt.Printf("❌ FAILED: %v\n", err)
os.Exit(1)
}
// Other errors (like connection errors) are also failures
fmt.Printf("❌ FAILED: Unexpected error: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ PASSED: No events received (correctly filtered by policy)")
// Test 6: Read event 10306 with unauthorized pubkey - should be blocked
fmt.Println("\nTest 6: Reading event 10306 with unauthorized pubkey (should be blocked)...")
// If no error is returned, that means no events were received (which is correct)
// If an error is returned about receiving an event, that's a failure
if err := testReadEvent(ctx, *url, 10306, unauthorizedSigner); err != nil {
// Connection/subscription errors are failures
fmt.Printf("❌ FAILED: Unexpected error: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ PASSED: No events received (correctly filtered by policy)")
fmt.Println("\n✅ All tests passed!")
}
func testWriteEvent(ctx context.Context, url string, kindNum uint16, eventSigner, authSigner *p256k.Signer) error {
rl, err := ws.RelayConnect(ctx, url)
if err != nil {
return fmt.Errorf("connect error: %w", err)
}
defer rl.Close()
// Send a REQ first to trigger AUTH challenge (when AuthToWrite is enabled)
// This is needed because challenges are sent on REQ, not on connect
limit := uint(1)
ff := filter.NewS(&filter.F{
Kinds: kind.NewS(kind.New(kindNum)),
Limit: &limit,
})
sub, err := rl.Subscribe(ctx, ff)
if err != nil {
return fmt.Errorf("subscription error (may be expected): %w", err)
}
// Wait a bit for challenge to arrive
time.Sleep(500 * time.Millisecond)
sub.Unsub()
// Authenticate
if err = rl.Auth(ctx, authSigner); err != nil {
return fmt.Errorf("auth error: %w", err)
}
// Create and sign event
ev := &event.E{
CreatedAt: time.Now().Unix(),
Kind: kind.K{K: kindNum}.K,
Tags: tag.NewS(),
Content: []byte(fmt.Sprintf("test event kind %d", kindNum)),
}
// Add p tag for privileged check
pTag := tag.NewFromAny("p", hex.Enc(authSigner.Pub()))
ev.Tags.Append(pTag)
// Add d tag for addressable events (kinds 30000-39999)
if kindNum >= 30000 && kindNum < 40000 {
dTag := tag.NewFromAny("d", "test")
ev.Tags.Append(dTag)
}
if err = ev.Sign(eventSigner); err != nil {
return fmt.Errorf("sign error: %w", err)
}
// Publish
if err = rl.Publish(ctx, ev); err != nil {
return fmt.Errorf("publish error: %w", err)
}
return nil
}
func testWriteEventUnauthenticated(ctx context.Context, url string, kindNum uint16, eventSigner *p256k.Signer) error {
rl, err := ws.RelayConnect(ctx, url)
if err != nil {
return fmt.Errorf("connect error: %w", err)
}
defer rl.Close()
// Do NOT authenticate
// Create and sign event
ev := &event.E{
CreatedAt: time.Now().Unix(),
Kind: kind.K{K: kindNum}.K,
Tags: tag.NewS(),
Content: []byte(fmt.Sprintf("test event kind %d (unauthenticated)", kindNum)),
}
// Add d tag for addressable events (kinds 30000-39999)
if kindNum >= 30000 && kindNum < 40000 {
dTag := tag.NewFromAny("d", "test")
ev.Tags.Append(dTag)
}
if err = ev.Sign(eventSigner); err != nil {
return fmt.Errorf("sign error: %w", err)
}
// Publish (should fail)
if err = rl.Publish(ctx, ev); err != nil {
return fmt.Errorf("publish error (expected): %w", err)
}
return nil
}
func testReadEvent(ctx context.Context, url string, kindNum uint16, authSigner *p256k.Signer) error {
rl, err := ws.RelayConnect(ctx, url)
if err != nil {
return fmt.Errorf("connect error: %w", err)
}
defer rl.Close()
// Send a REQ first to trigger AUTH challenge (when AuthToWrite is enabled)
// Then authenticate
ff := filter.NewS(&filter.F{
Kinds: kind.NewS(kind.New(kindNum)),
})
sub, err := rl.Subscribe(ctx, ff)
if err != nil {
return fmt.Errorf("subscription error: %w", err)
}
// Wait a bit for challenge to arrive
time.Sleep(500 * time.Millisecond)
// Authenticate
if err = rl.Auth(ctx, authSigner); err != nil {
sub.Unsub()
return fmt.Errorf("auth error: %w", err)
}
// Wait for events or timeout
// If we receive any events, return nil (success)
// If we don't receive events, also return nil (no events found, which may be expected)
select {
case ev := <-sub.Events:
if ev != nil {
sub.Unsub()
return nil // Event received
}
case <-sub.EndOfStoredEvents:
// EOSE received, no more events
sub.Unsub()
return nil
case <-time.After(5 * time.Second):
// No events received - this might be OK if no events exist or they're filtered
sub.Unsub()
return nil
case <-ctx.Done():
sub.Unsub()
return ctx.Err()
}
return nil
}
func testReadEventUnauthenticated(ctx context.Context, url string, kindNum uint16) error {
rl, err := ws.RelayConnect(ctx, url)
if err != nil {
return fmt.Errorf("connect error: %w", err)
}
defer rl.Close()
// Do NOT authenticate
// Subscribe to events
ff := filter.NewS(&filter.F{
Kinds: kind.NewS(kind.New(kindNum)),
})
sub, err := rl.Subscribe(ctx, ff)
if err != nil {
return fmt.Errorf("subscription error (may be expected): %w", err)
}
defer sub.Unsub()
// Wait for events or timeout
// If we receive any events, that's a failure (should be blocked)
select {
case ev := <-sub.Events:
if ev != nil {
return fmt.Errorf("unexpected event received: should have been blocked by policy (event ID: %s)", hex.Enc(ev.ID))
}
case <-sub.EndOfStoredEvents:
// EOSE received, no events (this is expected for unauthenticated privileged events)
return nil
case <-time.After(5 * time.Second):
// No events received - this is expected for unauthenticated requests
return nil
case <-ctx.Done():
return ctx.Err()
}
return nil
}

View File

@@ -0,0 +1,516 @@
package policy
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"lol.mleku.dev/chk"
"next.orly.dev/pkg/crypto/p256k"
"next.orly.dev/pkg/encoders/event"
"next.orly.dev/pkg/encoders/hex"
"next.orly.dev/pkg/encoders/kind"
"next.orly.dev/pkg/encoders/tag"
)
// TestPolicyIntegration runs the relay with policy enabled and tests event filtering
func TestPolicyIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Generate test keys
allowedSigner := &p256k.Signer{}
if err := allowedSigner.Generate(); chk.E(err) {
t.Fatalf("Failed to generate allowed signer: %v", err)
}
allowedPubkeyHex := hex.Enc(allowedSigner.Pub())
unauthorizedSigner := &p256k.Signer{}
if err := unauthorizedSigner.Generate(); chk.E(err) {
t.Fatalf("Failed to generate unauthorized signer: %v", err)
}
// Create temporary directory for policy config
tempDir := t.TempDir()
configDir := filepath.Join(tempDir, "ORLY_TEST")
if err := os.MkdirAll(configDir, 0755); chk.E(err) {
t.Fatalf("Failed to create config directory: %v", err)
}
// Create policy JSON with generated keys
policyJSON := map[string]interface{}{
"kind": map[string]interface{}{
"whitelist": []int{4678, 10306, 30520, 30919},
},
"rules": map[string]interface{}{
"4678": map[string]interface{}{
"description": "Zenotp message events",
"script": filepath.Join(configDir, "validate4678.js"), // Won't exist, should fall back to default
"privileged": true,
},
"10306": map[string]interface{}{
"description": "End user whitelist changes",
"read_allow": []string{allowedPubkeyHex},
"privileged": true,
},
"30520": map[string]interface{}{
"description": "Zenotp events",
"write_allow": []string{allowedPubkeyHex},
"privileged": true,
},
"30919": map[string]interface{}{
"description": "Zenotp events",
"write_allow": []string{allowedPubkeyHex},
"privileged": true,
},
},
}
policyJSONBytes, err := json.MarshalIndent(policyJSON, "", " ")
if err != nil {
t.Fatalf("Failed to marshal policy JSON: %v", err)
}
policyPath := filepath.Join(configDir, "policy.json")
if err := os.WriteFile(policyPath, policyJSONBytes, 0644); chk.E(err) {
t.Fatalf("Failed to write policy file: %v", err)
}
// Create events with proper signatures
// Event 1: Kind 30520 with allowed pubkey (should be allowed)
event30520Allowed := event.New()
event30520Allowed.CreatedAt = time.Now().Unix()
event30520Allowed.Kind = kind.K{K: 30520}.K
event30520Allowed.Content = []byte("test event 30520")
event30520Allowed.Tags = tag.NewS()
addPTag(event30520Allowed, allowedSigner.Pub()) // Add p tag for privileged check
if err := event30520Allowed.Sign(allowedSigner); chk.E(err) {
t.Fatalf("Failed to sign event30520Allowed: %v", err)
}
// Event 2: Kind 30520 with unauthorized pubkey (should be denied)
event30520Unauthorized := event.New()
event30520Unauthorized.CreatedAt = time.Now().Unix()
event30520Unauthorized.Kind = kind.K{K: 30520}.K
event30520Unauthorized.Content = []byte("test event 30520 unauthorized")
event30520Unauthorized.Tags = tag.NewS()
if err := event30520Unauthorized.Sign(unauthorizedSigner); chk.E(err) {
t.Fatalf("Failed to sign event30520Unauthorized: %v", err)
}
// Event 3: Kind 10306 with allowed pubkey (should be readable by allowed user)
event10306Allowed := event.New()
event10306Allowed.CreatedAt = time.Now().Unix()
event10306Allowed.Kind = kind.K{K: 10306}.K
event10306Allowed.Content = []byte("test event 10306")
event10306Allowed.Tags = tag.NewS()
addPTag(event10306Allowed, allowedSigner.Pub()) // Add p tag for privileged check
if err := event10306Allowed.Sign(allowedSigner); chk.E(err) {
t.Fatalf("Failed to sign event10306Allowed: %v", err)
}
// Event 4: Kind 4678 with allowed pubkey (script-based, should fall back to default)
event4678Allowed := event.New()
event4678Allowed.CreatedAt = time.Now().Unix()
event4678Allowed.Kind = kind.K{K: 4678}.K
event4678Allowed.Content = []byte("test event 4678")
event4678Allowed.Tags = tag.NewS()
addPTag(event4678Allowed, allowedSigner.Pub()) // Add p tag for privileged check
if err := event4678Allowed.Sign(allowedSigner); chk.E(err) {
t.Fatalf("Failed to sign event4678Allowed: %v", err)
}
// Test policy loading
policy, err := New(policyJSONBytes)
if err != nil {
t.Fatalf("Failed to create policy: %v", err)
}
// Verify policy loaded correctly
if len(policy.Rules) != 4 {
t.Errorf("Expected 4 rules, got %d", len(policy.Rules))
}
// Test policy checks directly
t.Run("policy checks", func(t *testing.T) {
// Test 1: Event 30520 with allowed pubkey should be allowed
allowed, err := policy.CheckPolicy("write", event30520Allowed, allowedSigner.Pub(), "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event30520Allowed to be allowed")
}
// Test 2: Event 30520 with unauthorized pubkey should be denied
allowed, err = policy.CheckPolicy("write", event30520Unauthorized, unauthorizedSigner.Pub(), "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event30520Unauthorized to be denied")
}
// Test 3: Event 10306 should be readable by allowed user
allowed, err = policy.CheckPolicy("read", event10306Allowed, allowedSigner.Pub(), "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event10306Allowed to be readable by allowed user")
}
// Test 4: Event 10306 should NOT be readable by unauthorized user
allowed, err = policy.CheckPolicy("read", event10306Allowed, unauthorizedSigner.Pub(), "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event10306Allowed to be denied for unauthorized user")
}
// Test 5: Event 10306 should NOT be readable without authentication
allowed, err = policy.CheckPolicy("read", event10306Allowed, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event10306Allowed to be denied without authentication (privileged)")
}
// Test 6: Event 30520 should NOT be writable without authentication
allowed, err = policy.CheckPolicy("write", event30520Allowed, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event30520Allowed to be denied without authentication (privileged)")
}
// Test 7: Event 4678 should fall back to default policy (allow) when script not running
allowed, err = policy.CheckPolicy("write", event4678Allowed, allowedSigner.Pub(), "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event4678Allowed to be allowed when script not running (falls back to default)")
}
// Test 8: Event 4678 should be denied without authentication (privileged check)
allowed, err = policy.CheckPolicy("write", event4678Allowed, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event4678Allowed to be denied without authentication (privileged)")
}
})
// Test with relay simulation (checking log output)
t.Run("relay simulation", func(t *testing.T) {
// Note: We can't easily capture log output in tests, so we just verify
// that policy checks work correctly
// Simulate policy checks that would happen in relay
// First, publish events (simulate write checks)
checks := []struct {
name string
event *event.E
loggedInPubkey []byte
access string
shouldAllow bool
shouldLog string // Expected log message substring, empty means no specific log expected
}{
{
name: "write 30520 with allowed pubkey",
event: event30520Allowed,
loggedInPubkey: allowedSigner.Pub(),
access: "write",
shouldAllow: true,
},
{
name: "write 30520 with unauthorized pubkey",
event: event30520Unauthorized,
loggedInPubkey: unauthorizedSigner.Pub(),
access: "write",
shouldAllow: false,
},
{
name: "read 10306 with allowed pubkey",
event: event10306Allowed,
loggedInPubkey: allowedSigner.Pub(),
access: "read",
shouldAllow: true,
},
{
name: "read 10306 with unauthorized pubkey",
event: event10306Allowed,
loggedInPubkey: unauthorizedSigner.Pub(),
access: "read",
shouldAllow: false,
},
{
name: "read 10306 without authentication",
event: event10306Allowed,
loggedInPubkey: nil,
access: "read",
shouldAllow: false,
},
{
name: "write 30520 without authentication",
event: event30520Allowed,
loggedInPubkey: nil,
access: "write",
shouldAllow: false,
},
{
name: "write 4678 with allowed pubkey",
event: event4678Allowed,
loggedInPubkey: allowedSigner.Pub(),
access: "write",
shouldAllow: true,
shouldLog: "", // Should not log "policy rule is inactive" if script is not configured
},
}
for _, check := range checks {
t.Run(check.name, func(t *testing.T) {
allowed, err := policy.CheckPolicy(check.access, check.event, check.loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
if allowed != check.shouldAllow {
t.Errorf("Expected allowed=%v, got %v", check.shouldAllow, allowed)
}
})
}
})
// Test event IDs are regenerated correctly after signing
t.Run("event ID regeneration", func(t *testing.T) {
// Create a new event, sign it, then verify ID is correct
testEvent := event.New()
testEvent.CreatedAt = time.Now().Unix()
testEvent.Kind = kind.K{K: 30520}.K
testEvent.Content = []byte("test content")
testEvent.Tags = tag.NewS()
// Sign the event
if err := testEvent.Sign(allowedSigner); chk.E(err) {
t.Fatalf("Failed to sign test event: %v", err)
}
// Verify event ID is correct (should be SHA256 of serialized event)
if len(testEvent.ID) != 32 {
t.Errorf("Expected event ID to be 32 bytes, got %d", len(testEvent.ID))
}
// Verify signature is correct
if len(testEvent.Sig) != 64 {
t.Errorf("Expected event signature to be 64 bytes, got %d", len(testEvent.Sig))
}
// Verify signature validates using event's Verify method
valid, err := testEvent.Verify()
if err != nil {
t.Errorf("Failed to verify signature: %v", err)
}
if !valid {
t.Error("Event signature verification failed")
}
})
// Test WebSocket client simulation (for future integration)
t.Run("websocket client simulation", func(t *testing.T) {
// This test simulates what would happen if we connected via WebSocket
// For now, we'll just verify the events can be serialized correctly
events := []*event.E{
event30520Allowed,
event30520Unauthorized,
event10306Allowed,
event4678Allowed,
}
for i, ev := range events {
t.Run(fmt.Sprintf("event_%d", i), func(t *testing.T) {
// Serialize event
serialized := ev.Serialize()
if len(serialized) == 0 {
t.Error("Event serialization returned empty")
}
// Verify event can be parsed back (simplified check)
if len(ev.ID) != 32 {
t.Errorf("Event ID length incorrect: %d", len(ev.ID))
}
if len(ev.Pubkey) != 32 {
t.Errorf("Event pubkey length incorrect: %d", len(ev.Pubkey))
}
if len(ev.Sig) != 64 {
t.Errorf("Event signature length incorrect: %d", len(ev.Sig))
}
})
}
})
}
// TestPolicyWithRelay creates a comprehensive test that simulates relay behavior
func TestPolicyWithRelay(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
// Generate keys
allowedSigner := &p256k.Signer{}
if err := allowedSigner.Generate(); chk.E(err) {
t.Fatalf("Failed to generate allowed signer: %v", err)
}
allowedPubkeyHex := hex.Enc(allowedSigner.Pub())
unauthorizedSigner := &p256k.Signer{}
if err := unauthorizedSigner.Generate(); chk.E(err) {
t.Fatalf("Failed to generate unauthorized signer: %v", err)
}
// Create policy JSON
policyJSON := map[string]interface{}{
"kind": map[string]interface{}{
"whitelist": []int{4678, 10306, 30520, 30919},
},
"rules": map[string]interface{}{
"10306": map[string]interface{}{
"description": "End user whitelist changes",
"read_allow": []string{allowedPubkeyHex},
"privileged": true,
},
"30520": map[string]interface{}{
"description": "Zenotp events",
"write_allow": []string{allowedPubkeyHex},
"privileged": true,
},
"30919": map[string]interface{}{
"description": "Zenotp events",
"write_allow": []string{allowedPubkeyHex},
"privileged": true,
},
},
}
policyJSONBytes, err := json.Marshal(policyJSON)
if err != nil {
t.Fatalf("Failed to marshal policy JSON: %v", err)
}
policy, err := New(policyJSONBytes)
if err != nil {
t.Fatalf("Failed to create policy: %v", err)
}
// Create test event (kind 30520) with allowed pubkey
testEvent := event.New()
testEvent.CreatedAt = time.Now().Unix()
testEvent.Kind = kind.K{K: 30520}.K
testEvent.Content = []byte("test content")
testEvent.Tags = tag.NewS()
addPTag(testEvent, allowedSigner.Pub())
if err := testEvent.Sign(allowedSigner); chk.E(err) {
t.Fatalf("Failed to sign test event: %v", err)
}
// Test scenarios
scenarios := []struct {
name string
loggedInPubkey []byte
expectedResult bool
description string
}{
{
name: "authenticated as allowed pubkey",
loggedInPubkey: allowedSigner.Pub(),
expectedResult: true,
description: "Should allow when authenticated as allowed pubkey",
},
{
name: "unauthenticated",
loggedInPubkey: nil,
expectedResult: false,
description: "Should deny when not authenticated (privileged check)",
},
{
name: "authenticated as different pubkey",
loggedInPubkey: unauthorizedSigner.Pub(),
expectedResult: false,
description: "Should deny when authenticated as different pubkey",
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
allowed, err := policy.CheckPolicy("write", testEvent, scenario.loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
if allowed != scenario.expectedResult {
t.Errorf("%s: Expected allowed=%v, got %v", scenario.description, scenario.expectedResult, allowed)
}
})
}
// Test read access for kind 10306
readEvent := event.New()
readEvent.CreatedAt = time.Now().Unix()
readEvent.Kind = kind.K{K: 10306}.K
readEvent.Content = []byte("test read event")
readEvent.Tags = tag.NewS()
addPTag(readEvent, allowedSigner.Pub())
if err := readEvent.Sign(allowedSigner); chk.E(err) {
t.Fatalf("Failed to sign read event: %v", err)
}
readScenarios := []struct {
name string
loggedInPubkey []byte
expectedResult bool
description string
}{
{
name: "read authenticated as allowed pubkey",
loggedInPubkey: allowedSigner.Pub(),
expectedResult: true,
description: "Should allow read when authenticated as allowed pubkey",
},
{
name: "read unauthenticated",
loggedInPubkey: nil,
expectedResult: false,
description: "Should deny read when not authenticated (privileged check)",
},
{
name: "read authenticated as different pubkey",
loggedInPubkey: unauthorizedSigner.Pub(),
expectedResult: false,
description: "Should deny read when authenticated as different pubkey",
},
}
for _, scenario := range readScenarios {
t.Run(scenario.name, func(t *testing.T) {
allowed, err := policy.CheckPolicy("read", readEvent, scenario.loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}
if allowed != scenario.expectedResult {
t.Errorf("%s: Expected allowed=%v, got %v", scenario.description, scenario.expectedResult, allowed)
}
})
}
}

View File

@@ -1495,3 +1495,363 @@ func TestDefaultPolicyLogicWithRules(t *testing.T) {
t.Error("Expected kind 2 to be allowed (no rule, default policy is allow)")
}
}
func TestPolicyFilterProcessing(t *testing.T) {
// Test policy filter processing using the provided filter JSON specification
filterJSON := []byte(`{
"kind": {
"whitelist": [4678, 10306, 30520, 30919]
},
"rules": {
"4678": {
"description": "Zenotp message events",
"script": "/home/orly/.config/ORLY/validate4678.js",
"privileged": true
},
"10306": {
"description": "End user whitelist changes",
"read_allow": [
"04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
],
"privileged": true
},
"30520": {
"description": "Zenotp events",
"write_allow": [
"04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
],
"privileged": true
},
"30919": {
"description": "Zenotp events",
"write_allow": [
"04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
],
"privileged": true
}
}
}`)
// Create policy from JSON
policy, err := New(filterJSON)
if err != nil {
t.Fatalf("Failed to create policy from JSON: %v", err)
}
// Verify whitelist is set correctly
if len(policy.Kind.Whitelist) != 4 {
t.Errorf("Expected whitelist to have 4 kinds, got %d", len(policy.Kind.Whitelist))
}
expectedKinds := map[int]bool{4678: true, 10306: true, 30520: true, 30919: true}
for _, kind := range policy.Kind.Whitelist {
if !expectedKinds[kind] {
t.Errorf("Unexpected kind in whitelist: %d", kind)
}
}
// Verify rules are loaded correctly
if len(policy.Rules) != 4 {
t.Errorf("Expected 4 rules, got %d", len(policy.Rules))
}
// Verify rule 4678 (script-based)
rule4678, ok := policy.Rules[4678]
if !ok {
t.Fatal("Rule 4678 not found")
}
if rule4678.Description != "Zenotp message events" {
t.Errorf("Expected description 'Zenotp message events', got '%s'", rule4678.Description)
}
if rule4678.Script != "/home/orly/.config/ORLY/validate4678.js" {
t.Errorf("Expected script path '/home/orly/.config/ORLY/validate4678.js', got '%s'", rule4678.Script)
}
if !rule4678.Privileged {
t.Error("Expected rule 4678 to be privileged")
}
// Verify rule 10306 (read_allow)
rule10306, ok := policy.Rules[10306]
if !ok {
t.Fatal("Rule 10306 not found")
}
if rule10306.Description != "End user whitelist changes" {
t.Errorf("Expected description 'End user whitelist changes', got '%s'", rule10306.Description)
}
if len(rule10306.ReadAllow) != 1 {
t.Errorf("Expected 1 read_allow pubkey, got %d", len(rule10306.ReadAllow))
}
if rule10306.ReadAllow[0] != "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5" {
t.Errorf("Expected read_allow pubkey '04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5', got '%s'", rule10306.ReadAllow[0])
}
if !rule10306.Privileged {
t.Error("Expected rule 10306 to be privileged")
}
// Verify rule 30520 (write_allow)
rule30520, ok := policy.Rules[30520]
if !ok {
t.Fatal("Rule 30520 not found")
}
if rule30520.Description != "Zenotp events" {
t.Errorf("Expected description 'Zenotp events', got '%s'", rule30520.Description)
}
if len(rule30520.WriteAllow) != 1 {
t.Errorf("Expected 1 write_allow pubkey, got %d", len(rule30520.WriteAllow))
}
if rule30520.WriteAllow[0] != "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5" {
t.Errorf("Expected write_allow pubkey '04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5', got '%s'", rule30520.WriteAllow[0])
}
if !rule30520.Privileged {
t.Error("Expected rule 30520 to be privileged")
}
// Verify rule 30919 (write_allow)
rule30919, ok := policy.Rules[30919]
if !ok {
t.Fatal("Rule 30919 not found")
}
if rule30919.Description != "Zenotp events" {
t.Errorf("Expected description 'Zenotp events', got '%s'", rule30919.Description)
}
if len(rule30919.WriteAllow) != 1 {
t.Errorf("Expected 1 write_allow pubkey, got %d", len(rule30919.WriteAllow))
}
if rule30919.WriteAllow[0] != "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5" {
t.Errorf("Expected write_allow pubkey '04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5', got '%s'", rule30919.WriteAllow[0])
}
if !rule30919.Privileged {
t.Error("Expected rule 30919 to be privileged")
}
// Test kind whitelist filtering
t.Run("kind whitelist filtering", func(t *testing.T) {
eventSigner, eventPubkey := generateTestKeypair(t)
_, loggedInPubkey := generateTestKeypair(t)
// Test whitelisted kind (should pass kind check, but may fail other checks)
whitelistedEvent := createTestEvent(t, eventSigner, "test content", 4678)
addPTag(whitelistedEvent, loggedInPubkey)
allowed, err := policy.CheckPolicy("write", whitelistedEvent, loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// Should be allowed because script isn't running (falls back to default "allow")
// and privileged check passes (loggedInPubkey is in p tag)
if !allowed {
t.Error("Expected whitelisted kind to be allowed when script not running and privileged check passes")
}
// Test non-whitelisted kind (should be denied)
nonWhitelistedEvent := createTestEvent(t, eventSigner, "test content", 1)
allowed, err = policy.CheckPolicy("write", nonWhitelistedEvent, eventPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected non-whitelisted kind to be denied")
}
})
// Test read access for kind 10306
t.Run("read access for kind 10306", func(t *testing.T) {
allowedPubkeyHex := "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
allowedPubkeyBytes, err := hex.Dec(allowedPubkeyHex)
if err != nil {
t.Fatalf("Failed to decode allowed pubkey: %v", err)
}
// Create event with allowed pubkey using a temporary signer
// Note: We can't actually sign with just the pubkey, so we'll create the event
// with a random signer and then manually set the pubkey for testing
tempSigner, _ := generateTestKeypair(t)
event10306 := createTestEvent(t, tempSigner, "test content", 10306)
event10306.Pubkey = allowedPubkeyBytes
// Re-sign won't work without private key, but policy checks use the pubkey field
// So we'll test with the pubkey set correctly
// Test read access with allowed pubkey (logged in user matches event pubkey)
allowed, err := policy.CheckPolicy("read", event10306, allowedPubkeyBytes, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event to be allowed for read access with allowed pubkey")
}
// Test read access with non-allowed pubkey
_, unauthorizedPubkey := generateTestKeypair(t)
allowed, err = policy.CheckPolicy("read", event10306, unauthorizedPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied for read access with non-allowed pubkey")
}
// Test read access without authentication (privileged check)
allowed, err = policy.CheckPolicy("read", event10306, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied for read access without authentication (privileged)")
}
})
// Test write access for kind 30520
t.Run("write access for kind 30520", func(t *testing.T) {
allowedPubkeyHex := "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
allowedPubkeyBytes, err := hex.Dec(allowedPubkeyHex)
if err != nil {
t.Fatalf("Failed to decode allowed pubkey: %v", err)
}
// Create event with allowed pubkey using a temporary signer
// We'll set the pubkey manually for testing since we don't have the private key
tempSigner, _ := generateTestKeypair(t)
event30520 := createTestEvent(t, tempSigner, "test content", 30520)
event30520.Pubkey = allowedPubkeyBytes
// Test write access with allowed pubkey (event pubkey matches write_allow)
allowed, err := policy.CheckPolicy("write", event30520, allowedPubkeyBytes, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event to be allowed for write access with allowed pubkey")
}
// Test write access with non-allowed pubkey
unauthorizedSigner, unauthorizedPubkey := generateTestKeypair(t)
unauthorizedEvent := createTestEvent(t, unauthorizedSigner, "test content", 30520)
allowed, err = policy.CheckPolicy("write", unauthorizedEvent, unauthorizedPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied for write access with non-allowed pubkey")
}
// Test write access without authentication (privileged check)
allowed, err = policy.CheckPolicy("write", event30520, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied for write access without authentication (privileged)")
}
})
// Test write access for kind 30919
t.Run("write access for kind 30919", func(t *testing.T) {
allowedPubkeyHex := "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
allowedPubkeyBytes, err := hex.Dec(allowedPubkeyHex)
if err != nil {
t.Fatalf("Failed to decode allowed pubkey: %v", err)
}
// Create event with allowed pubkey using a temporary signer
// We'll set the pubkey manually for testing since we don't have the private key
tempSigner, _ := generateTestKeypair(t)
event30919 := createTestEvent(t, tempSigner, "test content", 30919)
event30919.Pubkey = allowedPubkeyBytes
// Test write access with allowed pubkey (event pubkey matches write_allow)
allowed, err := policy.CheckPolicy("write", event30919, allowedPubkeyBytes, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event to be allowed for write access with allowed pubkey")
}
// Test write access with non-allowed pubkey
unauthorizedSigner, unauthorizedPubkey := generateTestKeypair(t)
unauthorizedEvent := createTestEvent(t, unauthorizedSigner, "test content", 30919)
allowed, err = policy.CheckPolicy("write", unauthorizedEvent, unauthorizedPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied for write access with non-allowed pubkey")
}
// Test write access without authentication (privileged check)
allowed, err = policy.CheckPolicy("write", event30919, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied for write access without authentication (privileged)")
}
})
// Test privileged flag behavior with p tags
t.Run("privileged flag with p tags", func(t *testing.T) {
eventSigner, _ := generateTestKeypair(t)
_, loggedInPubkey := generateTestKeypair(t)
allowedPubkeyHex := "04eeb1ed409c0b9205e722f8bf1780f553b61876ef323aff16c9f80a9d8ee9f5"
allowedPubkeyBytes, err := hex.Dec(allowedPubkeyHex)
if err != nil {
t.Fatalf("Failed to decode allowed pubkey: %v", err)
}
// Create event with allowed pubkey and logged-in pubkey in p tag
event30520 := createTestEvent(t, eventSigner, "test content", 30520)
event30520.Pubkey = allowedPubkeyBytes
addPTag(event30520, loggedInPubkey)
// Test that event is allowed when logged-in pubkey is in p tag (privileged)
// and event pubkey matches write_allow
allowed, err := policy.CheckPolicy("write", event30520, loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !allowed {
t.Error("Expected event to be allowed when event pubkey matches write_allow and logged-in pubkey is in p tag")
}
// Test that event is denied when logged-in pubkey is not in p tag and doesn't match event pubkey
event30520NoPTag := createTestEvent(t, eventSigner, "test content", 30520)
event30520NoPTag.Pubkey = allowedPubkeyBytes
allowed, err = policy.CheckPolicy("write", event30520NoPTag, loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if allowed {
t.Error("Expected event to be denied when logged-in pubkey is not in p tag (privileged check fails)")
}
})
// Test script-based rule (kind 4678)
t.Run("script-based rule for kind 4678", func(t *testing.T) {
eventSigner, _ := generateTestKeypair(t)
_, loggedInPubkey := generateTestKeypair(t)
event4678 := createTestEvent(t, eventSigner, "test content", 4678)
addPTag(event4678, loggedInPubkey)
// Test with script not running (should fall back to default policy)
allowed, err := policy.CheckPolicy("write", event4678, loggedInPubkey, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// Should allow because default policy is "allow" and script is not running
// and privileged check passes (loggedInPubkey is in p tag)
if !allowed {
t.Error("Expected event to be allowed when script is not running (falls back to default 'allow') and privileged check passes")
}
// Test without authentication (privileged check should fail)
allowed, err = policy.CheckPolicy("write", event4678, nil, "127.0.0.1")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// Should be denied because privileged check fails without authentication
// The privileged check happens in checkRulePolicy before script check
// So it should be denied even though script is not running
if allowed {
t.Error("Expected event to be denied without authentication (privileged check)")
}
})
}

View File

@@ -1 +1 @@
v0.20.0
v0.20.2

198
scripts/run-policy-filter-test.sh Executable file
View File

@@ -0,0 +1,198 @@
#!/bin/bash
set -euo pipefail
# Policy Filter Integration Test
# This script runs the relay with the example policy and tests event filtering
# Config
PORT=${PORT:-34568}
URL=${URL:-ws://127.0.0.1:${PORT}}
LOG=/tmp/orly-policy-filter.out
PID=/tmp/orly-policy-filter.pid
DATADIR=$(mktemp -d)
CONFIG_DIR="$HOME/.config/ORLY_POLICY_TEST"
cleanup() {
trap - EXIT
if [[ -f "$PID" ]]; then
kill -INT "$(cat "$PID")" 2>/dev/null || true
rm -f "$PID"
fi
rm -rf "$DATADIR"
rm -rf "$CONFIG_DIR"
}
trap cleanup EXIT
echo "🧪 Policy Filter Integration Test"
echo "=================================="
# Create config directory
mkdir -p "$CONFIG_DIR"
# Generate keys using Go helper
echo "🔑 Generating test keys..."
KEYGEN_TMP=$(mktemp)
cat > "$KEYGEN_TMP.go" <<'EOF'
package main
import (
"encoding/json"
"fmt"
"next.orly.dev/pkg/crypto/p256k"
"next.orly.dev/pkg/encoders/hex"
)
func main() {
// Generate allowed signer
allowedSigner := &p256k.Signer{}
if err := allowedSigner.Generate(); err != nil {
panic(err)
}
allowedPubkeyHex := hex.Enc(allowedSigner.Pub())
allowedSecHex := hex.Enc(allowedSigner.Sec())
// Generate unauthorized signer
unauthorizedSigner := &p256k.Signer{}
if err := unauthorizedSigner.Generate(); err != nil {
panic(err)
}
unauthorizedPubkeyHex := hex.Enc(unauthorizedSigner.Pub())
unauthorizedSecHex := hex.Enc(unauthorizedSigner.Sec())
result := map[string]string{
"allowedPubkey": allowedPubkeyHex,
"allowedSec": allowedSecHex,
"unauthorizedPubkey": unauthorizedPubkeyHex,
"unauthorizedSec": unauthorizedSecHex,
}
jsonBytes, _ := json.Marshal(result)
fmt.Println(string(jsonBytes))
}
EOF
# Run from the project root directory
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$PROJECT_ROOT"
KEYS=$(go run -tags=cgo "$KEYGEN_TMP.go" 2>&1 | grep -E '^\{.*\}$' || true)
rm -f "$KEYGEN_TMP.go"
cd - > /dev/null
ALLOWED_PUBKEY=$(echo "$KEYS" | jq -r '.allowedPubkey')
ALLOWED_SEC=$(echo "$KEYS" | jq -r '.allowedSec')
UNAUTHORIZED_PUBKEY=$(echo "$KEYS" | jq -r '.unauthorizedPubkey')
UNAUTHORIZED_SEC=$(echo "$KEYS" | jq -r '.unauthorizedSec')
echo "✅ Generated keys:"
echo " Allowed pubkey: $ALLOWED_PUBKEY"
echo " Unauthorized pubkey: $UNAUTHORIZED_PUBKEY"
# Create policy JSON with generated keys
echo "📝 Creating policy.json..."
cat > "$CONFIG_DIR/policy.json" <<EOF
{
"kind": {
"whitelist": [4678, 10306, 30520, 30919]
},
"rules": {
"4678": {
"description": "Zenotp message events",
"script": "$CONFIG_DIR/validate4678.js",
"privileged": true
},
"10306": {
"description": "End user whitelist changes",
"read_allow": [
"$ALLOWED_PUBKEY"
],
"privileged": true
},
"30520": {
"description": "Zenotp events",
"write_allow": [
"$ALLOWED_PUBKEY"
],
"privileged": true
},
"30919": {
"description": "Zenotp events",
"write_allow": [
"$ALLOWED_PUBKEY"
],
"privileged": true
}
}
}
EOF
echo "✅ Policy file created at: $CONFIG_DIR/policy.json"
# Build relay and test client
echo "🔨 Building relay..."
go build -o orly .
# Start relay
echo "🚀 Starting relay on ${URL} with policy enabled..."
ORLY_APP_NAME="ORLY_POLICY_TEST" \
ORLY_DATA_DIR="$DATADIR" \
ORLY_PORT=${PORT} \
ORLY_POLICY_ENABLED=true \
ORLY_ACL_MODE=none \
ORLY_AUTH_TO_WRITE=true \
ORLY_LOG_LEVEL=info \
./orly >"$LOG" 2>&1 & echo $! >"$PID"
# Wait for relay to start
sleep 3
if ! ps -p "$(cat "$PID")" >/dev/null 2>&1; then
echo "❌ Relay failed to start; logs:" >&2
sed -n '1,200p' "$LOG" >&2
exit 1
fi
echo "✅ Relay started (PID: $(cat "$PID"))"
# Build test client
echo "🔨 Building test client..."
go build -o cmd/policyfiltertest/policyfiltertest ./cmd/policyfiltertest
# Export keys for test client
export ALLOWED_PUBKEY
export ALLOWED_SEC
export UNAUTHORIZED_PUBKEY
export UNAUTHORIZED_SEC
# Run tests
echo "🧪 Running policy filter tests..."
set +e
cmd/policyfiltertest/policyfiltertest -url "${URL}" -allowed-pubkey "$ALLOWED_PUBKEY" -allowed-sec "$ALLOWED_SEC" -unauthorized-pubkey "$UNAUTHORIZED_PUBKEY" -unauthorized-sec "$UNAUTHORIZED_SEC"
TEST_RESULT=$?
set -e
# Check logs for "policy rule is inactive" messages
echo "📋 Checking logs for policy rule inactivity..."
if grep -q "policy rule is inactive" "$LOG"; then
echo "⚠️ WARNING: Found 'policy rule is inactive' messages in logs"
grep "policy rule is inactive" "$LOG" | head -5
else
echo "✅ No 'policy rule is inactive' messages found (good)"
fi
# Check logs for policy filtered events
echo "📋 Checking logs for policy filtered events..."
if grep -q "policy filtered out event" "$LOG"; then
echo "✅ Found policy filtered events (expected):"
grep "policy filtered out event" "$LOG" | head -5
fi
if [ $TEST_RESULT -eq 0 ]; then
echo "✅ All tests passed!"
exit 0
else
echo "❌ Tests failed with exit code $TEST_RESULT"
echo "📋 Last 50 lines of relay log:"
tail -50 "$LOG"
exit $TEST_RESULT
fi

Submodule scripts/secp256k1 deleted from 0cdc758a56

0
scripts/sprocket/SPROCKET_TEST_README.md Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-complete.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-demo.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-example.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-final.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-manual.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-simple.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket-working.sh Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket.py Normal file → Executable file
View File

0
scripts/sprocket/test-sprocket.sh Normal file → Executable file
View File