From e947e6d3f49f2292ba3262de9a4fe5eb3aecf43b Mon Sep 17 00:00:00 2001 From: Siddharth Singh Date: Wed, 7 May 2025 08:49:21 +0530 Subject: [PATCH] add more tests for policy edge cases --- fixtures/policy.ts | 2 +- packages/ditto/workers/policy.test.ts | 114 +++++++++++++++++++------- 2 files changed, 87 insertions(+), 29 deletions(-) diff --git a/fixtures/policy.ts b/fixtures/policy.ts index b893fe48..e405084d 100644 --- a/fixtures/policy.ts +++ b/fixtures/policy.ts @@ -3,7 +3,7 @@ import { HashtagPolicy } from '@nostrify/policies'; export default class TestPolicy implements NPolicy { call(event: NostrEvent): Promise { - return new HashtagPolicy(['other-blocked-tag']).call(event); + return new HashtagPolicy(['potato']).call(event); } info?: NostrRelayInfo | undefined; } diff --git a/packages/ditto/workers/policy.test.ts b/packages/ditto/workers/policy.test.ts index c6c42a7c..00e7ae98 100644 --- a/packages/ditto/workers/policy.test.ts +++ b/packages/ditto/workers/policy.test.ts @@ -1,45 +1,103 @@ import { DittoConf } from '@ditto/conf'; import { generateSecretKey, nip19 } from 'nostr-tools'; - import { PolicyWorker } from '@/workers/policy.ts'; -import { assertEquals } from '@std/assert/assert-equals'; +import { assert, assertEquals } from '@std/assert'; import { join } from '@std/path'; +import { createPolicyEvent } from '../utils/policies/mod.ts'; +import { createTestDB } from '../test.ts'; const blocked = { id: '19afd70437944671e7f5a02b29221ad444ef7cf60113a5731667e272e59a3979', pubkey: '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', kind: 1, - tags: [['t', 'porn'], ['t', 'other-blocked-tag']], + tags: [['t', 'potato'], ['t', 'tomato']], content: 'this is a test of the policy system', sig: '1d73a7480cfd737b89dc1e0e7175dff67119915f31d24a279a45d56622f4b991b01e431d07b693ee6cd652f3f27274d9e203ee43ae44af7e70ce8647e5326196', created_at: 1743685015, }; -Deno.test('PolicyWorker with script policy', async () => { - const conf = new DittoConf( - new Map([ - ['DITTO_NSEC', nip19.nsecEncode(generateSecretKey())], - ['DATABASE_URL', Deno.env.get('DATABASE_URL')], - ['DITTO_POLICY', join(Deno.cwd(), 'fixtures', 'policy.ts')], - ]), - ); +Deno.test('Tests for policy workers', async (t) => { + const nsec = nip19.nsecEncode(generateSecretKey()); + const env = new Map([ + ['DITTO_NSEC', nsec], + ['DATABASE_URL', Deno.env.get('DATABASE_URL')], + ]); - const worker = new PolicyWorker(conf); - const [, , ok] = await worker.call(blocked); - assertEquals(ok, false); -}); - -Deno.test('PolicyWorker with event policy', async () => { - const conf = new DittoConf( - new Map([ - ['DITTO_NSEC', nip19.nsecEncode(generateSecretKey())], - ['DATABASE_URL', Deno.env.get('DATABASE_URL')], - ]), - ); - - const worker = new PolicyWorker(conf); - const [, , ok] = await worker.call(blocked); - - assertEquals(ok, false); + await using db = await createTestDB(); + + async function clearPolicyEvents() { + await db.store.remove([{ kinds: [11984] }]); + } + await clearPolicyEvents(); + + await t.step('No DITTO_POLICY, no event-based policy (default allow)', async () => { + await clearPolicyEvents(); + const conf = new DittoConf(env); + + const worker = new PolicyWorker(conf); + const [, , ok] = await worker.call(blocked); + + assertEquals(ok, true, 'Should not block anything in default config'); + }); + + // Edge 2: No DITTO_POLICY, valid event-based policy (blocks "tomato") + await t.step('No DITTO_POLICY, valid event-based policy (blocks "tomato")', async () => { + await clearPolicyEvents(); + const conf = new DittoConf(env); + + await db.store.event( + await createPolicyEvent(conf, { + policies: [ + { 'name': 'HashtagPolicy', 'params': { 'hashtags': ['tomato'] } }, + ], + }), + ); + + using worker = new PolicyWorker(conf); + const [, , ok] = await worker.call(blocked); + + assert(!ok, 'Event policy should block events with #tomato'); + }); + + // Edge 3: DITTO_POLICY set but policy script is missing (should fallback) + await t.step('DITTO_POLICY set but file is missing (should fallback)', async () => { + await clearPolicyEvents(); + + const thisEnv = new Map([...env, ['DITTO_POLICY', 'not-a-policy.ts']]); + const conf = new DittoConf(thisEnv); + + using worker = new PolicyWorker(conf); + const [, , ok] = await worker.call(blocked); + + assertEquals( + ok, + true, + 'Missing script policy should fall back to allowing (default policy)', + ); + }); + + await t.step('Both DITTO_POLICY and event policy', async () => { + await clearPolicyEvents(); + + const policyScriptPath = join(Deno.cwd(), 'fixtures', 'policy.ts'); + const thisEnv = new Map([...env, ['DITTO_POLICY', policyScriptPath]]); + const conf = new DittoConf(thisEnv); + + await db.store.event( + await createPolicyEvent(conf, { + policies: [ + { 'name': 'HashtagPolicy', 'params': { 'hashtags': ['tomato'] } }, + ], + }), + ); + + using worker = new PolicyWorker(conf); + const [, , ok] = await worker.call(blocked); + + assert( + !ok, + 'Both script and event-based policy are present: event should be blocked if either blocks', + ); + }); });