@go-to-k/cdkd 0.284.35 → 0.284.37

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.
@@ -875,6 +875,42 @@ var CrossAccountSecretRefusalError = class CrossAccountSecretRefusalError extend
875
875
  }
876
876
  };
877
877
  /**
878
+ * A `{{resolve:...}}` reference whose REGION cannot be established (issue
879
+ * [#2134](https://github.com/go-to-k/cdkd/issues/2134)): it names no region,
880
+ * and the stack it sits in is on record as reading across a region boundary.
881
+ *
882
+ * A SUBCLASS rather than a bare code, because the consumers that must not
883
+ * swallow it identify it by CLASS. `cdkd scrub` wraps its resolution passes in
884
+ * best-effort `catch { logger.debug }` blocks so that one unresolvable resource
885
+ * does not abandon the rest of the scrub -- and a refusal swallowed there is
886
+ * the exact outcome the refusal exists to prevent: no needle is recorded for
887
+ * the reference, the plaintext survives in `state.json`, and the command
888
+ * reports `No plaintext secrets found` and exits 0. The pre-pass refusals in
889
+ * `scrub.ts` are placed OUTSIDE those catches for the same reason; this one
890
+ * fires from inside `resolveDynamicReferences`, so it cannot be placed --
891
+ * it has to be re-raised.
892
+ *
893
+ * USER-FIXABLE, so it deliberately does NOT extend
894
+ * {@link CrossAccountSecretRefusalError}, whose subclass identity marks the one
895
+ * PERMANENT refusal `scrub.ts`'s `isByDesignRefusal` reports as unclearable.
896
+ * Spelling the reference as a full ARN names its region and clears this.
897
+ *
898
+ * The CODE names the domain (`DYNAMIC_REFERENCE_REGION_AMBIGUOUS`) rather than
899
+ * carrying the base class's `INTRINSIC_RESOLUTION_REFUSAL_` prefix its one
900
+ * sibling uses. Deliberate: no consumer keys on that prefix, so it is not a
901
+ * contract, and the prefixed spelling would read
902
+ * `INTRINSIC_RESOLUTION_REFUSAL_DYNAMIC_REFERENCE_REGION_AMBIGUOUS`. Consumers
903
+ * that must act on this identify it by CLASS, which is what the subclass is
904
+ * for.
905
+ */
906
+ var DynamicReferenceRegionAmbiguousError = class DynamicReferenceRegionAmbiguousError extends IntrinsicResolutionRefusalError {
907
+ constructor(message, cause) {
908
+ super(message, cause, "DYNAMIC_REFERENCE_REGION_AMBIGUOUS");
909
+ this.name = "DynamicReferenceRegionAmbiguousError";
910
+ Object.setPrototypeOf(this, DynamicReferenceRegionAmbiguousError.prototype);
911
+ }
912
+ };
913
+ /**
878
914
  * Dependency resolution errors
879
915
  */
880
916
  var DependencyError = class DependencyError extends CdkdError {
@@ -10325,6 +10361,226 @@ function s3BucketWebsiteUrl(bucketName, region) {
10325
10361
  return `http://${bucketName}.s3-website${S3_WEBSITE_ENDPOINT_LEGACY_DASH_REGIONS.has(folded) ? "-" : "."}${folded}.${urlSuffix}`;
10326
10362
  }
10327
10363
 
10364
+ //#endregion
10365
+ //#region src/deployment/secret-region-classification.ts
10366
+ /**
10367
+ * The `{{resolve:<service>:...}}` families whose value can be a SECRET, and
10368
+ * therefore the only ones the region question below is asked about: every
10369
+ * `secretsmanager` reference by spelling, and every `ssm` one, which is secret
10370
+ * exactly when its parameter is a `SecureString` (issue #1901).
10371
+ *
10372
+ * Every OTHER service is `local` because cdkd cannot resolve it at all, NOT
10373
+ * because it is public. `ssm-secure` is the live example and is emphatically
10374
+ * not public: `resolveDynamicReferences` has no arm for it, so the literal
10375
+ * token is passed through to AWS and CloudFormation resolves it SERVER-side.
10376
+ * cdkd never holds its value, so there is no region for cdkd to get wrong —
10377
+ * which is the only reason it can be waved through here.
10378
+ */
10379
+ const REPLAY_SECRET_SERVICES = /* @__PURE__ */ new Set(["secretsmanager", "ssm"]);
10380
+ /**
10381
+ * Split a `{{resolve:secretsmanager:...}}` inner body into its SECRET_ID.
10382
+ *
10383
+ * Mirrors `IntrinsicFunctionResolver.resolveSecretsManagerReference`'s own
10384
+ * split — including the END-ANCHORED whole-secret form — because a secret ID
10385
+ * may legitimately contain colons (an ARN always does), so `split(':')[1]` is
10386
+ * wrong for exactly the shape this file cares about most.
10387
+ */
10388
+ function secretsManagerSecretId(inner) {
10389
+ const afterService = inner.substring(15);
10390
+ let stringIdx = afterService.indexOf(":SecretString:");
10391
+ let binaryIdx = afterService.indexOf(":SecretBinary:");
10392
+ if (stringIdx < 0 && afterService.endsWith(":SecretString")) stringIdx = afterService.length - 13;
10393
+ if (binaryIdx < 0 && afterService.endsWith(":SecretBinary")) binaryIdx = afterService.length - 13;
10394
+ const delimiterIdx = stringIdx >= 0 && binaryIdx >= 0 ? Math.min(stringIdx, binaryIdx) : stringIdx >= 0 ? stringIdx : binaryIdx;
10395
+ return delimiterIdx >= 0 ? afterService.substring(0, delimiterIdx) : afterService;
10396
+ }
10397
+ /**
10398
+ * The parameter name an `{{resolve:ssm:...}}` reference asks for — byte-for-byte
10399
+ * what `IntrinsicFunctionResolver.resolveSSMReference` passes as `GetParameter`'s
10400
+ * `Name`, which is `parts.slice(1).join(':')` on the colon-split inner body.
10401
+ *
10402
+ * The whole remainder, deliberately, with NOTHING stripped:
10403
+ *
10404
+ * - An SSM dynamic reference CAN name a full ARN. The resolver joins the tail
10405
+ * back together, so `{{resolve:ssm:arn:aws:ssm:us-west-2:111122223333:parameter/db/pw}}`
10406
+ * reaches AWS as that ARN. A `split(':')[1]` here would yield the literal
10407
+ * `'arn'` — a parameter that does not exist — and then report the reference
10408
+ * as region-LESS and refuse it, which is the guess-in-the-other-direction the
10409
+ * `named-region` arm exists to prevent.
10410
+ * - A trailing `:<version>` / `:<label>` is part of the name AS SSM PARSES IT
10411
+ * (`GetParameter` accepts `name:3` / `name:prod`), so stripping it would name
10412
+ * a different thing in the refusal message than the one that would be read.
10413
+ */
10414
+ function ssmParameterName(inner) {
10415
+ return inner.substring(4);
10416
+ }
10417
+ /**
10418
+ * The region an ARN names, or `undefined` for anything that is not an ARN with
10419
+ * a populated region field (`arn:<partition>:<service>:<region>:...`).
10420
+ */
10421
+ function arnRegion(secretId) {
10422
+ if (!secretId.startsWith("arn:")) return void 0;
10423
+ const region = secretId.split(":")[3];
10424
+ return region ? region : void 0;
10425
+ }
10426
+ /**
10427
+ * The producer regions a stack's persisted cross-stack reads name, for
10428
+ * the replay's `RollbackExecutorContext.importedProducerRegions` (issue #2057).
10429
+ *
10430
+ * Both record kinds count, and for the same reason: each one is a value this
10431
+ * stack read out of ANOTHER region's state, so each one is a way a
10432
+ * foreign-region `{{resolve:...}}` expression can have reached this stack's own
10433
+ * record. `imports` is the strong `Fn::ImportValue` edge; `outputReads` is the
10434
+ * weak `Fn::GetStackOutput` one (schema v8), which is the EASIER of the two to
10435
+ * point across a region boundary because the reference carries its own
10436
+ * `Region` argument.
10437
+ *
10438
+ * Deduplicated case-insensitively, keeping each region's first-recorded
10439
+ * spelling so the refusal message echoes what the user will see in
10440
+ * `state.json`. The consumer's own region is deliberately NOT filtered here —
10441
+ * {@link classifyReplaySecretRegion} does that, because it is the one that
10442
+ * knows which region is asking.
10443
+ *
10444
+ * Exported so the two `RollbackExecutorContext` construction sites derive the
10445
+ * list identically — `cdkd rollback` from the state it loaded, and
10446
+ * `DeployEngine.rollbackExecutorContext` from `crossStackReadsForPartialSave`,
10447
+ * which unions that snapshot with the reads the failing deploy itself made.
10448
+ */
10449
+ function producerRegionsFromState(state) {
10450
+ const seen = /* @__PURE__ */ new Set();
10451
+ const regions = [];
10452
+ for (const entry of [...state.imports ?? [], ...state.outputReads ?? []]) {
10453
+ const canonical = canonicalizeRegion(entry.sourceRegion);
10454
+ if (!canonical || seen.has(canonical)) continue;
10455
+ seen.add(canonical);
10456
+ regions.push(entry.sourceRegion);
10457
+ }
10458
+ return regions;
10459
+ }
10460
+ /**
10461
+ * Decide which region must answer for a single `{{resolve:...}}` expression a
10462
+ * rollback replay is about to re-resolve — issue
10463
+ * [#2057](https://github.com/go-to-k/cdkd/issues/2057).
10464
+ *
10465
+ * WHY A REPLAY CAN BE HOLDING A FOREIGN REGION'S EXPRESSION AT ALL. Since
10466
+ * issue #1934 a cross-stack consumer re-resolves a redacted producer value in
10467
+ * the PRODUCER's region (`reresolveCrossStackValue` /
10468
+ * `resolverForProducerRegion`) — correct, because a Secrets Manager secret or
10469
+ * an SSM `SecureString` of the same NAME in two regions is two independent
10470
+ * values. The plaintext is then recorded into the CONSUMER's
10471
+ * `recordedSecretValues`, so the consumer's `state.json` (and from there the
10472
+ * rollback journal) persists the PRODUCER's spelling of the expression. That is
10473
+ * the right thing to persist, and it is region-less: the reader cannot tell
10474
+ * from the string which region produced it.
10475
+ *
10476
+ * The replay rebuilds its resolver from the CONSUMER's region alone, so
10477
+ * re-resolving that expression locally answers from a same-named secret in the
10478
+ * wrong region and writes it to a LIVE resource. Silent, and on the recovery
10479
+ * path. The rule applied here is the family's, from issue #1957: A NAMED REGION
10480
+ * BINDS; NEVER SUBSTITUTE A GUESS. The three verdicts are that one sentence:
10481
+ *
10482
+ * - **`named-region`** — the expression's SECRET_ID is an ARN, which names its
10483
+ * own region. The region is ESTABLISHED, so it binds: the caller resolves
10484
+ * through a resolver pinned to it (each command's own `*Resolvers.forRegion`) rather
10485
+ * than refusing. Refusing here would be the guess in the other direction.
10486
+ *
10487
+ * cdkd would otherwise get this wrong, which is why the arm exists at all:
10488
+ * `resolveSecretsManagerReference` builds its client from
10489
+ * `this.explicitRegion` and passes the ARN through as an opaque `SecretId`,
10490
+ * and `@aws-sdk/client-secrets-manager`'s endpoint ruleset has NO
10491
+ * ARN-derived endpoint rule (unlike, say, S3 access points), so a
10492
+ * foreign-region ARN is sent to the stack's own regional endpoint. What the
10493
+ * SERVICE then does with it is not something this repo can settle offline —
10494
+ * see the fixture note in
10495
+ * `tests/integration/rollback-cross-region-secret/README.md`. Pinning the
10496
+ * client to the ARN's region is correct either way: if Secrets Manager would
10497
+ * have refused the foreign ARN, this turns a hard failure into a correct
10498
+ * resolution; if it would have honoured it, this reaches the same value by
10499
+ * the documented route. Neither outcome is a regression.
10500
+ *
10501
+ * - **`ambiguous`** — the expression names no region (the plain name form) AND
10502
+ * this stack has a foreign producer region on record
10503
+ * (the replay's `RollbackExecutorContext.importedProducerRegions`). Nothing on hand
10504
+ * can establish the origin, so the replay refuses instead of guessing.
10505
+ *
10506
+ * KNOWN OVER-REFUSAL, accepted deliberately, and WIDER THAN THE SSM CASE
10507
+ * ALONE — state both, because the second one is the common shape:
10508
+ *
10509
+ * (a) Any NAME-FORM `secretsmanager` reference in a stack that has ANY
10510
+ * foreign producer region on record is refused, even when that secret is
10511
+ * the stack's own purely-local one and has nothing to do with the
10512
+ * cross-region read. The evidence is per-STACK, not per-reference, so one
10513
+ * cross-region export plus one ordinary
10514
+ * `{{resolve:secretsmanager:mysecret:SecretString:pw}}` is enough — and CDK's
10515
+ * `secretValueFromJson` emits exactly that name form, so this is the shape
10516
+ * most people will meet. It also persists: with the union the producer
10517
+ * region stays on record until the next SUCCESSFUL deploy. Per-reference
10518
+ * evidence is what would narrow it, and that needs the region recorded
10519
+ * ALONGSIDE the expression — the persisted-shape change issue #2057
10520
+ * deliberately deferred (its options 1 and 2). Until then the refusal is
10521
+ * loud, names the ARN spelling as the remedy, and is the fail-closed side
10522
+ * of a trade whose other side is a silent wrong-secret write.
10523
+ *
10524
+ * (b) An `ssm` reference is secret only when its parameter is a
10525
+ * `SecureString`, and this arm cannot tell. So a `{{resolve:ssm:/app/env}}`
10526
+ * naming a PUBLIC `String` that reached a persisted bag (issue #2036's
10527
+ * acknowledged over-redaction) is refused too. Narrowing it by
10528
+ * `isRecordedSecretExpression` was considered and REJECTED, and not because
10529
+ * the store is unreachable — it is imported by this very file. It is
10530
+ * unusable: `recordedSecretExpressions` is populated BY resolution, and in
10531
+ * the standalone `cdkd rollback` process nothing has resolved anything when
10532
+ * the first op is classified, so the store is empty and every `ssm` verdict
10533
+ * would come back "not secret" — turning the protection off for exactly the
10534
+ * SecureString case it exists for. Worse, once one op DID resolve a
10535
+ * reference the store would be warm for the next, so the verdict would
10536
+ * depend on OP ORDER. A resolve-the-type-first probe is unsound for the
10537
+ * same reason the whole issue exists: the TYPE is region-dependent (#1957),
10538
+ * so probing locally can report `String` for a name that is `SecureString`
10539
+ * in the producer's region and wave through the very write this refuses.
10540
+ * The residual is therefore a loud, actionable error on a narrow
10541
+ * intersection (an over-redacted public ssm reference AND a cross-region
10542
+ * read on record), which is the fail-closed side of the trade.
10543
+ *
10544
+ * - **`local`** — everything else, which is the overwhelmingly common case:
10545
+ * every non-secret service, every same-region ARN (the ordinary CDK
10546
+ * `secretValueFromJson` shape), and every name-form expression in a stack
10547
+ * with no foreign producer region recorded. Resolved exactly as before this
10548
+ * change.
10549
+ *
10550
+ * A same-region ARN answers `local` even when a foreign producer region IS on
10551
+ * record: the expression settles the question itself, so the weaker evidence
10552
+ * never gets consulted.
10553
+ */
10554
+ function classifyReplaySecretRegion(expression, consumerRegion, importedProducerRegions) {
10555
+ const inner = expression.startsWith("{{resolve:") ? expression.slice(10, -2) : void 0;
10556
+ if (inner === void 0) return { kind: "local" };
10557
+ const service = inner.split(":")[0];
10558
+ if (service === void 0 || !REPLAY_SECRET_SERVICES.has(service)) return { kind: "local" };
10559
+ const secretName = service === "secretsmanager" ? secretsManagerSecretId(inner) : ssmParameterName(inner);
10560
+ if (!secretName) return { kind: "local" };
10561
+ const named = arnRegion(secretName);
10562
+ if (named !== void 0) return canonicalizeRegion(named) === canonicalizeRegion(consumerRegion) ? { kind: "local" } : {
10563
+ kind: "named-region",
10564
+ secretName,
10565
+ region: named
10566
+ };
10567
+ const seen = /* @__PURE__ */ new Set();
10568
+ const foreignProducerRegions = [];
10569
+ for (const candidate of importedProducerRegions ?? []) {
10570
+ const canonical = canonicalizeRegion(candidate);
10571
+ if (!canonical || canonical === canonicalizeRegion(consumerRegion)) continue;
10572
+ if (seen.has(canonical)) continue;
10573
+ seen.add(canonical);
10574
+ foreignProducerRegions.push(candidate);
10575
+ }
10576
+ if (foreignProducerRegions.length === 0) return { kind: "local" };
10577
+ return {
10578
+ kind: "ambiguous",
10579
+ secretName,
10580
+ foreignProducerRegions
10581
+ };
10582
+ }
10583
+
10328
10584
  //#endregion
10329
10585
  //#region src/deployment/secret-redaction.ts
10330
10586
  /** Fixed marker substituted for a secret value in log / error output. */
@@ -13566,6 +13822,33 @@ function buildUnknownIntrinsicError(key) {
13566
13822
  return /* @__PURE__ */ new Error(`Unsupported CloudFormation intrinsic function "${key}": cdkd does not support resolving it yet. Deploying this template would produce a broken value. Please request support by opening an issue: ${issueUrl}`);
13567
13823
  }
13568
13824
  /**
13825
+ * The same context with the `producerRegions` EVIDENCE removed (issue #2134
13826
+ * review rounds 1 and 2).
13827
+ *
13828
+ * That field means "the CONSUMER stack reads from these regions", and it is
13829
+ * only meaningful where the origin of a reference is genuinely UNKNOWN. Hand it
13830
+ * to a resolution whose origin is already established and it re-judges a
13831
+ * reference cdkd has just proven, verdicting `ambiguous`.
13832
+ *
13833
+ * ROUND 1 stripped it by RESOLVER IDENTITY -- "is this a different instance?"
13834
+ * -- and round 2 measured that that is the wrong question. When the producer
13835
+ * lives in the CONSUMER's own region `resolverForProducerRegion` returns `this`,
13836
+ * so the identity test passed the evidence straight through and a name-form
13837
+ * reference read out of that producer was refused. The LOCAL producer failed
13838
+ * while the CROSS-REGION one succeeded, which is backwards, and after the
13839
+ * round-1 re-raise it aborted the whole stack's scrub rather than logging a
13840
+ * debug line.
13841
+ *
13842
+ * The right question is whether the ORIGIN IS KNOWN, so each caller answers it
13843
+ * for itself and this helper only performs the strip. Returned BY IDENTITY when
13844
+ * there is no evidence to remove, so the ordinary path allocates nothing.
13845
+ */
13846
+ function withoutProducerRegions(context) {
13847
+ if (context?.producerRegions === void 0) return context;
13848
+ const { producerRegions: _stripped, ...rest } = context;
13849
+ return rest;
13850
+ }
13851
+ /**
13569
13852
  * Does `value` carry a CloudFormation dynamic reference anywhere inside it?
13570
13853
  *
13571
13854
  * Used as the identity fast path of {@link
@@ -15467,8 +15750,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
15467
15750
  async reresolveCrossStackValue(value, producerRegion, context, origin, sourceKey) {
15468
15751
  if (!carriesDynamicReference(value)) return value;
15469
15752
  const resolver = this.resolverForProducerRegion(producerRegion);
15753
+ const pinnedContext = producerRegion ? withoutProducerRegions(context) : context;
15470
15754
  const walk = async (v) => {
15471
- if (typeof v === "string") return v.includes("{{resolve:") ? await resolver.resolveDynamicReferences(v, context) : v;
15755
+ if (typeof v === "string") return v.includes("{{resolve:") ? await resolver.resolveDynamicReferences(v, pinnedContext) : v;
15472
15756
  if (Array.isArray(v)) {
15473
15757
  const out = new Array(v.length);
15474
15758
  for (let i = 0; i < v.length; i++) out[i] = await walk(v[i]);
@@ -16132,6 +16416,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
16132
16416
  const service = inner.split(":")[0];
16133
16417
  const isKnownSecret = service === "secretsmanager" || recordedSecretExpressions.has(fullMatch);
16134
16418
  if (isKnownSecret && context?.skipDynamicReferences) continue;
16419
+ const regionVerdict = classifyReplaySecretRegion(fullMatch, this.explicitRegion ?? this.resolverRegion, context?.producerRegions);
16420
+ if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${fullMatch}: it names '${regionVerdict.secretName}' without a region, and this stack reads from ${regionVerdict.foreignProducerRegions.join(", ")} as well as its own region. cdkd cannot tell which one must answer, and resolving against the wrong one yields a different secret. Spell the reference as a full ARN to say which region owns it.`));
16421
+ if (regionVerdict.kind === "named-region") {
16422
+ const foreign = await this.resolverForProducerRegion(regionVerdict.region).resolveDynamicReferences(fullMatch, withoutProducerRegions(context));
16423
+ result = result.replace(fullMatch, () => foreign);
16424
+ continue;
16425
+ }
16135
16426
  const cached = this.cachedDynamicReferences.get(fullMatch);
16136
16427
  if (cached) {
16137
16428
  if (cached.secret && cached.value) context?.recordedSecretValues?.set(cached.value, fullMatch);
@@ -17273,7 +17564,7 @@ var CloudControlProvider = class {
17273
17564
  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);
17274
17565
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
17275
17566
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
17276
- const { ASGProvider } = await import("./asg-provider-bJ8nim2C.js").then((n) => n.n);
17567
+ const { ASGProvider } = await import("./asg-provider-BbWubpjP.js").then((n) => n.n);
17277
17568
  return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
17278
17569
  }
17279
17570
  const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
@@ -25148,223 +25439,6 @@ async function resolveReplayProps(props, resolvers, secrets, execCtx, logicalId)
25148
25439
  return await walk(props, "");
25149
25440
  }
25150
25441
  /**
25151
- * The `{{resolve:<service>:...}}` families whose value can be a SECRET, and
25152
- * therefore the only ones the region question below is asked about: every
25153
- * `secretsmanager` reference by spelling, and every `ssm` one, which is secret
25154
- * exactly when its parameter is a `SecureString` (issue #1901).
25155
- *
25156
- * Every OTHER service is `local` because cdkd cannot resolve it at all, NOT
25157
- * because it is public. `ssm-secure` is the live example and is emphatically
25158
- * not public: `resolveDynamicReferences` has no arm for it, so the literal
25159
- * token is passed through to AWS and CloudFormation resolves it SERVER-side.
25160
- * cdkd never holds its value, so there is no region for cdkd to get wrong —
25161
- * which is the only reason it can be waved through here.
25162
- */
25163
- const REPLAY_SECRET_SERVICES = /* @__PURE__ */ new Set(["secretsmanager", "ssm"]);
25164
- /**
25165
- * Split a `{{resolve:secretsmanager:...}}` inner body into its SECRET_ID.
25166
- *
25167
- * Mirrors `IntrinsicFunctionResolver.resolveSecretsManagerReference`'s own
25168
- * split — including the END-ANCHORED whole-secret form — because a secret ID
25169
- * may legitimately contain colons (an ARN always does), so `split(':')[1]` is
25170
- * wrong for exactly the shape this file cares about most.
25171
- */
25172
- function secretsManagerSecretId(inner) {
25173
- const afterService = inner.substring(15);
25174
- let stringIdx = afterService.indexOf(":SecretString:");
25175
- let binaryIdx = afterService.indexOf(":SecretBinary:");
25176
- if (stringIdx < 0 && afterService.endsWith(":SecretString")) stringIdx = afterService.length - 13;
25177
- if (binaryIdx < 0 && afterService.endsWith(":SecretBinary")) binaryIdx = afterService.length - 13;
25178
- const delimiterIdx = stringIdx >= 0 && binaryIdx >= 0 ? Math.min(stringIdx, binaryIdx) : stringIdx >= 0 ? stringIdx : binaryIdx;
25179
- return delimiterIdx >= 0 ? afterService.substring(0, delimiterIdx) : afterService;
25180
- }
25181
- /**
25182
- * The parameter name an `{{resolve:ssm:...}}` reference asks for — byte-for-byte
25183
- * what `IntrinsicFunctionResolver.resolveSSMReference` passes as `GetParameter`'s
25184
- * `Name`, which is `parts.slice(1).join(':')` on the colon-split inner body.
25185
- *
25186
- * The whole remainder, deliberately, with NOTHING stripped:
25187
- *
25188
- * - An SSM dynamic reference CAN name a full ARN. The resolver joins the tail
25189
- * back together, so `{{resolve:ssm:arn:aws:ssm:us-west-2:111122223333:parameter/db/pw}}`
25190
- * reaches AWS as that ARN. A `split(':')[1]` here would yield the literal
25191
- * `'arn'` — a parameter that does not exist — and then report the reference
25192
- * as region-LESS and refuse it, which is the guess-in-the-other-direction the
25193
- * `named-region` arm exists to prevent.
25194
- * - A trailing `:<version>` / `:<label>` is part of the name AS SSM PARSES IT
25195
- * (`GetParameter` accepts `name:3` / `name:prod`), so stripping it would name
25196
- * a different thing in the refusal message than the one that would be read.
25197
- */
25198
- function ssmParameterName(inner) {
25199
- return inner.substring(4);
25200
- }
25201
- /**
25202
- * The region an ARN names, or `undefined` for anything that is not an ARN with
25203
- * a populated region field (`arn:<partition>:<service>:<region>:...`).
25204
- */
25205
- function arnRegion(secretId) {
25206
- if (!secretId.startsWith("arn:")) return void 0;
25207
- const region = secretId.split(":")[3];
25208
- return region ? region : void 0;
25209
- }
25210
- /**
25211
- * The producer regions a stack's persisted cross-stack reads name, for
25212
- * {@link RollbackExecutorContext.importedProducerRegions} (issue #2057).
25213
- *
25214
- * Both record kinds count, and for the same reason: each one is a value this
25215
- * stack read out of ANOTHER region's state, so each one is a way a
25216
- * foreign-region `{{resolve:...}}` expression can have reached this stack's own
25217
- * record. `imports` is the strong `Fn::ImportValue` edge; `outputReads` is the
25218
- * weak `Fn::GetStackOutput` one (schema v8), which is the EASIER of the two to
25219
- * point across a region boundary because the reference carries its own
25220
- * `Region` argument.
25221
- *
25222
- * Deduplicated case-insensitively, keeping each region's first-recorded
25223
- * spelling so the refusal message echoes what the user will see in
25224
- * `state.json`. The consumer's own region is deliberately NOT filtered here —
25225
- * {@link classifyReplaySecretRegion} does that, because it is the one that
25226
- * knows which region is asking.
25227
- *
25228
- * Exported so the two `RollbackExecutorContext` construction sites derive the
25229
- * list identically — `cdkd rollback` from the state it loaded, and
25230
- * `DeployEngine.rollbackExecutorContext` from `crossStackReadsForPartialSave`,
25231
- * which unions that snapshot with the reads the failing deploy itself made.
25232
- */
25233
- function producerRegionsFromState(state) {
25234
- const seen = /* @__PURE__ */ new Set();
25235
- const regions = [];
25236
- for (const entry of [...state.imports ?? [], ...state.outputReads ?? []]) {
25237
- const canonical = canonicalizeRegion(entry.sourceRegion);
25238
- if (!canonical || seen.has(canonical)) continue;
25239
- seen.add(canonical);
25240
- regions.push(entry.sourceRegion);
25241
- }
25242
- return regions;
25243
- }
25244
- /**
25245
- * Decide which region must answer for a single `{{resolve:...}}` expression a
25246
- * rollback replay is about to re-resolve — issue
25247
- * [#2057](https://github.com/go-to-k/cdkd/issues/2057).
25248
- *
25249
- * WHY A REPLAY CAN BE HOLDING A FOREIGN REGION'S EXPRESSION AT ALL. Since
25250
- * issue #1934 a cross-stack consumer re-resolves a redacted producer value in
25251
- * the PRODUCER's region (`reresolveCrossStackValue` /
25252
- * `resolverForProducerRegion`) — correct, because a Secrets Manager secret or
25253
- * an SSM `SecureString` of the same NAME in two regions is two independent
25254
- * values. The plaintext is then recorded into the CONSUMER's
25255
- * `recordedSecretValues`, so the consumer's `state.json` (and from there the
25256
- * rollback journal) persists the PRODUCER's spelling of the expression. That is
25257
- * the right thing to persist, and it is region-less: the reader cannot tell
25258
- * from the string which region produced it.
25259
- *
25260
- * The replay rebuilds its resolver from the CONSUMER's region alone, so
25261
- * re-resolving that expression locally answers from a same-named secret in the
25262
- * wrong region and writes it to a LIVE resource. Silent, and on the recovery
25263
- * path. The rule applied here is the family's, from issue #1957: A NAMED REGION
25264
- * BINDS; NEVER SUBSTITUTE A GUESS. The three verdicts are that one sentence:
25265
- *
25266
- * - **`named-region`** — the expression's SECRET_ID is an ARN, which names its
25267
- * own region. The region is ESTABLISHED, so it binds: the caller resolves
25268
- * through a resolver pinned to it ({@link ReplayResolvers.forRegion}) rather
25269
- * than refusing. Refusing here would be the guess in the other direction.
25270
- *
25271
- * cdkd would otherwise get this wrong, which is why the arm exists at all:
25272
- * `resolveSecretsManagerReference` builds its client from
25273
- * `this.explicitRegion` and passes the ARN through as an opaque `SecretId`,
25274
- * and `@aws-sdk/client-secrets-manager`'s endpoint ruleset has NO
25275
- * ARN-derived endpoint rule (unlike, say, S3 access points), so a
25276
- * foreign-region ARN is sent to the stack's own regional endpoint. What the
25277
- * SERVICE then does with it is not something this repo can settle offline —
25278
- * see the fixture note in
25279
- * `tests/integration/rollback-cross-region-secret/README.md`. Pinning the
25280
- * client to the ARN's region is correct either way: if Secrets Manager would
25281
- * have refused the foreign ARN, this turns a hard failure into a correct
25282
- * resolution; if it would have honoured it, this reaches the same value by
25283
- * the documented route. Neither outcome is a regression.
25284
- *
25285
- * - **`ambiguous`** — the expression names no region (the plain name form) AND
25286
- * this stack has a foreign producer region on record
25287
- * ({@link RollbackExecutorContext.importedProducerRegions}). Nothing on hand
25288
- * can establish the origin, so the replay refuses instead of guessing.
25289
- *
25290
- * KNOWN OVER-REFUSAL, accepted deliberately, and WIDER THAN THE SSM CASE
25291
- * ALONE — state both, because the second one is the common shape:
25292
- *
25293
- * (a) Any NAME-FORM `secretsmanager` reference in a stack that has ANY
25294
- * foreign producer region on record is refused, even when that secret is
25295
- * the stack's own purely-local one and has nothing to do with the
25296
- * cross-region read. The evidence is per-STACK, not per-reference, so one
25297
- * cross-region export plus one ordinary
25298
- * `{{resolve:secretsmanager:mysecret:SecretString:pw}}` is enough — and CDK's
25299
- * `secretValueFromJson` emits exactly that name form, so this is the shape
25300
- * most people will meet. It also persists: with the union the producer
25301
- * region stays on record until the next SUCCESSFUL deploy. Per-reference
25302
- * evidence is what would narrow it, and that needs the region recorded
25303
- * ALONGSIDE the expression — the persisted-shape change issue #2057
25304
- * deliberately deferred (its options 1 and 2). Until then the refusal is
25305
- * loud, names the ARN spelling as the remedy, and is the fail-closed side
25306
- * of a trade whose other side is a silent wrong-secret write.
25307
- *
25308
- * (b) An `ssm` reference is secret only when its parameter is a
25309
- * `SecureString`, and this arm cannot tell. So a `{{resolve:ssm:/app/env}}`
25310
- * naming a PUBLIC `String` that reached a persisted bag (issue #2036's
25311
- * acknowledged over-redaction) is refused too. Narrowing it by
25312
- * `isRecordedSecretExpression` was considered and REJECTED, and not because
25313
- * the store is unreachable — it is imported by this very file. It is
25314
- * unusable: `recordedSecretExpressions` is populated BY resolution, and in
25315
- * the standalone `cdkd rollback` process nothing has resolved anything when
25316
- * the first op is classified, so the store is empty and every `ssm` verdict
25317
- * would come back "not secret" — turning the protection off for exactly the
25318
- * SecureString case it exists for. Worse, once one op DID resolve a
25319
- * reference the store would be warm for the next, so the verdict would
25320
- * depend on OP ORDER. A resolve-the-type-first probe is unsound for the
25321
- * same reason the whole issue exists: the TYPE is region-dependent (#1957),
25322
- * so probing locally can report `String` for a name that is `SecureString`
25323
- * in the producer's region and wave through the very write this refuses.
25324
- * The residual is therefore a loud, actionable error on a narrow
25325
- * intersection (an over-redacted public ssm reference AND a cross-region
25326
- * read on record), which is the fail-closed side of the trade.
25327
- *
25328
- * - **`local`** — everything else, which is the overwhelmingly common case:
25329
- * every non-secret service, every same-region ARN (the ordinary CDK
25330
- * `secretValueFromJson` shape), and every name-form expression in a stack
25331
- * with no foreign producer region recorded. Resolved exactly as before this
25332
- * change.
25333
- *
25334
- * A same-region ARN answers `local` even when a foreign producer region IS on
25335
- * record: the expression settles the question itself, so the weaker evidence
25336
- * never gets consulted.
25337
- */
25338
- function classifyReplaySecretRegion(expression, consumerRegion, importedProducerRegions) {
25339
- const inner = expression.startsWith("{{resolve:") ? expression.slice(10, -2) : void 0;
25340
- if (inner === void 0) return { kind: "local" };
25341
- const service = inner.split(":")[0];
25342
- if (service === void 0 || !REPLAY_SECRET_SERVICES.has(service)) return { kind: "local" };
25343
- const secretName = service === "secretsmanager" ? secretsManagerSecretId(inner) : ssmParameterName(inner);
25344
- if (!secretName) return { kind: "local" };
25345
- const named = arnRegion(secretName);
25346
- if (named !== void 0) return canonicalizeRegion(named) === canonicalizeRegion(consumerRegion) ? { kind: "local" } : {
25347
- kind: "named-region",
25348
- secretName,
25349
- region: named
25350
- };
25351
- const seen = /* @__PURE__ */ new Set();
25352
- const foreignProducerRegions = [];
25353
- for (const candidate of importedProducerRegions ?? []) {
25354
- const canonical = canonicalizeRegion(candidate);
25355
- if (!canonical || canonical === canonicalizeRegion(consumerRegion)) continue;
25356
- if (seen.has(canonical)) continue;
25357
- seen.add(canonical);
25358
- foreignProducerRegions.push(candidate);
25359
- }
25360
- if (foreignProducerRegions.length === 0) return { kind: "local" };
25361
- return {
25362
- kind: "ambiguous",
25363
- secretName,
25364
- foreignProducerRegions
25365
- };
25366
- }
25367
- /**
25368
25442
  * The replay's resolvers: the stack's own, plus one pinned sibling per FOREIGN
25369
25443
  * region an ARN-named reference asks for (issue #2057).
25370
25444
  *
@@ -26186,7 +26260,7 @@ const FLUSH_INTERVAL_MS = 2e3;
26186
26260
  const FLUSH_EVENT_THRESHOLD = 50;
26187
26261
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
26188
26262
  function getCdkdVersion() {
26189
- return "0.284.35";
26263
+ return "0.284.37";
26190
26264
  }
26191
26265
  /**
26192
26266
  * Generate a time-sortable unique run id, e.g.
@@ -28806,5 +28880,5 @@ var DeployEngine = class {
28806
28880
  };
28807
28881
 
28808
28882
  //#endregion
28809
- export { endCommandInterruptScope as $, ConfigError as $n, buildAssetRedirectMap as $t, MULTI_REGION_RECREATE_BLOCKED_TYPES as A, resolveStateBucketWithDefaultAndSource as An, maskSecretsInError as At, collectDeclaredOutputNames as B, PARTITION_TABLE as Bn, DiffCalculator as Bt, ccRoutedFinalSnapshotError as C, getDefaultStateBucketName as Cn, isThrottlingError as Cr, STATE_SOURCED_CROSS_GENERATION_RULES as Ct, unsupportedFinalSnapshotError as D, resolveCaptureObservedState as Dn, dynamicReferenceTokens as Dt, refusesFinalSnapshot as E, resolveAutoAssetStorage as En, createSecretMasker as Et, cyan as F, CFN_TEMPLATE_URL_LIMIT as Fn, s3BucketDomainName as Ft, stateKeySecretExposure as G, clearBucketRegionCache as Gn, TemplateParser as Gt, exportAliasCollisionScrubWarning as H, derivePartitionAndUrlSuffix as Hn, describeTypeWithThrottleRetry as Ht, gray as I, MIGRATE_TMP_PREFIX as In, s3BucketDualStackDomainName as It, clearOnUpdateRemoval as J, getAwsClients as Jn, rebuildClientForBucketRegion as Jt, IAMRoleProvider as K, resolveBucketRegion as Kn, LockManager as Kt, green as L, findLargeInlineResources as Ln, s3BucketRegionalDomainName as Lt, renderStatefulReason as M, stateBucketExistenceConfirmed as Mn, redactSecretsForState as Mt, formatResourceLine as N, warnDeprecatedNoPrefixCliFlag as Nn, scrubResourceRecord as Nt, makeCanonicalizePropertiesFn as O, resolveSkipPrefix as On, errorCauseChain as Ot, bold as P, CFN_TEMPLATE_BODY_LIMIT as Pn, s3BucketArn as Pt, beginCommandInterruptScope as Q, CdkdError as Qn, WorkGraph as Qt, red as R, uploadCfnTemplate as Rn, s3BucketWebsiteUrl as Rt, buildFinalSnapshotIdentifier as S, synthesisStatusMessage as Sn, isRetryableTransientError as Sr, requireConfigString as St, isFinalSnapshotError as T, resolveApp as Tn, __exportAll as Tr, TEMPLATE_SOURCED_RULES as Tt, isExportAliasCollision as U, AssemblyReader as Un, withRetry as Ut, collectPublishedOutputNames as V, canonicalizeRegion as Vn, INTRINSIC_KEYS as Vt, secretBearingStateKeyWarning as W, processStackMessages as Wn, DagBuilder as Wt, findActionableSilentDrops as X, setAwsClients as Xn, AssetPublisher as Xt, ProviderRegistry as Y, resetAwsClients as Yn, shouldRetainResource as Yt, findSilentDropProperties as Z, AssetError as Zn, stringifyValue as Zt, maskingRetryLogger as _, runDockerForeground as _n, formatError as _r, configStringRefusal as _t, DeploymentEventsStore as a, AssetModeResolver as an, LocalStartServiceError as ar, isTerminationProtectionPropagationError as at, ATOMIC_FINAL_SNAPSHOT_TYPES as b, getDockerImageBySourceHash as bn, withErrorHandling as br, requireConfigArray as bt, planRollback as c, getBootstrapMarkerKey as cn, NestedStackChildDirectDestroyError as cr, cfnRefValueFromPhysicalId as ct, replayRollback as d, validateAssetBucketName as dn, ResourceTimeoutError as dr, WAFv2WebACLProvider as dt, createAssetRedirectResolver as en, CrossAccountSecretRefusalError as er, isInterruptedWaitError as et, updatePartialMessage as f, validateContainerRepoName as fn, ResourceUpdateNotSupportedError as fr, normalizeAwsTagsToCfn as ft, withResourceDeadline as g, getDockerCmd as gn, SynthesisError as gr, configBooleanRefusal as gt, deleteSkipReason as h, formatDockerLoginError as hn, StateError as hr, coerceCfnBoolean as ht, DeploymentEventsReader as i, stripControlChars as in, LocalMigrateError as ir, disableInstanceApiTermination as it, isStatefulRecreateTargetSync as j, resolveUseCdkBootstrapAssets as jn, maskSecretsInText as jt, extractDeploymentEventError as k, resolveStateBucketWithDefault as kn, isSingleDynamicReferenceToken as kt, producerRegionsFromState as l, parseBootstrapMarker as ln, PartialFailureError as lr, getAccountInfo as lt, UNSPECIFIED_SKIP_REASON as m, buildDockerImage as mn, StackTerminationProtectionError as mr, assertRegionMatch as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, rewriteTemplateAssetReferences as nn, DeployCancelledError as nr, CloudControlProvider as nt, classifyReplaySecretRegion as o, BOOTSTRAP_MARKER_PREFIX as on, LockError as or, IntrinsicFunctionResolver as ot, updatePartialReason as p, buildDenyExternalAccessPolicy as pn, StackHasActiveImportsError as pr, resolveExplicitPhysicalId as pt, collectInlinePolicyNamesManagedBySiblings as q, AwsClients as qn, S3StateBackend as qt, DeployEngine as r, escapeRegExp$1 as rn, LocalInvokeBuildError as rr, slowCcOperationTimeoutMs as rt, planFailedOps as s, ensureAssetStorage as sn, MissingCdkCliError as sr, carriesDynamicReference as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, loadPublishableAssetManifest as tn, DependencyError as tr, startInterruptWatch as tt, replayFailedOperations as u, readBootstrapMarkerBody as un, ProvisioningError as ur, refStateLookupFromResource as ut, IMPLICIT_DELETE_DEPENDENCIES as v, runDockerStreaming as vn, isCdkdError as vr, readConfigString as vt, createPreDeleteFinalSnapshot as w, getLegacyStateBucketName as wn, markNonRetryable as wr, STATE_SOURCED_READBACK_RULES as wt, PRE_DELETE_SNAPSHOT_TYPES as x, Synthesizer as xn, isMarkedNonRetryable as xr, requireConfigObject as xt, computeImplicitDeleteEdges as y, AssetManifestLoader as yn, normalizeAwsError as yr, replayWarn as yt, yellow as z, expectedOwnerParam as zn, applyRoleArnIfSet as zt };
28810
- //# sourceMappingURL=deploy-engine-Wei5Yw-_.js.map
28883
+ export { startInterruptWatch as $, ConfigError as $n, buildAssetRedirectMap as $t, renderStatefulReason as A, resolveStateBucketWithDefaultAndSource as An, redactSecretsForState as At, exportAliasCollisionScrubWarning as B, PARTITION_TABLE as Bn, DiffCalculator as Bt, isFinalSnapshotError as C, getDefaultStateBucketName as Cn, isRetryableTransientError as Cr, TEMPLATE_SOURCED_RULES as Ct, extractDeploymentEventError as D, resolveCaptureObservedState as Dn, isSingleDynamicReferenceToken as Dt, makeCanonicalizePropertiesFn as E, resolveAutoAssetStorage as En, __exportAll as Er, errorCauseChain as Et, green as F, CFN_TEMPLATE_URL_LIMIT as Fn, s3BucketDomainName as Ft, collectInlinePolicyNamesManagedBySiblings as G, clearBucketRegionCache as Gn, TemplateParser as Gt, secretBearingStateKeyWarning as H, derivePartitionAndUrlSuffix as Hn, describeTypeWithThrottleRetry as Ht, red as I, MIGRATE_TMP_PREFIX as In, s3BucketDualStackDomainName as It, findActionableSilentDrops as J, getAwsClients as Jn, rebuildClientForBucketRegion as Jt, clearOnUpdateRemoval as K, resolveBucketRegion as Kn, LockManager as Kt, yellow as L, findLargeInlineResources as Ln, s3BucketRegionalDomainName as Lt, bold as M, stateBucketExistenceConfirmed as Mn, classifyReplaySecretRegion as Mt, cyan as N, warnDeprecatedNoPrefixCliFlag as Nn, producerRegionsFromState as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, resolveSkipPrefix as On, maskSecretsInError as Ot, gray as P, CFN_TEMPLATE_BODY_LIMIT as Pn, s3BucketArn as Pt, isInterruptedWaitError as Q, CdkdError as Qn, WorkGraph as Qt, collectDeclaredOutputNames as R, uploadCfnTemplate as Rn, s3BucketWebsiteUrl as Rt, createPreDeleteFinalSnapshot as S, synthesisStatusMessage as Sn, isMarkedNonRetryable as Sr, STATE_SOURCED_READBACK_RULES as St, unsupportedFinalSnapshotError as T, resolveApp as Tn, markNonRetryable as Tr, dynamicReferenceTokens as Tt, stateKeySecretExposure as U, AssemblyReader as Un, withRetry as Ut, isExportAliasCollision as V, canonicalizeRegion as Vn, INTRINSIC_KEYS as Vt, IAMRoleProvider as W, processStackMessages as Wn, DagBuilder as Wt, beginCommandInterruptScope as X, setAwsClients as Xn, AssetPublisher as Xt, findSilentDropProperties as Y, resetAwsClients as Yn, shouldRetainResource as Yt, endCommandInterruptScope as Z, AssetError as Zn, stringifyValue as Zt, computeImplicitDeleteEdges as _, runDockerForeground as _n, SynthesisError as _r, replayWarn as _t, DeploymentEventsStore as a, AssetModeResolver as an, LocalMigrateError as ar, carriesDynamicReference as at, buildFinalSnapshotIdentifier as b, getDockerImageBySourceHash as bn, normalizeAwsError as br, requireConfigString as bt, replayFailedOperations as c, getBootstrapMarkerKey as cn, MissingCdkCliError as cr, refStateLookupFromResource as ct, updatePartialReason as d, validateAssetBucketName as dn, ProvisioningError as dr, resolveExplicitPhysicalId as dt, createAssetRedirectResolver as en, CrossAccountSecretRefusalError as er, CloudControlProvider as et, UNSPECIFIED_SKIP_REASON as f, validateContainerRepoName as fn, ResourceTimeoutError as fr, assertRegionMatch as ft, IMPLICIT_DELETE_DEPENDENCIES as g, getDockerCmd as gn, StateError as gr, readConfigString as gt, maskingRetryLogger as h, formatDockerLoginError as hn, StackTerminationProtectionError as hr, configStringRefusal as ht, DeploymentEventsReader as i, stripControlChars as in, LocalInvokeBuildError as ir, IntrinsicFunctionResolver as it, formatResourceLine as j, resolveUseCdkBootstrapAssets as jn, scrubResourceRecord as jt, isStatefulRecreateTargetSync as k, resolveStateBucketWithDefault as kn, maskSecretsInText as kt, replayRollback as l, parseBootstrapMarker as ln, NestedStackChildDirectDestroyError as lr, WAFv2WebACLProvider as lt, withResourceDeadline as m, buildDockerImage as mn, StackHasActiveImportsError as mr, configBooleanRefusal as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, rewriteTemplateAssetReferences as nn, DeployCancelledError as nr, disableInstanceApiTermination as nt, planFailedOps as o, BOOTSTRAP_MARKER_PREFIX as on, LocalStartServiceError as or, cfnRefValueFromPhysicalId as ot, deleteSkipReason as p, buildDenyExternalAccessPolicy as pn, ResourceUpdateNotSupportedError as pr, coerceCfnBoolean as pt, ProviderRegistry as q, AwsClients as qn, S3StateBackend as qt, DeployEngine as r, escapeRegExp$1 as rn, DynamicReferenceRegionAmbiguousError as rr, isTerminationProtectionPropagationError as rt, planRollback as s, ensureAssetStorage as sn, LockError as sr, getAccountInfo as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, loadPublishableAssetManifest as tn, DependencyError as tr, slowCcOperationTimeoutMs as tt, updatePartialMessage as u, readBootstrapMarkerBody as un, PartialFailureError as ur, normalizeAwsTagsToCfn as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, runDockerStreaming as vn, formatError as vr, requireConfigArray as vt, refusesFinalSnapshot as w, getLegacyStateBucketName as wn, isThrottlingError as wr, createSecretMasker as wt, ccRoutedFinalSnapshotError as x, Synthesizer as xn, withErrorHandling as xr, STATE_SOURCED_CROSS_GENERATION_RULES as xt, PRE_DELETE_SNAPSHOT_TYPES as y, AssetManifestLoader as yn, isCdkdError as yr, requireConfigObject as yt, collectPublishedOutputNames as z, expectedOwnerParam as zn, applyRoleArnIfSet as zt };
28884
+ //# sourceMappingURL=deploy-engine-C62UGXid.js.map