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,213 @@
|
||||
import { performance } from 'node:perf_hooks';
|
||||
import { Arbiter } from '../src/core/Arbiter.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);
|
||||
let total = 0;
|
||||
for (let i = 0; i < durations.length; i++) total += durations[i];
|
||||
const avg = total / 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 runBenchmark(name, iterations, fn) {
|
||||
const warmup = Math.min(1000, Math.max(100, Math.floor(iterations / 10)));
|
||||
for (let i = 0; i < warmup; i++) fn();
|
||||
|
||||
const durations = new Array(iterations);
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const start = performance.now();
|
||||
fn();
|
||||
durations[i] = performance.now() - start;
|
||||
}
|
||||
summarize(name, durations);
|
||||
}
|
||||
|
||||
function setupBusinessArbiter() {
|
||||
const arbiter = new Arbiter({
|
||||
partialGraphPolicy: {
|
||||
conflict_mode: 'deterministic',
|
||||
reducers: {
|
||||
request_has_timestamp: 'latest',
|
||||
caller_risk_hint: 'strongest'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('group:1', 'group');
|
||||
arbiter.addNode('mid:1', 'intermediate');
|
||||
arbiter.addNode('doc:1', 'document');
|
||||
arbiter.addNode('feature:1', 'feature');
|
||||
arbiter.addNode('value:1', 'value');
|
||||
|
||||
arbiter.setRelationConfig('request_has_timestamp', {
|
||||
type: 'direct',
|
||||
partial_graph: { reducer: 'latest' }
|
||||
});
|
||||
arbiter.setRelationConfig('caller_risk_hint', {
|
||||
type: 'direct',
|
||||
partial_graph: { reducer: 'strongest' }
|
||||
});
|
||||
arbiter.setRelationConfig('request_has_id', { type: 'direct' });
|
||||
|
||||
arbiter.setRelationConfig('can_chain', {
|
||||
type: 'chain',
|
||||
steps: [
|
||||
{ relation: 'request_has_timestamp', direction: 'out' },
|
||||
{ relation: 'caller_risk_hint', direction: 'out' }
|
||||
]
|
||||
});
|
||||
|
||||
arbiter.setRelationConfig('can_reach', {
|
||||
type: 'multi_hop',
|
||||
relation: 'caller_risk_hint',
|
||||
maxDepth: 3
|
||||
});
|
||||
|
||||
arbiter.setRelationConfig('can_access', {
|
||||
type: 'tuple_to_userset',
|
||||
tuplesetRelation: 'request_has_id',
|
||||
computedRelation: 'request_has_timestamp',
|
||||
reverse: false
|
||||
});
|
||||
|
||||
arbiter.setRelationConfig('can_pay', {
|
||||
type: 'relational_comparator',
|
||||
left: {
|
||||
rule: { type: 'direct', relation: 'request_has_timestamp' },
|
||||
extractValue: true,
|
||||
aggregation: 'max',
|
||||
decayRate: 0,
|
||||
decayFunction: 'rational'
|
||||
},
|
||||
right: {
|
||||
rule: { type: 'direct', relation: 'request_has_id', evaluateFrom: 'object' },
|
||||
extractValue: true,
|
||||
aggregation: 'min',
|
||||
decayRate: 0,
|
||||
decayFunction: 'rational',
|
||||
evaluateFrom: 'object'
|
||||
},
|
||||
comparator: '>=',
|
||||
fallbackBehavior: 'deny'
|
||||
});
|
||||
|
||||
arbiter.addRelation('group:1', 'caller_risk_hint', 'doc:1', 0.9);
|
||||
arbiter.addRelation('feature:1', 'request_has_id', 'feature:1', { value: 50, possibility: 1 });
|
||||
|
||||
const partialGraph = {
|
||||
options: {
|
||||
reducers: {
|
||||
request_has_timestamp: 'latest',
|
||||
caller_risk_hint: 'strongest'
|
||||
}
|
||||
},
|
||||
relations: [
|
||||
{
|
||||
src: 'user:1',
|
||||
relation: 'request_has_timestamp',
|
||||
dst: 'group:1',
|
||||
possibility: 0.95,
|
||||
value: 120,
|
||||
updated_last_at: 100,
|
||||
layer_name: 'request_observed',
|
||||
source_class: 'gateway_observed'
|
||||
},
|
||||
{
|
||||
src: 'user:1',
|
||||
relation: 'request_has_timestamp',
|
||||
dst: 'group:1',
|
||||
possibility: 0.2,
|
||||
value: 20,
|
||||
updated_last_at: 200,
|
||||
layer_name: 'request_observed',
|
||||
source_class: 'gateway_observed'
|
||||
},
|
||||
{
|
||||
src: 'group:1',
|
||||
relation: 'caller_risk_hint',
|
||||
dst: 'doc:1',
|
||||
possibility: 0.8,
|
||||
layer_name: 'caller_declared',
|
||||
source_class: 'caller_input'
|
||||
},
|
||||
{
|
||||
src: 'doc:1',
|
||||
relation: 'request_has_id',
|
||||
dst: 'group:1',
|
||||
possibility: 1,
|
||||
layer_name: 'request_observed'
|
||||
},
|
||||
{
|
||||
src: 'user:1',
|
||||
relation: 'request_has_timestamp',
|
||||
dst: 'feature:1',
|
||||
value: 20,
|
||||
possibility: 1,
|
||||
updated_last_at: 200,
|
||||
layer_name: 'request_observed'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return { arbiter, partialGraph };
|
||||
}
|
||||
|
||||
function run() {
|
||||
const { arbiter, partialGraph } = setupBusinessArbiter();
|
||||
|
||||
const conformantClaims = [
|
||||
{ relation: 'from_ip', object: 'ip:10.0.0.1' },
|
||||
{ relation: 'request_has_id', object: 'request:abc' }
|
||||
];
|
||||
const nonConformantClaims = [
|
||||
{ relation: 'delegated_authority', object: 'resource:x' }
|
||||
];
|
||||
|
||||
console.log('Business operations benchmark');
|
||||
runBenchmark('business.layer_conformance.accept', 15000, () => {
|
||||
validateClaimsForLayer('request_observed', conformantClaims);
|
||||
});
|
||||
runBenchmark('business.layer_conformance.reject', 15000, () => {
|
||||
validateClaimsForLayer('caller_declared', nonConformantClaims);
|
||||
});
|
||||
|
||||
runBenchmark('business.partial_graph_policy.snapshot', 15000, () => {
|
||||
arbiter.getPartialGraphPolicySnapshot();
|
||||
});
|
||||
|
||||
runBenchmark('business.auth.direct_partial', 12000, () => {
|
||||
arbiter.check('user:1', 'request_has_timestamp', 'group:1', { partialGraph });
|
||||
});
|
||||
runBenchmark('business.auth.chain_partial', 12000, () => {
|
||||
arbiter.check('user:1', 'can_chain', 'doc:1', { partialGraph });
|
||||
});
|
||||
runBenchmark('business.auth.multi_hop_partial', 12000, () => {
|
||||
arbiter.check('user:1', 'can_reach', 'doc:1', { partialGraph });
|
||||
});
|
||||
runBenchmark('business.auth.tuple_to_userset_partial', 12000, () => {
|
||||
arbiter.check('user:1', 'can_access', 'doc:1', { partialGraph });
|
||||
});
|
||||
runBenchmark('business.auth.relational_comparator_partial', 12000, () => {
|
||||
arbiter.check('user:1', 'can_pay', 'feature:1', { partialGraph });
|
||||
});
|
||||
|
||||
runBenchmark('business.explain.chain_debug', 6000, () => {
|
||||
arbiter.explain('user:1', 'can_chain', 'doc:1', {
|
||||
partialGraph,
|
||||
includeMeta: true,
|
||||
collectValues: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
run();
|
||||
Reference in New Issue
Block a user