/** * Bake-guard for `docker.buildArgs` — the advisory tripwire that keeps a * credential out of the `--build-arg` channel. * * A `--build-arg` value is baked into the image and PUBLISHED to three surfaces * (named verbatim in every finding/warning so the author sees the blast radius): * - `docker history --no-trunc` of the pushed image, * - image provenance / SBOM attestations, and * - the `-cache` mode=max ECR repo, which exports every intermediate * layer to a SEPARATE registry repository. * * The guard is an ADVISORY tripwire, not a wall. The SSM/Secrets-Manager-ref * reject (R1) is the primary signal; the `maskSensitiveOutput`-shape reject * (R2) is one CHEAP heuristic that catches the well-known credential shapes * (AWS keys, `password=…`, `postgres://u:p@h`) but does NOT catch base64 blobs, * bare high-entropy tokens, or a credential concatenated across two innocuous * `buildArgs`. No admission guard catches those — the real controls are the * documented Dockerfile contract (use `RUN --mount=type=secret`) plus the * least-privilege build-secret identity (design § C1). * * Public, design § "Research validation & mandatory corrections" C3: * `acknowledgePublic: true` opts a value out of R1/R2 — a conscious * public-but-sensitive bake (restricted Stripe pk, scoped Mapbox token, Sentry * DSN) must not fight the guard. */ import type { DockerBuildArgValue } from "../manifest/schemas.js"; /** * The exposure clause naming the three publication surfaces. Shared so every * finding/warning message states the same blast radius (design R4). */ export declare const BAKE_GUARD_EXPOSURE_CLAUSE: string; /** * Creates a per-deploy de-duplicator for bake-exposure warnings. * * A buildArg baked into more than one service image of the same app (an app + * its workers, built as separate groups) produces byte-identical exposure * warnings — the exposure is a property of the KEY, not of each image, so the * operator only needs to see each warning once per deploy. Returns a predicate * that is `true` the first time it sees a message and `false` thereafter; share * one instance across a deploy's build groups. */ export declare function createBakeWarningDeduper(): (message: string) => boolean; export type BakeGuardFindingReason = "sourced-ref" | "credential-shape"; export interface BakeGuardFinding { /** The offending `buildArgs` key. */ key: string; reason: BakeGuardFindingReason; /** Author-facing remediation message — already names the exposure surfaces. */ message: string; } export interface BakeGuardWarning { key: string; message: string; } export interface BakeGuardResult { findings: BakeGuardFinding[]; warnings: BakeGuardWarning[]; } /** * Evaluate `buildArgs` against the four bake-guard rules. * * - **R1 (reject):** an `ssm`/`secretsManager`-sourced value belongs in * `buildSecrets`. An `env`-sourced value is allowed — shell sourcing of * public config is the documented per-deploy override path. Bypassed by * `acknowledgePublic: true` (a deliberate public-but-sensitive bake). * - **R2 (reject):** a literal-string value whose `maskSensitiveOutput`-masked * form differs from the original (a credential SHAPE) belongs in * `buildSecrets`. Bypassed by `acknowledgePublic: true` — but a plain string * carries no acknowledgement, so for a string the only escape is to move it * to the object form and acknowledge, or to `buildSecrets`. * - **R3 (warn, non-blocking):** a non-secret key NOT starting with a public * prefix is frozen into the image at build time; a runtime env var varies * per deploy without a rebuild. * * `appPrefix` is the app-name kebab prefix used only for messaging context (it * does not change which rules fire); pass the kebab app name. */ export declare function evaluateBakeGuard(buildArgs: Record | undefined, appPrefix: string): BakeGuardResult; /** * The set of `buildArgs` keys whose DECLARED value is an acknowledged * public-but-sensitive object form (`acknowledgePublic: true`). These are * exempt from the post-resolution value-shape reject, mirroring the * pre-resolution R2 bypass — a deliberate public-but-sensitive bake must not * fight the guard at either stage. */ export declare function acknowledgedBuildArgKeys(buildArgs: Record | undefined): Set; /** * Post-resolution value-shape check (R2 only). Runs the * `maskSensitiveOutput`-shape reject on a RESOLVED `buildArgs` map (keys mapped * to their final string values) and returns credential-shape findings. * * This closes the composition gap the pre-resolution `evaluateBakeGuard` cannot * see: a `.env`-inferred key (discovered during resolution) or an explicit key * whose `.env`/shell-resolved value is secret-shaped never reaches the declared * pre-resolution pass. Callers run this AFTER `resolveBuildArgs` and fail closed * on any finding. * * Value-shape only — it does NOT emit R3 prefix-warnings (those stay at the * pre-resolution pass to avoid double-warning). Keys in `acknowledgedKeys` are * skipped (an acknowledged public-but-sensitive bake is intentional). */ export declare function evaluateResolvedBuildArgValues(resolvedBuildArgs: Record, appPrefix: string, acknowledgedKeys: ReadonlySet): BakeGuardFinding[];