import { test, describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { setupChainRuleTestGraph } from './helpers.js'; describe('ChainRule Comprehensive Tests', () => { describe('Value Extraction and Aggregation', () => { it('extracts and sums values from chain endpoints', () => { const arbiter = setupChainRuleTestGraph(); // Test: user → group → project → budget (extract budget values) arbiter.setRelationConfig('user_budget_access', { type: 'chain', steps: [ { relation: 'member_of', direction: 'out' }, // user → group { relation: 'manages', direction: 'out' }, // group → project { relation: 'has_budget', direction: 'out' } // project → budget ], extractValues: true, extractFrom: 2, // Extract from step 2 (projects) extractRelation: 'has_budget', // Extract budget values valueAggregation: 'sum' // Sum all budgets }); // Alice should have access to engineering budgets const result1 = arbiter.check('user:alice', 'user_budget_access', 'budget:tech-2024'); // Authorization should succeed assert.equal(result1.possibility, 1); assert.equal(result1.reason, 'allow_rule_matched'); // Values should NOT be in the authorization result (they're internal only) assert.equal(result1.value, undefined); assert.equal(result1.hasValue, undefined); // The ChainRule internally calculated values for potential use by other rules, // but authorization results only contain allow/deny possibilities }); it('aggregates values using max aggregation', () => { const arbiter = setupChainRuleTestGraph(); arbiter.setRelationConfig('max_project_budget', { type: 'chain', steps: [ { relation: 'member_of', direction: 'out' }, { relation: 'manages', direction: 'out' }, { relation: 'has_budget', direction: 'out' } ], extractValues: true, extractFrom: 2, extractRelation: 'has_budget', valueAggregation: 'max' // Use maximum budget }); // Alice should have access to budgets const result = arbiter.check('user:alice', 'max_project_budget', 'budget:tech-2024'); assert.equal(result.possibility, 1); // Values are internal only, not exposed in authorization results assert.equal(result.value, undefined); }); it('aggregates values using min aggregation', () => { const arbiter = setupChainRuleTestGraph(); arbiter.setRelationConfig('min_project_cost', { type: 'chain', steps: [ { relation: 'member_of', direction: 'out' }, { relation: 'manages', direction: 'out' }, { relation: 'has_cost', direction: 'out' } ], extractValues: true, extractFrom: 2, extractRelation: 'has_cost', valueAggregation: 'min' // Use minimum cost }); // Alice should have access to cost information const result = arbiter.check('user:alice', 'min_project_cost', 'budget:tech-2024'); assert.equal(result.possibility, 1); // Values are internal only, not exposed in authorization results assert.equal(result.value, undefined); }); }); });