178 lines
7.3 KiB
JavaScript
178 lines
7.3 KiB
JavaScript
|
|
/**
|
||
|
|
* 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');
|
||
|
|
}
|
||
|
|
});
|