/**
 * HITL Phase 2b — auto-pack-generator perRuleActions bake tests.
 *
 * RED→GREEN: verifies that when perRuleActions has { action: 'BLOCK', notify_hitl: true }
 * for findingId X, the generated pack has:
 *   - categoryActions[capability(X)] === 'BLOCK'
 *   - categoryHitl[capability(X)] === true
 *
 * Also covers:
 *   - notify_hitl=false → capability absent from categoryHitl (default false)
 *   - unknown findingId is silently ignored
 *   - categoryHitl is absent from pack when no notify_hitl flags are set
 *
 * Step 0 probe (verified before coding):
 *   auto-pack-generator.ts had no perRuleActions parameter; the generated pack
 *   had no categoryHitl field; PackDataPolicy had no categoryHitl field.
 *
 * @connexum/ai-governance  HITL Phase 2b
 */
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { autoGenerateCompanyPack } from '../auto-pack-generator.js';
// ---- helpers ---------------------------------------------------------------
function minimalManifest(over = {}) {
    return {
        agentId: 'agent-hitl-bake',
        name: 'HITL bake test agent',
        tools: ['Bash', 'WebFetch'],
        hooks: { preToolUse: true, postToolUse: true, postResponse: true },
        llmProvider: 'anthropic/claude-sonnet-4-6',
        pluginIntegrityVerified: true,
        rateLimitsConfigured: false,
        declaredApprovalGates: [],
        declaredForbiddenCapabilities: [],
        ...over,
    };
}
/**
 * Build a synthetic OwaspFinding with a suggestedRule for the given capability.
 * The findingId used by the dashboard Step 4 picker is the capability string.
 */
function syntheticFinding(capability) {
    return {
        risk: 'A08-excessive-agency',
        severity: 'HIGH',
        title: `Test finding for ${capability}`,
        detail: 'Synthetic finding for HITL bake test.',
        remediation: 'Add a BLOCK rule.',
        suggestedRule: { capability, action: 'WARN' },
    };
}
// ---- tests -----------------------------------------------------------------
describe('HITL Phase 2b — autoGenerateCompanyPack perRuleActions bake', () => {
    it('bakes BLOCK action and notify_hitl=true into the pack for a matched findingId', () => {
        const capability = 'capability:network-egress';
        const finding = syntheticFinding(capability);
        const packIdPrefix = 'agent-hitl-bake';
        const packId = `${packIdPrefix}-agent-hitl-bake`;
        const result = autoGenerateCompanyPack(minimalManifest(), {
            packIdPrefix,
            // Start with the suggested rule from the scan to give us a baseline.
            acceptedRules: [{ capability, action: 'WARN' }],
            perRuleActions: {
                [packId]: {
                    [capability]: { action: 'BLOCK', notify_hitl: true },
                },
            },
            scanFindings: [finding],
        });
        // The override should have replaced WARN → BLOCK.
        assert.equal(result.pack.dataPolicy.categoryActions[capability], 'BLOCK', 'categoryActions should be overridden to BLOCK');
        // The HITL flag should be baked in.
        assert.equal(result.pack.dataPolicy.categoryHitl?.[capability], true, 'categoryHitl should be true for the matched capability');
        // categoryHitl should be exposed in the result's own field too.
        assert.equal(result.categoryHitl[capability], true, 'result.categoryHitl should carry the flag');
    });
    it('bakes BLOCK + notify_hitl=true even when acceptedRules did not include the capability', () => {
        const capability = 'capability:shell-exec';
        const finding = syntheticFinding(capability);
        const packId = 'agent-hitl-bake-agent-hitl-bake';
        const result = autoGenerateCompanyPack(minimalManifest(), {
            packIdPrefix: 'agent-hitl-bake',
            acceptedRules: [], // no rules initially
            perRuleActions: {
                [packId]: {
                    [capability]: { action: 'BLOCK', notify_hitl: true },
                },
            },
            scanFindings: [finding],
        });
        assert.equal(result.pack.dataPolicy.categoryActions[capability], 'BLOCK', 'capability should be added to categoryActions even if not in initial acceptedRules');
        assert.equal(result.pack.dataPolicy.categoryHitl?.[capability], true);
    });
    it('does NOT add categoryHitl when notify_hitl is false', () => {
        const capability = 'capability:network-egress';
        const finding = syntheticFinding(capability);
        const packId = 'agent-hitl-bake-agent-hitl-bake';
        const result = autoGenerateCompanyPack(minimalManifest(), {
            packIdPrefix: 'agent-hitl-bake',
            acceptedRules: [{ capability, action: 'WARN' }],
            perRuleActions: {
                [packId]: {
                    [capability]: { action: 'LOG', notify_hitl: false },
                },
            },
            scanFindings: [finding],
        });
        // Action should be overridden.
        assert.equal(result.pack.dataPolicy.categoryActions[capability], 'LOG');
        // categoryHitl should be absent (no notify_hitl=true flags).
        assert.equal(result.pack.dataPolicy.categoryHitl, undefined, 'categoryHitl should be absent when no notify_hitl=true flags are set');
        assert.deepEqual(result.categoryHitl, {});
    });
    it('silently ignores unknown findingIds in perRuleActions', () => {
        const capability = 'capability:network-egress';
        const finding = syntheticFinding(capability);
        const packId = 'agent-hitl-bake-agent-hitl-bake';
        // Use a findingId that does not match any finding's capability.
        const result = autoGenerateCompanyPack(minimalManifest(), {
            packIdPrefix: 'agent-hitl-bake',
            acceptedRules: [{ capability, action: 'WARN' }],
            perRuleActions: {
                [packId]: {
                    'capability:does-not-exist-xyz': { action: 'BLOCK', notify_hitl: true },
                },
            },
            scanFindings: [finding],
        });
        // Original rule untouched.
        assert.equal(result.pack.dataPolicy.categoryActions[capability], 'WARN');
        assert.equal(result.pack.dataPolicy.categoryHitl, undefined);
        assert.deepEqual(result.categoryHitl, {});
    });
    it('does not bake perRuleActions when scanFindings is empty', () => {
        const capability = 'capability:network-egress';
        const packId = 'agent-hitl-bake-agent-hitl-bake';
        const result = autoGenerateCompanyPack(minimalManifest(), {
            packIdPrefix: 'agent-hitl-bake',
            acceptedRules: [{ capability, action: 'WARN' }],
            perRuleActions: {
                [packId]: {
                    [capability]: { action: 'BLOCK', notify_hitl: true },
                },
            },
            scanFindings: [], // empty — no findings to resolve
        });
        // Without findings, the override cannot be resolved — action stays WARN.
        assert.equal(result.pack.dataPolicy.categoryActions[capability], 'WARN');
        assert.equal(result.pack.dataPolicy.categoryHitl, undefined);
    });
    it('does not bake perRuleActions when options.perRuleActions is absent', () => {
        const capability = 'capability:network-egress';
        const result = autoGenerateCompanyPack(minimalManifest(), {
            packIdPrefix: 'agent-hitl-bake',
            acceptedRules: [{ capability, action: 'WARN' }],
            // No perRuleActions, no scanFindings.
        });
        assert.equal(result.pack.dataPolicy.categoryActions[capability], 'WARN');
        assert.equal(result.pack.dataPolicy.categoryHitl, undefined);
        assert.deepEqual(result.categoryHitl, {});
    });
    it('result.categoryHitl is empty object (not undefined) when no HITL flags set', () => {
        const result = autoGenerateCompanyPack(minimalManifest());
        assert.ok(typeof result.categoryHitl === 'object', 'categoryHitl should always be an object');
        assert.deepEqual(result.categoryHitl, {});
    });
});
//# sourceMappingURL=auto-pack-generator-hitl-bake.test.js.map