"use strict";
/**
 * RED-GREEN tests for F-NEW-PRODUCT-CAPABILITY-CLASS-RULES (W1.5 of
 * F-NEW-PRODUCT-AGENT-VISIBILITY-CLUSTER-2026-05-12).
 *
 * Customer-path probe:
 *   1. Customer authors a company pack with `{ capability: 'capability:mcp', action: 'BLOCK' }`
 *   2. Agent attempts an MCP tool call
 *   3. PackEvaluator returns DENY (BLOCK -> DENY in actionToVerdict)
 *
 * Same probe verified for: WEB_FETCH, EXTERNAL_DB_WRITE, SHELL_EXEC,
 * FILESYSTEM_WRITE, NETWORK_EGRESS, SECRET_ACCESS, and the REQUIRE_APPROVAL
 * variant (-> PENDING which queues an ApprovalRecord through the existing
 * pack-verdict-adapter pipeline).
 *
 * Failure modes intentionally probed:
 *   - Unknown capability id at build time -> throws (fail closed)
 *   - Tool call that should NOT match the capability stays ALLOW
 *   - REQUIRE_APPROVAL maps to PENDING (the approval-required customer path)
 *
 * @connexum/ai-governance
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const node_test_1 = require("node:test");
const assert = __importStar(require("node:assert/strict"));
const pack_evaluator_1 = require("./pack-evaluator");
const index_1 = require("../packs/index");
const event_bus_1 = require("../audit/event-bus");
const index_2 = require("../adapters/index");
const company_pack_builder_1 = require("./company-pack-builder");
const capability_classes_1 = require("./capability-classes");
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
function freshRegistryWith(pack) {
    const registry = new index_1.PackRegistry();
    registry.register(pack);
    registry.activate(pack.id);
    return registry;
}
function freshEvaluator(registry) {
    const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cap-class-'));
    const bus = new event_bus_1.EventBus({ eventDir: dir, agentName: 'test-cap' });
    return new pack_evaluator_1.PackEvaluator(registry, bus, { ttlMs: 60_000, enableCache: false });
}
function action(toolName, input = {}) {
    return (0, index_2.createActionContext)(toolName, input, { name: 'cap-test-agent', orgId: 'tenant-cap' });
}
(0, node_test_1.describe)('F-NEW-PRODUCT-CAPABILITY-CLASS-RULES — capability-class rule vocabulary', () => {
    (0, node_test_1.it)('BLOCK on capability:mcp denies an MCP tool call', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-1',
            name: 'No MCP company rule',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'agent-1', action('mcp__list_resources'));
        assert.equal(verdict.verdict, 'DENY');
        assert.ok(verdict.triggeringClassifierIds.includes(capability_classes_1.CAPABILITY_CLASS.MCP));
        assert.ok(verdict.triggeringPackIds.includes('co-pack-1'));
    });
    (0, node_test_1.it)('REQUIRE_APPROVAL on capability:external-db-write returns PENDING for DROP TABLE', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-db',
            name: 'No destructive SQL without approval',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.EXTERNAL_DB_WRITE, action: 'REQUIRE_APPROVAL' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'agent-1', action('postgres_query', { query: 'DROP TABLE users' }));
        assert.equal(verdict.verdict, 'PENDING');
        assert.ok(verdict.triggeringClassifierIds.includes(capability_classes_1.CAPABILITY_CLASS.EXTERNAL_DB_WRITE));
    });
    (0, node_test_1.it)('BLOCK on capability:external-db-write does NOT fire on a SELECT (read-only)', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-db-2',
            name: 'No destructive SQL',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.EXTERNAL_DB_WRITE, action: 'BLOCK' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'agent-1', action('postgres_query', { query: 'SELECT * FROM users LIMIT 10' }));
        assert.equal(verdict.verdict, 'ALLOW');
    });
    (0, node_test_1.it)('BLOCK on capability:shell-exec denies Bash', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-sh',
            name: 'No shell',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.SHELL_EXEC, action: 'BLOCK' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'agent-1', action('Bash', { command: 'ls' }));
        assert.equal(verdict.verdict, 'DENY');
    });
    (0, node_test_1.it)('BLOCK on capability:web-fetch denies WebFetch and Fetch alike', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-web',
            name: 'No web fetch',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.WEB_FETCH, action: 'BLOCK' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const v1 = evaluator.evaluate('tenant-cap', 'a', action('WebFetch', { url: 'https://x' }));
        const v2 = evaluator.evaluate('tenant-cap', 'a', action('fetch', { url: 'https://x' }));
        assert.equal(v1.verdict, 'DENY');
        assert.equal(v2.verdict, 'DENY');
    });
    (0, node_test_1.it)('REQUIRE_APPROVAL on capability:filesystem-write returns PENDING for Write', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-fs',
            name: 'Approval on file writes',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.FILESYSTEM_WRITE, action: 'REQUIRE_APPROVAL' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'agent-1', action('Write', { file_path: '/etc/passwd', content: 'x' }));
        assert.equal(verdict.verdict, 'PENDING');
    });
    (0, node_test_1.it)('BLOCK on capability:secret-access fires on tool name AND on secret-shaped args', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-sec',
            name: 'No secrets',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.SECRET_ACCESS, action: 'BLOCK' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const byTool = evaluator.evaluate('tenant-cap', 'a', action('vault_read', { path: 'secret/data/db' }));
        const byArgs = evaluator.evaluate('tenant-cap', 'a', action('http_post', { url: 'https://x', headers: { Authorization: 'Bearer secrettoken1' } }));
        assert.equal(byTool.verdict, 'DENY');
        assert.equal(byArgs.verdict, 'DENY');
    });
    (0, node_test_1.it)('unrelated tool call stays ALLOW when capability rules do not match', () => {
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-clean',
            name: 'No MCP',
            orgId: 'tenant-cap',
            rules: [{ capability: capability_classes_1.CAPABILITY_CLASS.MCP, action: 'BLOCK' }],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'a', action('summarize', { text: 'hello' }));
        assert.equal(verdict.verdict, 'ALLOW');
        assert.equal(verdict.triggeringClassifierIds.length, 0);
    });
    (0, node_test_1.it)('buildCompanyPack throws on unknown capability id (fail-closed)', () => {
        assert.throws(() => (0, company_pack_builder_1.buildCompanyPack)({
            id: 'bad',
            name: 'bad',
            orgId: 'tenant-cap',
            // @ts-expect-error — intentional unknown capability id
            rules: [{ capability: 'capability:does-not-exist', action: 'BLOCK' }],
        }), /unknown capability class/i);
    });
    (0, node_test_1.it)('strictest-wins across multiple rules on the same call (BLOCK over REQUIRE_APPROVAL)', () => {
        // Two rules on different capability classes both fire for the same call:
        // web-fetch returns BLOCK; network-egress returns REQUIRE_APPROVAL. Strictest wins => DENY.
        const pack = (0, company_pack_builder_1.buildCompanyPack)({
            id: 'co-pack-multi',
            name: 'Multi-class',
            orgId: 'tenant-cap',
            rules: [
                { capability: capability_classes_1.CAPABILITY_CLASS.WEB_FETCH, action: 'BLOCK' },
                { capability: capability_classes_1.CAPABILITY_CLASS.NETWORK_EGRESS, action: 'REQUIRE_APPROVAL' },
            ],
        });
        const evaluator = freshEvaluator(freshRegistryWith(pack));
        const verdict = evaluator.evaluate('tenant-cap', 'a', action('WebFetch', { url: 'https://x' }));
        assert.equal(verdict.verdict, 'DENY');
        assert.ok(verdict.triggeringClassifierIds.includes(capability_classes_1.CAPABILITY_CLASS.WEB_FETCH));
    });
});
//# sourceMappingURL=capability-classes.test.js.map