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,534 @@
|
||||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { DSLCompiler } from '../../src/ast/DSLCompiler.js';
|
||||
|
||||
function createMockArbiter() {
|
||||
const relationConfigs = new Map();
|
||||
return {
|
||||
relationConfigs,
|
||||
setRelationConfig(relation, config) {
|
||||
relationConfigs.set(relation, config);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
const arbiter = createMockArbiter();
|
||||
const compiler = new DSLCompiler(arbiter);
|
||||
|
||||
test('Complete authorization system', () => {
|
||||
const completeSystem = `
|
||||
// Type definitions with complex behaviors
|
||||
definition User {
|
||||
role: string
|
||||
isActive: boolean
|
||||
lastActive: timestamp BEHAVES {
|
||||
decaying down hourly
|
||||
} CACHE lazy
|
||||
isSuspended: boolean
|
||||
balance: number BEHAVES {
|
||||
decaying down hourly
|
||||
} CACHE eager
|
||||
score: number BEHAVES {
|
||||
blurring adaptive confidence_95
|
||||
} CACHE lazy
|
||||
session: string BEHAVES {
|
||||
ttl 24h
|
||||
} CACHE eager
|
||||
clearance: string BEHAVES {
|
||||
blurring fixed
|
||||
} CACHE eager
|
||||
reputation: number BEHAVES {
|
||||
decaying up daily
|
||||
} CACHE lazy
|
||||
}
|
||||
|
||||
definition Group {
|
||||
name: string
|
||||
permissions: Permission[]
|
||||
level: string
|
||||
isPublic: boolean CACHE eager
|
||||
created: timestamp BEHAVES {
|
||||
decaying stable monthly
|
||||
} CACHE lazy
|
||||
}
|
||||
|
||||
definition Document {
|
||||
level: string
|
||||
owner: User
|
||||
tags: string[]
|
||||
content: string BEHAVES {
|
||||
blurring fixed
|
||||
} CACHE lazy
|
||||
accessCount: number BEHAVES {
|
||||
decaying up daily
|
||||
} CACHE eager
|
||||
expiresAt: timestamp BEHAVES {
|
||||
ttl 30d
|
||||
} CACHE eager
|
||||
isPublic: boolean CACHE eager
|
||||
}
|
||||
|
||||
definition Resource {
|
||||
level: string
|
||||
owner: User
|
||||
permissions: Permission[]
|
||||
isPublic: boolean CACHE eager
|
||||
accessCount: number BEHAVES {
|
||||
decaying up daily
|
||||
} CACHE eager
|
||||
}
|
||||
|
||||
// Facts with various properties and caching
|
||||
fact hasRole(user: User, role: string) CACHE eager
|
||||
fact isMember(user: User, group: Group) transitive CACHE lazy limit 10
|
||||
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100
|
||||
fact owns(user: User, doc: Document) CACHE eager
|
||||
fact isSuspended(user: User) CACHE lazy
|
||||
fact hasPermission(user: User, resource: Resource, action: string) CACHE eager
|
||||
fact isAdmin(user: User) CACHE eager
|
||||
fact isOwner(user: User, resource: Resource) CACHE eager
|
||||
fact hasAccess(user: User, resource: Resource, level: string) CACHE lazy
|
||||
fact isColleague(user: User, colleague: User) symmetrical CACHE lazy limit 50
|
||||
fact isParentOf(parent: User, child: User) transitive CACHE eager limit 3
|
||||
|
||||
// Evidence rules with complex logic
|
||||
evidence canRead(user: User, doc: Document) {
|
||||
owns(user, doc)
|
||||
|
||||
isMember(user, *group) {
|
||||
canRead(group, doc)
|
||||
} limit 5
|
||||
|
||||
parentOf(user, *parent) {
|
||||
canRead(parent, doc)
|
||||
} limit 3
|
||||
|
||||
similar(doc, *similar) |similarity| {
|
||||
canRead(user, similar)
|
||||
} with similarity > 0.7 limit 5
|
||||
|
||||
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
|
||||
}
|
||||
|
||||
evidence canWrite(user: User, doc: Document) {
|
||||
owns(user, doc)
|
||||
|
||||
isMember(user, *group) {
|
||||
canWrite(group, doc)
|
||||
} limit 3
|
||||
|
||||
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
|
||||
|
||||
REQUIRES user.isActive
|
||||
}
|
||||
|
||||
evidence canDelete(user: User, doc: Document) {
|
||||
owns(user, doc)
|
||||
|
||||
ALWAYS user.isActive
|
||||
|
||||
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
|
||||
|
||||
REQUIRES user.isActive
|
||||
}
|
||||
|
||||
evidence canAccessCritical(user: User, resource: Resource) {
|
||||
fusion min {
|
||||
hasClearance(user, resource.level)
|
||||
user.isActive
|
||||
NOT user.isBlacklisted
|
||||
}
|
||||
|
||||
fusion max {
|
||||
hasRole(user, 'admin')
|
||||
fusion majority {
|
||||
hasClearance(user, 'secret')
|
||||
user.isTrusted
|
||||
user.lastActive within 1hr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
evidence canAccessSensitive(user: User, doc: Document) {
|
||||
ALWAYS user.isActive
|
||||
|
||||
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
|
||||
|
||||
REQUIRES hasClearance(user, doc.level)
|
||||
|
||||
fusion majority {
|
||||
user.isTrusted
|
||||
user.hasRecentActivity
|
||||
}
|
||||
}
|
||||
|
||||
// Measures for computed values
|
||||
measure userRole(user: User) {
|
||||
user.role
|
||||
} PROVIDES string
|
||||
|
||||
measure userPermissions(user: User) {
|
||||
fusion max {
|
||||
user.role.permissions
|
||||
user.group.permissions
|
||||
}
|
||||
} PROVIDES Permission[]
|
||||
|
||||
measure effectiveClearance(user: User) {
|
||||
fusion majority {
|
||||
user.clearance
|
||||
user.role.clearance
|
||||
user.group.clearance
|
||||
}
|
||||
} PROVIDES string
|
||||
|
||||
measure userTrustScore(user: User) {
|
||||
fusion average {
|
||||
user.reputation
|
||||
user.activityScore
|
||||
user.verificationLevel
|
||||
}
|
||||
} PROVIDES number
|
||||
|
||||
measure userBalance(user: User) {
|
||||
user.balance
|
||||
} PROVIDES number
|
||||
|
||||
measure userScore(user: User) {
|
||||
user.score
|
||||
} PROVIDES number
|
||||
`;
|
||||
|
||||
const result = compiler.compile(completeSystem, 'test-complete-system');
|
||||
assert.ok(result.success, 'Complete authorization system should compile successfully');
|
||||
assert.ok(result.program.definitions.length >= 4, 'Should have multiple definitions');
|
||||
assert.ok(result.program.facts.length >= 10, 'Should have multiple facts');
|
||||
assert.ok(result.program.evidence.length >= 5, 'Should have multiple evidence rules');
|
||||
assert.ok(result.program.measures.length >= 6, 'Should have multiple measures');
|
||||
});
|
||||
|
||||
test('Multi-domain system', () => {
|
||||
const multiDomain = `
|
||||
// Authentication domain
|
||||
definition User {
|
||||
role: string
|
||||
isActive: boolean
|
||||
lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy
|
||||
session: string BEHAVES { ttl 24h } CACHE eager
|
||||
}
|
||||
|
||||
fact hasRole(user: User, role: string) CACHE eager
|
||||
fact isActive(user: User) CACHE eager
|
||||
|
||||
evidence canAuthenticate(user: User) {
|
||||
user.isActive
|
||||
user.session within 24h
|
||||
}
|
||||
|
||||
// Authorization domain
|
||||
definition Resource {
|
||||
level: string
|
||||
owner: User
|
||||
permissions: Permission[]
|
||||
}
|
||||
|
||||
fact owns(user: User, resource: Resource) CACHE eager
|
||||
fact hasPermission(user: User, resource: Resource, action: string) CACHE eager
|
||||
|
||||
evidence canAccess(user: User, resource: Resource) {
|
||||
owns(user, resource)
|
||||
hasPermission(user, resource, 'read')
|
||||
}
|
||||
|
||||
// Finance domain
|
||||
definition Account {
|
||||
balance: number BEHAVES { decaying down hourly } CACHE eager
|
||||
owner: User
|
||||
isActive: boolean CACHE eager
|
||||
}
|
||||
|
||||
fact hasAccount(user: User, account: Account) CACHE eager
|
||||
fact hasBalance(user: User, amount: number) CACHE eager
|
||||
|
||||
evidence canWithdraw(user: User, amount: number) {
|
||||
hasBalance(user, amount)
|
||||
user.isActive
|
||||
}
|
||||
|
||||
// Social domain
|
||||
definition Group {
|
||||
name: string
|
||||
members: User[]
|
||||
isPublic: boolean CACHE eager
|
||||
}
|
||||
|
||||
fact isMember(user: User, group: Group) transitive CACHE lazy limit 10
|
||||
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100
|
||||
|
||||
evidence canAccessGroup(user: User, group: Group) {
|
||||
isMember(user, group)
|
||||
group.isPublic
|
||||
}
|
||||
`;
|
||||
|
||||
const result = compiler.compile(multiDomain, 'test-multi-domain');
|
||||
assert.ok(result.success, 'Multi-domain system should compile successfully');
|
||||
assert.ok(result.program.definitions.length >= 4, 'Should have multiple domain definitions');
|
||||
assert.ok(result.program.facts.length >= 8, 'Should have multiple domain facts');
|
||||
assert.ok(result.program.evidence.length >= 4, 'Should have multiple domain evidence rules');
|
||||
});
|
||||
|
||||
test('Hierarchical access', () => {
|
||||
const hierarchicalSystem = `
|
||||
definition User {
|
||||
role: string
|
||||
level: string
|
||||
isActive: boolean
|
||||
clearance: string
|
||||
}
|
||||
|
||||
definition Organization {
|
||||
name: string
|
||||
level: string
|
||||
parent: Organization
|
||||
}
|
||||
|
||||
fact isMember(user: User, org: Organization) transitive CACHE lazy limit 5
|
||||
fact isParentOf(parent: Organization, child: Organization) transitive CACHE eager limit 3
|
||||
fact hasRole(user: User, role: string) CACHE eager
|
||||
fact hasClearance(user: User, level: string) CACHE eager
|
||||
|
||||
evidence canAccessOrg(user: User, org: Organization) {
|
||||
isMember(user, org)
|
||||
|
||||
isParentOf(org, *parentOrg) {
|
||||
canAccessOrg(user, parentOrg)
|
||||
} limit 3
|
||||
|
||||
WHEN hasRole(user, 'admin') UNLESS user.isSuspended
|
||||
}
|
||||
|
||||
evidence canAccessResource(user: User, resource: Resource) {
|
||||
isMember(user, *org) {
|
||||
canAccessResource(org, resource)
|
||||
} limit 5
|
||||
|
||||
parentOf(user, *parent) {
|
||||
canAccessResource(parent, resource)
|
||||
} limit 2
|
||||
}
|
||||
`;
|
||||
|
||||
const result = compiler.compile(hierarchicalSystem, 'test-hierarchical');
|
||||
assert.ok(result.success, 'Hierarchical access system should compile successfully');
|
||||
});
|
||||
|
||||
test('Similarity-based access', () => {
|
||||
const similaritySystem = `
|
||||
definition User {
|
||||
profile: string
|
||||
interests: string[]
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
definition Document {
|
||||
content: string
|
||||
tags: string[]
|
||||
isPublic: boolean
|
||||
owner: User
|
||||
}
|
||||
|
||||
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100
|
||||
fact hasInterest(user: User, interest: string) CACHE lazy
|
||||
fact hasTag(doc: Document, tag: string) CACHE lazy
|
||||
|
||||
evidence canRead(user: User, doc: Document) {
|
||||
owns(user, doc)
|
||||
|
||||
similar(doc, *similar) |similarity| {
|
||||
canRead(user, similar)
|
||||
similar.isPublic
|
||||
} with similarity > 0.7 limit 10
|
||||
|
||||
isFriend(user, *friend) {
|
||||
canRead(friend, doc)
|
||||
} limit 5
|
||||
|
||||
fusion majority {
|
||||
user.interests
|
||||
doc.tags
|
||||
}
|
||||
}
|
||||
|
||||
evidence canRecommend(user: User, doc: Document) {
|
||||
similar(user, *similarUser) |similarity| {
|
||||
canRead(similarUser, doc)
|
||||
} with similarity > 0.8 limit 20
|
||||
|
||||
fusion average {
|
||||
user.profile
|
||||
doc.content
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const result = compiler.compile(similaritySystem, 'test-similarity');
|
||||
assert.ok(result.success, 'Similarity-based access system should compile successfully');
|
||||
});
|
||||
|
||||
test('Temporal access', () => {
|
||||
const temporalSystem = `
|
||||
definition User {
|
||||
lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy
|
||||
session: string BEHAVES { ttl 24h } CACHE eager
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
definition Event {
|
||||
startTime: timestamp
|
||||
endTime: timestamp
|
||||
isPublic: boolean
|
||||
}
|
||||
|
||||
fact hasAccess(user: User, event: Event) CACHE lazy
|
||||
fact isParticipant(user: User, event: Event) CACHE eager
|
||||
|
||||
evidence canAccessEvent(user: User, event: Event) {
|
||||
user.lastActive within 1h
|
||||
|
||||
isParticipant(user, event)
|
||||
|
||||
WHEN event.isPublic UNLESS user.isSuspended
|
||||
|
||||
fusion min {
|
||||
user.session within 24h
|
||||
user.isActive
|
||||
}
|
||||
}
|
||||
|
||||
evidence canAccessHistorical(user: User, event: Event) {
|
||||
user.lastActive within 24h
|
||||
|
||||
fusion majority {
|
||||
user.isActive
|
||||
user.session within 24h
|
||||
event.isPublic
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const result = compiler.compile(temporalSystem, 'test-temporal');
|
||||
assert.ok(result.success, 'Temporal access system should compile successfully');
|
||||
});
|
||||
|
||||
test('Complex behaviors', () => {
|
||||
const behaviorSystem = `
|
||||
definition User {
|
||||
balance: number BEHAVES { decaying down hourly } CACHE eager
|
||||
score: number BEHAVES { blurring adaptive confidence_95 } CACHE lazy
|
||||
session: string BEHAVES { ttl 24h } CACHE eager
|
||||
reputation: number BEHAVES { decaying up daily } CACHE lazy
|
||||
clearance: string BEHAVES { blurring fixed } CACHE eager
|
||||
lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy
|
||||
}
|
||||
|
||||
definition Document {
|
||||
content: string BEHAVES { blurring fixed } CACHE lazy
|
||||
accessCount: number BEHAVES { decaying up daily } CACHE eager
|
||||
expiresAt: timestamp BEHAVES { ttl 30d } CACHE eager
|
||||
isPublic: boolean CACHE eager
|
||||
}
|
||||
|
||||
fact hasBalance(user: User, amount: number) CACHE eager
|
||||
fact hasScore(user: User, score: number) CACHE lazy
|
||||
fact hasReputation(user: User, reputation: number) CACHE lazy
|
||||
|
||||
evidence canAccessDocument(user: User, doc: Document) {
|
||||
user.balance > 0
|
||||
|
||||
user.score > 0.5
|
||||
|
||||
user.reputation > 0.3
|
||||
|
||||
doc.accessCount < 1000
|
||||
|
||||
fusion majority {
|
||||
user.isActive
|
||||
user.lastActive within 1h
|
||||
doc.isPublic
|
||||
}
|
||||
}
|
||||
|
||||
measure userEffectiveScore(user: User) {
|
||||
fusion average {
|
||||
user.score
|
||||
user.reputation
|
||||
user.balance
|
||||
}
|
||||
} PROVIDES number
|
||||
|
||||
measure documentPopularity(doc: Document) {
|
||||
doc.accessCount
|
||||
} PROVIDES number
|
||||
`;
|
||||
|
||||
const result = compiler.compile(behaviorSystem, 'test-behaviors');
|
||||
assert.ok(result.success, 'Complex behaviors system should compile successfully');
|
||||
});
|
||||
|
||||
test('Performance scenarios', () => {
|
||||
const performanceSystem = `
|
||||
definition User {
|
||||
role: string
|
||||
isActive: boolean
|
||||
permissions: Permission[] CACHE eager
|
||||
}
|
||||
|
||||
definition Resource {
|
||||
level: string
|
||||
owner: User
|
||||
permissions: Permission[] CACHE eager
|
||||
}
|
||||
|
||||
// High-frequency facts with limits
|
||||
fact isMember(user: User, group: Group) transitive CACHE lazy limit 5
|
||||
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 50
|
||||
fact hasPermission(user: User, resource: Resource, action: string) CACHE eager
|
||||
fact owns(user: User, resource: Resource) CACHE eager
|
||||
|
||||
// Optimized evidence rules
|
||||
evidence canAccess(user: User, resource: Resource) {
|
||||
owns(user, resource)
|
||||
|
||||
isMember(user, *group) {
|
||||
canAccess(group, resource)
|
||||
} limit 3
|
||||
|
||||
WHEN hasPermission(user, resource, 'read')
|
||||
}
|
||||
|
||||
evidence canModify(user: User, resource: Resource) {
|
||||
owns(user, resource)
|
||||
|
||||
isMember(user, *group) {
|
||||
canModify(group, resource)
|
||||
} limit 2
|
||||
|
||||
WHEN hasPermission(user, resource, 'write')
|
||||
}
|
||||
|
||||
// Efficient measures
|
||||
measure userEffectivePermissions(user: User) {
|
||||
user.permissions
|
||||
} PROVIDES Permission[]
|
||||
|
||||
measure resourceAccessLevel(resource: Resource) {
|
||||
resource.level
|
||||
} PROVIDES string
|
||||
`;
|
||||
|
||||
const result = compiler.compile(performanceSystem, 'test-performance');
|
||||
assert.ok(result.success, 'Performance scenarios should compile successfully');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user