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 @@
|
||||
/**
|
||||
* Snapshot read-only guard tests — verifies that public write paths
|
||||
* throw when _snapshotReadOnly is true.
|
||||
*
|
||||
* After the P1.4 fix, the following methods must reject writes:
|
||||
* - addRelation (public, existing guard)
|
||||
* - removeRelation (public, existing guard)
|
||||
*
|
||||
* Run: node --test --test-force-exit lib/tests/property-based/snapshot-read-only.test.js
|
||||
*/
|
||||
import { Arbiter } from '../../src/core/Arbiter.js';
|
||||
import { describe, it, beforeEach } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
describe('Snapshot Read-Only Guards', () => {
|
||||
let arbiter;
|
||||
|
||||
beforeEach(() => {
|
||||
arbiter = new Arbiter({ fastConstructionMode: true, enableInference: false });
|
||||
arbiter.addNode('user:alice', 'user');
|
||||
arbiter.addNode('project:secret', 'project');
|
||||
arbiter._snapshotReadOnly = true;
|
||||
});
|
||||
|
||||
it('addRelation throws when read-only', () => {
|
||||
assert.throws(
|
||||
() => arbiter.addRelation('user:alice', 'can_read', 'project:secret', 0.9),
|
||||
/Cannot add relation while in snapshot read-only mode/
|
||||
);
|
||||
});
|
||||
|
||||
it('removeRelation throws when read-only', () => {
|
||||
arbiter._snapshotReadOnly = false;
|
||||
arbiter.addRelation('user:alice', 'can_read', 'project:secret', 0.9);
|
||||
arbiter._snapshotReadOnly = true;
|
||||
|
||||
assert.throws(
|
||||
() => arbiter.removeRelation('user:alice', 'can_read', 'project:secret'),
|
||||
/Cannot remove relation while in snapshot read-only mode/
|
||||
);
|
||||
});
|
||||
|
||||
it('writes succeed when not in read-only mode', () => {
|
||||
arbiter._snapshotReadOnly = false;
|
||||
arbiter.addRelation('user:alice', 'can_read', 'project:secret', 0.9);
|
||||
assert.strictEqual(arbiter.relations.length, 1);
|
||||
|
||||
arbiter.addRelation('user:alice', 'can_write', 'project:secret', 0.5);
|
||||
assert.strictEqual(arbiter.relations.length, 2);
|
||||
});
|
||||
|
||||
it('deserialized snapshot rejects writes', () => {
|
||||
arbiter._snapshotReadOnly = false;
|
||||
arbiter.addRelation('user:alice', 'can_read', 'project:secret', 0.9);
|
||||
|
||||
arbiter._snapshotReadOnly = true;
|
||||
|
||||
assert.throws(
|
||||
() => arbiter.addRelation('user:alice', 'can_write', 'project:secret', 0.5),
|
||||
/Cannot add relation while in snapshot read-only mode/
|
||||
);
|
||||
});
|
||||
|
||||
it('fresh arbiter in read-only mode rejects writes immediately', () => {
|
||||
assert.throws(
|
||||
() => arbiter.addRelation('user:alice', 'can_read', 'project:secret', 0.5),
|
||||
/Cannot add relation while in snapshot read-only mode/
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user