import { type KeyObject } from "node:crypto"; import { Cage } from "./cage.js"; import { type TraceEvent } from "./attestation.js"; declare const WF_KIND = "nucleus.workflow-receipt.v1"; export interface WorkflowNodeSpec { /** Unique node id within the workflow. */ id: string; /** This node's capability boundary (the tools it may call). */ boundary: string[]; /** Parent node ids — the DAG edges (data flows parent → this node). */ after?: string[]; } export interface WorkflowReceiptNode { id: string; after: string[]; boundary: string[]; events: TraceEvent[]; /** Independently recomputed by the verifier; the emitter's claim is not trusted. */ inBounds: boolean; } export interface WorkflowReceipt { kind: typeof WF_KIND; principal: string; nodes: WorkflowReceiptNode[]; rootHash: string; publicKey: string; signature: string; signedAt?: string; } /** * An information-flow policy checked across the whole DAG, grounded in the * Denning lattice (`./ifc`, a faithful port of nucleus-ifc — Lean-proven laws). * `sources`/`sinks` are the confidentiality axis (don't leak a secret to a * public sink); the optional axes cover integrity / indirect prompt injection. */ export interface FlowPolicy { /** Tools that read SECRET data (raise confidentiality). */ sources: string[]; /** Public-egress tools a secret must never reach. */ sinks: string[]; /** Nodes that sanitize — they clear incoming taint (a declassifier). */ declassifiers?: string[]; /** Tools that introduce ADVERSARIAL integrity (e.g. web fetch) — the indirect * prompt-injection taint. */ adversarialSources?: string[]; /** Action tools that must only fire on trusted, directive-authority data — * adversarial / no-authority data reaching them is a leak. */ actionSinks?: string[]; } export interface FlowLeak { node: string; sink: string; taintedVia: "reads-source" | "upstream"; } export interface WorkflowVerifyReport { /** `signatureOk && dagOk && nodesOk && flowOk`. */ ok: boolean; /** Ed25519 signature verifies AND the recomputed rootHash matches. */ signatureOk: boolean; /** Edges reference real nodes and the graph is acyclic. */ dagOk: boolean; /** Every node's recorded calls were within its declared boundary. */ nodesOk: boolean; /** No source→sink information flow across the DAG (per the flow policy). */ flowOk: boolean; /** The source→sink leaks found (empty when `flowOk`). */ leaks: FlowLeak[]; /** Nodes whose recompute found an out-of-boundary call. */ outOfBoundsNodes: string[]; reason: string | null; } /** * A DAG cage. Register nodes (each gets a {@link Cage}), run your agents through * the caged tools, then {@link Workflow.attest} a single signed receipt over the * whole graph — verifiable offline, including the cross-node information flow. */ export declare class Workflow { private readonly principal; private readonly nodes; constructor(principal: string); /** Register a node and return its cage. The cage's tool calls are recorded * under this node; `after` declares the edges into it. */ node(spec: WorkflowNodeSpec): Cage; private receiptNodes; /** Sign one workflow receipt over the whole DAG. */ attest(privateKey: KeyObject, opts?: { signedAt?: string; }): WorkflowReceipt; } /** * Verify a workflow receipt fully and offline: the signature + the per-node * in-bounds recompute + the DAG (acyclic, real edges) + the cross-node * information flow. Never throws — failures surface as `ok:false` + `reason`. */ export declare function verifyWorkflowReceipt(wr: WorkflowReceipt, flow?: FlowPolicy): WorkflowVerifyReport; export {};