Files
John Dvorak 717ae1031e 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.
2026-07-31 13:44:06 -07:00

108 lines
3.5 KiB
JavaScript

import { test, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { setupChainRuleTestGraph } from './helpers.js';
describe('ChainRule Comprehensive Tests', () => {
describe('Edge Cases and Error Handling', () => {
it('handles empty chains gracefully', () => {
const arbiter = setupChainRuleTestGraph();
arbiter.setRelationConfig('empty_chain', {
type: 'chain',
steps: [] // Empty steps
});
const result = arbiter.check('user:alice', 'empty_chain', 'project:web-app');
assert.equal(result.possibility, 0);
assert.equal(result.reason, 'no_chain_steps_defined');
});
it('handles broken chains correctly', () => {
const arbiter = setupChainRuleTestGraph();
arbiter.setRelationConfig('broken_chain', {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'nonexistent_relation', direction: 'out' } // Broken link
]
});
const result = arbiter.check('user:alice', 'broken_chain', 'project:web-app');
assert.equal(result.possibility, 0);
});
it('handles invalid extractFrom indices', () => {
const arbiter = setupChainRuleTestGraph();
arbiter.setRelationConfig('invalid_extract', {
type: 'chain',
steps: [
{ relation: 'member_of', direction: 'out' },
{ relation: 'manages', direction: 'out' }
],
extractValues: true,
extractFrom: 10, // Invalid index (only 2 steps)
extractRelation: 'has_budget'
});
const result = arbiter.check('user:alice', 'invalid_extract', 'budget:tech-2024');
// Should handle gracefully without crashing
assert.ok(typeof result.possibility === 'number');
});
it('handles circular chain references', () => {
const arbiter = setupChainRuleTestGraph();
// Create a circular reference
arbiter.addNode('node:a', 'node');
arbiter.addNode('node:b', 'node');
arbiter.addNode('node:c', 'node');
arbiter.addRelation('node:a', 'connects_to', 'node:b');
arbiter.addRelation('node:b', 'connects_to', 'node:c');
arbiter.addRelation('node:c', 'connects_to', 'node:a'); // Circular
arbiter.setRelationConfig('connects_to', { type: 'direct' });
arbiter.setRelationConfig('circular_chain', {
type: 'chain',
steps: [
{ relation: 'connects_to', direction: 'out' },
{ relation: 'connects_to', direction: 'out' },
{ relation: 'connects_to', direction: 'out' }
]
});
const result = arbiter.check('node:a', 'circular_chain', 'node:a');
// Should complete the circle
assert.equal(result.possibility, 1);
});
it('validates step configuration correctness', () => {
const arbiter = setupChainRuleTestGraph();
// Test with malformed step configuration
try {
arbiter.setRelationConfig('malformed_chain', {
type: 'chain',
steps: [
{ relation: 'member_of' }, // Missing direction
{ direction: 'out' } // Missing relation
]
});
const result = arbiter.check('user:alice', 'malformed_chain', 'project:web-app');
// Should handle gracefully
assert.equal(result.possibility, 0);
} catch (error) {
// Or might throw validation error - both acceptable
assert.ok(error.message.includes('relation') || error.message.includes('direction'));
}
});
});
});