import { describe, it, expect } from 'vitest'; import { canAct } from '../../lib/auth/capability.js'; const ownerActor = { kind: 'user', id: null }; const readAgent = { kind: 'agent', id: 'a1', capabilities: { read: true, suggest: true, write: false }, scopes: {} }; const writeAgent = { kind: 'agent', id: 'a2', capabilities: { read: true, suggest: true, write: true }, scopes: { page: true } }; describe('canAct', () => { it('owner can do anything', () => { expect(canAct(ownerActor, 'create', 'page')).toBe('allow'); expect(canAct(ownerActor, 'delete', 'resource')).toBe('allow'); }); it('read-only agent can read', () => { expect(canAct(readAgent, 'read', 'page')).toBe('allow'); }); it('default agent on create returns "suggest"', () => { expect(canAct(readAgent, 'create', 'page')).toBe('suggest'); }); it('write-scoped agent can write to its scope', () => { expect(canAct(writeAgent, 'create', 'page')).toBe('allow'); }); it('write-capable agent without scope still suggests outside it', () => { expect(canAct(writeAgent, 'create', 'resource')).toBe('suggest'); }); it('agent with no capabilities is deny on mutations', () => { expect(canAct({ kind: 'agent', id: 'x', capabilities: {} }, 'create', 'page')).toBe('deny'); }); it('agent with no read capability is deny on read', () => { expect(canAct({ kind: 'agent', id: 'x', capabilities: {} }, 'read', 'page')).toBe('deny'); }); it('null actor is deny', () => { expect(canAct(null, 'read', 'page')).toBe('deny'); }); it('cron/worker/system get allow', () => { expect(canAct({ kind: 'cron', id: null }, 'create', 'page')).toBe('allow'); expect(canAct({ kind: 'worker', id: null }, 'update', 'page')).toBe('allow'); expect(canAct({ kind: 'system', id: null }, 'delete', 'page')).toBe('allow'); }); });