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:
@@ -0,0 +1,70 @@
|
||||
import { performance } from 'node:perf_hooks';
|
||||
import { Arbiter } from '../src/core/Arbiter.js';
|
||||
import { PartialGraphContext } from '../src/core/PartialGraphContext.js';
|
||||
import { validateClaimsForLayer } from '../src/core/partial-graph/layer-registry.js';
|
||||
|
||||
function percentile(sorted, p) {
|
||||
if (!sorted.length) return 0;
|
||||
const idx = Math.min(sorted.length - 1, Math.max(0, Math.floor(sorted.length * p) - 1));
|
||||
return sorted[idx];
|
||||
}
|
||||
|
||||
function summarize(name, durations) {
|
||||
const sorted = [...durations].sort((a, b) => a - b);
|
||||
const avg = durations.reduce((a, b) => a + b, 0) / durations.length;
|
||||
const p95 = percentile(sorted, 0.95);
|
||||
const p99 = percentile(sorted, 0.99);
|
||||
console.log(`${name}: avg=${avg.toFixed(4)}ms p95=${p95.toFixed(4)}ms p99=${p99.toFixed(4)}ms`);
|
||||
}
|
||||
|
||||
function benchmarkLayerRegistry(iterations = 20000) {
|
||||
const claims = [
|
||||
{ relation: 'delegated_authority', object: 'resource:alpha:item:1', ttl_seconds: 60 },
|
||||
{ relation: 'workflow_step', object: 'workflow:loan:step:2', ttl_seconds: 60 }
|
||||
];
|
||||
const durations = [];
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const start = performance.now();
|
||||
validateClaimsForLayer('workflow_overlay', claims, ['delegated_authority', 'workflow_step']);
|
||||
durations.push(performance.now() - start);
|
||||
}
|
||||
summarize('layer_registry.validate', durations);
|
||||
}
|
||||
|
||||
function benchmarkPartialGraphLookup(iterations = 20000) {
|
||||
const arbiter = new Arbiter();
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('doc:1', 'doc');
|
||||
const context = new PartialGraphContext(arbiter, {
|
||||
relations: [{ src: 'user:1', relation: 'can_read', dst: 'doc:1', possibility: 1.0 }]
|
||||
});
|
||||
const srcId = context.nodeIdByKey.get('user:1');
|
||||
const dstId = context.nodeIdByKey.get('doc:1');
|
||||
const durations = [];
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const start = performance.now();
|
||||
context.getDirectRelation(srcId, 'can_read', dstId);
|
||||
durations.push(performance.now() - start);
|
||||
}
|
||||
summarize('partial_graph_context.get_direct_relation', durations);
|
||||
}
|
||||
|
||||
function benchmarkArbiterCheck(iterations = 10000) {
|
||||
const arbiter = new Arbiter();
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('doc:1', 'doc');
|
||||
arbiter.setRelationConfig('can_read', { type: 'direct' });
|
||||
arbiter.addRelation('user:1', 'can_read', 'doc:1', 1.0);
|
||||
const durations = [];
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const start = performance.now();
|
||||
arbiter.check('user:1', 'can_read', 'doc:1');
|
||||
durations.push(performance.now() - start);
|
||||
}
|
||||
summarize('arbiter.check_direct', durations);
|
||||
}
|
||||
|
||||
console.log('Core performance benchmark');
|
||||
benchmarkLayerRegistry();
|
||||
benchmarkPartialGraphLookup();
|
||||
benchmarkArbiterCheck();
|
||||
Reference in New Issue
Block a user