import test from 'node:test'; import assert from 'node:assert/strict'; import { DEFAULT_USER_CAPABILITIES } from './capabilities.mjs'; import { applyPoliciesToCapabilities, DEFAULT_USER_POLICIES, evaluateProxyRequest, normalizePolicyPatch, resolveAgentGooseMode, resolvePolicies, } from './policies.mjs'; test('default user policies are conservative', () => { assert.equal(DEFAULT_USER_POLICIES.goose_mode, 'chat'); assert.equal(DEFAULT_USER_POLICIES.network_egress, 'deny'); assert.equal(DEFAULT_USER_POLICIES.api_lockdown, true); assert.equal(DEFAULT_USER_POLICIES.code_delegate_executor, 'auto'); assert.equal(DEFAULT_USER_POLICIES.code_task_routing, 'balanced'); }); test('readonly workspace strips write capabilities', () => { const effective = applyPoliciesToCapabilities( { shell: true, filesystem: true, code_browse: true, aider: true, openhands: true }, { workspace_access: 'readonly' }, ); assert.equal(effective.shell, false); assert.equal(effective.filesystem, false); assert.equal(effective.code_browse, true); assert.equal(effective.aider, false); assert.equal(effective.openhands, false); }); test('network deny strips egress capabilities', () => { const effective = applyPoliciesToCapabilities( { shell: true, computer: true, web: true, charts: true }, { network_egress: 'deny' }, ); assert.equal(effective.shell, false); assert.equal(effective.computer, false); assert.equal(effective.web, false); assert.equal(effective.charts, true); }); test('network deny keeps shell for static_publish sandbox users', () => { const effective = applyPoliciesToCapabilities( { static_publish: true, shell: true, computer: true }, { network_egress: 'deny' }, ); assert.equal(effective.shell, true); assert.equal(effective.computer, false); }); test('api lockdown blocks extension admin routes', () => { const denied = evaluateProxyRequest('POST', '/agent/add_extension', { api_lockdown: true, }); assert.equal(denied.allowed, false); const allowed = evaluateProxyRequest('POST', '/sessions/abc/reply', { api_lockdown: true, }); assert.equal(allowed.allowed, true); const agentRunCreate = evaluateProxyRequest('POST', '/agent/runs', { api_lockdown: true, }); assert.equal(agentRunCreate.allowed, true); const agentRunGet = evaluateProxyRequest('GET', '/agent/runs/run-1', { api_lockdown: true, }); assert.equal(agentRunGet.allowed, true); const agentRunEvents = evaluateProxyRequest('GET', '/agent/runs/run-1/events', { api_lockdown: true, }); assert.equal(agentRunEvents.allowed, true); const deleteAllowed = evaluateProxyRequest('DELETE', '/sessions/abc', { api_lockdown: true, }); assert.equal(deleteAllowed.allowed, true); }); test('api lockdown blocks native H5 APIs from agent proxy fallback', () => { const denied = evaluateProxyRequest( 'POST', '/mindspace/v1/pages/demo/thumbnail/regenerate', { api_lockdown: true }, ); assert.equal(denied.allowed, false); assert.match(denied.reason ?? '', /H5 本地接口不应走 Agent 代理/); }); test('unrestricted users bypass api lockdown', () => { const result = evaluateProxyRequest('POST', '/config/permissions', {}, { unrestricted: true }); assert.equal(result.allowed, true); }); test('resolvePolicies maps legacy approve modes to auto', () => { const resolved = resolvePolicies({ goose_mode: 'approve' }, {}); assert.equal(resolved.goose_mode, 'auto'); }); test('resolveAgentGooseMode uses chat when no tools are enabled', () => { const chatOnly = { ...DEFAULT_USER_CAPABILITIES, skills: false, chat_recall: false, memory_store: false, context_memory: false, image_read: false, }; assert.equal(resolveAgentGooseMode(chatOnly, { goose_mode: 'auto' }), 'chat'); }); test('resolveAgentGooseMode auto-runs tools without end-user prompts', () => { assert.equal( resolveAgentGooseMode(DEFAULT_USER_CAPABILITIES, { goose_mode: 'chat' }), 'auto', ); assert.equal( resolveAgentGooseMode( { ...DEFAULT_USER_CAPABILITIES, static_publish: true }, { goose_mode: 'chat' }, ), 'auto', ); assert.equal( resolveAgentGooseMode( { ...DEFAULT_USER_CAPABILITIES, static_publish: true }, { goose_mode: 'approve' }, ), 'auto', ); assert.equal( resolveAgentGooseMode( { ...DEFAULT_USER_CAPABILITIES, openhands: true, skills: false, chat_recall: false }, { goose_mode: 'chat' }, ), 'auto', ); }); test('resolvePolicies merges role and user overrides', () => { const resolved = resolvePolicies( { goose_mode: 'approve', api_lockdown: true, code_delegate_executor: 'aider', code_task_routing: 'force_aider', }, { goose_mode: 'chat', code_delegate_executor: 'openhands', code_task_routing: 'split', }, ); assert.equal(resolved.goose_mode, 'chat'); assert.equal(resolved.api_lockdown, true); assert.equal(resolved.code_delegate_executor, 'openhands'); assert.equal(resolved.code_task_routing, 'split'); }); test('normalizePolicyPatch ignores invalid values', () => { assert.deepEqual( normalizePolicyPatch({ goose_mode: 'invalid', api_lockdown: true, code_delegate_executor: 'openhands', code_task_routing: 'force_openhands', bogus: 'x', }), { api_lockdown: true, code_delegate_executor: 'openhands', code_task_routing: 'force_openhands', }, ); });