/** * Test reachability integration with all rule types */ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { BigGraphGenerator } from '../helpers/big-graph-generator.js'; import { ChainRule } from '../../src/authorization/rules/ChainRule.js'; import { DirectRule } from '../../src/authorization/rules/DirectRule.js'; import { MultiHopRule } from '../../src/authorization/rules/MultiHopRule.js'; test('verifies all rules can use quick reachability failure checks', async () => { if (process.env.TEST_DEBUG === '1') console.log('🔍 Testing reachability integration with all rule types...'); const generator = new BigGraphGenerator(); const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker await arbiter.initializeReachabilityChecker({ strategy: 'auto', twoHopOptions: { remainderBits: 8 }, treeCoverOptions: { remainderBits: 8 } }); if (process.env.TEST_DEBUG === '1') console.log(' ✅ Reachability checker initialized'); // Test with different rule types const ruleTypes = [ { name: 'ChainRule', rule: new ChainRule(arbiter) }, { name: 'DirectRule', rule: new DirectRule(arbiter) }, { name: 'MultiHopRule', rule: new MultiHopRule(arbiter) } ]; const testRelations = graphData.relations.filter(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') ).slice(0, 3); for (const { name, rule } of ruleTypes) { if (process.env.TEST_DEBUG === '1') console.log(` Testing ${name} reachability integration...`); // Test quick reachability check const sourceKey = testRelations[0].src; const targetKey = testRelations[0].dst; // Test _quickReachabilityCheck const isReachable = rule._quickReachabilityCheck(sourceKey, targetKey); if (process.env.TEST_DEBUG === '1') console.log(` ${name} quick check: ${sourceKey} -> ${targetKey}: ${isReachable}`); assert.ok(typeof isReachable === 'boolean' || isReachable === null, 'Should return boolean or null'); // Test _quickReachabilityFailure const failureResult = rule._quickReachabilityFailure(sourceKey, targetKey, `Test failure for ${name}`); if (failureResult) { if (process.env.TEST_DEBUG === '1') console.log(` ${name} quick failure: ${failureResult.possibility} (${failureResult.reason})`); assert.ok(failureResult.possibility === 0, 'Quick failure should return 0 possibility'); assert.ok(failureResult.reason.includes(name), 'Should include rule name in reason'); } else { if (process.env.TEST_DEBUG === '1') console.log(` ${name} quick failure: No failure (reachable or no checker)`); } // Test _getReachableNodes const reachableNodes = rule._getReachableNodes(sourceKey, 5); if (reachableNodes) { if (process.env.TEST_DEBUG === '1') console.log(` ${name} reachable nodes: ${reachableNodes.length} found`); assert.ok(Array.isArray(reachableNodes), 'Should return array of reachable nodes'); } else { if (process.env.TEST_DEBUG === '1') console.log(` ${name} reachable nodes: No checker available`); } // Test _getReachingNodes const reachingNodes = rule._getReachingNodes(targetKey, 5); if (reachingNodes) { if (process.env.TEST_DEBUG === '1') console.log(` ${name} reaching nodes: ${reachingNodes.length} found`); assert.ok(Array.isArray(reachingNodes), 'Should return array of reaching nodes'); } else { if (process.env.TEST_DEBUG === '1') console.log(` ${name} reaching nodes: No checker available`); } if (process.env.TEST_DEBUG === '1') console.log(` ✅ ${name} reachability integration working`); } if (process.env.TEST_DEBUG === '1') console.log(' ✅ All rule types can use reachability failure checks'); }); test('verifies batch reachability checking', async () => { if (process.env.TEST_DEBUG === '1') console.log('📦 Testing batch reachability checking...'); const generator = new BigGraphGenerator(); const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker await arbiter.initializeReachabilityChecker({ strategy: 'auto', twoHopOptions: { remainderBits: 8 }, treeCoverOptions: { remainderBits: 8 } }); const rule = new ChainRule(arbiter); // Test batch reachability check const testPairs = graphData.relations.filter(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') ).slice(0, 5).map(r => ({ sourceKey: r.src, targetKey: r.dst })); if (process.env.TEST_DEBUG === '1') console.log(` Testing batch check for ${testPairs.length} pairs...`); const batchResults = rule._batchReachabilityCheck(testPairs); if (batchResults) { if (process.env.TEST_DEBUG === '1') console.log(` Batch results: ${Object.keys(batchResults).length} pairs checked`); for (const [pair, result] of Object.entries(batchResults)) { if (process.env.TEST_DEBUG === '1') console.log(` ${pair}: ${result}`); assert.ok(typeof result === 'boolean' || result === null, 'Should return boolean or null'); } if (process.env.TEST_DEBUG === '1') console.log(' ✅ Batch reachability checking working'); } else { if (process.env.TEST_DEBUG === '1') console.log(' 📝 No reachability checker available for batch checking'); } }); test('verifies reachability integration in rule evaluation', async () => { if (process.env.TEST_DEBUG === '1') console.log('⚡ Testing reachability integration in actual rule evaluation...'); const generator = new BigGraphGenerator(); const graphData = generator.generateGraph('enterprise'); const arbiter = generator.loadIntoArbiter(graphData); // Initialize reachability checker await arbiter.initializeReachabilityChecker({ strategy: 'auto', twoHopOptions: { remainderBits: 8 }, treeCoverOptions: { remainderBits: 8 } }); const rule = new ChainRule(arbiter); // Test actual rule evaluation with reachability const testRelation = graphData.relations.find(r => r.src.startsWith('user:') && r.dst.startsWith('doc:') ); if (testRelation) { if (process.env.TEST_DEBUG === '1') console.log(` Testing rule evaluation: ${testRelation.src} -> ${testRelation.dst}`); // Create a simple chain rule configuration const ruleConfig = { type: 'chain', relations: ['role_membership', 'role_permission'], maxSteps: 3 }; // Test rule evaluation const result = rule.evaluate( arbiter.nodeIdByKey.get(testRelation.src), testRelation.src, arbiter.nodeIdByKey.get(testRelation.dst), testRelation.dst, ruleConfig, new Set(), 'can_read_via_role', {} ); if (process.env.TEST_DEBUG === '1') console.log(` Rule evaluation result: ${result.possibility} (${result.reason})`); if (process.env.TEST_DEBUG === '1') console.log(` Meta method: ${result.meta?.method || 'unknown'}`); assert.ok(typeof result.possibility === 'number', 'Should return numeric possibility'); assert.ok(result.reason, 'Should have a reason'); if (process.env.TEST_DEBUG === '1') console.log(' ✅ Rule evaluation with reachability integration working'); } else { if (process.env.TEST_DEBUG === '1') console.log(' 📝 No suitable test relation found'); } });