@go-to-k/cdkd 0.278.26 → 0.278.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9094,6 +9094,133 @@ async function applyRoleArnIfSet(opts) {
9094
9094
  }
9095
9095
  }
9096
9096
 
9097
+ //#endregion
9098
+ //#region src/provisioning/config-shape.ts
9099
+ /**
9100
+ * Shape guards for nested CloudFormation config blocks read by SDK providers.
9101
+ *
9102
+ * The bug class this exists for (issue #1471): a provider reads a string out
9103
+ * of a nested block with
9104
+ *
9105
+ * ```ts
9106
+ * const status = (versioningConfig['Status'] as string) || 'Suspended';
9107
+ * ```
9108
+ *
9109
+ * When `versioningConfig` is a STRING / array / number rather than the object
9110
+ * the template was supposed to carry, the index yields `undefined` and the
9111
+ * `||` substitutes the default — which is frequently the OPPOSITE of what the
9112
+ * template declared. `VersioningConfiguration: 'Enabled'` (a hand-written L1
9113
+ * template, or an intrinsic the resolver could not resolve) therefore turned
9114
+ * versioning OFF on a live bucket with no error anywhere. The same shape was
9115
+ * measured at 16 sites across 5 providers.
9116
+ *
9117
+ * `readConfigString` is that read, done safely, in ONE place — so the class is
9118
+ * fixed by construction rather than by 16 hand-written `throw`s that can each
9119
+ * be subtly different.
9120
+ *
9121
+ * Four rules, each of which the versioning case forced (see #1471):
9122
+ *
9123
+ * 1. **An absent container is not an error.** `undefined` / `null` means the
9124
+ * template omitted the block, and the caller's default is the right answer.
9125
+ * 2. **A present-but-non-object container is refused.** This is the headline
9126
+ * bug: a string container silently produced the default.
9127
+ * 3. **An absent KEY is not an error** — `{}` legitimately means "defaulted",
9128
+ * e.g. `VersioningConfiguration: {}` really does mean Suspended.
9129
+ * 4. **A present-but-unusable key is refused.** `{ Status: null }` and
9130
+ * `{ Status: '' }` both pass a `typeof container === 'object'` check and
9131
+ * still fall through to the default, so validating the CONTAINER alone is
9132
+ * not enough — the FIELD has to be validated too.
9133
+ *
9134
+ * **Callers must pass the DESIRED side only.** The previous side comes from
9135
+ * cdkd state, not from the user's template: a stack deployed by an older cdkd
9136
+ * that already recorded a malformed value would otherwise throw on every
9137
+ * subsequent `cdkd deploy`, with no way out except hand-editing the S3 state
9138
+ * file (editing the template does not help, because the previous side stays
9139
+ * malformed until a deploy succeeds). An earlier attempt at this fix guarded
9140
+ * both sides and turned a silent misbehavior into an unrecoverable one; that
9141
+ * is why `KinesisProvider`'s read of `previousProperties.StreamModeDetails`
9142
+ * is deliberately left unguarded.
9143
+ *
9144
+ * This is a provider-layer guard rather than a pre-flight template check
9145
+ * because **rule 4** is only decidable AFTER intrinsic resolution: at pre-flight
9146
+ * time a legitimate `Fn::If`-valued block is an object whose `Status` key does
9147
+ * not exist yet, so a pre-flight field check would reject valid templates.
9148
+ * (Rule 3 is permissive and so cannot false-positive at any layer — it simply
9149
+ * could never be STRENGTHENED at pre-flight, since an absent key there is
9150
+ * indistinguishable from one an intrinsic will supply. Rule 2 alone genuinely
9151
+ * IS pre-flight-able; splitting one guard across two layers for it was judged
9152
+ * not worth the divergence.)
9153
+ *
9154
+ * The trade-off that choice accepts, recorded rather than left implicit: the
9155
+ * issue's pre-flight proposal would have failed BEFORE any AWS mutation,
9156
+ * whereas a provider-layer guard can throw after `CreateBucket` has already
9157
+ * succeeded. `create()` self-heals by deleting the partially-created bucket,
9158
+ * but a downstream refusal can still leave earlier sub-config PUTs applied —
9159
+ * the same exposure the pre-existing `applyOwnershipControls` throw has, and
9160
+ * still strictly better than a silent wrong-direction PUT.
9161
+ */
9162
+ /**
9163
+ * Read an optional string field out of a nested CFn config block, refusing a
9164
+ * container or a value whose shape would otherwise be silently defaulted away.
9165
+ *
9166
+ * @param container The block the field lives in. Pass the provider's own
9167
+ * `properties` bag directly when the field is top-level.
9168
+ * @param key The CFn field name.
9169
+ * @param fallback The value to use when the container or the key is absent.
9170
+ * @param containerPath CFn path of the CONTAINER, used to build both error
9171
+ * messages, e.g. `AWS::S3::Bucket VersioningConfiguration` (the field is
9172
+ * reported as `<containerPath>.<key>`).
9173
+ * @throws Error when the container is present but not a plain object, or the
9174
+ * key is present but not a non-blank string.
9175
+ */
9176
+ function readConfigString(container, key, fallback, containerPath) {
9177
+ if (container === void 0 || container === null) return fallback;
9178
+ if (!isPlainObject$1(container)) throw new Error(`${containerPath} must be an object (got ${describe(container)}) — check for an unresolved intrinsic or a mis-nested template value`);
9179
+ return requireConfigString(container[key], fallback, `${containerPath}.${key}`);
9180
+ }
9181
+ /**
9182
+ * The value-level half of {@link readConfigString}, for a value the caller has
9183
+ * ALREADY read out of a container it knows is a plain object — in practice a
9184
+ * TOP-LEVEL property read straight off the provider's `properties` bag, where
9185
+ * only rules 3 and 4 can apply.
9186
+ *
9187
+ * Keep this form at top-level call sites rather than passing `properties` to
9188
+ * {@link readConfigString}: the `handled-property-wiring` critic
9189
+ * (`scripts/gen-handled-property-wiring.ts`) recognises a property as WIRED
9190
+ * from the `properties['X']` element-read at the call site, and deliberately
9191
+ * does not treat a whole-bag forward into a helper as evidence. Hiding the
9192
+ * read inside the helper made `S3DirectoryBucketProvider` and
9193
+ * `WAFv2WebACLProvider` report un-wired — a false handled claim, which is the
9194
+ * exact thing that critic exists to prevent.
9195
+ *
9196
+ * @param value The already-read field value.
9197
+ * @param fallback The value to use when the field is absent.
9198
+ * @param path CFn path used in the error message, e.g. `AWS::WAFv2::WebACL Scope`.
9199
+ * @throws Error when the value is present but not a non-blank string.
9200
+ */
9201
+ function requireConfigString(value, fallback, path) {
9202
+ if (value === void 0) return fallback;
9203
+ if (fallback === "" && typeof value === "string") return value;
9204
+ if (typeof value !== "string" || value.trim() === "") throw new Error(`${path} must be a non-empty string (got ${describe(value)}) — check for an unresolved intrinsic or a mis-nested template value. Omit the field entirely to use the default` + (fallback === "" ? "" : ` (${fallback})`));
9205
+ return value;
9206
+ }
9207
+ /**
9208
+ * A plain object, i.e. something a CFn config block can legitimately be.
9209
+ * Arrays are excluded on purpose: an array where an object belongs is one of
9210
+ * the malformed shapes this module exists to catch, and `typeof [] === 'object'`
9211
+ * would otherwise wave it through.
9212
+ */
9213
+ function isPlainObject$1(value) {
9214
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9215
+ }
9216
+ /** Human-readable type for an error message, without dumping user data. */
9217
+ function describe(value) {
9218
+ if (value === null) return "null";
9219
+ if (Array.isArray(value)) return "an array";
9220
+ if (typeof value === "string") return value.trim() === "" ? "a blank string" : "a string";
9221
+ return typeof value === "object" ? "an object" : `a ${typeof value}`;
9222
+ }
9223
+
9097
9224
  //#endregion
9098
9225
  //#region src/provisioning/region-check.ts
9099
9226
  /**
@@ -9601,7 +9728,7 @@ var WAFv2WebACLProvider = class {
9601
9728
  async create(logicalId, resourceType, properties) {
9602
9729
  this.logger.debug(`Creating WAFv2 WebACL ${logicalId}`);
9603
9730
  const name = properties["Name"] || generateResourceName(logicalId, { maxLength: 128 });
9604
- const scope = properties["Scope"] || "REGIONAL";
9731
+ const scope = requireConfigString(properties["Scope"], "REGIONAL", "AWS::WAFv2::WebACL Scope");
9605
9732
  this.warnOnSdkUnsupportedRuleKeys(logicalId, properties["Rules"]);
9606
9733
  try {
9607
9734
  const tags = [];
@@ -12430,7 +12557,7 @@ var CloudControlProvider = class {
12430
12557
  if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
12431
12558
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
12432
12559
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
12433
- const { ASGProvider } = await import("./asg-provider-DLScqiT2.js").then((n) => n.n);
12560
+ const { ASGProvider } = await import("./asg-provider-BJnh483x.js").then((n) => n.n);
12434
12561
  await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
12435
12562
  return;
12436
12563
  }
@@ -18128,6 +18255,32 @@ async function withResourceDeadline(operation, opts) {
18128
18255
  /** The `--skip-final-snapshot` flag name cited by every refusal below. */
18129
18256
  const SKIP_FINAL_SNAPSHOT_FLAG = "--skip-final-snapshot";
18130
18257
  /**
18258
+ * The {@link CreateContext} every reverse-replacement re-create passes
18259
+ * (issue #1463). Both arms of that path — the create-first attempt and the
18260
+ * delete-new-first retry — revive the OLD resource from
18261
+ * `previousState.properties`, i.e. from a cdkd STATE record rather than the
18262
+ * template, so a provider pre-flight refusal has no template-side remedy and
18263
+ * must downgrade to a warning. Declared once so the two arms cannot drift.
18264
+ *
18265
+ * These are the only create call sites that can DECLARE a replay. The deploy
18266
+ * engine's five sites (CREATE, the property-driven replacement, the
18267
+ * `--recreate-via-*` destroy-then-create, the `--replace` delete-first
18268
+ * fallback, and the update-failure replacement) are all driven by freshly
18269
+ * resolved TEMPLATE properties, so they deliberately pass no context and the
18270
+ * refusal stands where the user can edit the input.
18271
+ *
18272
+ * The remaining call sites are the providers that re-create inside their own
18273
+ * `update()` (`this.create(...)` in ACM certificate / IAM managed policy / IAM
18274
+ * role / Lambda permission / SNS subscription). Those are NOT template-driven
18275
+ * — this executor's `revert` arm calls `provider.update(...)` with
18276
+ * `previousState.properties`, so they forward a STATE record on a replay — but
18277
+ * they CANNOT receive a context, because `update()` has no context parameter.
18278
+ * The constraint that follows is on providers, not on this constant: a
18279
+ * provider with a create-side pre-flight refusal must not re-create inside
18280
+ * `update()`. See `CreateContext` in `src/types/resource.ts`.
18281
+ */
18282
+ const REPLAYING_STATE_CREATE_CONTEXT = { replayingState: true };
18283
+ /**
18131
18284
  * Which provisioning layer a delete must be judged against: the CURRENT
18132
18285
  * state record wins (it is what state says AWS holds right now), with the
18133
18286
  * journaled op's routing as the legacy-state fallback. Shared by both
@@ -18542,7 +18695,7 @@ async function replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds
18542
18695
  let deletedNewFirst = false;
18543
18696
  let createResult;
18544
18697
  try {
18545
- createResult = await withRetry(() => createProvider.create(op.logicalId, op.resourceType, { ...prev.properties }), op.logicalId, {
18698
+ createResult = await withRetry(() => createProvider.create(op.logicalId, op.resourceType, { ...prev.properties }, REPLAYING_STATE_CREATE_CONTEXT), op.logicalId, {
18546
18699
  ...RECREATE_RETRY_SCHEDULE,
18547
18700
  logger,
18548
18701
  ...isInterrupted && {
@@ -18565,7 +18718,7 @@ async function replaySingle(op, stateResources, stackName, ctx, orphanLogicalIds
18565
18718
  delete stateResources[op.logicalId];
18566
18719
  await afterOp?.(op.logicalId);
18567
18720
  try {
18568
- createResult = await withRetry(() => createProvider.create(op.logicalId, op.resourceType, { ...prev.properties }), op.logicalId, {
18721
+ createResult = await withRetry(() => createProvider.create(op.logicalId, op.resourceType, { ...prev.properties }, REPLAYING_STATE_CREATE_CONTEXT), op.logicalId, {
18569
18722
  ...RECREATE_RETRY_SCHEDULE,
18570
18723
  logger,
18571
18724
  ...isInterrupted && {
@@ -18898,7 +19051,7 @@ const FLUSH_INTERVAL_MS = 2e3;
18898
19051
  const FLUSH_EVENT_THRESHOLD = 50;
18899
19052
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
18900
19053
  function getCdkdVersion() {
18901
- return "0.278.26";
19054
+ return "0.278.28";
18902
19055
  }
18903
19056
  /**
18904
19057
  * Generate a time-sortable unique run id, e.g.
@@ -21009,5 +21162,5 @@ var DeployEngine = class {
21009
21162
  };
21010
21163
 
21011
21164
  //#endregion
21012
- export { isThrottlingError as $, setAwsClients as $t, red as A, getLegacyStateBucketName as At, isTerminationProtectionPropagationError as B, CFN_TEMPLATE_BODY_LIMIT as Bt, isStatefulRecreateTargetSync as C, __exportAll as Cn, runDockerForeground as Ct, cyan as D, Synthesizer as Dt, bold as E, getDockerImageBySourceHash as Et, ProviderRegistry as F, resolveStateBucketWithDefault as Ft, normalizeAwsTagsToCfn as G, expectedOwnerParam as Gt, cfnRefValueFromPhysicalId as H, MIGRATE_TMP_PREFIX as Ht, findActionableSilentDrops as I, resolveStateBucketWithDefaultAndSource as It, applyRoleArnIfSet as J, clearBucketRegionCache as Jt, resolveExplicitPhysicalId as K, AssemblyReader as Kt, CloudControlProvider as L, resolveUseCdkBootstrapAssets as Lt, IAMRoleProvider as M, resolveAutoAssetStorage as Mt, collectInlinePolicyNamesManagedBySiblings as N, resolveCaptureObservedState as Nt, gray as O, synthesisStatusMessage as Ot, clearOnUpdateRemoval as P, resolveSkipPrefix as Pt, isRetryableTransientError as Q, resetAwsClients as Qt, slowCcOperationTimeoutMs as R, stateBucketExistenceConfirmed as Rt, MULTI_REGION_RECREATE_BLOCKED_TYPES as S, withErrorHandling as Sn, getDockerCmd as St, formatResourceLine as T, AssetManifestLoader as Tt, refStateLookupFromResource as U, findLargeInlineResources as Ut, IntrinsicFunctionResolver as V, CFN_TEMPLATE_URL_LIMIT as Vt, WAFv2WebACLProvider as W, uploadCfnTemplate as Wt, describeTypeWithThrottleRetry as X, AwsClients as Xt, DiffCalculator as Y, resolveBucketRegion as Yt, withRetry as Z, getAwsClients as Zt, createPreDeleteFinalSnapshot as _, StateError as _n, parseBootstrapMarker as _t, DeploymentEventsStore as a, LocalInvokeBuildError as an, shouldRetainResource as at, unsupportedFinalSnapshotError as b, isCdkdError as bn, buildDockerImage as bt, replayFailedOperations as c, LockError as cn, WorkGraph as ct, IMPLICIT_DELETE_DEPENDENCIES as d, PartialFailureError as dn, loadPublishableAssetManifest as dt, AssetError as en, DagBuilder as et, computeImplicitDeleteEdges as f, ProvisioningError as fn, rewriteTemplateAssetReferences as ft, ccRoutedFinalSnapshotError as g, StackTerminationProtectionError as gn, getBootstrapMarkerKey as gt, buildFinalSnapshotIdentifier as h, StackHasActiveImportsError as hn, ensureAssetStorage as ht, DeploymentEventsReader as i, DeployCancelledError as in, rebuildClientForBucketRegion as it, yellow as j, resolveApp as jt, green as k, getDefaultStateBucketName as kt, replayRollback as l, MissingCdkCliError as ln, buildAssetRedirectMap as lt, PRE_DELETE_SNAPSHOT_TYPES as m, ResourceUpdateNotSupportedError as mn, BOOTSTRAP_MARKER_PREFIX as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, ConfigError as nn, LockManager as nt, planFailedOps as o, LocalMigrateError as on, AssetPublisher as ot, ATOMIC_FINAL_SNAPSHOT_TYPES as p, ResourceTimeoutError as pn, AssetModeResolver as pt, assertRegionMatch as q, processStackMessages as qt, DeployEngine as r, DependencyError as rn, S3StateBackend as rt, planRollback as s, LocalStartServiceError as sn, stringifyValue as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, CdkdError as tn, TemplateParser as tt, withResourceDeadline as u, NestedStackChildDirectDestroyError as un, createAssetRedirectResolver as ut, isFinalSnapshotError as v, SynthesisError as vn, validateAssetBucketName as vt, renderStatefulReason as w, runDockerStreaming as wt, extractDeploymentEventError as x, normalizeAwsError as xn, formatDockerLoginError as xt, refusesFinalSnapshot as y, formatError as yn, validateContainerRepoName as yt, disableInstanceApiTermination as z, warnDeprecatedNoPrefixCliFlag as zt };
21013
- //# sourceMappingURL=deploy-engine-BsHkBRtK.js.map
21165
+ export { withRetry as $, getAwsClients as $t, red as A, synthesisStatusMessage as At, isTerminationProtectionPropagationError as B, stateBucketExistenceConfirmed as Bt, isStatefulRecreateTargetSync as C, normalizeAwsError as Cn, formatDockerLoginError as Ct, cyan as D, AssetManifestLoader as Dt, bold as E, runDockerStreaming as Et, ProviderRegistry as F, resolveCaptureObservedState as Ft, normalizeAwsTagsToCfn as G, findLargeInlineResources as Gt, cfnRefValueFromPhysicalId as H, CFN_TEMPLATE_BODY_LIMIT as Ht, findActionableSilentDrops as I, resolveSkipPrefix as It, readConfigString as J, AssemblyReader as Jt, resolveExplicitPhysicalId as K, uploadCfnTemplate as Kt, CloudControlProvider as L, resolveStateBucketWithDefault as Lt, IAMRoleProvider as M, getLegacyStateBucketName as Mt, collectInlinePolicyNamesManagedBySiblings as N, resolveApp as Nt, gray as O, getDockerImageBySourceHash as Ot, clearOnUpdateRemoval as P, resolveAutoAssetStorage as Pt, describeTypeWithThrottleRetry as Q, AwsClients as Qt, slowCcOperationTimeoutMs as R, resolveStateBucketWithDefaultAndSource as Rt, MULTI_REGION_RECREATE_BLOCKED_TYPES as S, isCdkdError as Sn, buildDockerImage as St, formatResourceLine as T, __exportAll as Tn, runDockerForeground as Tt, refStateLookupFromResource as U, CFN_TEMPLATE_URL_LIMIT as Ut, IntrinsicFunctionResolver as V, warnDeprecatedNoPrefixCliFlag as Vt, WAFv2WebACLProvider as W, MIGRATE_TMP_PREFIX as Wt, applyRoleArnIfSet as X, clearBucketRegionCache as Xt, requireConfigString as Y, processStackMessages as Yt, DiffCalculator as Z, resolveBucketRegion as Zt, createPreDeleteFinalSnapshot as _, StackHasActiveImportsError as _n, ensureAssetStorage as _t, DeploymentEventsStore as a, DependencyError as an, S3StateBackend as at, unsupportedFinalSnapshotError as b, SynthesisError as bn, validateAssetBucketName as bt, replayFailedOperations as c, LocalMigrateError as cn, AssetPublisher as ct, IMPLICIT_DELETE_DEPENDENCIES as d, MissingCdkCliError as dn, buildAssetRedirectMap as dt, resetAwsClients as en, isRetryableTransientError as et, computeImplicitDeleteEdges as f, NestedStackChildDirectDestroyError as fn, createAssetRedirectResolver as ft, ccRoutedFinalSnapshotError as g, ResourceUpdateNotSupportedError as gn, BOOTSTRAP_MARKER_PREFIX as gt, buildFinalSnapshotIdentifier as h, ResourceTimeoutError as hn, AssetModeResolver as ht, DeploymentEventsReader as i, ConfigError as in, LockManager as it, yellow as j, getDefaultStateBucketName as jt, green as k, Synthesizer as kt, replayRollback as l, LocalStartServiceError as ln, stringifyValue as lt, PRE_DELETE_SNAPSHOT_TYPES as m, ProvisioningError as mn, rewriteTemplateAssetReferences as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, AssetError as nn, DagBuilder as nt, planFailedOps as o, DeployCancelledError as on, rebuildClientForBucketRegion as ot, ATOMIC_FINAL_SNAPSHOT_TYPES as p, PartialFailureError as pn, loadPublishableAssetManifest as pt, assertRegionMatch as q, expectedOwnerParam as qt, DeployEngine as r, CdkdError as rn, TemplateParser as rt, planRollback as s, LocalInvokeBuildError as sn, shouldRetainResource as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, setAwsClients as tn, isThrottlingError as tt, withResourceDeadline as u, LockError as un, WorkGraph as ut, isFinalSnapshotError as v, StackTerminationProtectionError as vn, getBootstrapMarkerKey as vt, renderStatefulReason as w, withErrorHandling as wn, getDockerCmd as wt, extractDeploymentEventError as x, formatError as xn, validateContainerRepoName as xt, refusesFinalSnapshot as y, StateError as yn, parseBootstrapMarker as yt, disableInstanceApiTermination as z, resolveUseCdkBootstrapAssets as zt };
21166
+ //# sourceMappingURL=deploy-engine-Dcg1nH3d.js.map