"use strict";
/**
 * Unified Audit Chain Emitter.
 *
 * Many cluster surfaces emit their own event types (OverrideEvent from W1.9,
 * PackVersionEvent from W1.4, SelfRegistrationEvent from W2.2, etc). This
 * helper normalises them into a single AuditChainEntry shape and hash-chains
 * the entries so downstream verifiers can detect tampering.
 *
 * Chain invariant:
 *   - Each entry carries `prevHash` (SHA-256 of the prior canonical entry).
 *   - Each entry carries `selfHash` (SHA-256 of the current canonical entry
 *     WITHOUT the selfHash field).
 *   - Verifier walks the chain head-to-tail and checks both fields.
 *
 * Pure helper — no IO. Storage / fan-out is the caller's job (Postgres
 * append, OTLP emit, S3 archive, etc.). This keeps the audit-chain logic
 * unit-testable and free of side effects.
 *
 * @connexum/ai-governance  Audit chain unification (tamper-evident integrity)
 */
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.AuditChainEmitter = void 0;
exports.fromOverrideEvent = fromOverrideEvent;
exports.fromPackVersionEvent = fromPackVersionEvent;
exports.fromSelfRegistrationEvent = fromSelfRegistrationEvent;
exports.fromApprovalNotification = fromApprovalNotification;
exports.fromCircuitBreakerEvent = fromCircuitBreakerEvent;
exports.verifyAuditChain = verifyAuditChain;
const crypto = __importStar(require("node:crypto"));
const GENESIS_PREV = 'GENESIS';
function canonicalJson(value) {
    if (value === undefined)
        return 'null';
    if (value === null || typeof value !== 'object')
        return JSON.stringify(value);
    if (Array.isArray(value))
        return '[' + value.map(canonicalJson).join(',') + ']';
    const obj = value;
    // Skip undefined-valued keys so hashes survive JSON round-trips
    // (JSON.stringify drops undefined entries from objects).
    const keys = Object.keys(obj).filter((k) => obj[k] !== undefined).sort();
    return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalJson(obj[k])).join(',') + '}';
}
function sha256B64url(input) {
    return crypto.createHash('sha256').update(input).digest().toString('base64url');
}
function computeSelfHash(entry) {
    return sha256B64url(canonicalJson(entry));
}
/** Adapters that normalise source events into the chain-entry shape. */
function fromOverrideEvent(ev) {
    return {
        at: ev.composedAt,
        source: 'OVERRIDE',
        sourceId: ev.overrideId,
        orgId: ev.orgId,
        agentId: ev.agentId,
        actor: ev.approver,
        data: {
            capability: ev.capability,
            baselineAction: ev.baselineAction,
            relaxedAction: ev.relaxedAction,
            justification: ev.justification,
            approvedAt: ev.approvedAt,
        },
    };
}
function fromPackVersionEvent(ev, orgId) {
    return {
        at: ev.timestamp,
        source: 'PACK_VERSION',
        sourceId: `${ev.packId}:${ev.version}:${ev.kind}`,
        orgId,
        actor: ev.actor,
        data: {
            kind: ev.kind,
            packId: ev.packId,
            version: ev.version,
            previousVersion: ev.previousVersion,
            detail: ev.detail,
        },
    };
}
function fromSelfRegistrationEvent(ev) {
    return {
        at: ev.timestamp,
        source: ev.kind === 'AGENT_REGISTERED' ? 'AGENT_REGISTERED' : 'AGENT_TOOL_OBSERVED',
        sourceId: `${ev.orgId}::${ev.agentId}::${ev.tool}`,
        orgId: ev.orgId,
        agentId: ev.agentId,
        data: {
            tool: ev.tool,
            toolInventory: ev.manifest.tools,
            // F-NEW-DASHBOARD-E2E-006 (2026-05-13): persist the build-shape fields
            // the trust-score-refresh pipeline needs to compute
            // `agent_build_structure`. Without these, `recomputeBuildStructureScore`
            // falls back to ZERO_BUILD and `has_human_in_loop` is structurally
            // always false. Stored under `manifest` so the gov-server's manifestFor
            // lookup can recover the shape from the audit chain.
            manifest: {
                agentId: ev.manifest.agentId,
                tools: ev.manifest.tools,
                hooks: ev.manifest.hooks,
                llmProvider: ev.manifest.llmProvider,
                pluginIntegrityVerified: ev.manifest.pluginIntegrityVerified,
                declaredApprovalGates: ev.manifest.declaredApprovalGates,
                declaredForbiddenCapabilities: ev.manifest.declaredForbiddenCapabilities,
            },
        },
    };
}
function fromApprovalNotification(ev) {
    return {
        at: ev.at,
        source: 'APPROVAL_NOTIFICATION',
        sourceId: `${ev.ticketId}::${ev.recipientId}::${ev.channel}`,
        orgId: ev.orgId,
        agentId: ev.agentId,
        actor: ev.recipientId,
        data: {
            ticketId: ev.ticketId,
            channel: ev.channel,
            delivered: ev.delivered,
            providerMessageId: ev.providerMessageId,
            error: ev.error,
        },
    };
}
function fromCircuitBreakerEvent(ev) {
    return {
        at: ev.at,
        source: ev.kind === 'tripped' ? 'CIRCUIT_BREAKER_TRIPPED' : 'CIRCUIT_BREAKER_ADVISORY',
        sourceId: `${ev.orgId}::${ev.agentId}::${ev.kind}::${ev.at}`,
        orgId: ev.orgId,
        agentId: ev.agentId,
        data: {
            kind: ev.kind,
            reason: ev.reason,
            owaspTag: 'ASI-08',
        },
    };
}
/**
 * Append-only in-process audit chain. Persistence is the caller's job —
 * subscribe to onAppend and forward to Postgres / OTLP / S3 / etc.
 */
class AuditChainEmitter {
    entries = [];
    onAppend;
    constructor(options = {}) {
        this.onAppend = options.onAppend;
    }
    append(prepared) {
        const seq = this.entries.length;
        const prevHash = seq === 0 ? GENESIS_PREV : this.entries[seq - 1].selfHash;
        const skeleton = { ...prepared, seq, prevHash };
        const selfHash = computeSelfHash(skeleton);
        const entry = { ...skeleton, selfHash };
        this.entries.push(entry);
        this.onAppend?.(entry);
        return entry;
    }
    /** Read-only view of the chain. */
    list() {
        return [...this.entries];
    }
    /** Look up by sequence number. */
    get(seq) {
        return this.entries[seq];
    }
    /** Length of the chain. */
    size() {
        return this.entries.length;
    }
}
exports.AuditChainEmitter = AuditChainEmitter;
/**
 * Verify chain integrity head-to-tail. Returns OK or the first failure.
 * Safe to call against an externally-supplied list (e.g. after persistence
 * round-trip).
 */
function verifyAuditChain(entries) {
    let prevHash = GENESIS_PREV;
    for (let i = 0; i < entries.length; i++) {
        const e = entries[i];
        if (e.seq !== i)
            return { code: 'OUT_OF_ORDER_SEQ', seq: e.seq, expected: i };
        if (e.prevHash !== prevHash)
            return { code: 'PREV_HASH_MISMATCH', seq: e.seq };
        // Reconstruct the exact pre-hash skeleton: every field of `e` EXCEPT selfHash.
        // Preserves the original key set (undefined / missing distinction matters
        // for canonical hashing).
        const { selfHash: _ignored, ...skeleton } = e;
        const recomputed = computeSelfHash(skeleton);
        if (recomputed !== e.selfHash)
            return { code: 'SELF_HASH_MISMATCH', seq: e.seq };
        prevHash = e.selfHash;
    }
    return { code: 'OK' };
}
//# sourceMappingURL=audit-chain-emitter.js.map