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,89 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { describe, test } from 'node:test';
|
||||
import { Arbiter } from '../../src/core/Arbiter.js';
|
||||
|
||||
describe('Graph Structure and Queries', () => {
|
||||
test('basic node and relation creation', () => {
|
||||
const arbiter = new Arbiter();
|
||||
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('resource:1', 'resource');
|
||||
|
||||
const nodeId1 = arbiter.resolveNodeId('user:1');
|
||||
const nodeId2 = arbiter.resolveNodeId('resource:1');
|
||||
|
||||
assert.ok(nodeId1 !== undefined, 'user node ID resolved');
|
||||
assert.ok(nodeId2 !== undefined, 'resource node ID resolved');
|
||||
assert.strictEqual(arbiter.resolveKey(nodeId1), 'user:1', 'reverse key lookup works');
|
||||
});
|
||||
|
||||
test('direct relation authorization', () => {
|
||||
const arbiter = new Arbiter();
|
||||
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('resource:1', 'resource');
|
||||
arbiter.setRelationConfig('owner', { type: 'direct' });
|
||||
|
||||
arbiter.addRelation('user:1', 'owner', 'resource:1', 1.0);
|
||||
|
||||
const result = arbiter.check('user:1', 'owner', 'resource:1');
|
||||
assert.strictEqual(result.possibility, 1.0, 'owner relation grants access');
|
||||
assert.strictEqual(result.reason, 'direct_match', 'reason is direct_match');
|
||||
});
|
||||
|
||||
test('absence of relation denies access', () => {
|
||||
const arbiter = new Arbiter();
|
||||
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('resource:1', 'resource');
|
||||
arbiter.addNode('user:2', 'user');
|
||||
arbiter.setRelationConfig('owner', { type: 'direct' });
|
||||
|
||||
arbiter.addRelation('user:1', 'owner', 'resource:1', 1.0);
|
||||
|
||||
const result = arbiter.check('user:2', 'owner', 'resource:1');
|
||||
assert.strictEqual(result.possibility, 0.0, 'non-owner denied');
|
||||
assert.strictEqual(result.reason, 'no_relation', 'reason is no_relation');
|
||||
});
|
||||
|
||||
test('node data storage and retrieval', () => {
|
||||
const arbiter = new Arbiter();
|
||||
|
||||
arbiter.addNode('user:1', 'user', { tier: 'premium', level: 5 });
|
||||
const data = arbiter.getNodeData('user:1');
|
||||
|
||||
assert.strictEqual(data.tier, 'premium');
|
||||
assert.strictEqual(data.level, 5);
|
||||
});
|
||||
|
||||
test('node data update', () => {
|
||||
const arbiter = new Arbiter();
|
||||
|
||||
arbiter.addNode('user:1', 'user', { tier: 'premium' });
|
||||
arbiter.updateNodeData('user:1', { tier: 'enterprise', level: 10 });
|
||||
|
||||
const data = arbiter.getNodeData('user:1');
|
||||
assert.strictEqual(data.tier, 'enterprise');
|
||||
assert.strictEqual(data.level, 10);
|
||||
});
|
||||
|
||||
test('multiple relations between different node types', () => {
|
||||
const arbiter = new Arbiter();
|
||||
|
||||
arbiter.addNode('user:1', 'user');
|
||||
arbiter.addNode('group:1', 'group');
|
||||
arbiter.addNode('resource:1', 'resource');
|
||||
|
||||
arbiter.setRelationConfig('member', { type: 'direct' });
|
||||
arbiter.setRelationConfig('can_view', { type: 'direct' });
|
||||
|
||||
arbiter.addRelation('user:1', 'member', 'group:1', 1.0);
|
||||
arbiter.addRelation('group:1', 'can_view', 'resource:1', 1.0);
|
||||
|
||||
const memberResult = arbiter.check('user:1', 'member', 'group:1');
|
||||
const viewResult = arbiter.check('group:1', 'can_view', 'resource:1');
|
||||
|
||||
assert.strictEqual(memberResult.possibility, 1.0);
|
||||
assert.strictEqual(viewResult.possibility, 1.0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user