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,76 @@
|
||||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { Arbiter } from '../../src/core/Arbiter.js';
|
||||
|
||||
describe('Cache invalidation paths', () => {
|
||||
test('relation lookup cache clears on removal', () => {
|
||||
const arbiter = new Arbiter();
|
||||
arbiter.addNode('user', 'user');
|
||||
arbiter.addNode('doc', 'document');
|
||||
arbiter.addRelation('user', 'can_read', 'doc', 1.0);
|
||||
|
||||
const srcId = arbiter.nodeIdByKey.get('user');
|
||||
const dstId = arbiter.nodeIdByKey.get('doc');
|
||||
const cacheKey = arbiter.relationManager._makeDirectCacheKey(srcId, 'can_read', dstId);
|
||||
|
||||
const relation = arbiter.relationManager.getDirectRelation(srcId, 'can_read', dstId);
|
||||
assert.ok(relation);
|
||||
// RF-08: cache state moved entirely to RelationCaches.
|
||||
assert.ok(arbiter.relationManager._caches.relationLookupCache.has(cacheKey));
|
||||
|
||||
arbiter.removeRelation('user', 'can_read', 'doc');
|
||||
assert.ok(!arbiter.relationManager._caches.relationLookupCache.has(cacheKey));
|
||||
});
|
||||
|
||||
test('value cache clears on relation modification', () => {
|
||||
const arbiter = new Arbiter();
|
||||
arbiter.addNode('user', 'user');
|
||||
arbiter.addNode('account', 'account');
|
||||
arbiter.addRelation('user', 'has_balance', 'account', 1.0, { value: 10 });
|
||||
|
||||
const srcId = arbiter.nodeIdByKey.get('user');
|
||||
const dstId = arbiter.nodeIdByKey.get('account');
|
||||
const cacheKey = arbiter.relationManager._makeValueCacheKey(srcId, 'has_balance', dstId);
|
||||
|
||||
const valueRelation = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId);
|
||||
assert.ok(valueRelation);
|
||||
assert.ok(arbiter.relationManager._caches.valueLookupCache.has(cacheKey));
|
||||
|
||||
arbiter.relationManager._modifyRelation('user', 'has_balance', 'account', { value: 20 });
|
||||
assert.ok(!arbiter.relationManager._caches.valueLookupCache.has(cacheKey));
|
||||
});
|
||||
|
||||
test('direct check cache clears on relation removal', () => {
|
||||
const arbiter = new Arbiter();
|
||||
arbiter.addNode('user', 'user');
|
||||
arbiter.addNode('doc', 'document');
|
||||
arbiter.addRelation('user', 'can_read', 'doc', 1.0);
|
||||
arbiter.setRelationConfig('can_read', { type: 'direct' });
|
||||
|
||||
const result = arbiter.check('user', 'can_read', 'doc');
|
||||
assert.strictEqual(result.possibility, 1.0);
|
||||
|
||||
const srcId = arbiter.keyManager.getStringId('user');
|
||||
const dstId = arbiter.keyManager.getStringId('doc');
|
||||
const cacheKey = arbiter.keyManager.createCompositeKey(srcId, 'can_read', dstId);
|
||||
assert.ok(arbiter.directCheckCache.has(cacheKey));
|
||||
|
||||
arbiter.removeRelation('user', 'can_read', 'doc');
|
||||
assert.ok(!arbiter.directCheckCache.has(cacheKey));
|
||||
});
|
||||
|
||||
test('value cache invalidation schedules stale recompute', () => {
|
||||
const arbiter = new Arbiter();
|
||||
arbiter.addNode('user', 'user');
|
||||
arbiter.addNode('account', 'account');
|
||||
arbiter.addRelation('user', 'has_balance', 'account', 1.0, { value: 10 });
|
||||
|
||||
const srcId = arbiter.nodeIdByKey.get('user');
|
||||
const dstId = arbiter.nodeIdByKey.get('account');
|
||||
const valueRelation = arbiter.relationManager.getValueRelation(srcId, 'has_balance', dstId);
|
||||
assert.ok(valueRelation);
|
||||
|
||||
arbiter.relationManager._modifyRelation('user', 'has_balance', 'account', { value: 20 });
|
||||
assert.strictEqual(arbiter.valueManager.staleValueItemsIndex.size, 0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user