initial commit: @arbiter/core authorization engine with js-rigor hardening

Zanzibar-style authorization graph engine (direct/chain/TTU/defeasible/
binary modes, condensed snapshots, value relations) with 39 rigor test
campaigns. Includes fixes for snapshot binary writer/reader format
mismatch (snapshot-of-snapshot corruption), possibility write-boundary
validation, empty-graph snapshot serialization, relation lookup cache
direction collision, config-redefinition cache invalidation, binary
threshold semantics, defeasible compiled routing, and comparator
reason whitelisting.
This commit is contained in:
John Dvorak
2026-07-31 13:44:06 -07:00
commit 717ae1031e
373 changed files with 654131 additions and 0 deletions
@@ -0,0 +1,362 @@
/**
* Test performance of different reachability indexing strategies
*/
import { test as _test } from 'node:test';
const test = process.env.RUN_PERF_TESTS === '1' ? _test : _test.skip;
import assert from 'node:assert/strict';
import { BigGraphGenerator } from '../helpers/big-graph-generator.js';
import { ChainRule } from '../../src/authorization/rules/ChainRule.js';
test('compares reachability strategy performance', async () => {
if (process.env.TEST_DEBUG === '1') console.log('🔍 Comparing reachability strategy performance...');
const generator = new BigGraphGenerator();
const graphData = generator.generateGraph('enterprise');
// Test different strategies
const strategies = ['auto', 'twohop', 'treecover', 'hybrid'];
const results = {};
for (const strategy of strategies) {
if (process.env.TEST_DEBUG === '1') console.log(` Testing strategy: ${strategy}`);
// Create new arbiter for each strategy
const arbiter = generator.loadIntoArbiter(graphData);
// Initialize reachability checker with specific strategy
await arbiter.reachabilityChecker.initialize({
strategy: strategy,
twoHopOptions: { maxNodes: 1000 },
treeCoverOptions: { maxTrees: 3 }
});
const rule = new ChainRule(arbiter);
// Create a chain rule
const chainRule = {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'can_read', direction: 'out' }
],
collectValues: false,
valueAggregation: 'sum'
};
// Find actual chain paths
const actualChains = [];
const roleMemberships = graphData.relations.filter(r =>
r.relation === 'member_of' && r.dst.startsWith('role:')
);
for (const membership of roleMemberships) {
const userId = membership.src;
const roleId = membership.dst;
const roleReadPermissions = graphData.relations.filter(r =>
r.relation === 'can_read' && r.src === roleId
);
for (const permission of roleReadPermissions) {
actualChains.push({
user: userId,
object: permission.dst
});
}
}
if (process.env.TEST_DEBUG === '1') console.log(` Found ${actualChains.length} chain paths`);
// Test performance
const start = Date.now();
let queryCount = 0;
let positiveResults = 0;
const end = start + 2000; // 2 seconds
while (Date.now() < end) {
for (const chain of actualChains) {
const result = rule.evaluate(
arbiter.nodeIdByKey.get(chain.user),
chain.user,
arbiter.nodeIdByKey.get(chain.object),
chain.object,
chainRule,
new Set(),
'can_read_via_role',
{}
);
if (result.possibility > 0) {
positiveResults++;
}
queryCount++;
}
}
const duration = Date.now() - start;
const qps = (queryCount / duration) * 1000;
const positiveRate = (positiveResults / queryCount) * 100;
results[strategy] = {
qps: qps,
queryCount: queryCount,
positiveRate: positiveRate,
duration: duration,
cacheSize: rule.chainResultCache.size
};
if (process.env.TEST_DEBUG === '1') console.log(` ${strategy}: ${qps.toFixed(2)} QPS (${queryCount} queries, ${positiveRate.toFixed(1)}% positive)`);
if (process.env.TEST_DEBUG === '1') console.log(` Cache size: ${rule.chainResultCache.size} results`);
// Get reachability stats
const reachabilityStats = arbiter.reachabilityChecker.getStats();
if (process.env.TEST_DEBUG === '1') console.log(` Reachability stats:`, reachabilityStats);
}
// Compare results
if (process.env.TEST_DEBUG === '1') console.log(' 📊 Strategy comparison:');
const sortedResults = Object.entries(results).sort((a, b) => b[1].qps - a[1].qps);
sortedResults.forEach(([strategy, result], index) => {
const rank = index + 1;
const improvement = index === 0 ? '🏆' : `-${((sortedResults[0][1].qps - result.qps) / sortedResults[0][1].qps * 100).toFixed(1)}%`;
if (process.env.TEST_DEBUG === '1') console.log(` ${rank}. ${strategy}: ${result.qps.toFixed(2)} QPS ${improvement}`);
});
// Verify that we have results
assert.ok(Object.keys(results).length > 0, 'Should have results for all strategies');
if (process.env.TEST_DEBUG === '1') console.log(' ✅ Reachability strategy comparison completed');
});
test('measures strategy performance with different graph sizes', async () => {
if (process.env.TEST_DEBUG === '1') console.log('📈 Testing strategy performance with different graph sizes...');
const graphSizes = ['small', 'medium', 'enterprise'];
const strategies = ['auto', 'twohop', 'treecover', 'hybrid'];
const results = {};
for (const size of graphSizes) {
if (process.env.TEST_DEBUG === '1') console.log(` Testing ${size} graph...`);
results[size] = {};
for (const strategy of strategies) {
if (process.env.TEST_DEBUG === '1') console.log(` Strategy: ${strategy}`);
const generator = new BigGraphGenerator();
const graphData = generator.generateGraph(size);
const arbiter = generator.loadIntoArbiter(graphData);
// Initialize reachability checker
await arbiter.reachabilityChecker.initialize({
strategy: strategy,
twoHopOptions: { maxNodes: 1000 },
treeCoverOptions: { maxTrees: 3 }
});
const rule = new ChainRule(arbiter);
// Create a chain rule
const chainRule = {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'can_read', direction: 'out' }
],
collectValues: false,
valueAggregation: 'sum'
};
// Find actual chain paths
const actualChains = [];
const roleMemberships = graphData.relations.filter(r =>
r.relation === 'member_of' && r.dst.startsWith('role:')
);
for (const membership of roleMemberships) {
const userId = membership.src;
const roleId = membership.dst;
const roleReadPermissions = graphData.relations.filter(r =>
r.relation === 'can_read' && r.src === roleId
);
for (const permission of roleReadPermissions) {
actualChains.push({
user: userId,
object: permission.dst
});
}
}
// Test performance
const start = Date.now();
let queryCount = 0;
let positiveResults = 0;
const end = start + 1000; // 1 second
while (Date.now() < end) {
for (const chain of actualChains) {
const result = rule.evaluate(
arbiter.nodeIdByKey.get(chain.user),
chain.user,
arbiter.nodeIdByKey.get(chain.object),
chain.object,
chainRule,
new Set(),
'can_read_via_role',
{}
);
if (result.possibility > 0) {
positiveResults++;
}
queryCount++;
}
}
const duration = Date.now() - start;
const qps = (queryCount / duration) * 1000;
const positiveRate = (positiveResults / queryCount) * 100;
results[size][strategy] = {
qps: qps,
queryCount: queryCount,
positiveRate: positiveRate,
chainCount: actualChains.length
};
if (process.env.TEST_DEBUG === '1') console.log(` ${strategy}: ${qps.toFixed(2)} QPS (${actualChains.length} chains)`);
}
}
// Compare results across graph sizes
if (process.env.TEST_DEBUG === '1') console.log(' 📊 Results by graph size:');
for (const size of graphSizes) {
if (process.env.TEST_DEBUG === '1') console.log(` ${size}:`);
const sortedResults = Object.entries(results[size]).sort((a, b) => b[1].qps - a[1].qps);
sortedResults.forEach(([strategy, result], index) => {
const rank = index + 1;
if (process.env.TEST_DEBUG === '1') console.log(` ${rank}. ${strategy}: ${result.qps.toFixed(2)} QPS (${result.chainCount} chains)`);
});
}
if (process.env.TEST_DEBUG === '1') console.log(' ✅ Graph size strategy comparison completed');
});
test('measures strategy performance with different chain lengths', async () => {
if (process.env.TEST_DEBUG === '1') console.log('🔗 Testing strategy performance with different chain lengths...');
const generator = new BigGraphGenerator();
const graphData = generator.generateGraph('enterprise');
const strategies = ['auto', 'twohop', 'treecover', 'hybrid'];
const chainLengths = [2, 3, 4];
const results = {};
for (const length of chainLengths) {
if (process.env.TEST_DEBUG === '1') console.log(` Testing chain length: ${length}`);
results[length] = {};
for (const strategy of strategies) {
if (process.env.TEST_DEBUG === '1') console.log(` Strategy: ${strategy}`);
const arbiter = generator.loadIntoArbiter(graphData);
// Initialize reachability checker
await arbiter.reachabilityChecker.initialize({
strategy: strategy,
twoHopOptions: { maxNodes: 1000 },
treeCoverOptions: { maxTrees: 3 }
});
const rule = new ChainRule(arbiter);
// Create a chain rule with specified length
const chainRule = {
type: 'chain',
steps: Array.from({ length }, (_, i) => ({
relation: i === 0 ? 'member_of' : 'can_read',
direction: 'out'
})),
collectValues: false,
valueAggregation: 'sum'
};
// Find actual chain paths
const actualChains = [];
const roleMemberships = graphData.relations.filter(r =>
r.relation === 'member_of' && r.dst.startsWith('role:')
);
for (const membership of roleMemberships) {
const userId = membership.src;
const roleId = membership.dst;
const roleReadPermissions = graphData.relations.filter(r =>
r.relation === 'can_read' && r.src === roleId
);
for (const permission of roleReadPermissions) {
actualChains.push({
user: userId,
object: permission.dst
});
}
}
// Test performance
const start = Date.now();
let queryCount = 0;
let positiveResults = 0;
const end = start + 1000; // 1 second
while (Date.now() < end) {
for (const chain of actualChains) {
const result = rule.evaluate(
arbiter.nodeIdByKey.get(chain.user),
chain.user,
arbiter.nodeIdByKey.get(chain.object),
chain.object,
chainRule,
new Set(),
'can_read_via_role',
{}
);
if (result.possibility > 0) {
positiveResults++;
}
queryCount++;
}
}
const duration = Date.now() - start;
const qps = (queryCount / duration) * 1000;
const positiveRate = (positiveResults / queryCount) * 100;
results[length][strategy] = {
qps: qps,
queryCount: queryCount,
positiveRate: positiveRate,
chainCount: actualChains.length
};
if (process.env.TEST_DEBUG === '1') console.log(` ${strategy}: ${qps.toFixed(2)} QPS (${actualChains.length} chains)`);
}
}
// Compare results across chain lengths
if (process.env.TEST_DEBUG === '1') console.log(' 📊 Results by chain length:');
for (const length of chainLengths) {
if (process.env.TEST_DEBUG === '1') console.log(` Length ${length}:`);
const sortedResults = Object.entries(results[length]).sort((a, b) => b[1].qps - a[1].qps);
sortedResults.forEach(([strategy, result], index) => {
const rank = index + 1;
if (process.env.TEST_DEBUG === '1') console.log(` ${rank}. ${strategy}: ${result.qps.toFixed(2)} QPS (${result.chainCount} chains)`);
});
}
if (process.env.TEST_DEBUG === '1') console.log(' ✅ Chain length strategy comparison completed');
});