/** * Client-side authorization gate (P0-b/c) — mirrors the server §106 (binding), §111 (fail-closed on * degraded) and §115 (safe_for_agent) in the guard. All checks are LOCAL and fail-closed. * * Threat model (bounded): a raw execution_action is not trusted alone when the response has NO * receipt — without a signed decision_body_hash, a proxy or intermediary can flip fields. When a * receipt IS present, decision_body_hash covers the RFC 8785-canonical envelope (minus receipt and * the hash field itself) and the receipt signature covers that hash, so execution_action cannot be * flipped without the recomputed hash diverging or a forged signature. The gate still reconciles * decision↔action locally (stricter wins), fails closed on a PRESENT-but-unrecognised action * (version skew — not a missing-action fallback), and never treats an unknown value as permission. * * Composes with the P0-a receipt binding (receipt-binding.ts). This module reconciles the DECISION * itself; receipt-binding authenticates the envelope the decision rides on. */ import type { IntegrityCause, Artifact } from './types.js'; import { type BundleFingerprintContext } from './execution-time-fingerprint.js'; type Action = 'CONTINUE' | 'CONTINUE_WITH_MONITORING' | 'REQUEST_APPROVAL' | 'STOP'; /** Local artifact_digest — byte-identical to the server change-set.js algorithm (sorted by type,id). */ export declare function computeArtifactDigest(artifacts: Artifact[]): string; /** * Local crbundle.v1 bundle fingerprint — byte-identical to the server producer * (coderifts-app change-set.js computeBundleFingerprint). * * THIS WAS WRONG AND SHIPPED WRONG. Until now this function took only `artifacts` and built its * OWN preimage, which omitted two elements the server includes: the artifact COUNT, and the whole * trailing context block (operation, environment, repository, branch, pull_request, * policy_profile). On identical inputs it returned sha256:1a0e7470… where the server returned * sha256:049650f2… — so any third party who used it to check a receipt's `fp` against their own * change set got a mismatch, with nothing to tell them the verifier was at fault rather than the * receipt. A verifier that is quietly wrong is worse than one that is honestly absent. * * The root cause was a SECOND PREIMAGE in this package: execution-time-fingerprint.ts already * carried a faithful mirror, under the comment "Do NOT invent a second preimage". This function * was that second preimage. It is now a thin delegation, so the package has exactly one. * * `context` is optional to keep the call signature source-compatible, but omitting it produces a * DIFFERENT (and, for any request that carried a context, still non-matching) digest — the server * folds the context in unconditionally. Pass the same context you sent with the request. */ export declare function computeBundleFingerprint(artifacts: Artifact[], context?: BundleFingerprintContext | null): string; export type GateResult = { verdict: 'allow'; kind: 'ALLOW' | 'MONITOR'; } | { verdict: 'block-strict'; decision: 'BLOCK' | 'REQUIRE_APPROVAL'; } | { verdict: 'fail-closed'; cause: IntegrityCause; detail?: string; }; /** * Reconcile an envelope's decision fail-closed. Order: * 0. execution_action PRESENT but not in closed set → EXECUTION_ACTION_UNRECOGNISED * (version skew; distinct from DECISION_INCONSISTENT — reconciliation is impossible) * 1. decision present + valid enum (CE-EP-04) → DECISION_INCONSISTENT * 2. effective decision = STRICTEST(envelope.decision, action-implied, top-level decision/action) * (CE-EP-01, CE-CC-01) — BLOCK/REQUIRE_APPROVAL → clean block (positive control CE-EP-02 kept) * 3. safe_for_agent === false on an allow-class decision (CE-EP-03/§115) → DECISION_INCONSISTENT * 4. degraded / analysis_complete=false / coverage_gap (CE-CC-02/§111) → ANALYSIS_DEGRADED * 5. artifact_digest / input_fingerprint local compare (CE-AF-03/#6) → ARTIFACT_MISMATCH * * @param response the raw preflight response (for the top-level decision/action, CE-CC-01) * @param envelope the decision_result envelope * @param executionAction rd.executionAction from readDecision (closed Action, or raw string if unrecognised) * @param sentArtifacts the artifacts the guard sent to preflight (for the digest bind) */ export declare function evaluateEnvelope(response: unknown, envelope: Record, executionAction: Action | string, sentArtifacts: Artifact[]): GateResult; export {}; //# sourceMappingURL=enforcement-gate.d.ts.map