/** * L8 G-c artifact — the signed deploy-authenticity evidence the [ref] §5.2 G-c aggregator requires * (SPEC-RSI-L7-L8 §A.3). The artifact is canonical-JSON serialized and ed25519-signed so the GO aggregator can * verify it was produced by a real L8 run and link it to a commit + adapter build + boundary. * * 🔴 SIGNING IS PROVENANCE, NOT AUTHENTICITY-OF-RESULT (SPEC §A.3 RISK-4): a valid signature only proves "this * run, with this key, produced these probe VALUES"; it does NOT prove the probes hit a real boundary — that is * the P0 fail-loud + the external collector's job. The aggregator MUST check `gC.satisfied` AND * `boundary.isolationClassVerified` AND `p1Mode !== "adapter-RO-seam-absent"`, never just "signature valid". * * 🔴 ED25519, NOT HMAC: a shared HMAC secret is forgeable by anyone who holds it; ed25519 is asymmetric * — the private key signs (control-plane held, env L8_SIGNER_KEY_B64), the PUBLIC key (shipped to the aggregator) * only verifies. node:crypto's ed25519 is built-in (no new dep). * * 🔴 TIMESTAMPS ARE INJECTED, NOT `Date.now()` (deterministic-test requirement): `buildArtifact` takes * `producedAt` from the caller (the live runner passes a real ISO string; the unit test passes a fixed one), so * the canonical JSON is byte-stable in tests. */ import { type KeyObject } from "node:crypto"; import { type L8SchemaVersion, type L8Escape } from "./escape.js"; import type { Backend, P1Mode } from "./probes.js"; export interface L8Boundary { provisioned: boolean; /** What the adapter SELF-DECLARES (capabilities.isolation) — recorded but never load-bearing. */ isolationClassClaimed: "out_of_process" | "in_process_probe_only"; /** What L8 PROVED (P0+P2) — the load-bearing field. */ isolationClassVerified: boolean; /** kata only; null+reason on e2b (RISK-7). */ guestKernel: string | null; hostKernel: string | null; runtimeClass: string; /** P1 sanity: escalation failed because CAP_SYS_ADMIN is gone, not because we silently had it. */ capSysAdminAbsent: boolean; } export interface ProbeRecord { id: string; name: string; /** The verdict for this probe. `null` ⇒ the probe is in an honest PENDING state (blocked on a cross-team dep). */ passed: boolean | null; /** Honest pending flag — set when the probe could not run for real (the blocker is in `pendingReason`). */ pending: boolean; pendingReason?: string; /** P1-specific honest mode (only on the immutable-mount probe). */ p1Mode?: P1Mode; /** Per-probe structured observation fields (kept open so each probe records what it asserts). */ observations?: Record; /** The command(s) the probe issued (for audit; the live runner fills these). */ commands?: string[]; /** The INDEPENDENT observer's result for this probe (e.g. collector nonce log / inode check). */ independentObserver?: Record; } export interface L8GcResult { /** G-c = no escapes ∧ isolationClassVerified ∧ every probe passed (none pending/failed) ∧ p1Mode present. */ satisfied: boolean; reason: string; } export interface L8Signature { alg: "ed25519"; keyId: string; /** base64 detached signature over the canonical JSON of the artifact MINUS the `signature` field. */ sig: string; } /** The l8.v1 artifact. `signature` is absent until {@link signArtifact}. */ export interface L8DeployContractArtifact { schemaVersion: L8SchemaVersion; kind: "deploy-contract-authenticity"; /** Injected ISO timestamp — NOT Date.now() (deterministic-test requirement). */ producedAt: string; serviceCommit: string; coreVersion: string; backend: Backend; boundary: L8Boundary; probes: ProbeRecord[]; escapes: L8Escape[]; gC: L8GcResult; /** Content hash linking the artifact body (everything except `signature`) — the thing the signature covers. */ contentHash: string; signature?: L8Signature; } export interface BuildArtifactMeta { producedAt: string; serviceCommit: string; coreVersion: string; backend: Backend; boundary: L8Boundary; } /** * Canonical JSON: object keys sorted recursively, no insignificant whitespace, arrays preserve order. Stable * across re-serialization so the signature/contentHash are deterministic. Rejects non-finite numbers (NaN/Inf * would serialize as `null` and silently corrupt the canonical form). * * [ref](2026-08-31)起 = 本仓共享件 `src/canonical-json.ts#canonicalJsonStrict` 的再导出:校验集/错误文案与 * 合并前本文件的 `serialize` 逐字同(`/non-finite/` 等钉在 test/l8-deploy-contract.test.ts),通过校验的输入域上 * 输出字节与合并前逐字节相同(test/canonical-json-golden.test.ts,基线 cb543ad 的 contentHash 落盘)。 * 签名/contentHash 的载荷语义一个字节不动。 */ export declare function canonicalJson(value: unknown): string; /** sha256 of the canonical body — links the signature to the exact body bytes. */ export declare function computeContentHash(a: L8DeployContractArtifact): string; /** * Fold G-c (SPEC §A.3): satisfied iff * - no escapes, AND * - boundary.provisioned AND boundary.isolationClassVerified, AND * - every probe passed (NONE pending, NONE failed), AND * - the immutable-mount probe's p1Mode is NOT "adapter-RO-seam-absent". * G-c is necessary-non-sufficient: any pending/failed probe ⇒ NO-GO. This is what keeps tier-ON NO-GO honest. */ export declare function foldGc(boundary: L8Boundary, probes: ProbeRecord[], escapes: L8Escape[]): L8GcResult; /** Build the artifact body + contentHash. Pure: timestamps injected, gC folded. No signature yet. */ export declare function buildArtifact(meta: BuildArtifactMeta, probes: ProbeRecord[], escapes: L8Escape[]): L8DeployContractArtifact; /** Load an ed25519 private key from a base64 PKCS8 DER (the L8_SIGNER_KEY_B64 control-plane secret). */ export declare function loadPrivateKeyB64(b64: string): KeyObject; /** Load an ed25519 public key from a base64 SPKI DER (the key shipped to the aggregator). */ export declare function loadPublicKeyB64(b64: string): KeyObject; /** * Sign the artifact: recompute the contentHash (defends against a body mutated after build), sign the canonical * body with ed25519 (`sign(null, msg, key)` — ed25519 takes no separate digest algorithm), attach the detached * base64 signature. Returns a NEW artifact (does not mutate the input). */ export declare function signArtifact(artifact: L8DeployContractArtifact, privateKey: KeyObject, keyId: string): L8DeployContractArtifact; /** * Verify an artifact: recompute the contentHash over the body and check it matches the stored one (rewrite of any * body field flips the hash), then ed25519-verify the detached signature over the canonical body. Returns false * (never throws) on a missing/garbage signature, a content-hash mismatch, or a bad signature. * * 🔴 A `true` here means INTEGRITY/PROVENANCE only — the caller MUST still gate on gC.satisfied AND * boundary.isolationClassVerified AND p1Mode (see file header). Verification alone is NOT a GO. */ export declare function verifyArtifact(artifact: L8DeployContractArtifact, publicKey: KeyObject): boolean; //# sourceMappingURL=artifact.d.ts.map