"use strict";
/**
 * ASI-04 (OWASP Agentic Top 10) — Agentic Supply Chain: AI Bill of Materials.
 *
 * Microsoft AGT parity for the supply-chain gap. The existing SupplyChain module
 * audits npm dependencies; this produces the AI-BOM — a structured, tamper-evident
 * inventory of everything that composes an agent (its models, tools, MCP servers,
 * compliance packs, and dependencies) anchored by a `bomHash`, plus a minimal
 * SLSA-style provenance statement that binds that hash as its subject. A relying
 * org verifies the AI-BOM to trust the agent's supply chain.
 *
 * Invariants: pure in-process compute (I-10). `verifyAiBom` NEVER throws (I-2/I-3).
 *
 * @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 });
exports.canonicalBomJson = canonicalBomJson;
exports.generateAiBom = generateAiBom;
exports.verifyAiBom = verifyAiBom;
exports.generateSlsaProvenance = generateSlsaProvenance;
const crypto = __importStar(require("node:crypto"));
// ---------------------------------------------------------------------------
// Canonical JSON (deterministic, key-order independent)
// ---------------------------------------------------------------------------
function canonicalBomJson(value) {
    if (value === null || typeof value !== 'object')
        return JSON.stringify(value) ?? 'null';
    if (Array.isArray(value))
        return '[' + value.map((v) => canonicalBomJson(v)).join(',') + ']';
    const obj = value;
    const keys = Object.keys(obj).sort();
    return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalBomJson(obj[k])).join(',') + '}';
}
/** Stable component sort: by type, then id, then version — so order in never affects the hash. */
function sortComponents(components) {
    return [...components].sort((a, b) => a.type.localeCompare(b.type) || a.id.localeCompare(b.id) || (a.version ?? '').localeCompare(b.version ?? ''));
}
function hashComponents(components) {
    return crypto.createHash('sha256').update(canonicalBomJson(sortComponents(components)), 'utf-8').digest('hex');
}
// ---------------------------------------------------------------------------
// Generate / verify
// ---------------------------------------------------------------------------
/** Build the AI-BOM for an agent from its composed parts. */
function generateAiBom(input) {
    const components = [];
    for (const m of input.models ?? []) {
        components.push({ type: 'model', id: m.id, version: m.version, supplier: m.provider, hash: m.hash });
    }
    for (const t of input.tools ?? []) {
        components.push({ type: 'tool', id: t, name: t });
    }
    for (const s of input.mcpServers ?? []) {
        components.push({ type: 'mcp-server', id: s });
    }
    for (const p of input.compliancePacks ?? []) {
        components.push({ type: 'compliance-pack', id: p });
    }
    for (const d of input.dependencies ?? []) {
        components.push({ type: 'dependency', id: d.name, name: d.name, version: d.version, hash: d.hash });
    }
    const sorted = sortComponents(components);
    return {
        bomFormat: 'connexum-ai-bom',
        specVersion: '1.0',
        agentId: input.agentId,
        generatedAt: input.generatedAt ?? new Date().toISOString(),
        components: sorted,
        bomHash: hashComponents(sorted),
    };
}
/**
 * Verify an AI-BOM: recompute the hash over its components and compare. NEVER
 * throws — malformed input returns false.
 */
function verifyAiBom(bom) {
    try {
        if (!bom || typeof bom !== 'object' || !Array.isArray(bom.components) || typeof bom.bomHash !== 'string') {
            return false;
        }
        const expected = hashComponents(bom.components);
        if (expected.length !== bom.bomHash.length)
            return false;
        return crypto.timingSafeEqual(Buffer.from(expected, 'utf-8'), Buffer.from(bom.bomHash, 'utf-8'));
    }
    catch {
        return false;
    }
}
/**
 * Produce a minimal SLSA provenance statement binding the AI-BOM's `bomHash` as
 * the signed subject. A registration pipeline emits this so a relying org can
 * verify WHO built the agent's supply-chain inventory and WHAT it covered.
 */
function generateSlsaProvenance(bom, opts) {
    return {
        _type: 'https://in-toto.io/Statement/v1',
        predicateType: 'https://slsa.dev/provenance/v1',
        subject: [{ name: `ai-bom:${bom.agentId}`, digest: { sha256: bom.bomHash } }],
        predicate: {
            buildType: opts.buildType,
            builder: { id: opts.builder },
            metadata: {
                invocationId: opts.invocationId ?? bom.bomHash.slice(0, 16),
                startedOn: bom.generatedAt,
            },
        },
    };
}
//# sourceMappingURL=ai-bom.js.map