/**
 * RED-GREEN tests for F-NEW-PRODUCT-PER-AGENT-OVERRIDE-AUTHORITY (W1.9).
 *
 * Thomas directive 2026-05-12: "individual agents can be overridden by the
 * developer or CISO to allow MCP usage or to delete a database... we're not
 * going to restrict them. We'll just notify them if they override it and an
 * accident happens, as long as we have the incident recorded and we have
 * approval for an employee to change the requirement."
 *
 * Validates:
 *   - Override RELAXES a baseline BLOCK on a specific agent
 *   - OverrideEvent is emitted with full provenance (approver / justification /
 *     baseline action / relaxed action / overrideId)
 *   - Override requires approver + justification + approvedAt (fail-closed)
 *   - Overrides do NOT affect agents without that override (cross-agent isolation)
 *   - Without override, strictest-wins still applies
 *
 * @connexum/ai-governance  F-NEW-PRODUCT-PER-AGENT-OVERRIDE-AUTHORITY
 */
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { buildOrgBaselinePack, composeAgentPack, } from './pack-inheritance.js';
import { CAPABILITY_CLASS } from './capability-classes.js';
import { PackEvaluator } from './pack-evaluator.js';
import { PackRegistry } from '../packs/index.js';
import { EventBus } from '../audit/event-bus.js';
import { createActionContext } from '../adapters/index.js';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
function evalActionWithPack(pack, toolName, input = {}) {
    const registry = new PackRegistry();
    registry.register(pack);
    registry.activate(pack.id);
    const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ov-'));
    const bus = new EventBus({ eventDir: dir, agentName: 'ov-test' });
    const evaluator = new PackEvaluator(registry, bus, { ttlMs: 60_000, enableCache: false });
    const ac = createActionContext(toolName, input, { name: 'agent-x', orgId: 'org-x' });
    return evaluator.evaluate('org-x', 'agent-x', ac);
}
describe('F-NEW-PRODUCT-PER-AGENT-OVERRIDE-AUTHORITY (W1.9)', () => {
    it('override RELAXES baseline BLOCK on a specific agent', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        const composed = composeAgentPack(baseline, {
            id: 'agent-mcp-allowed',
            name: 'agent allowed MCP via override',
            orgId: 'org-x',
            agentId: 'agent-mcp-allowed',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.MCP,
                    action: 'LOG', // relaxed from BLOCK -> LOG
                    approver: 'cto-bob',
                    justification: 'Agent integrates with internal MCP server; vetted by Security Council 2026-05-12.',
                    approvedAt: '2026-05-12T10:00:00.000Z',
                },
            ],
        });
        const verdict = evalActionWithPack(composed, 'mcp__list_resources');
        assert.equal(verdict.verdict, 'ALLOW', 'override LOG action allows the MCP call (was BLOCK without override)');
    });
    it('override emits an OverrideEvent with full provenance', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.EXTERNAL_DB_WRITE, action: 'BLOCK' }],
        });
        const events = [];
        composeAgentPack(baseline, {
            id: 'agent-db-allowed',
            name: 'agent allowed DB writes',
            orgId: 'org-x',
            agentId: 'agent-db-allowed',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.EXTERNAL_DB_WRITE,
                    action: 'REQUIRE_APPROVAL',
                    approver: 'ciso-alice',
                    justification: 'DB writes required for nightly batch ETL; gated by approval workflow.',
                    approvedAt: '2026-05-12T11:00:00.000Z',
                    overrideId: 'ov-db-001',
                },
            ],
        }, { onOverride: (ev) => events.push(ev) });
        assert.equal(events.length, 1);
        const ev = events[0];
        assert.equal(ev.overrideId, 'ov-db-001');
        assert.equal(ev.capability, CAPABILITY_CLASS.EXTERNAL_DB_WRITE);
        assert.equal(ev.baselineAction, 'BLOCK');
        assert.equal(ev.relaxedAction, 'REQUIRE_APPROVAL');
        assert.equal(ev.approver, 'ciso-alice');
        assert.equal(ev.agentId, 'agent-db-allowed');
        assert.equal(ev.orgId, 'org-x');
        assert.ok(ev.composedAt.length > 0);
    });
    it('override without approver throws fail-closed', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        assert.throws(() => composeAgentPack(baseline, {
            id: 'agent-bad',
            name: 'agent bad',
            orgId: 'org-x',
            agentId: 'agent-bad',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.MCP,
                    action: 'LOG',
                    approver: '', // empty -- fail-closed
                    justification: 'ok',
                    approvedAt: '2026-05-12T10:00:00.000Z',
                },
            ],
        }), /missing an approver/i);
    });
    it('override without justification throws fail-closed', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        assert.throws(() => composeAgentPack(baseline, {
            id: 'agent-bad',
            name: 'agent bad',
            orgId: 'org-x',
            agentId: 'agent-bad',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.MCP,
                    action: 'LOG',
                    approver: 'cto-bob',
                    justification: '',
                    approvedAt: '2026-05-12T10:00:00.000Z',
                },
            ],
        }), /missing a justification/i);
    });
    it('override invalid approvedAt throws fail-closed', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        assert.throws(() => composeAgentPack(baseline, {
            id: 'agent-bad',
            name: 'agent bad',
            orgId: 'org-x',
            agentId: 'agent-bad',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.MCP,
                    action: 'LOG',
                    approver: 'cto-bob',
                    justification: 'ok',
                    approvedAt: 'not-a-timestamp',
                },
            ],
        }), /invalid approvedAt/i);
    });
    it('no overrides -> strictest-wins still applies (unchanged W1.3 behavior)', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        const composed = composeAgentPack(baseline, {
            id: 'agent-no-override',
            name: 'no override',
            orgId: 'org-x',
            agentId: 'agent-no-override',
            rules: [],
        });
        const v = evalActionWithPack(composed, 'mcp__list_resources');
        assert.equal(v.verdict, 'DENY', 'baseline BLOCK survives in absence of override');
    });
    it('cross-agent isolation: override on agent A does not affect agent B', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        const packA = composeAgentPack(baseline, {
            id: 'agent-a-pack',
            name: 'A',
            orgId: 'org-x',
            agentId: 'agent-a',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.MCP,
                    action: 'LOG',
                    approver: 'cto-bob',
                    justification: 'Agent A only',
                    approvedAt: '2026-05-12T10:00:00.000Z',
                },
            ],
        });
        const packB = composeAgentPack(baseline, {
            id: 'agent-b-pack',
            name: 'B',
            orgId: 'org-x',
            agentId: 'agent-b',
            rules: [],
        });
        const vA = evalActionWithPack(packA, 'mcp__list_resources');
        const vB = evalActionWithPack(packB, 'mcp__list_resources');
        assert.equal(vA.verdict, 'ALLOW', 'A has override -> ALLOW');
        assert.equal(vB.verdict, 'DENY', 'B has no override -> baseline BLOCK -> DENY');
    });
    it('override action REQUIRE_APPROVAL produces PENDING at runtime', () => {
        const baseline = buildOrgBaselinePack({
            orgId: 'org-x',
            rules: [{ capability: CAPABILITY_CLASS.SHELL_EXEC, action: 'BLOCK' }],
        });
        const composed = composeAgentPack(baseline, {
            id: 'agent-shell-via-approval',
            name: 'shell via approval',
            orgId: 'org-x',
            agentId: 'agent-shell-via-approval',
            rules: [],
            overrides: [
                {
                    capability: CAPABILITY_CLASS.SHELL_EXEC,
                    action: 'REQUIRE_APPROVAL',
                    approver: 'cto-bob',
                    justification: 'Operator allowed shell exec gated by per-call approval.',
                    approvedAt: '2026-05-12T10:00:00.000Z',
                },
            ],
        });
        const v = evalActionWithPack(composed, 'Bash', { command: 'ls' });
        assert.equal(v.verdict, 'PENDING');
    });
});
//# sourceMappingURL=per-agent-override.test.js.map