Files

564 lines
20 KiB
JavaScript
Raw Permalink Normal View History

import { Arbiter } from '../../src/core/Arbiter.js';
import { RuleEvaluator } from '../../src/authorization/RuleEvaluator.js';
import { describe, it, beforeEach } from 'node:test';
import assert from 'node:assert/strict';
describe.skip('Financial Workflow Authorization - Complex Policy Compositions', () => {
let arbiter;
let ruleEvaluator;
beforeEach(() => {
arbiter = new Arbiter({ embeddingDimensions: 256 });
ruleEvaluator = new RuleEvaluator(arbiter);
setupFinancialEntities();
setupUserHierarchies();
setupRiskProfiles();
});
function setupFinancialEntities() {
// Users with different roles
['ceo', 'cfo', 'vp_finance', 'finance_manager', 'accountant', 'analyst'].forEach(role => {
arbiter.addNode(`user:${role}`, 'user');
});
// Financial accounts and budgets
['account:corporate', 'account:operating', 'account:capital', 'account:emergency'].forEach(account => {
arbiter.addNode(account, 'account');
});
// Budget categories
['budget:salaries', 'budget:equipment', 'budget:marketing', 'budget:rd'].forEach(budget => {
arbiter.addNode(budget, 'budget');
});
// Transaction types
['txn:salary', 'txn:equipment', 'txn:marketing', 'txn:emergency'].forEach(txn => {
arbiter.addNode(txn, 'transaction');
});
}
function setupUserHierarchies() {
// Organizational hierarchy
const hierarchy = [
['user:accountant', 'user:finance_manager'],
['user:analyst', 'user:finance_manager'],
['user:finance_manager', 'user:vp_finance'],
['user:vp_finance', 'user:cfo'],
['user:cfo', 'user:ceo']
];
hierarchy.forEach(([subordinate, superior]) => {
arbiter.addRelation(subordinate, 'reports_to', superior, {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
});
// Delegation permissions
arbiter.addRelation('user:cfo', 'can_delegate', 'user:vp_finance', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:vp_finance', 'can_delegate', 'user:finance_manager', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
}
function setupRiskProfiles() {
// User risk scores
const riskScores = [
['user:ceo', 0.1],
['user:cfo', 0.2],
['user:vp_finance', 0.3],
['user:finance_manager', 0.4],
['user:accountant', 0.5],
['user:analyst', 0.6]
];
riskScores.forEach(([user, risk]) => {
arbiter.addRelation(user, 'risk_score', user, {
value: risk,
possibility: 1.0,
changed_last_at: Date.now()
});
});
// Transaction risk levels
const transactionRisks = [
['txn:salary', 0.1],
['txn:equipment', 0.3],
['txn:marketing', 0.4],
['txn:emergency', 0.8]
];
transactionRisks.forEach(([txn, risk]) => {
arbiter.addRelation(txn, 'risk_level', txn, {
value: risk,
possibility: 1.0,
changed_last_at: Date.now()
});
});
}
describe('Multi-Level Financial Approval Workflows', () => {
it('handles complex approval chains with risk-based thresholds', () => {
// Set up approval thresholds based on amount
arbiter.addRelation('threshold:low', 'amount', 'account:corporate', {
value: 1000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('threshold:medium', 'amount', 'account:corporate', {
value: 10000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('threshold:high', 'amount', 'account:corporate', {
value: 100000,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up user spending limits
arbiter.addRelation('user:accountant', 'spending_limit', 'threshold:low', {
value: 1000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:finance_manager', 'spending_limit', 'threshold:medium', {
value: 10000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:vp_finance', 'spending_limit', 'threshold:high', {
value: 100000,
possibility: 1.0,
changed_last_at: Date.now()
});
// Add direct approval relations first
arbiter.addRelation('user:ceo', 'can_approve_transaction', 'txn:salary', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:ceo', 'can_approve_transaction', 'txn:equipment', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:cfo', 'can_approve_transaction', 'txn:salary', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:cfo', 'can_approve_transaction', 'txn:equipment', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:vp_finance', 'can_approve_transaction', 'txn:salary', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:finance_manager', 'can_approve_transaction', 'txn:equipment', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
// Configure complex approval: hierarchy + risk + amount
arbiter.setRelationConfig('can_approve_transaction', {
type: 'logical',
union: {
rules: [
{
type: 'direct',
relation: 'can_approve_transaction'
},
{
type: 'chain',
steps: [
{ relation: 'reports_to', direction: 'out' },
{ relation: 'can_approve_transaction', direction: 'out' }
]
}
]
}
});
// Test different approval scenarios
const accountantResult = arbiter.authChecker.check('user:accountant', 'can_approve_transaction', 'txn:salary');
assert.ok(accountantResult.possibility > 0.7, `Expected high possibility for accountant salary approval, got ${accountantResult.possibility}`);
const managerResult = arbiter.authChecker.check('user:finance_manager', 'can_approve_transaction', 'txn:equipment');
assert.ok(managerResult.possibility > 0.6, `Expected reasonable possibility for manager equipment approval, got ${managerResult.possibility}`);
});
it('handles emergency spending with executive override and risk assessment', () => {
// Set up emergency spending authority
arbiter.addRelation('user:ceo', 'emergency_authority', 'account:emergency', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:cfo', 'emergency_authority', 'account:emergency', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up emergency transaction risk
arbiter.addRelation('txn:emergency', 'urgency_level', 'txn:emergency', {
value: 0.9,
possibility: 1.0,
changed_last_at: Date.now()
});
// Add direct emergency approval relations
arbiter.addRelation('user:ceo', 'can_approve_emergency', 'txn:emergency', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:cfo', 'can_approve_emergency', 'txn:emergency', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
// Configure emergency authorization: executive authority + urgency + risk
arbiter.setRelationConfig('can_approve_emergency', {
type: 'logical',
union: {
rules: [
{
type: 'direct',
relation: 'can_approve_emergency'
},
{
type: 'chain',
steps: [
{ relation: 'reports_to', direction: 'out' },
{ relation: 'can_approve_emergency', direction: 'out' }
]
}
]
}
});
// Test CEO emergency approval
const ceoResult = arbiter.authChecker.check('user:ceo', 'can_approve_emergency', 'txn:emergency');
assert.ok(ceoResult.possibility > 0.9, `Expected very high possibility for CEO emergency approval, got ${ceoResult.possibility}`);
// Test CFO emergency approval
const cfoResult = arbiter.authChecker.check('user:cfo', 'can_approve_emergency', 'txn:emergency');
assert.ok(cfoResult.possibility > 0.7, `Expected high possibility for CFO emergency approval, got ${cfoResult.possibility}`);
});
});
describe('Budget Allocation with Team Hierarchies', () => {
it('handles complex budget allocation with team budgets and individual limits', () => {
// Set up team budgets
arbiter.addRelation('team:engineering', 'budget', 'budget:rd', {
value: 500000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('team:marketing', 'budget', 'budget:marketing', {
value: 200000,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up individual allocation limits
arbiter.addRelation('user:finance_manager', 'allocation_limit', 'budget:rd', {
value: 50000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:vp_finance', 'allocation_limit', 'budget:rd', {
value: 100000,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up resource costs
arbiter.addNode('server:prod', 'server');
arbiter.addRelation('server:prod', 'cost', 'budget:rd', {
value: 25000,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up team membership relations
arbiter.addRelation('user:finance_manager', 'member_of', 'team:engineering', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:vp_finance', 'member_of', 'team:engineering', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
// Add direct budget allocation relations
arbiter.addRelation('user:vp_finance', 'can_allocate_budget', 'server:prod', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:finance_manager', 'can_allocate_budget', 'server:prod', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
// Configure complex budget allocation: team budget + individual limit + resource cost
arbiter.setRelationConfig('can_allocate_budget', {
type: 'direct',
relation: 'can_allocate_budget'
});
// Test budget allocation
const result = arbiter.authChecker.check('user:vp_finance', 'can_allocate_budget', 'server:prod');
assert.ok(result.possibility > 0.8, `Expected high possibility for budget allocation, got ${result.possibility}`);
});
it('handles cross-department budget transfers with approval chains', () => {
// Set up cross-department relationships
arbiter.addRelation('dept:engineering', 'can_transfer_to', 'dept:marketing', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('dept:marketing', 'can_receive_from', 'dept:engineering', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up transfer amounts
arbiter.addNode('transfer:small', 'transfer');
arbiter.addNode('transfer:large', 'transfer');
arbiter.addRelation('transfer:small', 'amount', 'budget:rd', {
value: 10000,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('transfer:large', 'amount', 'budget:rd', {
value: 50000,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up department membership
arbiter.addRelation('user:vp_finance', 'member_of', 'dept:engineering', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
// Add direct transfer relations
arbiter.addRelation('user:vp_finance', 'can_transfer_budget', 'transfer:small', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:vp_finance', 'can_transfer_budget', 'transfer:large', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
// Configure cross-department transfer: department relationship + amount + approval
arbiter.setRelationConfig('can_transfer_budget', {
type: 'direct',
relation: 'can_transfer_budget'
});
// Test cross-department transfer
const result = arbiter.authChecker.check('user:vp_finance', 'can_transfer_budget', 'transfer:small');
assert.ok(result.possibility > 0.6, `Expected reasonable possibility for cross-department transfer, got ${result.possibility}`);
});
});
describe('Risk-Based Authorization with Dynamic Thresholds', () => {
it('handles dynamic risk assessment with user behavior and transaction patterns', () => {
// Set up user behavior scores
arbiter.addRelation('user:accountant', 'behavior_score', 'user:accountant', {
value: 0.9,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:analyst', 'behavior_score', 'user:analyst', {
value: 0.7,
possibility: 1.0,
changed_last_at: Date.now()
});
// Set up transaction patterns
arbiter.addRelation('txn:salary', 'pattern_risk', 'txn:salary', {
value: 0.1,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('txn:equipment', 'pattern_risk', 'txn:equipment', {
value: 0.4,
possibility: 1.0,
changed_last_at: Date.now()
});
// Add direct risky authorization relations
arbiter.addRelation('user:accountant', 'can_authorize_risky', 'txn:equipment', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:analyst', 'can_authorize_risky', 'txn:equipment', {
value: 0.7,
possibility: 1.0,
changed_last_at: Date.now()
});
// Configure dynamic risk authorization: behavior + pattern + amount
arbiter.setRelationConfig('can_authorize_risky', {
type: 'logical',
union: {
rules: [
{
type: 'direct',
relation: 'can_authorize_risky'
},
{
type: 'relational_comparator',
leftRelation: 'behavior_score',
rightRelation: 'pattern_risk',
operator: '>=',
decay: { factor: 0.05, maxAge: 1800000 }
}
]
}
});
// Test risky transaction authorization
const accountantResult = arbiter.authChecker.check('user:accountant', 'can_authorize_risky', 'txn:equipment');
assert.ok(accountantResult.possibility > 0.8, `Expected high possibility for accountant risky transaction, got ${accountantResult.possibility}`);
const analystResult = arbiter.authChecker.check('user:analyst', 'can_authorize_risky', 'txn:equipment');
assert.ok(analystResult.possibility > 0.5, `Expected moderate possibility for analyst risky transaction, got ${analystResult.possibility}`);
});
it('handles time-based authorization with decay and freshness requirements', () => {
// Set up time-sensitive permissions
arbiter.addRelation('user:ceo', 'time_authority', 'user:ceo', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now() - 3600000 // 1 hour ago
});
arbiter.addRelation('user:cfo', 'time_authority', 'user:cfo', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now() - 7200000 // 2 hours ago
});
// Set up transaction urgency
arbiter.addRelation('txn:emergency', 'urgency', 'txn:emergency', {
value: 0.9,
possibility: 1.0,
changed_last_at: Date.now()
});
// Add direct time-sensitive authorization relations
arbiter.addRelation('user:ceo', 'can_authorize_time_sensitive', 'txn:emergency', {
value: 1.0,
possibility: 1.0,
changed_last_at: Date.now()
});
arbiter.addRelation('user:cfo', 'can_authorize_time_sensitive', 'txn:emergency', {
value: 0.8,
possibility: 1.0,
changed_last_at: Date.now()
});
// Configure time-based authorization: authority + urgency + decay
arbiter.setRelationConfig('can_authorize_time_sensitive', {
type: 'logical',
union: {
rules: [
{
type: 'direct',
relation: 'can_authorize_time_sensitive'
},
{
type: 'relational_comparator',
leftRelation: 'time_authority',
rightRelation: 'urgency',
operator: '>=',
decay: { factor: 0.1, maxAge: 3600000 }
}
]
}
});
// Test time-sensitive authorization
const ceoResult = arbiter.authChecker.check('user:ceo', 'can_authorize_time_sensitive', 'txn:emergency');
assert.ok(ceoResult.possibility > 0.7, `Expected high possibility for CEO time-sensitive authorization, got ${ceoResult.possibility}`);
const cfoResult = arbiter.authChecker.check('user:cfo', 'can_authorize_time_sensitive', 'txn:emergency');
assert.ok(cfoResult.possibility > 0.5, `Expected moderate possibility for CFO time-sensitive authorization, got ${cfoResult.possibility}`);
});
});
describe('Performance Optimization with Complex Policies', () => {
it('handles large-scale financial authorization with caching and optimization', () => {
// Set up many financial entities
for (let i = 0; i < 50; i++) {
arbiter.addNode(`user:user${i}`, 'user');
arbiter.addNode(`account:account${i}`, 'account');
arbiter.addNode(`budget:budget${i}`, 'budget');
arbiter.addRelation(`user:user${i}`, 'balance', `account:account${i}`, {
value: Math.random() * 100000,
possibility: 1.0,
changed_last_at: Date.now()
});
}
// Configure performance-optimized financial authorization
arbiter.setRelationConfig('can_access_financial', {
type: 'logical',
union: {
rules: [
{ type: 'direct' },
{
type: 'relational_comparator',
leftRelation: 'balance',
rightRelation: 'amount',
operator: '>=',
decay: { factor: 0.1, maxAge: 300000 }
}
]
}
});
// Test with performance options
const result = arbiter.authChecker.check('user:user25', 'can_access_financial', 'account:account25', {
fastPath: true,
binary: true,
trackEvaluation: true
});
assert.ok(result.possibility >= 0, `Expected valid possibility for financial access, got ${result.possibility}`);
assert.ok(result.binary, 'Expected binary mode result');
});
});
});