@go-to-k/cdkd 0.291.22 → 0.291.23

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.
@@ -1,6 +1,6 @@
1
1
  import { C as displayAwsMessage, D as isPasteableIdent, E as displayStackName, O as truncateCodePoints, S as UNRENDERABLE, T as displaySafe, d as applyDefaultNameForFallback, f as explicitNamePropertyFor, g as looksLikeCdkdGeneratedName, h as getCurrentStackName, m as generateResourceNameWithFallback, n as getLogger, p as generateResourceName, r as isStdoutReservedForPayload, s as getLiveRenderer, v as withStackName, w as displayIdent, x as STACK_REF_MAX_CODE_POINTS, y as withoutGeneratedFallbackName } from "./logger-Bt0RGDfb.js";
2
2
  import { a as setAssumedRoleCredentials, c as currentStackAwsScope, i as getPreAssumeEnvCredentials, l as runInStackAwsScope, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, s as ambientRegion, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-jISU4PHo.js";
3
- import { t as getCdkdVersion } from "./version-BuD41yiK.js";
3
+ import { t as getCdkdVersion } from "./version-BLo_Pzd-.js";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { createHash, randomUUID } from "node:crypto";
6
6
  import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
@@ -7389,7 +7389,7 @@ var Synthesizer = class {
7389
7389
  let accountId;
7390
7390
  try {
7391
7391
  const stsClient = new STSClient({
7392
- ...awsClientDefaults(),
7392
+ ...ambientClientDefaults(),
7393
7393
  ...region && { region }
7394
7394
  });
7395
7395
  accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
@@ -7485,7 +7485,7 @@ var Synthesizer = class {
7485
7485
  let accountId = resolved?.accountId;
7486
7486
  if (resolved === void 0 && !options.stateBucket) try {
7487
7487
  const stsClient = new STSClient({
7488
- ...awsClientDefaults(),
7488
+ ...ambientClientDefaults(),
7489
7489
  region
7490
7490
  });
7491
7491
  accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
@@ -16238,13 +16238,14 @@ const CONFLICTING_PLAINTEXT = Symbol("conflicting plaintext");
16238
16238
  * no bag can equal, which refuses it exactly as the scan did.
16239
16239
  *
16240
16240
  * The branch is HARD to reach from the resolver — one resolver's
16241
- * `cachedDynamicReferences` yields one plaintext per expression, so a single
16242
- * pass cannot produce two — but it is no longer unreachable from there since
16243
- * that cache became per-resolver (issue #1933): two resolvers in two regions
16244
- * legitimately resolve one expression to two different plaintexts, and a caller
16245
- * merging their maps lands exactly here. It is reachable through this module's
16246
- * API regardless, and it is FENCED, by the "recorded against MORE THAN ONE
16247
- * plaintext" case. An earlier draft of this comment claimed the divergence was
16241
+ * `cachedDynamicReferences` yields one plaintext per expression and credential
16242
+ * identity (issue #3660), so a single pass cannot produce two — but it is no
16243
+ * longer unreachable from there since that cache became per-resolver (issue
16244
+ * #1933): two resolvers in two regions legitimately resolve one expression to
16245
+ * two different plaintexts, and a caller merging their maps lands exactly here.
16246
+ * It is reachable through this module's API regardless, and it is FENCED, by
16247
+ * the "recorded against MORE THAN ONE plaintext" case. An earlier draft of
16248
+ * this comment claimed the divergence was
16248
16249
  * unobservable, reasoning that `plaintextOf[E] === bag` implies
16249
16250
  * `secrets.get(bag) === E` so accepting and falling back agree. That misses the
16250
16251
  * case where a SECOND candidate also matches: accepting `E` then makes it two
@@ -29809,11 +29810,26 @@ function isDeliberateResolutionRefusal(err) {
29809
29810
  if (errorCauseChain(err).some((link) => link instanceof IntrinsicResolutionRefusalError)) return true;
29810
29811
  return isNamelessDynamicReferenceError(err);
29811
29812
  }
29812
- let cachedAccountIdentity = null;
29813
29813
  /**
29814
- * Cache for availability zones per region
29814
+ * The real (non-fabricated) account identity, per CREDENTIAL IDENTITY: keyed by
29815
+ * {@link credentialFingerprint} of the active `AwsClients`' credential
29816
+ * configuration (issue [#3660](https://github.com/go-to-k/cdkd/issues/3660)).
29817
+ *
29818
+ * Process-wide, and a CLI run has one identity, so for the CLI this holds one
29819
+ * entry. A LIBRARY caller can install `AwsClients` for account A, deploy, then
29820
+ * install account B's in the same process (or run both in per-stack scopes);
29821
+ * keyed by nothing, B's `AWS::AccountId` and every ARN built from it resolved
29822
+ * as A's. The fabricated window and the in-flight slot below share the key.
29823
+ */
29824
+ const cachedAccountIdentities = /* @__PURE__ */ new Map();
29825
+ /**
29826
+ * Availability-zone names per (credential identity, region): keyed by
29827
+ * `injectiveKey(credentialFingerprint, region)` (issue
29828
+ * [#3660](https://github.com/go-to-k/cdkd/issues/3660)). The zone list is an
29829
+ * ACCOUNT's answer — an opt-in or restricted zone is visible to one account and
29830
+ * not another — so a region-only key served one identity's list to the next.
29815
29831
  */
29816
- const cachedAvailabilityZones = {};
29832
+ const cachedAvailabilityZones = /* @__PURE__ */ new Map();
29817
29833
  /**
29818
29834
  * The `{{resolve:...}}` expressions this process has PROVEN resolve to a
29819
29835
  * SECRET, reached through `secret-redaction.ts`'s `recordedSecretExpressions`
@@ -30288,9 +30304,12 @@ function isClientSafeRegion(region) {
30288
30304
  }
30289
30305
  /** Test seam for {@link FABRICATED_ACCOUNT_INFO_TTL_MS} expiry. */
30290
30306
  const accountInfoClock = { now: () => Date.now() };
30291
- let fabricatedAccountIdentity = null;
30307
+ /** The bounded fabricated-answer window, per credential identity (see {@link cachedAccountIdentities}). */
30308
+ const fabricatedAccountIdentities = /* @__PURE__ */ new Map();
30292
30309
  /**
30293
- * The single in-flight lookup, so N concurrent callers share ONE round trip.
30310
+ * The single in-flight lookup PER CREDENTIAL IDENTITY, so N concurrent callers
30311
+ * of one identity share ONE round trip, and a second identity never joins the
30312
+ * first's (issue #3660).
30294
30313
  *
30295
30314
  * The TTL above collapses SEQUENTIAL callers; this collapses PARALLEL ones
30296
30315
  * (PR review). `cdkd deploy --concurrency 10` resolves ten resources' intrinsics
@@ -30298,34 +30317,43 @@ let fabricatedAccountIdentity = null;
30298
30317
  * each with the SDK's own 3-attempt retry — and ten identical warnings per
30299
30318
  * window. Cleared in a `finally` so a failure cannot wedge it.
30300
30319
  */
30301
- let accountInfoInFlight = null;
30320
+ const accountInfoInFlight = /* @__PURE__ */ new Map();
30302
30321
  /**
30303
30322
  * Bumped by {@link resetAccountInfoCache}, so a lookup that was already in
30304
30323
  * flight cannot write the cache it was asked to forget.
30305
30324
  *
30306
30325
  * Without it the reset only cleared the SETTLED caches: an in-flight resolve
30307
- * would land afterwards and re-populate `cachedAccountIdentity`, so the next
30326
+ * would land afterwards and re-populate `cachedAccountIdentities`, so the next
30308
30327
  * caller read the pre-reset account. That is the `*Once`-leak shape one layer
30309
30328
  * down — a later test silently inheriting an earlier one's answer — and the
30310
30329
  * reset's own comment already claimed to forget it.
30311
30330
  */
30312
30331
  let accountInfoGeneration = 0;
30313
30332
  /**
30314
- * Get AWS account information from STS
30333
+ * Get AWS account information from STS, for the ACTIVE credential identity.
30334
+ *
30335
+ * `identityKey` is read FIRST and synchronously, and `resolveAccountIdentity`
30336
+ * reads `getAwsClients().sts` before its first `await`, so the key and the
30337
+ * client that answers come from ONE reading of the active clients (issue
30338
+ * #3660). Never log the key.
30315
30339
  */
30316
30340
  async function getAccountInfo(overrideRegion) {
30317
- if (cachedAccountIdentity) return accountInfoFor(cachedAccountIdentity, overrideRegion);
30318
- if (fabricatedAccountIdentity && accountInfoClock.now() < fabricatedAccountIdentity.expiresAt) return accountInfoFor(fabricatedAccountIdentity.identity, overrideRegion);
30319
- if (accountInfoInFlight) return accountInfoFor(await accountInfoInFlight, overrideRegion);
30320
- const inFlight = resolveAccountIdentity();
30321
- accountInfoInFlight = inFlight;
30341
+ const identityKey = credentialFingerprint(ambientCredentialConfig());
30342
+ const cached = cachedAccountIdentities.get(identityKey);
30343
+ if (cached) return accountInfoFor(cached, overrideRegion);
30344
+ const fabricated = fabricatedAccountIdentities.get(identityKey);
30345
+ if (fabricated && accountInfoClock.now() < fabricated.expiresAt) return accountInfoFor(fabricated.identity, overrideRegion);
30346
+ const pending = accountInfoInFlight.get(identityKey);
30347
+ if (pending) return accountInfoFor(await pending, overrideRegion);
30348
+ const inFlight = resolveAccountIdentity(identityKey);
30349
+ accountInfoInFlight.set(identityKey, inFlight);
30322
30350
  try {
30323
30351
  return accountInfoFor(await inFlight, overrideRegion);
30324
30352
  } finally {
30325
- if (accountInfoInFlight === inFlight) accountInfoInFlight = null;
30353
+ if (accountInfoInFlight.get(identityKey) === inFlight) accountInfoInFlight.delete(identityKey);
30326
30354
  }
30327
30355
  }
30328
- async function resolveAccountIdentity() {
30356
+ async function resolveAccountIdentity(identityKey) {
30329
30357
  const generation = accountInfoGeneration;
30330
30358
  const stillCurrent = () => generation === accountInfoGeneration;
30331
30359
  const logger = getLogger().child("IntrinsicFunctionResolver");
@@ -30337,13 +30365,13 @@ async function resolveAccountIdentity() {
30337
30365
  accountId,
30338
30366
  ...response.Account ? {} : { fabricated: true }
30339
30367
  };
30340
- if (!stillCurrent()) {} else if (resolved.fabricated) fabricatedAccountIdentity = {
30368
+ if (!stillCurrent()) {} else if (resolved.fabricated) fabricatedAccountIdentities.set(identityKey, {
30341
30369
  identity: resolved,
30342
30370
  expiresAt: accountInfoClock.now() + FABRICATED_ACCOUNT_INFO_TTL_MS
30343
- };
30371
+ });
30344
30372
  else {
30345
- cachedAccountIdentity = resolved;
30346
- fabricatedAccountIdentity = null;
30373
+ cachedAccountIdentities.set(identityKey, resolved);
30374
+ fabricatedAccountIdentities.delete(identityKey);
30347
30375
  }
30348
30376
  logger.debug(`Retrieved AWS account info: ${accountId}`);
30349
30377
  return resolved;
@@ -30355,13 +30383,13 @@ async function resolveAccountIdentity() {
30355
30383
  };
30356
30384
  if (!stillCurrent()) return fallback;
30357
30385
  if (fallback.fabricated) {
30358
- if (!cachedAccountIdentity) fabricatedAccountIdentity = {
30386
+ if (!cachedAccountIdentities.has(identityKey)) fabricatedAccountIdentities.set(identityKey, {
30359
30387
  identity: fallback,
30360
30388
  expiresAt: accountInfoClock.now() + FABRICATED_ACCOUNT_INFO_TTL_MS
30361
- };
30389
+ });
30362
30390
  } else {
30363
- cachedAccountIdentity = fallback;
30364
- fabricatedAccountIdentity = null;
30391
+ cachedAccountIdentities.set(identityKey, fallback);
30392
+ fabricatedAccountIdentities.delete(identityKey);
30365
30393
  }
30366
30394
  return fallback;
30367
30395
  }
@@ -30738,10 +30766,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30738
30766
  * ({@link cfnExportsPromises}, {@link cfnStackOutputsCache}) carry the
30739
30767
  * fingerprint too.
30740
30768
  *
30741
- * THE CLIENT HALF IS CLOSED, NOT THE WHOLE CLASS: {@link cachedDynamicReferences}
30742
- * (keyed by the expression alone) and the PROCESS-GLOBAL account identity
30743
- * behind `getAccountInfo` still assume one identity per resolver and per
30744
- * process respectively — a value one identity read is served to the next.
30769
+ * The VALUE caches carry the fingerprint as well (issue
30770
+ * [#3660](https://github.com/go-to-k/cdkd/issues/3660)):
30771
+ * {@link cachedDynamicReferences}, and the process-global account identity
30772
+ * behind `getAccountInfo` and `cachedAvailabilityZones`.
30745
30773
  */
30746
30774
  regionScopedClients = /* @__PURE__ */ new Map();
30747
30775
  /**
@@ -30759,9 +30787,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30759
30787
  *
30760
30788
  * A whole resolver rather than a client bag, because what has to be
30761
30789
  * region-scoped is not only the lookup but the VALUE CACHE behind it:
30762
- * {@link cachedDynamicReferences} is keyed by the expression alone and is
30763
- * sound only because one resolver stands for one stack in one region (issue
30764
- * #1933). Resolving a producer's expression inside THIS resolver would put a
30790
+ * {@link cachedDynamicReferences} is keyed by the expression (plus the
30791
+ * credential identity, issue #3660) and is sound only because one resolver
30792
+ * stands for one stack in one region (issue #1933). Resolving a producer's expression inside THIS resolver would put a
30765
30793
  * foreign region's answer under a key the consumer's own lookups read — the
30766
30794
  * exact cross-region leak that field's instance scope closed. A separate
30767
30795
  * resolver per producer region keeps that invariant by construction.
@@ -30858,7 +30886,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30858
30886
  physicalIdFallbackCount = 0;
30859
30887
  /**
30860
30888
  * Resolved `{{resolve:secretsmanager:...}}` / `{{resolve:ssm:...}}` values,
30861
- * keyed by the full expression — INSTANCE-scoped, which closes the CACHE half
30889
+ * keyed by the full expression and the credential identity that read it
30890
+ * (`injectiveKey(credentialFingerprint, expression)`, issue
30891
+ * [#3660](https://github.com/go-to-k/cdkd/issues/3660): a library caller can
30892
+ * drive one resolver under two `AwsClients` identities, and the same NAME
30893
+ * read by two accounts is two values) — INSTANCE-scoped, which closes the CACHE half
30862
30894
  * of issue [#1933](https://github.com/go-to-k/cdkd/issues/1933). The issue is
30863
30895
  * only PARTIALLY addressed by this field: see "what this does NOT settle"
30864
30896
  * below.
@@ -34124,7 +34156,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
34124
34156
  region = (await getAccountInfo(this.resolverRegion)).region;
34125
34157
  clientRegion = this.explicitRegion;
34126
34158
  }
34127
- const cached = cachedAvailabilityZones[region];
34159
+ const azCacheKey = injectiveKey(credentialFingerprint(ambientCredentialConfig()), region);
34160
+ const cached = cachedAvailabilityZones.get(azCacheKey);
34128
34161
  if (cached) {
34129
34162
  this.logger.debug(`Resolved Fn::GetAZs from cache: ${this.displayMasked(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(cached, context))}`);
34130
34163
  return cached;
@@ -34145,7 +34178,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
34145
34178
  throw new Error(`Fn::GetAZs: failed to describe availability zones for region '${loggedRegion}': ${masks.text(error instanceof Error ? error.message : String(error))}`);
34146
34179
  }
34147
34180
  if (azNames.length === 0) throw new Error(`Fn::GetAZs: no availability zones returned for region '${this.displayMasked(loggedRegionText ?? region, context)}'. Either the region is not enabled on this account (opt-in regions must be enabled before use), or the request was answered by a different region's endpoint.`);
34148
- cachedAvailabilityZones[region] = azNames;
34181
+ cachedAvailabilityZones.set(azCacheKey, azNames);
34149
34182
  this.logger.debug(`Resolved Fn::GetAZs: ${this.displayMasked(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(azNames, context))}`);
34150
34183
  return azNames;
34151
34184
  }
@@ -34860,7 +34893,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
34860
34893
  if (!foreign.complete || foreign.substitutions.length !== 1) complete = false;
34861
34894
  continue;
34862
34895
  }
34863
- const cached = this.cachedDynamicReferences.get(fullMatch);
34896
+ const dynamicReferenceCacheKey = injectiveKey(credentialFingerprint(ambientCredentialConfig()), fullMatch);
34897
+ const cached = this.cachedDynamicReferences.get(dynamicReferenceCacheKey);
34864
34898
  if (cached) {
34865
34899
  if (cached.secret && cached.value) {
34866
34900
  context?.recordedSecretValues?.set(cached.value, fullMatch);
@@ -34917,7 +34951,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
34917
34951
  complete = false;
34918
34952
  continue;
34919
34953
  }
34920
- if (cacheable) this.cachedDynamicReferences.set(fullMatch, {
34954
+ if (cacheable) this.cachedDynamicReferences.set(dynamicReferenceCacheKey, {
34921
34955
  value: resolved,
34922
34956
  secret: isSecret
34923
34957
  });
@@ -35900,6 +35934,454 @@ function unescapeJsonPointerSegment(segment) {
35900
35934
  return segment.replace(/~1/g, "/").replace(/~0/g, "~");
35901
35935
  }
35902
35936
 
35937
+ //#endregion
35938
+ //#region src/provisioning/masked-retry-logger.ts
35939
+ /**
35940
+ * The masker a caller supplied, or the identity function when it supplied
35941
+ * none.
35942
+ *
35943
+ * ABSENT MEANS UNMASKED, and that is the back-compatible default the contract
35944
+ * mandates — `create()` / `update()` are also reached from the import path,
35945
+ * from `cdkd drift --revert`, and from tests, and a provider must not care
35946
+ * which caller it got. Centralised here so no call site re-spells the `??`
35947
+ * and accidentally makes the capability required.
35948
+ */
35949
+ function maskerOrIdentity(maskSecrets) {
35950
+ return maskSecrets ?? ((text) => text);
35951
+ }
35952
+ /**
35953
+ * A {@link RetryLogger} whose every line is routed through `maskSecrets`.
35954
+ *
35955
+ * `warn` is ALWAYS provided, never omitted. It is optional on `RetryLogger`,
35956
+ * and dropping it would silence the give-up summary on the calling path only —
35957
+ * trading a disclosure for the reporting hole issue #2018 closed. It goes
35958
+ * through the SAME mask as `debug` precisely because it is the line that
35959
+ * survives a run without `--verbose`; forwarding it unmasked would defeat the
35960
+ * fence at a HIGHER log level than the one the fence was written for.
35961
+ *
35962
+ * `logger` is typed structurally rather than as the concrete `Logger` so this
35963
+ * module stays a leaf and a test can pass two spies. That matches the
35964
+ * precedent already in the tree (`buildMfaConfigRequest` in
35965
+ * `cognito-provider.ts` takes an injected `logger?: { warn }`).
35966
+ */
35967
+ function createMaskedRetryLogger(logger, maskSecrets) {
35968
+ const mask = maskerOrIdentity(maskSecrets);
35969
+ return {
35970
+ debug: (message) => logger.debug(mask(message)),
35971
+ warn: (message) => logger.warn(mask(message))
35972
+ };
35973
+ }
35974
+ /**
35975
+ * Depth cap for {@link maskDeep}.
35976
+ *
35977
+ * What it actually bounds is unbounded WORK on a pathologically deep bag — see
35978
+ * the rationale at the cap itself, which is the authority. It is NOT primarily
35979
+ * a cycle guard: a template-derived bag cannot be cyclic, so that justification
35980
+ * over-claims (issue #2176 security review). It does still terminate one, which
35981
+ * is why the walk is safe to share with a caller that might hand it something
35982
+ * other than a template bag.
35983
+ *
35984
+ * Deliberately generous. Every shape these warnings exist to describe is a
35985
+ * scalar, a list of scalars, or a small record, so the walk does not reach
35986
+ * depth 2 in practice.
35987
+ */
35988
+ const MASK_WALK_MAX_DEPTH = 8;
35989
+ /**
35990
+ * What {@link maskDeep} substitutes for a subtree it declines to descend into.
35991
+ *
35992
+ * MUST equal `SECRET_MASK` in `src/deployment/secret-redaction.ts`. It is
35993
+ * spelled here rather than imported so this module keeps its single-import leaf
35994
+ * property (see the module note above); the two are fenced against drift by a
35995
+ * test that imports both.
35996
+ */
35997
+ const MASK_WALK_DEPTH_CAP_MARKER = "***";
35998
+ /**
35999
+ * Mask every string LEAF and KEY of an arbitrary value, returning a structure
36000
+ * safe to `JSON.stringify` into a log line or an error message (issue
36001
+ * [#2176](https://github.com/go-to-k/cdkd/issues/2176)).
36002
+ *
36003
+ * THE ORDERING IS THE WHOLE POINT, and it is why masking the finished message
36004
+ * is not a substitute. `maskSecretsInText` matches by literal occurrence, so:
36005
+ *
36006
+ * 1. ESCAPING. `JSON.stringify` escapes `"`, `\` and newlines, so a secret
36007
+ * containing any of them no longer OCCURS in the stringified text and a
36008
+ * mask applied afterwards cannot find it. That is not an exotic case — it
36009
+ * is every Secrets Manager JSON document, the commonest real secret shape.
36010
+ * Measured on the pre-fix tree for #2176: a plaintext of
36011
+ * `{"user":"admin","pw":"hunter2"}` interpolated as
36012
+ * `${JSON.stringify(value)}` came through a message-level mask COMPLETELY
36013
+ * unchanged, while masking the leaves first rendered it `"***"`.
36014
+ * 2. LENGTH. A finished message is always longer than the value inside it, so
36015
+ * it can only ever reach `maskSecretsInText`'s SUBSTRING arm, which ignores
36016
+ * needles below `MIN_NEEDLE_LENGTH` (4). Handing the masker each RAW leaf
36017
+ * reaches the WHOLE-VALUE arm, which has no floor. Measured the same way: a
36018
+ * 3-character secret survived `Value 'abc' at 'pin' failed ...` intact.
36019
+ *
36020
+ * Neither pass subsumes the other, so providers do BOTH — this walk on the
36021
+ * value, and the assembled message through the masker as well. The masker is
36022
+ * idempotent, so the overlap is free.
36023
+ *
36024
+ * Keys are masked as well as values: `JSON.stringify` renders them into the
36025
+ * same line, so a resolved secret used as a map key would otherwise escape.
36026
+ *
36027
+ * WHY THIS LIVES HERE rather than as a private walk per provider. SIX
36028
+ * hand-rolled copies had already accumulated — `elbv2-provider.ts`,
36029
+ * `cognito-provider.ts`, `sns-topic-provider.ts`, `dynamodb-table-provider.ts`,
36030
+ * `dynamodb-globaltable-provider.ts` and `apigatewayv2-provider.ts` — and
36031
+ * `elbv2-provider.ts` carried the standing instruction that "a THIRD site is
36032
+ * the point at which this should move into `../masked-retry-logger.ts` ... and
36033
+ * all three converge on it". That trigger had fired and been missed twice over,
36034
+ * and the copies had already diverged exactly as predicted: FOUR of the six
36035
+ * carried NO depth cap at all.
36036
+ *
36037
+ * Worth recording how the last two were nearly missed AGAIN, because it is the
36038
+ * same failure one level up: the first sweep for this issue grepped for
36039
+ * `maskDeep` / `MASK_WALK_MAX_DEPTH` — the SPELLINGS the known copies used —
36040
+ * and the two survivors spell it `maskLeaf` / `maskLeafValue` with no named
36041
+ * constant. Grep for the SHAPE, not the name. These copies encode a security
36042
+ * contract, and a hardening applied to one silently leaves the others behind.
36043
+ */
36044
+ function maskDeep(value, mask, depth = 0) {
36045
+ if (typeof value === "string") return mask(value);
36046
+ if (depth >= 8) return "***";
36047
+ if (Array.isArray(value)) return value.map((entry) => maskDeep(entry, mask, depth + 1));
36048
+ if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([k, v]) => [mask(k), maskDeep(v, mask, depth + 1)]));
36049
+ return value;
36050
+ }
36051
+
36052
+ //#endregion
36053
+ //#region src/provisioning/composite-id.ts
36054
+ /**
36055
+ * Refuse a composite physicalId whose segments would make it ambiguous
36056
+ * (issue [#1672](https://github.com/go-to-k/cdkd/issues/1672)).
36057
+ *
36058
+ * ## Why a composite id exists at all
36059
+ *
36060
+ * `ResourceProvider` passes a SINGLE `physicalId: string` as a resource's
36061
+ * identity, while CloudFormation keeps the physical id and its containing
36062
+ * scope as separate values. So every provider whose type needs more than one
36063
+ * value to address the resource PACKS them into one string joined by
36064
+ * {@link COMPOSITE_ID_SEPARATOR} — `<databaseName>|<tableName>` for
36065
+ * `AWS::Glue::Table`, `<apiId>|<typeName>|<fieldName>` for
36066
+ * `AWS::AppSync::Resolver`, and so on.
36067
+ *
36068
+ * ## Why it has to be guarded
36069
+ *
36070
+ * The separator is NOT escaped, so a segment that itself contains a `|`
36071
+ * produces an id with the wrong arity. Every decode site splits the stored id
36072
+ * back apart and the extra segment shifts everything — for a Glue table named
36073
+ * `a|b` in database `mydb` the recorded id `mydb|a|b` decodes to database
36074
+ * `mydb`, table `a`. Both halves are non-empty, so every existing
36075
+ * "is this id well-formed?" guard passes and the deploy SUCCEEDS. What breaks
36076
+ * is everything afterwards: `cdkd destroy` deletes the WRONG resource if one
36077
+ * exists under the decoded pair (or warn-and-skips, reporting success while
36078
+ * the real resource stays alive and billing), and `cdkd drift` reads back
36079
+ * `undefined` forever.
36080
+ *
36081
+ * AWS itself accepts such a name — verified live us-east-1 2026-08-12,
36082
+ * `glue:CreateTable` with `TableInput.Name: 'a|b'` succeeds — and
36083
+ * CloudFormation manages the resource fine. The limitation is cdkd's own, so
36084
+ * the honest answer is to REFUSE at deploy time with a message that says so,
36085
+ * rather than to record an id that silently names something else. Escaping the
36086
+ * separator, or dropping the packing where the decode sites already receive
36087
+ * the properties bag, are the two real fixes and both remain open on #1672;
36088
+ * this guard is what closes the data-loss path in the meantime.
36089
+ *
36090
+ * ## Two entry points, mirroring `config-shape.ts`
36091
+ *
36092
+ * {@link packCompositeId} is the ACTION (throw, or warn-and-pack under the
36093
+ * replay downgrade) and {@link compositeIdSeparatorRefusal} is the bare
36094
+ * PREDICATE, for a caller whose response is neither — the `import()` paths
36095
+ * warn and return `null` (`skipped-not-found`), which is the idiom those
36096
+ * methods already use for every other unusable id. Both share one message
36097
+ * builder so the two can never drift.
36098
+ *
36099
+ * ## Where to place the call
36100
+ *
36101
+ * Prefer computing the id BEFORE the create call rather than after it. The
36102
+ * refusal is a pre-flight check, and a throw placed after the AWS mutation has
36103
+ * already committed would leave an orphan resource behind with no state
36104
+ * record. Only where a segment is derived from the create RESPONSE (an
36105
+ * AWS-generated id) does the call have to sit after it — and those segments
36106
+ * are structurally incapable of carrying a `|` anyway. A post-call site must
36107
+ * also sit OUTSIDE the `try` whose `catch` re-wraps as
36108
+ * `ProvisioningError('Failed to create …')`, or a refusal would be
36109
+ * mis-reported as an AWS creation failure.
36110
+ *
36111
+ * ## What this does NOT cover
36112
+ *
36113
+ * The claim is "every composite packer this change reaches", not "every `|`
36114
+ * join in the tree". One deliberate exclusion, recorded so the scope is not
36115
+ * read as wider than it is:
36116
+ *
36117
+ * - **`intrinsic-function-resolver.ts`'s `|` joins** (the WAFv2 and
36118
+ * `AWS::Events::Rule` arms) are out of scope by KIND, not by ownership: they
36119
+ * build a `Ref` VALUE for the template resolver, never a physicalId cdkd
36120
+ * records and later splits. Nothing decodes them, so an ambiguous join has
36121
+ * no decode site to go wrong at.
36122
+ *
36123
+ * ## Guarding the PACKERS is not the whole story
36124
+ *
36125
+ * A packer that refuses ambiguity does nothing about an id an EARLIER binary
36126
+ * already recorded, or one an `import` was handed — and a type whose decoder is
36127
+ * loose will mis-decode both. Issue #1711 is where that was learned:
36128
+ * `AWS::Route53::RecordSet`'s `parseRecordSetCompositeId` accepts any three
36129
+ * NON-EMPTY segments, so a record name carrying two pipes decoded to a
36130
+ * DIFFERENT hosted zone at three sites this helper never sees — an `import`
36131
+ * early accept, an identity-resolution short-circuit, and `delete`'s own parse,
36132
+ * where `cdkd destroy` then reported success over a live record. When adopting
36133
+ * this guard for a new type, audit its DECODE sites in the same change and make
36134
+ * each one cross-check the parsed segments against something it can verify them
36135
+ * with (Route 53 uses the template's own `Name` / `Type`).
36136
+ */
36137
+ /** The character every composite physicalId in this codebase joins segments with. */
36138
+ const COMPOSITE_ID_SEPARATOR = "|";
36139
+ /** The issue tracking the real fix (escaping, or not packing at all). */
36140
+ const COMPOSITE_ID_ISSUE_URL = "https://github.com/go-to-k/cdkd/issues/1672";
36141
+ /** Render `<a>|<b>|<c>` from the segment names. */
36142
+ function idShape(segments) {
36143
+ return segments.map((segment) => `<${segment.name}>`).join("|");
36144
+ }
36145
+ /**
36146
+ * The refusal sentence for a composite id whose segments carry the separator,
36147
+ * or `undefined` when the id is unambiguous.
36148
+ *
36149
+ * Every offending segment is named, not just the first: a template that
36150
+ * mis-names one value frequently mis-names its sibling too, and reporting them
36151
+ * one deploy at a time is the shape of remedy nobody finishes.
36152
+ */
36153
+ function compositeIdSeparatorRefusal(resourceType, logicalId, segments, maskSecrets) {
36154
+ const offending = segments.filter((segment) => String(segment.value).includes("|"));
36155
+ if (offending.length === 0) return void 0;
36156
+ const mask = maskerOrIdentity(maskSecrets);
36157
+ return `${resourceType} ${logicalId}: ${offending.map((segment) => `${segment.name} '${mask(String(segment.value))}'`).join(" and ")} contains '${"|"}', which cdkd uses as the separator in this type's physical id (${idShape(segments)}). Recording it would produce an id that decodes back to a DIFFERENT resource, so a later cdkd destroy / drift / update would target the wrong one — or silently skip it while the real resource stays alive. AWS accepts the name and CloudFormation manages such a resource fine; this is a cdkd limitation tracked in ${COMPOSITE_ID_ISSUE_URL}. Rename the resource so no segment contains '${"|"}', or manage it outside cdkd.`;
36158
+ }
36159
+ /**
36160
+ * Join the segments into a composite physicalId, REFUSING one that would be
36161
+ * ambiguous.
36162
+ *
36163
+ * @throws ProvisioningError when a segment contains {@link COMPOSITE_ID_SEPARATOR},
36164
+ * unless `options.onRefusal` is supplied — under which the message is handed
36165
+ * to the callback and the ambiguous id is returned, keeping the pre-guard
36166
+ * behavior.
36167
+ */
36168
+ function packCompositeId(resourceType, logicalId, segments, options) {
36169
+ const refusal = compositeIdSeparatorRefusal(resourceType, logicalId, segments, options?.maskSecrets);
36170
+ if (refusal !== void 0) {
36171
+ if (options?.onRefusal) options.onRefusal(`${refusal} Continuing with the ambiguous id because the value comes from a cdkd state record, which no template edit can repair; the same value is REFUSED on a template-path create.`);
36172
+ else throw new ProvisioningError(refusal, resourceType, logicalId);
36173
+ }
36174
+ return segments.map((segment) => String(segment.value)).join("|");
36175
+ }
36176
+ /** Render the expected id shape, e.g. `<databaseName>|<tableName>`. */
36177
+ function formatShape(segments) {
36178
+ return segments.map((segment) => `<${segment}>`).join("|");
36179
+ }
36180
+ /**
36181
+ * The message EVERY malformed-composite-id decode site emits (issue
36182
+ * [#1657](https://github.com/go-to-k/cdkd/issues/1657)).
36183
+ *
36184
+ * ## Why one builder
36185
+ *
36186
+ * Roughly half the decode sites stated the expected shape and half only echoed
36187
+ * the value back, and the format is documented nowhere else — so on the silent
36188
+ * half the message was the user's only possible route to the answer and it did
36189
+ * not carry it. Routing the sites that already got it right through the same
36190
+ * builder is what stops them drifting back.
36191
+ *
36192
+ * ## This is a WORDING fix, not an acceptance change
36193
+ *
36194
+ * Each caller keeps its own split-and-guard exactly as it was. The arities
36195
+ * genuinely differ (some sites accept AT LEAST N segments, some destructure the
36196
+ * first N and tolerate extras — the #1672 ambiguity, tracked separately), and
36197
+ * folding them into one predicate here would silently change which ids deploy.
36198
+ *
36199
+ * ## The `skipping` variant
36200
+ *
36201
+ * On the DELETE path the established policy is warn-and-continue, so a
36202
+ * malformed record leaves the AWS resource ALIVE. That policy is unchanged —
36203
+ * the warning says what the skip costs, because an orphan the user is never
36204
+ * told about is one they cannot go and delete.
36205
+ *
36206
+ * Since issue [#1752](https://github.com/go-to-k/cdkd/issues/1752) the ACCOUNTING
36207
+ * around it is no longer a lie: an arm emitting this message must also return
36208
+ * `{ outcome: 'skipped', reason: COMPOSITE_ID_SKIP_REASON }` so `cdkd destroy`
36209
+ * prints a `⚠ … skipped` line instead of `✓ … deleted`, reports
36210
+ * `N deleted, 1 skipped`, KEEPS the state record, and exits non-zero. The
36211
+ * wording here changed accordingly — it used to promise unconditionally that
36212
+ * cdkd "will report this delete as successful", which is no longer true on
36213
+ * either path. Issue [#1762](https://github.com/go-to-k/cdkd/issues/1762) then
36214
+ * taught the deploy engine to consume the outcome too, so the message no longer
36215
+ * warns that deploy drops the record: the template-removal DELETE keeps it,
36216
+ * exactly like destroy. What it DOES still distinguish is the replacement /
36217
+ * rollback delete, which fails the resource and can leave the old one
36218
+ * untracked — there "drop the record with 'cdkd state orphan'" is not the
36219
+ * remedy, deleting the resource by hand is.
36220
+ */
36221
+ function compositeIdFormatMessage(format, logicalId, physicalId, options) {
36222
+ const accepted = format.alsoAccepts ? `"${formatShape(format.segments)}" or ${format.alsoAccepts}` : `"${formatShape(format.segments)}"`;
36223
+ const head = `Invalid physicalId format for ${format.label} ${logicalId}: expected ${accepted}, got "${physicalId}"`;
36224
+ if (!options?.skipping) return head;
36225
+ return `${head}. Skipping the delete — no AWS call is issued, so the resource is LEFT IN PLACE. The state record is KEPT and the run reports the skip: on 'cdkd destroy' / 'cdkd state destroy' (which exits non-zero) and, since issue 1762, on the plain DELETE of a resource removed from the template during cdkd deploy (which re-attempts it on the next deploy). So repair the id in state.json and re-run, or delete the resource by hand and drop the record with 'cdkd state orphan'. NOTE a deploy-side REPLACEMENT or rollback delete instead FAILS the resource (https://github.com/go-to-k/cdkd/issues/1762) — the old resource is left untracked there, so delete it by hand.`;
36226
+ }
36227
+ /**
36228
+ * The short `ResourceDeleteResult.reason` every malformed-composite-id DELETE
36229
+ * skip reports (issue [#1752](https://github.com/go-to-k/cdkd/issues/1752)).
36230
+ *
36231
+ * Deliberately short and IDENTICAL across the five arms: it is rendered inline
36232
+ * on the per-resource status line (`⚠ MyTable (AWS::Glue::Table) skipped
36233
+ * (malformed physicalId in state — no delete issued)`), where the full
36234
+ * remediation sentence built by {@link compositeIdFormatMessage} would not fit.
36235
+ * The full text is still emitted, as the `logger.warn` right beside it.
36236
+ *
36237
+ * A shared constant rather than five literals so the five arms cannot drift and
36238
+ * a grep for the wording finds all of them.
36239
+ */
36240
+ const COMPOSITE_ID_SKIP_REASON = "malformed physicalId in state — no delete issued";
36241
+ /**
36242
+ * The `ResourceDeleteResult` a malformed-composite-id DELETE arm returns.
36243
+ *
36244
+ * Pairs with the `{ skipping: true }` warning: emit the warning, return this.
36245
+ * Providers call it as `return compositeIdSkipResult();` so the arm reads as
36246
+ * the deliberate skip it is rather than as the bare `return;` that made issue
36247
+ * #1752's mis-accounting possible.
36248
+ */
36249
+ function compositeIdSkipResult() {
36250
+ return {
36251
+ outcome: "skipped",
36252
+ reason: COMPOSITE_ID_SKIP_REASON
36253
+ };
36254
+ }
36255
+
36256
+ //#endregion
36257
+ //#region src/provisioning/cc-import-identifier.ts
36258
+ /**
36259
+ * Map the physical id `cdkd import` hands `CloudControlProvider.import()` onto
36260
+ * the identifier Cloud Control's `GetResource` accepts (issue
36261
+ * [#3672](https://github.com/go-to-k/cdkd/issues/3672)).
36262
+ *
36263
+ * ## The mismatch
36264
+ *
36265
+ * Cloud Control identifies a resource whose schema `primaryIdentifier` has more
36266
+ * than one field by the field VALUES joined with `|`, in schema order. That
36267
+ * joined string is also what cdkd records as the physical id of every resource
36268
+ * it creates through Cloud Control. CloudFormation's `PhysicalResourceId` for
36269
+ * the same resource is often ONE of those values only — `AWS::EC2::VPCCidrBlock`
36270
+ * reports the bare `vpc-cidr-assoc-…` association id, while Cloud Control wants
36271
+ * `<Id>|<VpcId>`. `cdkd import --migrate-from-cloudformation` passes
36272
+ * CloudFormation's value through as `knownPhysicalId`, so `GetResource` failed,
36273
+ * the resource was not adopted, and retiring the stack orphaned it.
36274
+ *
36275
+ * ## The rule — schema-driven, not a per-type table
36276
+ *
36277
+ * The composite types that reach this path are exactly the ones with no SDK
36278
+ * provider, and the committed schema fixtures (`tests/fixtures/cfn-schemas/`)
36279
+ * cover SDK-provider types only, so no committed source enumerates them. The
36280
+ * registry schema is read at run time instead (`cloudformation:DescribeType`,
36281
+ * one call per type, cached), and a bare id is completed from the template:
36282
+ *
36283
+ * - every identifier field the template declares as a literal string — after
36284
+ * `cdkd import`'s `Ref` pre-substitution, so `VpcId: {Ref: Vpc}` arrives as
36285
+ * `vpc-…` under `--migrate-from-cloudformation` — takes that value;
36286
+ * - EXACTLY ONE field left over takes the supplied id;
36287
+ * - NO field left over means the template alone names the resource, and that
36288
+ * composite is used.
36289
+ *
36290
+ * Everything else is REFUSED with the composite shape to pass instead, rather
36291
+ * than guessed: two or more fields the template cannot supply, or a supplied id
36292
+ * equal to a value the template already gave another field (it cannot then be
36293
+ * told which field it is). A refused import is reported `failed` with that
36294
+ * remedy. It does NOT stop `--migrate-from-cloudformation` from retiring the
36295
+ * stack: `import.ts` counts it among the not-imported resources, warns that
36296
+ * they stay in AWS unmanaged, and retires anyway — the same outcome an
36297
+ * unresolvable id had before this module, now with the value to re-import by.
36298
+ *
36299
+ * Template values are read as literal strings, numbers or booleans (a
36300
+ * `RuleNumber: 100` renders `100`, as Cloud Control joins it); anything else —
36301
+ * an unresolved intrinsic, an object, a blank string — counts as unknown.
36302
+ *
36303
+ * An id that already carries the full arity, a single-field type, and a type
36304
+ * whose schema cannot be read are passed through UNCHANGED — the behaviour
36305
+ * before this module existed.
36306
+ */
36307
+ /**
36308
+ * Per-type cache of SUCCESSFUL lookups only (same discipline as
36309
+ * `read-only-properties.ts`): the stored promise is the recovered one, and a
36310
+ * failure deletes its own entry so a later call retries.
36311
+ */
36312
+ const primaryIdentifierCache = /* @__PURE__ */ new Map();
36313
+ /**
36314
+ * The type's schema `primaryIdentifier` as top-level property names, in schema
36315
+ * order — the order Cloud Control joins them in.
36316
+ *
36317
+ * `undefined` when the schema could not be read, declares no identifier, or
36318
+ * names a NESTED pointer (`/properties/A/B`), which no template property maps
36319
+ * onto. Never throws.
36320
+ */
36321
+ function getPrimaryIdentifierFields(resourceType) {
36322
+ if (hasNoRegistrySchema(resourceType)) return Promise.resolve(void 0);
36323
+ const cached = primaryIdentifierCache.get(resourceType);
36324
+ if (cached) return cached;
36325
+ const entry = fetchPrimaryIdentifierFields(resourceType).catch((error) => {
36326
+ primaryIdentifierCache.delete(resourceType);
36327
+ getLogger().child("CcImportIdentifier").debug(`Failed to resolve the primary identifier for ${displaySafe(resourceType, { asciiOnly: true })} via cloudformation:DescribeType (${describeAwsFailure(error).detail}); the import id is passed to Cloud Control unchanged.`);
36328
+ });
36329
+ primaryIdentifierCache.set(resourceType, entry);
36330
+ return entry;
36331
+ }
36332
+ async function fetchPrimaryIdentifierFields(resourceType) {
36333
+ const response = await describeTypeWithThrottleRetry(resourceType);
36334
+ if (!response.Schema) return void 0;
36335
+ const primary = JSON.parse(response.Schema).primaryIdentifier;
36336
+ if (!Array.isArray(primary) || primary.length === 0) return void 0;
36337
+ const fields = [];
36338
+ for (const pointer of primary) {
36339
+ if (typeof pointer !== "string") return void 0;
36340
+ const match = /^\/properties\/([^/]+)$/.exec(pointer);
36341
+ if (!match?.[1]) return void 0;
36342
+ fields.push(match[1].replace(/~1/g, "/").replace(/~0/g, "~"));
36343
+ }
36344
+ return fields;
36345
+ }
36346
+ /**
36347
+ * The identifier to send to Cloud Control `GetResource` — and to record as the
36348
+ * physical id, since it is the value every later Cloud Control call on the
36349
+ * resource needs. Pure; see the module header for the rule.
36350
+ *
36351
+ * @throws Error when the id cannot be completed unambiguously. The message names
36352
+ * the composite shape `--resource` accepts.
36353
+ */
36354
+ function toCloudControlIdentifier(input) {
36355
+ const { resourceType, logicalId, physicalId, properties, fields } = input;
36356
+ if (fields === void 0 || fields.length < 2) return physicalId;
36357
+ if (physicalId.split("|").length === fields.length) return physicalId;
36358
+ if (physicalId.trimStart().startsWith("{")) return physicalId;
36359
+ const safeType = displaySafe(resourceType, { asciiOnly: true });
36360
+ const safeLogicalId = displaySafe(logicalId, { asciiOnly: true });
36361
+ const safeId = displaySafe(physicalId, { asciiOnly: true });
36362
+ const shape = fields.map((field) => `<${field}>`).join("|");
36363
+ const remedy = `Pass the Cloud Control identifier instead: --resource '${safeLogicalId}=${shape}'.`;
36364
+ if (physicalId.includes("|")) throw new Error(`${safeType} ${safeLogicalId}: '${safeId}' has ${physicalId.split("|").length} '${"|"}'-separated segments, but Cloud Control identifies this type by ${fields.length} (${shape}). ${remedy}`);
36365
+ const values = fields.map((field) => {
36366
+ const value = Object.hasOwn(properties, field) ? properties[field] : void 0;
36367
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
36368
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
36369
+ });
36370
+ const missing = fields.filter((_, index) => values[index] === void 0);
36371
+ if (missing.length > 1) throw new Error(`${safeType} ${safeLogicalId}: Cloud Control identifies this type by ${shape}, and the template supplies no literal value for ${missing.join(" or ")}, so '${safeId}' cannot be placed. ${remedy}`);
36372
+ if (missing.length === 1 && values.includes(physicalId)) throw new Error(`${safeType} ${safeLogicalId}: '${safeId}' equals a value the template already gives another field of the identifier ${shape}, so it cannot be told which field it is. ${remedy}`);
36373
+ const completed = values.map((value) => value ?? physicalId);
36374
+ const refusal = compositeIdSeparatorRefusal(resourceType, logicalId, fields.map((name, index) => ({
36375
+ name,
36376
+ value: completed[index]
36377
+ })));
36378
+ if (refusal !== void 0) throw new Error(refusal);
36379
+ const identifier = completed.join("|");
36380
+ if (missing.length === 0 && !values.includes(physicalId)) getLogger().child("CcImportIdentifier").debug(`${safeType} ${safeLogicalId}: the template supplies every field of the Cloud Control identifier ${shape}, so '${displaySafe(identifier, { asciiOnly: true })}' is looked up and the supplied id '${safeId}' is not used.`);
36381
+ getLogger().child("CcImportIdentifier").debug(`${safeType} ${safeLogicalId}: completed '${safeId}' to the Cloud Control identifier '${displaySafe(identifier, { asciiOnly: true })}' (${shape}) from the template.`);
36382
+ return identifier;
36383
+ }
36384
+
35903
36385
  //#endregion
35904
36386
  //#region src/provisioning/cc-protection-properties.ts
35905
36387
  const CC_PROTECTION_PROPERTIES = {
@@ -37004,7 +37486,7 @@ var CloudControlProvider = class {
37004
37486
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
37005
37487
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
37006
37488
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
37007
- const { ASGProvider } = await import("./asg-provider-B5acrjOr.js").then((n) => n.n);
37489
+ const { ASGProvider } = await import("./asg-provider-ChgXLoRA.js").then((n) => n.n);
37008
37490
  const asgProvider = new ASGProvider();
37009
37491
  return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
37010
37492
  }
@@ -37999,7 +38481,9 @@ var CloudControlProvider = class {
37999
38481
  * parse `ResourceModel` (returned as a JSON string by CC API), and
38000
38482
  * return the ATTRIBUTE keys as `attributes` — see
38001
38483
  * {@link maskUncertifiedModelValues} for what "attribute" means here and
38002
- * why every other key comes back MASKED rather than dropped.
38484
+ * why every other key comes back MASKED rather than dropped. A bare id
38485
+ * for a type with a COMPOSITE primary identifier is first completed from
38486
+ * the template (`cc-import-identifier.ts`, issue #3672).
38003
38487
  * - Without `knownPhysicalId`: return `null`. CC API has no efficient
38004
38488
  * `aws:cdk:path`-tag lookup — `ListResources` returns identifiers
38005
38489
  * only, so tag lookup would require one `GetResource` per resource
@@ -38115,13 +38599,20 @@ var CloudControlProvider = class {
38115
38599
  */
38116
38600
  async import(input) {
38117
38601
  if (!input.knownPhysicalId) return null;
38602
+ const identifier = toCloudControlIdentifier({
38603
+ resourceType: input.resourceType,
38604
+ logicalId: input.logicalId,
38605
+ physicalId: input.knownPhysicalId,
38606
+ properties: input.properties,
38607
+ fields: await getPrimaryIdentifierFields(input.resourceType)
38608
+ });
38118
38609
  try {
38119
38610
  const resp = await this.cloudControlClient.send(new GetResourceCommand({
38120
38611
  TypeName: input.resourceType,
38121
- Identifier: input.knownPhysicalId
38612
+ Identifier: identifier
38122
38613
  }));
38123
38614
  const safeType = displaySafe(input.resourceType, { asciiOnly: true });
38124
- const safeId = displaySafe(input.knownPhysicalId, { asciiOnly: true });
38615
+ const safeId = displaySafe(identifier, { asciiOnly: true });
38125
38616
  let parsedModel;
38126
38617
  const raw = resp.ResourceDescription?.Properties;
38127
38618
  if (typeof raw === "string" && raw.length > 0) try {
@@ -38134,10 +38625,9 @@ var CloudControlProvider = class {
38134
38625
  } catch (parseErr) {
38135
38626
  this.logger.warn(`Failed to parse CC API ResourceModel for ${safeType}/${safeId}: ${parseErr instanceof Error ? parseErr.name : typeof parseErr}. Recording no attributes for it; an Fn::GetAtt against this resource will fall back to a value constructed from its physical id.`);
38136
38627
  }
38137
- const attributes = parsedModel === void 0 ? {} : await this.maskUncertifiedModelValues(parsedModel, input.resourceType, input.knownPhysicalId);
38138
38628
  return {
38139
- physicalId: input.knownPhysicalId,
38140
- attributes
38629
+ physicalId: identifier,
38630
+ attributes: parsedModel === void 0 ? {} : await this.maskUncertifiedModelValues(parsedModel, input.resourceType, identifier)
38141
38631
  };
38142
38632
  } catch (error) {
38143
38633
  if (error.name === "ResourceNotFoundException") return null;
@@ -38547,121 +39037,6 @@ function interruptWatchListenerCount() {
38547
39037
  return sharedSigintHandler === void 0 ? 0 : 1;
38548
39038
  }
38549
39039
 
38550
- //#endregion
38551
- //#region src/provisioning/masked-retry-logger.ts
38552
- /**
38553
- * The masker a caller supplied, or the identity function when it supplied
38554
- * none.
38555
- *
38556
- * ABSENT MEANS UNMASKED, and that is the back-compatible default the contract
38557
- * mandates — `create()` / `update()` are also reached from the import path,
38558
- * from `cdkd drift --revert`, and from tests, and a provider must not care
38559
- * which caller it got. Centralised here so no call site re-spells the `??`
38560
- * and accidentally makes the capability required.
38561
- */
38562
- function maskerOrIdentity(maskSecrets) {
38563
- return maskSecrets ?? ((text) => text);
38564
- }
38565
- /**
38566
- * A {@link RetryLogger} whose every line is routed through `maskSecrets`.
38567
- *
38568
- * `warn` is ALWAYS provided, never omitted. It is optional on `RetryLogger`,
38569
- * and dropping it would silence the give-up summary on the calling path only —
38570
- * trading a disclosure for the reporting hole issue #2018 closed. It goes
38571
- * through the SAME mask as `debug` precisely because it is the line that
38572
- * survives a run without `--verbose`; forwarding it unmasked would defeat the
38573
- * fence at a HIGHER log level than the one the fence was written for.
38574
- *
38575
- * `logger` is typed structurally rather than as the concrete `Logger` so this
38576
- * module stays a leaf and a test can pass two spies. That matches the
38577
- * precedent already in the tree (`buildMfaConfigRequest` in
38578
- * `cognito-provider.ts` takes an injected `logger?: { warn }`).
38579
- */
38580
- function createMaskedRetryLogger(logger, maskSecrets) {
38581
- const mask = maskerOrIdentity(maskSecrets);
38582
- return {
38583
- debug: (message) => logger.debug(mask(message)),
38584
- warn: (message) => logger.warn(mask(message))
38585
- };
38586
- }
38587
- /**
38588
- * Depth cap for {@link maskDeep}.
38589
- *
38590
- * What it actually bounds is unbounded WORK on a pathologically deep bag — see
38591
- * the rationale at the cap itself, which is the authority. It is NOT primarily
38592
- * a cycle guard: a template-derived bag cannot be cyclic, so that justification
38593
- * over-claims (issue #2176 security review). It does still terminate one, which
38594
- * is why the walk is safe to share with a caller that might hand it something
38595
- * other than a template bag.
38596
- *
38597
- * Deliberately generous. Every shape these warnings exist to describe is a
38598
- * scalar, a list of scalars, or a small record, so the walk does not reach
38599
- * depth 2 in practice.
38600
- */
38601
- const MASK_WALK_MAX_DEPTH = 8;
38602
- /**
38603
- * What {@link maskDeep} substitutes for a subtree it declines to descend into.
38604
- *
38605
- * MUST equal `SECRET_MASK` in `src/deployment/secret-redaction.ts`. It is
38606
- * spelled here rather than imported so this module keeps its single-import leaf
38607
- * property (see the module note above); the two are fenced against drift by a
38608
- * test that imports both.
38609
- */
38610
- const MASK_WALK_DEPTH_CAP_MARKER = "***";
38611
- /**
38612
- * Mask every string LEAF and KEY of an arbitrary value, returning a structure
38613
- * safe to `JSON.stringify` into a log line or an error message (issue
38614
- * [#2176](https://github.com/go-to-k/cdkd/issues/2176)).
38615
- *
38616
- * THE ORDERING IS THE WHOLE POINT, and it is why masking the finished message
38617
- * is not a substitute. `maskSecretsInText` matches by literal occurrence, so:
38618
- *
38619
- * 1. ESCAPING. `JSON.stringify` escapes `"`, `\` and newlines, so a secret
38620
- * containing any of them no longer OCCURS in the stringified text and a
38621
- * mask applied afterwards cannot find it. That is not an exotic case — it
38622
- * is every Secrets Manager JSON document, the commonest real secret shape.
38623
- * Measured on the pre-fix tree for #2176: a plaintext of
38624
- * `{"user":"admin","pw":"hunter2"}` interpolated as
38625
- * `${JSON.stringify(value)}` came through a message-level mask COMPLETELY
38626
- * unchanged, while masking the leaves first rendered it `"***"`.
38627
- * 2. LENGTH. A finished message is always longer than the value inside it, so
38628
- * it can only ever reach `maskSecretsInText`'s SUBSTRING arm, which ignores
38629
- * needles below `MIN_NEEDLE_LENGTH` (4). Handing the masker each RAW leaf
38630
- * reaches the WHOLE-VALUE arm, which has no floor. Measured the same way: a
38631
- * 3-character secret survived `Value 'abc' at 'pin' failed ...` intact.
38632
- *
38633
- * Neither pass subsumes the other, so providers do BOTH — this walk on the
38634
- * value, and the assembled message through the masker as well. The masker is
38635
- * idempotent, so the overlap is free.
38636
- *
38637
- * Keys are masked as well as values: `JSON.stringify` renders them into the
38638
- * same line, so a resolved secret used as a map key would otherwise escape.
38639
- *
38640
- * WHY THIS LIVES HERE rather than as a private walk per provider. SIX
38641
- * hand-rolled copies had already accumulated — `elbv2-provider.ts`,
38642
- * `cognito-provider.ts`, `sns-topic-provider.ts`, `dynamodb-table-provider.ts`,
38643
- * `dynamodb-globaltable-provider.ts` and `apigatewayv2-provider.ts` — and
38644
- * `elbv2-provider.ts` carried the standing instruction that "a THIRD site is
38645
- * the point at which this should move into `../masked-retry-logger.ts` ... and
38646
- * all three converge on it". That trigger had fired and been missed twice over,
38647
- * and the copies had already diverged exactly as predicted: FOUR of the six
38648
- * carried NO depth cap at all.
38649
- *
38650
- * Worth recording how the last two were nearly missed AGAIN, because it is the
38651
- * same failure one level up: the first sweep for this issue grepped for
38652
- * `maskDeep` / `MASK_WALK_MAX_DEPTH` — the SPELLINGS the known copies used —
38653
- * and the two survivors spell it `maskLeaf` / `maskLeafValue` with no named
38654
- * constant. Grep for the SHAPE, not the name. These copies encode a security
38655
- * contract, and a hardening applied to one silently leaves the others behind.
38656
- */
38657
- function maskDeep(value, mask, depth = 0) {
38658
- if (typeof value === "string") return mask(value);
38659
- if (depth >= 8) return "***";
38660
- if (Array.isArray(value)) return value.map((entry) => maskDeep(entry, mask, depth + 1));
38661
- if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([k, v]) => [mask(k), maskDeep(v, mask, depth + 1)]));
38662
- return value;
38663
- }
38664
-
38665
39040
  //#endregion
38666
39041
  //#region src/provisioning/providers/custom-resource-provider.ts
38667
39042
  /**
@@ -52421,5 +52796,5 @@ var DeployEngine = class DeployEngine {
52421
52796
  };
52422
52797
 
52423
52798
  //#endregion
52424
- export { yellow as $, MalformedProducerRecordRefusalError as $a, resolveSkipPrefix as $i, refuseMalformedOutputsForDestroy as $n, hasReadableExportSet as $r, requireConfigArray as $t, createPreDeleteFinalSnapshot as A, ownValue as Aa, describeDockerFailure as Ai, malformedExportSourceWarning as An, identityKeyFor as Ar, IntrinsicFunctionResolver as At, isStatefulRecreateTargetSync as B, runWithStackAwsClients as Ba, runDockerStreaming as Bi, malformedResourceEntriesWarning as Bn, redactSecretsForState as Br, refStateLookupFromResource as Bt, namesAnyDeclaredParameter as C, failedStageNote as Ca, validateAssetBucketName as Ci, displayLogicalId as Cn, safeStringify$1 as Co, STATE_SOURCED_CROSS_GENERATION_RULES as Cr, ccProtectionRegistryTypes as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, hasOwnKey as Da, resolveDockerContextDirectory as Di, isReadableOrphanRecord as Dn, createSecretMasker as Dr, isWaitAbandonedError as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, defineOwnKey as Ea, buildDockerImage as Ei, hasReadableResources as En, carriesSecretMask as Er, deleteSkipReason as Et, extractDeploymentEventError as F, clearBucketRegionCache as Fa, isDockerClientEnvKey as Fi, malformedOrphansRefusalMessage as Fn, maskSecretsInText as Fr, getAccountInfo as Ft, toCfnInteger as G, CrossAccountSecretRefusalError as Ga, getDockerImageBySourceHash as Gi, refuseDivergentRecordRegionForDestroy as Gn, UNREPRODUCIBLE_LOCK_CLAUSE as Gr, assertRegionMatch as Gt, WARM_THROUGHPUT_MEMBERS as H, AssetError as Ha, escapeRegExp$1 as Hi, malformedResourcesWarning as Hn, LockManager as Hr, WAFv2WebACLProvider as Ht, makeSiblingClaimReader as I, resolveBucketRegion as Ia, isMalformedEnvKey as Ii, malformedOrphansWarning as In, pathCrossesDottedKey as Ir, isImpossibleEmptyStoredAttribute as It, bold as J, DynamicReferenceRegionAmbiguousError as Ja, getDefaultStateBucketName as Ji, refuseMalformedOrphanRecordsForDestroy as Jn, forceQuitRecoveryClause as Jr, configBooleanRefusal as Jt, toFiniteNumber as K, DependencyError as Ka, Synthesizer as Ki, refuseMalformedNestedChildOutputs as Kn, buildForceUnlockCommand as Kr, coerceCfnBoolean as Kt, planOrphanAdoption as L, AwsClients as La, partitionSensitiveEnv as Li, malformedOutputsRefusalMessage as Ln, recordMaskOnlyValue as Lr, isNamelessDynamicReferenceError as Lt, refusesFinalSnapshot as M, displayAssemblyPath as Ma, finchSecretArgvRefusal as Mi, malformedOrphanRecordsRefusalMessage as Mn, isUncertifiedBaselineMaskPosition as Mr, carriesFetchableDynamicReference as Mt, unsupportedFinalSnapshotError as N, renderAssemblyPathEscape as Na, formatDockerLoginError as Ni, malformedOrphanRecordsWarning as Nn, markSameGenerationBag as Nr, cfnRefValueFromPhysicalId as Nt, buildFinalSnapshotIdentifier as O, hasPlainPrototype$1 as Oa, describeDockerCapturedOutput as Oi, isReadableResourceEntry as On, dynamicReferenceTokens as Or, disableInstanceApiTermination as Ot, makeCanonicalizePropertiesFn as P, resolveAssemblyPath as Pa, getDockerCmd as Pi, malformedOrphanRowsKeptWarning as Pn, maskSecretsInError as Pr, coerceParameterTypedValue as Pt, red as Q, LockError as Qa, resolveCaptureObservedState as Qi, refuseMalformedOutputs as Qn, exportNamesCarriedFrom as Qr, replayWarn as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, getAwsClients as Ra, redactDockerArgvValues as Ri, malformedOutputsWarning as Rn, recordMaskOnlyValuesIn as Rr, isUnboundTemplateParameter as Rt, computeParameterTaint as S, AssemblyReader as Sa, readBootstrapMarkerBody as Si, deployRefusesOrphanRowsReason as Sn, describeAwsFailure as So, STATE_SOURCED_BASELINE_RULES as Sr, slowCcOperationTimeoutMs as St, resourcesNamingDeclaredParameter as T, processStackMessages as Ta, buildDenyExternalAccessPolicy as Ti, hasReadableOutputs as Tn, TEMPLATE_SOURCED_RULES as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, CdkdError as Ua, stripControlChars as Ui, malformedStateRefusalMessage as Un, S3StateBackend as Ur, normalizeAwsTagsToCfn as Ut, renderStatefulReason as V, setAwsClients as Va, warnFinchArgvExposure as Vi, malformedResourcePropertiesWarning as Vn, scrubResourceRecord as Vr, isSettledInstanceState as Vt, isWarmThroughputDecrease as W, ConfigError as Wa, AssetManifestLoader as Wi, previewableOrphanRecords as Wn, rebuildClientForBucketRegion as Wr, resolveExplicitPhysicalId as Wt, gray as X, LocalInvokeBuildError as Xa, resolveApp as Xi, refuseMalformedOrphansForDestroy as Xn, CUSTOM_RESOURCE_RESPONSE_PREFIX as Xr, configStringRefusal as Xt, cyan as Y, IntrinsicResolutionRefusalError as Ya, getLegacyStateBucketName as Yi, refuseMalformedOrphans as Yn, formatLockExpiry as Yr, configIntegerRefusal as Yt, green as Z, LocalStartServiceError as Za, resolveAutoAssetStorage as Zi, refuseMalformedOrphansForOrphan as Zn, DEFAULT_STATE_PREFIX as Zr, readConfigString as Zt, bagHoldsSecretExpression as _, expectedOwnerParam as _a, assertAssetBucketRegion as _i, DiffCalculator as _n, isThrottlingError as _o, findSilentDropProperties as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, ssmResolvedValueType as aa, orphansAfterRollback as ai, producerRegionsFromState as an, StackHasActiveImportsError as ao, refuseMalformedState as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, derivePartitionAndUrlSuffix as ba, isCrossRegionRedirect as bi, UNREADABLE_ORPHANS_CONTAINER_ROW as bn, markRedactedCause as bo, DagBuilder as br, startInterruptWatch as bt, replayFailedOperations as c, MIGRATE_TMP_PREFIX as ca, AssetPublisher as ci, s3BucketDomainName as cn, SynthesisError as co, repairMalformedOutputsForReadOnly as cr, IAMRoleProvider as ct, updatePartialMessage as d, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as da, buildAssetRedirectMap as di, s3BucketWebsiteUrl as dn, normalizeAwsError as do, repairMalformedResourcesForReadOnly as dr, ProviderRegistry as dt, resolveStateBucketWithDefault as ea, hasReasonlessBaselineRefusal as ei, requireConfigObject as en, NestedStackChildDirectDestroyError as eo, refuseMalformedResourceAttributesForOrphan as er, collectDeclaredOutputNames as et, updatePartialReason as f, injectiveKey as fa, createAssetRedirectResolver as fi, applyRoleArnIfSet as fn, withErrorHandling as fo, safeRegion as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, decodeListingKey as ga, BOOTSTRAP_MARKER_PREFIX as gi, envCredentialsAreAssumedRole as gn, isRetryableTransientError as go, findActionableSilentDrops as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, producerRecordKey as ha, AssetModeResolver as hi, callerEnvCredentials as hn, isMarkedNonRetryable as ho, unreadableOrphanRecords as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, warnDeprecatedNoPrefixCliFlag as ia, isReadableBag as ii, classifyReplaySecretRegion as in, ResourceUpdateNotSupportedError as io, refuseMalformedResourcesForDestroy as ir, secretBearing as it, isFinalSnapshotError as j, absoluteAssemblyPathEscape as ja, dockerSpawnEnvWithSensitive as ji, malformedLocalOutputsWarning as jn, isSingleDynamicReferenceToken as jr, carriesDynamicReference as jt, ccRoutedFinalSnapshotError as k, nullPrototypeRecord as ka, describeDockerExecFailure as ki, malformedExportNamesWarning as kn, errorCauseChain as kr, isTerminationProtectionPropagationError as kt, replayRollback as l, findLargeInlineResources as la, stringifyValue as li, s3BucketDualStackDomainName as ln, formatError as lo, repairMalformedResourceEntriesForReadOnly as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, producerCoordinateKey as ma, rewriteTemplateAssetReferences as mi, applyCallerIdentityCredentials as mn, shellQuote as mo, unpreviewableOrphanRecords as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, resolveUseCdkBootstrapAssets as na, importableOutputKeys as ni, definedAttributes as nn, ProvisioningError as no, refuseMalformedResourceEntriesForOrphan as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, CFN_TEMPLATE_BODY_LIMIT as oa, orphansCarriedFrom as oi, withSharedDrainBudget as on, StackTerminationProtectionError as oo, repairMalformedOrphanRecordsForReadOnly as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, injectiveKeyPrefix as pa, loadPublishableAssetManifest as pi, AWS_CREDENTIAL_ENV_KEYS as pn, pasteableCommand as po, safeStackName as pr, createMaskedRetryLogger as pt, formatResourceLine as q, DeployCancelledError as qa, synthesisStatusMessage as qi, refuseMalformedOrphanRecords as qn, buildLockContentionMessage as qr, coerceCfnInteger as qt, DeployEngine as r, stateBucketExistenceConfirmed as ra, importableOutputs as ri, stringifyIfAssigned as rn, ResourceTimeoutError as ro, refuseMalformedResourcePropertiesForOrphan as rr, isExportAliasCollision as rt, planRollback as s, CFN_TEMPLATE_URL_LIMIT as sa, shouldRetainResource as si, s3BucketArn as sn, StateError as so, repairMalformedOrphansForReadOnly as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, resolveStateBucketWithDefaultAndSource as ta, hasUnverifiableParameterRefusal as ti, requireConfigString as tn, PartialFailureError as to, refuseMalformedResourceEntries as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, uploadCfnTemplate as ua, WorkGraph as ui, s3BucketRegionalDomainName as un, isCdkdError as uo, repairMalformedResourcePropertiesForReadOnly as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, PARTITION_TABLE as va, ensureAssetStorage as vi, INTRINSIC_KEYS as vn, isTransientServerError as vo, describeTypeWithThrottleRetry as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, globMatches as wa, validateContainerRepoName as wi, hasReadableOrphans as wn, __exportAll as wo, STATE_SOURCED_READBACK_RULES as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, ambientClientDefaults as xa, parseBootstrapMarker as xi, UNREADABLE_RESOURCES_MAP_ROW as xn, retryClassificationText as xo, TemplateParser as xr, CloudControlProvider as xt, keptWholeReasonText as y, canonicalizeRegion as ya, getBootstrapMarkerKey as yi, STATE_RESOURCES_MALFORMED as yn, markNonRetryable as yo, withRetry as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, resetAwsClients as za, runDockerForeground as zi, malformedRenderedContainersWarning as zn, recoverMaskedOutput as zr, parameterTypeMayLoseSecretIdentity as zt };
52425
- //# sourceMappingURL=deploy-engine-DGV6XNWO.js.map
52799
+ export { yellow as $, DependencyError as $a, getLegacyStateBucketName as $i, refuseMalformedOrphans as $n, formatLockExpiry as $r, configIntegerRefusal as $t, createPreDeleteFinalSnapshot as A, failedStageNote as Aa, buildDockerImage as Ai, hasReadableResources as An, safeStringify$1 as Ao, carriesSecretMask as Ar, deleteSkipReason as At, isStatefulRecreateTargetSync as B, renderAssemblyPathEscape as Ba, isMalformedEnvKey as Bi, malformedOrphansWarning as Bn, pathCrossesDottedKey as Br, isImpossibleEmptyStoredAttribute as Bt, namesAnyDeclaredParameter as C, canonicalizeRegion as Ca, getBootstrapMarkerKey as Ci, STATE_RESOURCES_MALFORMED as Cn, isRetryableTransientError as Co, withRetry as Cr, compositeIdSkipResult as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, clientDefaultsFor as Da, validateAssetBucketName as Di, displayLogicalId as Dn, markRedactedCause as Do, STATE_SOURCED_CROSS_GENERATION_RULES as Dr, maskerOrIdentity as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, ambientCredentialConfig as Ea, readBootstrapMarkerBody as Ei, deployRefusesOrphanRowsReason as En, markNonRetryable as Eo, STATE_SOURCED_BASELINE_RULES as Er, maskDeep as Et, extractDeploymentEventError as F, hasPlainPrototype$1 as Fa, dockerSpawnEnvWithSensitive as Fi, malformedLocalOutputsWarning as Fn, isSingleDynamicReferenceToken as Fr, carriesDynamicReference as Ft, toCfnInteger as G, getAwsClients as Ga, warnFinchArgvExposure as Gi, malformedResourcePropertiesWarning as Gn, scrubResourceRecord as Gr, isSettledInstanceState as Gt, WARM_THROUGHPUT_MEMBERS as H, clearBucketRegionCache as Ha, redactDockerArgvValues as Hi, malformedOutputsWarning as Hn, recordMaskOnlyValuesIn as Hr, isUnboundTemplateParameter as Ht, makeSiblingClaimReader as I, nullPrototypeRecord as Ia, finchSecretArgvRefusal as Ii, malformedOrphanRecordsRefusalMessage as In, isUncertifiedBaselineMaskPosition as Ir, carriesFetchableDynamicReference as It, bold as J, setAwsClients as Ja, AssetManifestLoader as Ji, previewableOrphanRecords as Jn, rebuildClientForBucketRegion as Jr, resolveExplicitPhysicalId as Jt, toFiniteNumber as K, resetAwsClients as Ka, escapeRegExp$1 as Ki, malformedResourcesWarning as Kn, LockManager as Kr, WAFv2WebACLProvider as Kt, planOrphanAdoption as L, ownValue as La, formatDockerLoginError as Li, malformedOrphanRecordsWarning as Ln, markSameGenerationBag as Lr, cfnRefValueFromPhysicalId as Lt, refusesFinalSnapshot as M, processStackMessages as Ma, describeDockerCapturedOutput as Mi, isReadableResourceEntry as Mn, dynamicReferenceTokens as Mr, disableInstanceApiTermination as Mt, unsupportedFinalSnapshotError as N, defineOwnKey as Na, describeDockerExecFailure as Ni, malformedExportNamesWarning as Nn, errorCauseChain as Nr, isTerminationProtectionPropagationError as Nt, buildFinalSnapshotIdentifier as O, credentialFingerprint as Oa, validateContainerRepoName as Oi, hasReadableOrphans as On, retryClassificationText as Oo, STATE_SOURCED_READBACK_RULES as Or, UNSPECIFIED_SKIP_REASON as Ot, makeCanonicalizePropertiesFn as P, hasOwnKey as Pa, describeDockerFailure as Pi, malformedExportSourceWarning as Pn, identityKeyFor as Pr, IntrinsicFunctionResolver as Pt, red as Q, CrossAccountSecretRefusalError as Qa, getDefaultStateBucketName as Qi, refuseMalformedOrphanRecordsForDestroy as Qn, forceQuitRecoveryClause as Qr, configBooleanRefusal as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, absoluteAssemblyPathEscape as Ra, getDockerCmd as Ri, malformedOrphanRowsKeptWarning as Rn, maskSecretsInError as Rr, coerceParameterTypedValue as Rt, computeParameterTaint as S, PARTITION_TABLE as Sa, ensureAssetStorage as Si, INTRINSIC_KEYS as Sn, isMarkedNonRetryable as So, describeTypeWithThrottleRetry as Sr, compositeIdSeparatorRefusal as St, resourcesNamingDeclaredParameter as T, ambientClientDefaults as Ta, parseBootstrapMarker as Ti, UNREADABLE_RESOURCES_MAP_ROW as Tn, isTransientServerError as To, TemplateParser as Tr, createMaskedRetryLogger as Tt, coerceWarmThroughput as U, resolveBucketRegion as Ua, runDockerForeground as Ui, malformedRenderedContainersWarning as Un, recoverMaskedOutput as Ur, parameterTypeMayLoseSecretIdentity as Ut, renderStatefulReason as V, resolveAssemblyPath as Va, partitionSensitiveEnv as Vi, malformedOutputsRefusalMessage as Vn, recordMaskOnlyValue as Vr, isNamelessDynamicReferenceError as Vt, isWarmThroughputDecrease as W, AwsClients as Wa, runDockerStreaming as Wi, malformedResourceEntriesWarning as Wn, redactSecretsForState as Wr, refStateLookupFromResource as Wt, gray as X, CdkdError as Xa, Synthesizer as Xi, refuseMalformedNestedChildOutputs as Xn, buildForceUnlockCommand as Xr, coerceCfnBoolean as Xt, cyan as Y, AssetError as Ya, getDockerImageBySourceHash as Yi, refuseDivergentRecordRegionForDestroy as Yn, UNREPRODUCIBLE_LOCK_CLAUSE as Yr, assertRegionMatch as Yt, green as Z, ConfigError as Za, synthesisStatusMessage as Zi, refuseMalformedOrphanRecords as Zn, buildLockContentionMessage as Zr, coerceCfnInteger as Zt, bagHoldsSecretExpression as _, injectiveKeyPrefix as _a, loadPublishableAssetManifest as _i, AWS_CREDENTIAL_ENV_KEYS as _n, isCdkdError as _o, safeStackName as _r, startInterruptWatch as _t, DeploymentEventsStore as a, resolveStateBucketWithDefaultAndSource as aa, hasUnverifiableParameterRefusal as ai, requireConfigString as an, LockError as ao, refuseMalformedResourceEntries as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, decodeListingKey as ba, BOOTSTRAP_MARKER_PREFIX as bi, envCredentialsAreAssumedRole as bn, pasteableCommand as bo, findActionableSilentDrops as br, ccProtectionRegistryTypes as bt, replayFailedOperations as c, warnDeprecatedNoPrefixCliFlag as ca, isReadableBag as ci, classifyReplaySecretRegion as cn, PartialFailureError as co, refuseMalformedResourcesForDestroy as cr, IAMRoleProvider as ct, updatePartialMessage as d, CFN_TEMPLATE_URL_LIMIT as da, shouldRetainResource as di, s3BucketArn as dn, ResourceUpdateNotSupportedError as do, repairMalformedOrphansForReadOnly as dr, ProviderRegistry as dt, resolveApp as ea, CUSTOM_RESOURCE_RESPONSE_PREFIX as ei, configStringRefusal as en, DeployCancelledError as eo, refuseMalformedOrphansForDestroy as er, collectDeclaredOutputNames as et, updatePartialReason as f, MIGRATE_TMP_PREFIX as fa, AssetPublisher as fi, s3BucketDomainName as fn, StackHasActiveImportsError as fo, repairMalformedOutputsForReadOnly as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, injectiveKey as ga, createAssetRedirectResolver as gi, applyRoleArnIfSet as gn, formatError as go, safeRegion as gr, isInterruptedWaitError as gt, IMPLICIT_DELETE_DEPENDENCIES as h, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as ha, buildAssetRedirectMap as hi, s3BucketWebsiteUrl as hn, SynthesisError as ho, repairMalformedResourcesForReadOnly as hr, interruptWatchListenerCount as ht, DeploymentEventsReader as i, resolveStateBucketWithDefault as ia, hasReasonlessBaselineRefusal as ii, requireConfigObject as in, LocalStartServiceError as io, refuseMalformedResourceAttributesForOrphan as ir, secretBearing as it, isFinalSnapshotError as j, globMatches as ja, resolveDockerContextDirectory as ji, isReadableOrphanRecord as jn, __exportAll as jo, createSecretMasker as jr, isWaitAbandonedError as jt, ccRoutedFinalSnapshotError as k, AssemblyReader as ka, buildDenyExternalAccessPolicy as ki, hasReadableOutputs as kn, describeAwsFailure as ko, TEMPLATE_SOURCED_RULES as kr, deleteIndeterminateGuards as kt, replayRollback as l, ssmResolvedValueType as la, orphansAfterRollback as li, producerRegionsFromState as ln, ProvisioningError as lo, refuseMalformedState as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, uploadCfnTemplate as ma, WorkGraph as mi, s3BucketRegionalDomainName as mn, StateError as mo, repairMalformedResourcePropertiesForReadOnly as mr, endCommandInterruptScope as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, resolveCaptureObservedState as na, exportNamesCarriedFrom as ni, replayWarn as nn, IntrinsicResolutionRefusalError as no, refuseMalformedOutputs as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, resolveUseCdkBootstrapAssets as oa, importableOutputKeys as oi, definedAttributes as on, MalformedProducerRecordRefusalError as oo, refuseMalformedResourceEntriesForOrphan as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, findLargeInlineResources as pa, stringifyValue as pi, s3BucketDualStackDomainName as pn, StackTerminationProtectionError as po, repairMalformedResourceEntriesForReadOnly as pr, beginCommandInterruptScope as pt, formatResourceLine as q, runWithStackAwsClients as qa, stripControlChars as qi, malformedStateRefusalMessage as qn, S3StateBackend as qr, normalizeAwsTagsToCfn as qt, DeployEngine as r, resolveSkipPrefix as ra, hasReadableExportSet as ri, requireConfigArray as rn, LocalInvokeBuildError as ro, refuseMalformedOutputsForDestroy as rr, isExportAliasCollision as rt, planRollback as s, stateBucketExistenceConfirmed as sa, importableOutputs as si, stringifyIfAssigned as sn, NestedStackChildDirectDestroyError as so, refuseMalformedResourcePropertiesForOrphan as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, resolveAutoAssetStorage as ta, DEFAULT_STATE_PREFIX as ti, readConfigString as tn, DynamicReferenceRegionAmbiguousError as to, refuseMalformedOrphansForOrphan as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, CFN_TEMPLATE_BODY_LIMIT as ua, orphansCarriedFrom as ui, withSharedDrainBudget as un, ResourceTimeoutError as uo, repairMalformedOrphanRecordsForReadOnly as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, producerCoordinateKey as va, rewriteTemplateAssetReferences as vi, applyCallerIdentityCredentials as vn, normalizeAwsError as vo, unpreviewableOrphanRecords as vr, CloudControlProvider as vt, reachableDivergentParameters as w, derivePartitionAndUrlSuffix as wa, isCrossRegionRedirect as wi, UNREADABLE_ORPHANS_CONTAINER_ROW as wn, isThrottlingError as wo, DagBuilder as wr, packCompositeId as wt, bindingSkippedOutputs as x, expectedOwnerParam as xa, assertAssetBucketRegion as xi, DiffCalculator as xn, shellQuote as xo, findSilentDropProperties as xr, compositeIdFormatMessage as xt, keptWholeReasonText as y, producerRecordKey as ya, AssetModeResolver as yi, callerEnvCredentials as yn, withErrorHandling as yo, unreadableOrphanRecords as yr, slowCcOperationTimeoutMs as yt, isStatefulRecreateTargetForReplace as z, displayAssemblyPath as za, isDockerClientEnvKey as zi, malformedOrphansRefusalMessage as zn, maskSecretsInText as zr, getAccountInfo as zt };
52800
+ //# sourceMappingURL=deploy-engine-CCvNP_dA.js.map