@go-to-k/cdkd 0.284.30 → 0.284.32
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.
- package/dist/{asg-provider-qMgJEhCM.js → asg-provider-BVzQ7mQX.js} +2 -2
- package/dist/{asg-provider-qMgJEhCM.js.map → asg-provider-BVzQ7mQX.js.map} +1 -1
- package/dist/cli.js +787 -141
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-BFgi0RJr.js → deploy-engine-DsUQ4GxO.js} +145 -37
- package/dist/deploy-engine-DsUQ4GxO.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-BFgi0RJr.js.map +0 -1
|
@@ -771,7 +771,7 @@ function formatDuration(ms) {
|
|
|
771
771
|
* "the referenced thing does not exist" miss (issue
|
|
772
772
|
* [#1740](https://github.com/go-to-k/cdkd/issues/1740)).
|
|
773
773
|
*
|
|
774
|
-
* The distinction exists for
|
|
774
|
+
* The distinction exists for one consumer of THIS class: `Fn::Sub`'s variable
|
|
775
775
|
* resolution, which speculatively tries `Ref` and then `Fn::GetAtt` and keeps
|
|
776
776
|
* the raw `${...}` placeholder when neither resolves. That warn-and-keep is the
|
|
777
777
|
* long-standing, deliberate behavior for a genuinely unknown variable — but a
|
|
@@ -782,11 +782,15 @@ function formatDuration(ms) {
|
|
|
782
782
|
*
|
|
783
783
|
* Throwing this class rather than a bare `Error` is what lets that catch
|
|
784
784
|
* re-raise a refusal (carrying its own message and remedy) while leaving the
|
|
785
|
-
* not-found path on warn-and-keep. Nothing else branches on
|
|
785
|
+
* not-found path on warn-and-keep. Nothing else branches on THIS class;
|
|
786
|
+
* `cdkd scrub` branches on the {@link CrossAccountSecretRefusalError} SUBCLASS,
|
|
787
|
+
* for the reason group 3 below gives.
|
|
786
788
|
*
|
|
787
|
-
* **Throw sites split into
|
|
789
|
+
* **Throw sites split into three groups, and the enumeration is worth keeping
|
|
788
790
|
* accurate** — an out-of-date one reads as "these are all of them", which is
|
|
789
|
-
* how the #1730 site below went unlisted for three releases
|
|
791
|
+
* how the #1730 site below went unlisted for three releases, and how the
|
|
792
|
+
* cross-account `Fn::GetStackOutput` site in group 3 went unlisted from the
|
|
793
|
+
* day it shipped. All live in
|
|
790
794
|
* `src/deployment/intrinsic-function-resolver.ts`:
|
|
791
795
|
*
|
|
792
796
|
* 1. Reachable from `Fn::Sub`'s `${LogicalId.Attribute}` form, i.e. the ones
|
|
@@ -800,29 +804,77 @@ function formatDuration(ms) {
|
|
|
800
804
|
* inspects it: `resolveSplit`'s two refusals of a non-string value (#1874).
|
|
801
805
|
* `Fn::Sub` cannot syntactically contain an `Fn::Split`, so those change no
|
|
802
806
|
* behavior by being this class.
|
|
807
|
+
* 3. PERMANENT — the one site where no user action and no re-run can make the
|
|
808
|
+
* read succeed: `resolveGetStackOutput`'s cross-account refusal to resolve a
|
|
809
|
+
* producer account's redacted dynamic reference with the consumer's
|
|
810
|
+
* credentials. It throws the SUBCLASS
|
|
811
|
+
* {@link CrossAccountSecretRefusalError} rather than this class, because
|
|
812
|
+
* every site in groups 1 and 2 is USER-FIXABLE (correct the stale
|
|
813
|
+
* placeholder ARN, deploy the producer so STS resolves, enrich the
|
|
814
|
+
* `Fn::GetAtt`, drop `--strict-getatt`, fix the malformed `Fn::Split`) and a
|
|
815
|
+
* consumer that treats "permanent" as a property of the CLASS silently
|
|
816
|
+
* downgrades all five. `cdkd scrub`'s cross-stack pre-pass is that consumer:
|
|
817
|
+
* it records a permanent refusal as a FINDING and scrubs the rest of the
|
|
818
|
+
* stack, but must REFUSE the stack for a fixable one, since a re-run after
|
|
819
|
+
* the fix would scrub it (issue
|
|
820
|
+
* [#2133](https://github.com/go-to-k/cdkd/issues/2133) review). Match on the
|
|
821
|
+
* subclass, never on this class.
|
|
803
822
|
*
|
|
804
823
|
* The class is deliberately NOT `markNonRetryable` at construction, unlike
|
|
805
824
|
* {@link ResourceUpdateNotSupportedError}: EXACTLY ONE of its throw sites is
|
|
806
825
|
* genuinely time-dependent — the fabricated-account guard, where
|
|
807
826
|
* `getAccountInfo` caches a fabricated answer for only 10s precisely so a
|
|
808
827
|
* later attempt can heal — so a constructor-level marker would wrongly make
|
|
809
|
-
* that one terminal. Every OTHER site marks at its own `throw`: all
|
|
828
|
+
* that one terminal. Every OTHER site marks at its own `throw`: all six
|
|
810
829
|
* decide from inputs a retry cannot change (a persisted state record, an
|
|
811
|
-
* attribute-name suffix, a CLI flag, an already-resolved value's type
|
|
812
|
-
*
|
|
830
|
+
* attribute-name suffix, a CLI flag, an already-resolved value's type, a
|
|
831
|
+
* template's literal `RoleArn`), and all six interpolate
|
|
832
|
+
* template-controlled text into their message, which the
|
|
813
833
|
* SUBSTRING-matching retry classifiers can read as transient (issue #1838 —
|
|
814
834
|
* a logical id like `MyDependencyViolationHandler` is enough). So the split is
|
|
815
835
|
* "which SITE can heal", not "which class"; do not read the unmarked class as
|
|
816
836
|
* a statement that these refusals are retryable.
|
|
817
837
|
*/
|
|
818
838
|
var IntrinsicResolutionRefusalError = class IntrinsicResolutionRefusalError extends CdkdError {
|
|
819
|
-
constructor(message, cause) {
|
|
820
|
-
super(message,
|
|
839
|
+
constructor(message, cause, code = "INTRINSIC_RESOLUTION_REFUSAL") {
|
|
840
|
+
super(message, code, cause);
|
|
821
841
|
this.name = "IntrinsicResolutionRefusalError";
|
|
822
842
|
Object.setPrototypeOf(this, IntrinsicResolutionRefusalError.prototype);
|
|
823
843
|
}
|
|
824
844
|
};
|
|
825
845
|
/**
|
|
846
|
+
* The ONE refusal in group 3 of {@link IntrinsicResolutionRefusalError}: a
|
|
847
|
+
* cross-account `Fn::GetStackOutput` whose stored value is a redacted dynamic
|
|
848
|
+
* reference (issue [#2133](https://github.com/go-to-k/cdkd/issues/2133)
|
|
849
|
+
* review).
|
|
850
|
+
*
|
|
851
|
+
* A SUBCLASS rather than a flag, so the two properties stay independent:
|
|
852
|
+
* `instanceof IntrinsicResolutionRefusalError` is still true, which is what
|
|
853
|
+
* `resolveSub`'s catch re-raises on (making this refusal propagate out of an
|
|
854
|
+
* `Fn::Sub` instead of being laundered into a literal `${...}`), while
|
|
855
|
+
* consumers that need "no re-run can change this" match on THIS class and
|
|
856
|
+
* therefore cannot capture the five user-fixable siblings.
|
|
857
|
+
*
|
|
858
|
+
* `code` is distinct for the same reason a message is not: a consumer keying
|
|
859
|
+
* on `INTRINSIC_RESOLUTION_REFUSAL` would capture every sibling, and one
|
|
860
|
+
* keying on message text breaks the moment the wording improves.
|
|
861
|
+
*
|
|
862
|
+
* `cdkd scrub` is the consumer today. Its cross-stack pre-pass records a
|
|
863
|
+
* refusal of THIS class as an unverifiable FINDING — the rest of the stack is
|
|
864
|
+
* still scrubbed, and the run exits non-zero — because refusing the whole
|
|
865
|
+
* stack would strand every other secret in it forever. A sibling refusal
|
|
866
|
+
* (a stale placeholder ARN, an unenriched `Fn::GetAtt`, a malformed
|
|
867
|
+
* `Fn::Split`, all reachable through an `Fn::Sub`-built export name) must
|
|
868
|
+
* REFUSE instead, since the user can fix the cause and re-run.
|
|
869
|
+
*/
|
|
870
|
+
var CrossAccountSecretRefusalError = class CrossAccountSecretRefusalError extends IntrinsicResolutionRefusalError {
|
|
871
|
+
constructor(message, cause) {
|
|
872
|
+
super(message, cause, "INTRINSIC_RESOLUTION_REFUSAL_CROSS_ACCOUNT_SECRET");
|
|
873
|
+
this.name = "CrossAccountSecretRefusalError";
|
|
874
|
+
Object.setPrototypeOf(this, CrossAccountSecretRefusalError.prototype);
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
/**
|
|
826
878
|
* Dependency resolution errors
|
|
827
879
|
*/
|
|
828
880
|
var DependencyError = class DependencyError extends CdkdError {
|
|
@@ -6798,6 +6850,11 @@ async function rebuildClientForBucketRegion(client, bucket, opts = {}) {
|
|
|
6798
6850
|
* deep — split off into a constant so call sites can clearly distinguish
|
|
6799
6851
|
* "two-segment legacy key" from "three-segment new key".
|
|
6800
6852
|
*/
|
|
6853
|
+
/**
|
|
6854
|
+
* `{stack}/state.json` — one segment plus the file, i.e. the v1 region-less
|
|
6855
|
+
* layout. Exported because `state-file-keys.ts` classifies the same layouts
|
|
6856
|
+
* from the other side and the two must not drift (issue #2001).
|
|
6857
|
+
*/
|
|
6801
6858
|
const LEGACY_KEY_DEPTH = 2;
|
|
6802
6859
|
/** The `version: 2` region-prefixed key. */
|
|
6803
6860
|
const NEW_KEY_DEPTH = 3;
|
|
@@ -7164,7 +7221,7 @@ var S3StateBackend = class {
|
|
|
7164
7221
|
}
|
|
7165
7222
|
continue;
|
|
7166
7223
|
}
|
|
7167
|
-
if (segments.length ===
|
|
7224
|
+
if (segments.length === 2) {
|
|
7168
7225
|
const [stackName] = segments;
|
|
7169
7226
|
if (!stackName) continue;
|
|
7170
7227
|
const region = await this.readLegacyRegion(stackName);
|
|
@@ -13238,6 +13295,12 @@ function buildUnknownIntrinsicError(key) {
|
|
|
13238
13295
|
* `Record<string, unknown>` and deliberately NOT coerced to string — a
|
|
13239
13296
|
* list-valued `Fn::GetAtt` persists a JSON array — so a secret-bearing output
|
|
13240
13297
|
* is not always a bare string.
|
|
13298
|
+
*
|
|
13299
|
+
* EXPORTED for `cdkd scrub` (issue
|
|
13300
|
+
* [#2133](https://github.com/go-to-k/cdkd/issues/2133)), which asks the inverse
|
|
13301
|
+
* question of the same value: a cross-stack read that comes back carrying NO
|
|
13302
|
+
* dynamic reference is one scrub could not turn into a needle, because a needle
|
|
13303
|
+
* is only ever recorded by resolving a `{{resolve:...}}` expression.
|
|
13241
13304
|
*/
|
|
13242
13305
|
function carriesDynamicReference(value) {
|
|
13243
13306
|
if (typeof value === "string") return value.includes("{{resolve:");
|
|
@@ -13366,6 +13429,14 @@ const FABRICATED_ACCOUNT_INFO_TTL_MS = 1e4;
|
|
|
13366
13429
|
*/
|
|
13367
13430
|
const MAX_DYNAMIC_REFERENCE_THROTTLE_RETRIES = 4;
|
|
13368
13431
|
/**
|
|
13432
|
+
* How many producer output KEYS an `Fn::GetStackOutput` not-found error may
|
|
13433
|
+
* enumerate (issue #2133 review). See {@link
|
|
13434
|
+
* IntrinsicFunctionResolver.describeAvailableOutputs} for why the list is
|
|
13435
|
+
* bounded at all; the value is "enough to fix a typo, few enough that one error
|
|
13436
|
+
* cannot dump a producer's whole key space".
|
|
13437
|
+
*/
|
|
13438
|
+
const MAX_LISTED_AVAILABLE_OUTPUTS = 10;
|
|
13439
|
+
/**
|
|
13369
13440
|
* Test seam: overriding `sleep` lets unit tests drive the backoff schedule
|
|
13370
13441
|
* without real waits (mirrors `describeTypeRetryDelays`).
|
|
13371
13442
|
*/
|
|
@@ -13398,9 +13469,13 @@ const dynamicReferenceRetryDelays = {};
|
|
|
13398
13469
|
* a hostname that does not exist and the SDK fails loudly.
|
|
13399
13470
|
*
|
|
13400
13471
|
* Note the sibling pattern in `src/cli/commands/state-file-keys.ts` is NOT
|
|
13401
|
-
* reusable here
|
|
13402
|
-
*
|
|
13403
|
-
*
|
|
13472
|
+
* reusable here, and the reason is structural rather than a gap in its
|
|
13473
|
+
* coverage: it is SHAPE-based because its job is the opposite one — telling a
|
|
13474
|
+
* region segment apart from a stack name sitting in the same key position —
|
|
13475
|
+
* so it must enumerate the shape this predicate refuses to. (Its prefix was
|
|
13476
|
+
* exactly `^[a-z]{2}` until issue #2001, which is what made it reject the
|
|
13477
|
+
* European Sovereign Cloud partition's four-letter `eusc-de-east-1`; it now
|
|
13478
|
+
* takes `{2,4}`, and is still the wrong tool here.)
|
|
13404
13479
|
*
|
|
13405
13480
|
* Callers must {@link canonicalizeRegion} first — `US-EAST-1` is a documented
|
|
13406
13481
|
* input and is lowercase-canonical, not invalid.
|
|
@@ -14966,7 +15041,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
14966
15041
|
const resolved1 = await this.resolveValue(value1, context);
|
|
14967
15042
|
const resolved2 = await this.resolveValue(value2, context);
|
|
14968
15043
|
const result = JSON.stringify(resolved1) === JSON.stringify(resolved2);
|
|
14969
|
-
this.logger.debug(`Resolved Fn::Equals: ${JSON.stringify(resolved1)} === ${JSON.stringify(resolved2)} -> ${result}`);
|
|
15044
|
+
this.logger.debug(`Resolved Fn::Equals: ${this.maskSecretsForLog(JSON.stringify(resolved1), context)} === ${this.maskSecretsForLog(JSON.stringify(resolved2), context)} -> ${result}`);
|
|
14970
15045
|
return result;
|
|
14971
15046
|
}
|
|
14972
15047
|
/**
|
|
@@ -15124,7 +15199,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15124
15199
|
}
|
|
15125
15200
|
return v;
|
|
15126
15201
|
};
|
|
15127
|
-
this.logger.debug(`Re-resolving dynamic reference(s) in ${origin}`);
|
|
15202
|
+
this.logger.debug(`Re-resolving dynamic reference(s) in ${this.maskSecretsForLog(origin, context)}`);
|
|
15128
15203
|
return await walk(value);
|
|
15129
15204
|
}
|
|
15130
15205
|
/**
|
|
@@ -15211,23 +15286,24 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15211
15286
|
const exportName = await this.resolveValue(importValueArg, context);
|
|
15212
15287
|
if (typeof exportName !== "string") throw new Error(`Fn::ImportValue: export name must resolve to a string, got ${typeof exportName}`);
|
|
15213
15288
|
if (!context.stateBackend) throw new Error("Fn::ImportValue: state backend is required for cross-stack references");
|
|
15214
|
-
this.
|
|
15289
|
+
const loggedExportName = this.maskSecretsForLog(exportName, context);
|
|
15290
|
+
this.logger.debug(`Resolving Fn::ImportValue: ${loggedExportName}`);
|
|
15215
15291
|
if (context.exportIndex) {
|
|
15216
15292
|
let entry;
|
|
15217
15293
|
try {
|
|
15218
15294
|
entry = await context.exportIndex.lookup(exportName);
|
|
15219
15295
|
} catch (err) {
|
|
15220
|
-
this.logger.warn(`Exports index lookup failed for '${
|
|
15296
|
+
this.logger.warn(`Exports index lookup failed for '${loggedExportName}': ${err instanceof Error ? err.message : String(err)}; falling back to state.json scan`);
|
|
15221
15297
|
entry = void 0;
|
|
15222
15298
|
}
|
|
15223
15299
|
if (entry && (!context.stackName || entry.producerStack !== context.stackName)) {
|
|
15224
15300
|
this.recordImport(context, exportName, entry.producerStack, entry.producerRegion);
|
|
15225
|
-
this.logger.info(`Resolved Fn::ImportValue: ${
|
|
15301
|
+
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from index: ${entry.producerStack} / ${entry.producerRegion}; ${carriesDynamicReference(entry.value) ? "redacted dynamic reference" : "literal value"})`);
|
|
15226
15302
|
return await this.reresolveCrossStackValue(entry.value, entry.producerRegion, context, `Fn::ImportValue '${exportName}' (producer ${entry.producerStack} / ${entry.producerRegion})`);
|
|
15227
15303
|
}
|
|
15228
15304
|
}
|
|
15229
15305
|
const allStacks = await context.stateBackend.listStacks();
|
|
15230
|
-
this.logger.debug(`Found ${allStacks.length} state record(s) to search for export: ${
|
|
15306
|
+
this.logger.debug(`Found ${allStacks.length} state record(s) to search for export: ${loggedExportName}`);
|
|
15231
15307
|
let found;
|
|
15232
15308
|
for (const ref of allStacks) {
|
|
15233
15309
|
const { stackName: refStack, region: refRegion } = ref;
|
|
@@ -15249,7 +15325,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15249
15325
|
const { state } = stateData;
|
|
15250
15326
|
if (state.outputs && exportName in state.outputs) {
|
|
15251
15327
|
const value = state.outputs[exportName];
|
|
15252
|
-
this.logger.info(`Resolved Fn::ImportValue: ${
|
|
15328
|
+
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from stack: ${refStack} / ${lookupRegion}; ${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
15253
15329
|
if (context.exportIndex) context.exportIndex.patchEntry(exportName, {
|
|
15254
15330
|
value,
|
|
15255
15331
|
producerStack: refStack,
|
|
@@ -15272,9 +15348,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15272
15348
|
}
|
|
15273
15349
|
if (found) return await this.reresolveCrossStackValue(found.value, found.lookupRegion, context, `Fn::ImportValue '${exportName}' (producer ${found.refStack} / ${found.lookupRegion})`);
|
|
15274
15350
|
if (this.cfnFallback) {
|
|
15275
|
-
const cfnExport = await this.lookupCfnExport(exportName);
|
|
15351
|
+
const cfnExport = await this.lookupCfnExport(exportName, context);
|
|
15276
15352
|
if (cfnExport) {
|
|
15277
|
-
this.logger.info(`Resolved Fn::ImportValue: ${
|
|
15353
|
+
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from CloudFormation exports${cfnExport.exportingStackId ? `; exporting stack: ${cfnExport.exportingStackId}` : ""}; weak reference — producer is not cdkd-managed)`);
|
|
15278
15354
|
return cfnExport.value;
|
|
15279
15355
|
}
|
|
15280
15356
|
}
|
|
@@ -15292,7 +15368,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15292
15368
|
* deliberate: without this fallback the deploy would have failed with
|
|
15293
15369
|
* the same not-found error anyway.
|
|
15294
15370
|
*/
|
|
15295
|
-
async lookupCfnExport(exportName) {
|
|
15371
|
+
async lookupCfnExport(exportName, context) {
|
|
15296
15372
|
let listing = this.cfnExportsPromise;
|
|
15297
15373
|
if (!listing) {
|
|
15298
15374
|
listing = this.fetchAllCfnExports();
|
|
@@ -15309,10 +15385,40 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15309
15385
|
};
|
|
15310
15386
|
return;
|
|
15311
15387
|
} catch (error) {
|
|
15312
|
-
this.logger.warn(`Fn::ImportValue: CloudFormation ListExports fallback failed for export '${exportName}' (region ${this.resolverRegion}): ${error instanceof Error ? error.message : String(error)}. Grant cloudformation:ListExports to resolve exports from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
|
|
15388
|
+
this.logger.warn(`Fn::ImportValue: CloudFormation ListExports fallback failed for export '${this.maskSecretsForLog(exportName, context)}' (region ${this.resolverRegion}): ${error instanceof Error ? error.message : String(error)}. Grant cloudformation:ListExports to resolve exports from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
|
|
15313
15389
|
return;
|
|
15314
15390
|
}
|
|
15315
15391
|
}
|
|
15392
|
+
/**
|
|
15393
|
+
* Render the `Available outputs: ...` tail of an `Fn::GetStackOutput`
|
|
15394
|
+
* not-found error (issue #2133 review).
|
|
15395
|
+
*
|
|
15396
|
+
* These are the PRODUCER's `state.outputs` / CloudFormation output KEYS, and
|
|
15397
|
+
* they land in a top-level ERROR — the one thing on this path that reaches a
|
|
15398
|
+
* CI log at default verbosity. A key can itself hold plaintext: that is the
|
|
15399
|
+
* `secretBearingStateKeyWarning` class (issue #1919), which `cdkd scrub`
|
|
15400
|
+
* counts and deliberately never prints, so the enumeration must not be the
|
|
15401
|
+
* one place that does.
|
|
15402
|
+
*
|
|
15403
|
+
* MASKED and CAPPED rather than dropped. Masking is the treatment every other
|
|
15404
|
+
* identifier on this path already gets, and the cap bounds what one error can
|
|
15405
|
+
* disclose (a producer with hundreds of outputs would otherwise dump all of
|
|
15406
|
+
* them). Dropping the names entirely was considered and rejected: a typo'd
|
|
15407
|
+
* `OutputName` is the overwhelmingly common cause, and the list is what makes
|
|
15408
|
+
* the error actionable.
|
|
15409
|
+
*
|
|
15410
|
+
* Residual, stated rather than hidden: the needles belong to the CONSUMER's
|
|
15411
|
+
* resolution, so a plaintext sitting in a PRODUCER key that this consumer
|
|
15412
|
+
* never resolved is not maskable from here. The cap is what bounds that case;
|
|
15413
|
+
* `cdkd scrub` reporting the producer's own `secretBearingKeys` is the remedy.
|
|
15414
|
+
*/
|
|
15415
|
+
describeAvailableOutputs(keys, context) {
|
|
15416
|
+
if (keys.length === 0) return "(none)";
|
|
15417
|
+
const shown = keys.slice(0, MAX_LISTED_AVAILABLE_OUTPUTS);
|
|
15418
|
+
const rendered = shown.map((k) => this.maskSecretsForLog(k, context)).join(", ");
|
|
15419
|
+
const hidden = keys.length - shown.length;
|
|
15420
|
+
return hidden > 0 ? `${rendered} (+${hidden} more)` : rendered;
|
|
15421
|
+
}
|
|
15316
15422
|
/** Full paginated ListExports walk backing {@link lookupCfnExport}'s memo. */
|
|
15317
15423
|
async fetchAllCfnExports() {
|
|
15318
15424
|
const client = this.getCfnClient(this.resolverRegion);
|
|
@@ -15335,7 +15441,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15335
15441
|
* logged for non-not-found failures). Same graceful-degradation
|
|
15336
15442
|
* contract as {@link lookupCfnExport}.
|
|
15337
15443
|
*/
|
|
15338
|
-
async lookupCfnStackOutputs(stackName, region) {
|
|
15444
|
+
async lookupCfnStackOutputs(stackName, region, context) {
|
|
15339
15445
|
const cacheKey = `${region}\0${stackName}`;
|
|
15340
15446
|
let fetch = this.cfnStackOutputsCache.get(cacheKey);
|
|
15341
15447
|
if (!fetch) {
|
|
@@ -15349,7 +15455,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15349
15455
|
return await fetch;
|
|
15350
15456
|
} catch (error) {
|
|
15351
15457
|
const message = error instanceof Error ? error.message : String(error);
|
|
15352
|
-
this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${stackName}' (${region}): ${message}. Grant cloudformation:DescribeStacks to resolve outputs from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
|
|
15458
|
+
this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${this.maskSecretsForLog(stackName, context)}' (${region}): ${message}. Grant cloudformation:DescribeStacks to resolve outputs from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
|
|
15353
15459
|
return;
|
|
15354
15460
|
}
|
|
15355
15461
|
}
|
|
@@ -15464,18 +15570,20 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15464
15570
|
roleArn = raw;
|
|
15465
15571
|
}
|
|
15466
15572
|
if (!roleArn && context.stackName && context.stackName === stackName && region === this.resolverRegion) throw new Error(`Fn::GetStackOutput: cannot reference own stack '${stackName}' in the same region '${region}'`);
|
|
15467
|
-
this.
|
|
15573
|
+
const loggedStackName = this.maskSecretsForLog(stackName, context);
|
|
15574
|
+
const loggedOutputName = this.maskSecretsForLog(outputName, context);
|
|
15575
|
+
this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${loggedStackName}, Region=${region}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${roleArn}` : ""}`);
|
|
15468
15576
|
const stateData = roleArn ? await this.getCrossAccountStackState(roleArn, stackName, region, context) : await this.getSameAccountStackState(stackName, region, context);
|
|
15469
15577
|
if (!stateData) {
|
|
15470
15578
|
if (!roleArn && this.cfnFallback) {
|
|
15471
|
-
const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region);
|
|
15579
|
+
const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region, context);
|
|
15472
15580
|
if (cfnOutputs) {
|
|
15473
15581
|
if (!(outputName in cfnOutputs)) {
|
|
15474
|
-
const available = Object.keys(cfnOutputs)
|
|
15582
|
+
const available = this.describeAvailableOutputs(Object.keys(cfnOutputs), context);
|
|
15475
15583
|
throw new Error(`Fn::GetStackOutput: output '${outputName}' not found in CloudFormation stack '${stackName}' (${region}). Available outputs: ${available}`);
|
|
15476
15584
|
}
|
|
15477
15585
|
const value = cfnOutputs[outputName];
|
|
15478
|
-
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${
|
|
15586
|
+
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${region}, OutputName=${loggedOutputName} (from CloudFormation stack outputs; weak reference — producer is not cdkd-managed)`);
|
|
15479
15587
|
return value;
|
|
15480
15588
|
}
|
|
15481
15589
|
}
|
|
@@ -15483,13 +15591,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15483
15591
|
}
|
|
15484
15592
|
const outputs = stateData.state.outputs ?? {};
|
|
15485
15593
|
if (!(outputName in outputs)) {
|
|
15486
|
-
const available = Object.keys(outputs)
|
|
15594
|
+
const available = this.describeAvailableOutputs(Object.keys(outputs), context);
|
|
15487
15595
|
throw new Error(`Fn::GetStackOutput: output '${outputName}' not found in stack '${stackName}' (${region}). Available outputs: ${available}`);
|
|
15488
15596
|
}
|
|
15489
15597
|
const value = outputs[outputName];
|
|
15490
|
-
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${
|
|
15598
|
+
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${region}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${roleArn}` : ""} (${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
15491
15599
|
if (!roleArn) this.recordOutputRead(context, stackName, region, outputName);
|
|
15492
|
-
if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new
|
|
15600
|
+
if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new CrossAccountSecretRefusalError(`Fn::GetStackOutput: output '${outputName}' of stack '${stackName}' (${region}) is a redacted dynamic reference, and this is a CROSS-ACCOUNT reference (RoleArn ${roleArn}). cdkd will not resolve a producer account's secret with the consumer's credentials — a same-named secret in the consumer account would answer instead. Export a non-secret value (e.g. the secret's ARN) and resolve it in the consumer stack, or reference the producer stack from within its own account.`));
|
|
15493
15601
|
return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput '${outputName}' (producer ${stackName} / ${region})`);
|
|
15494
15602
|
}
|
|
15495
15603
|
/**
|
|
@@ -16879,7 +16987,7 @@ var CloudControlProvider = class {
|
|
|
16879
16987
|
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);
|
|
16880
16988
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
16881
16989
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
16882
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
16990
|
+
const { ASGProvider } = await import("./asg-provider-BVzQ7mQX.js").then((n) => n.n);
|
|
16883
16991
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
16884
16992
|
}
|
|
16885
16993
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -25792,7 +25900,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
25792
25900
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
25793
25901
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
25794
25902
|
function getCdkdVersion() {
|
|
25795
|
-
return "0.284.
|
|
25903
|
+
return "0.284.32";
|
|
25796
25904
|
}
|
|
25797
25905
|
/**
|
|
25798
25906
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -28412,5 +28520,5 @@ var DeployEngine = class {
|
|
|
28412
28520
|
};
|
|
28413
28521
|
|
|
28414
28522
|
//#endregion
|
|
28415
|
-
export { endCommandInterruptScope as $,
|
|
28416
|
-
//# sourceMappingURL=deploy-engine-
|
|
28523
|
+
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 };
|
|
28524
|
+
//# sourceMappingURL=deploy-engine-DsUQ4GxO.js.map
|