/** * Change-set-without-execute probe — Layer 2 of the replacement oracle * (drift-remediation plan § 2). Creates a review-only CloudFormation change * set (`fjall-preflight-`, prefix-fenced from the cdk child's own * change sets), reads each resource's authoritative `Replacement` verdict, * and deletes the change set — nothing is ever executed. * * Escalation-only [G4]: callers invoke this ONLY for stacks whose registry * overlay verdicts `conditional`/`may` on a stateful or pinned-name resource * (`applyChangeSetEscalation`). The probe never fails a deploy: every failure * degrades to the caller's registry verdict, annotated unverified. * * Failure messages are pre-masked at construction — a change-set * `StatusReason` can embed template fragments, so every interpolation routes * through `maskSensitiveOutput`. */ import { type Result } from "@fjall/generator"; import type { AwsProvider } from "../../aws/AwsProvider.js"; /** Review-only change sets are fenced off the cdk child's by this prefix. */ export declare const PREFLIGHT_CHANGE_SET_PREFIX = "fjall-preflight-"; /** * `CreateChangeSet` accepts inline bodies up to 51,200 bytes; larger * templates upload to the CDK bootstrap assets bucket and pass `TemplateURL`. */ export declare const MAX_INLINE_TEMPLATE_BYTES = 51200; /** * The CDK bootstrap staging bucket for the default `hnb659fds` qualifier — * where `cdk deploy` itself stages oversized templates, so the deploy * principal always has access. Fjall bootstraps with the default qualifier. */ export declare function bootstrapAssetsBucketName(accountId: string, region: string): string; /** CloudFormation's authoritative per-resource replacement verdict. */ export type ChangeSetReplacementVerdict = "True" | "False" | "Conditional"; export interface StackReplacementProbeResult { /** Logical id → CFN's replacement verdict. A resource CFN's change set * omits entirely will not be touched — callers treat absence as `False`. */ replacementByLogicalId: Map; /** True when CFN reported the update contains no changes at all (the * benign `FAILED — didn't contain changes` outcome). */ noChanges: boolean; } export interface ProbeStackReplacementsParams { stackName: string; /** The already-synthesised cdk.out template, parsed from JSON. */ template: unknown; abortSignal?: AbortSignal; } /** * The narrow surface the plan escalation needs — ChangeSetProbe satisfies * it; tests substitute a stub. */ export interface ChangeSetProbeRunner { probeStackReplacements(params: ProbeStackReplacementsParams): Promise>; } export interface ChangeSetProbeOptions { /** Poll cadence for DescribeChangeSet; defaults to 2 s. */ pollIntervalMs?: number; /** Overall poll budget before the probe gives up; defaults to 90 s. */ pollTimeoutMs?: number; /** Injectable clock for leak-sweep and timeout tests. */ now?: () => number; } export declare class ChangeSetProbe implements ChangeSetProbeRunner { private readonly aws; private readonly pollIntervalMs; private readonly pollTimeoutMs; private readonly now; constructor(aws: AwsProvider, options?: ChangeSetProbeOptions); probeStackReplacements(params: ProbeStackReplacementsParams): Promise>; /** * Poll the change set to a terminal status, then page through its resource * changes. `FAILED — didn't contain changes` is benign (the update is a * no-op, so nothing can be replaced); any other FAILED is a probe failure. */ private collectVerdicts; /** * Best-effort startup sweep: delete leaked `fjall-preflight-*` change sets * older than one hour (a prior run whose finally-delete never fired). Runs * only when a probe engages, so non-escalated deploys pay nothing [G4] — a * leak can only exist on a stack a previous run probed. Never fails the * probe. */ private sweepLeakedChangeSets; /** Stage an oversized template body in the CDK bootstrap assets bucket. */ private uploadTemplate; /** Best-effort cleanup of the staged template — logged, never thrown. */ private deleteUploadedTemplate; }