@go-to-k/cdkd 0.290.13 → 0.290.14
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-CpUSth0q.js → asg-provider-BAYjqZuM.js} +2 -2
- package/dist/{asg-provider-CpUSth0q.js.map → asg-provider-BAYjqZuM.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-omGpC16W.js → deploy-engine-v7h1H_Ac.js} +306 -78
- package/dist/deploy-engine-v7h1H_Ac.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-BDNXyKp5.js → program-DD0X9qLM.js} +4 -4
- package/dist/{program-BDNXyKp5.js.map → program-DD0X9qLM.js.map} +1 -1
- package/dist/{version--dVnQSTI.js → version-CqnAWzcc.js} +2 -2
- package/dist/{version--dVnQSTI.js.map → version-CqnAWzcc.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-omGpC16W.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as displaySafe, S as displayIdent, 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, x as UNRENDERABLE, y as withoutGeneratedFallbackName } from "./logger-C17H06QA.js";
|
|
2
2
|
import { t as awsClientDefaults } from "./aws-client-defaults-D-iYiIJ6.js";
|
|
3
|
-
import { t as getCdkdVersion } from "./version
|
|
3
|
+
import { t as getCdkdVersion } from "./version-CqnAWzcc.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";
|
|
@@ -804,6 +804,96 @@ function isNameCollisionError(message) {
|
|
|
804
804
|
return /(?<!\b(?:must|not|should|may|cannot)\s)already exists?\b/i.test(message) || message.includes("AlreadyExists");
|
|
805
805
|
}
|
|
806
806
|
/**
|
|
807
|
+
* SDK exception NAMES that mean, on their own, "a resource with this NAME
|
|
808
|
+
* already exists" — nothing else (issue
|
|
809
|
+
* [#3208](https://github.com/go-to-k/cdkd/issues/3208)).
|
|
810
|
+
*
|
|
811
|
+
* This list is the NARROW exception to the paragraph above, not a reversal of
|
|
812
|
+
* it. That paragraph refuses name-based classification because a name like
|
|
813
|
+
* `ResourceConflictException` is AMBIGUOUS — Lambda raises it for a function in
|
|
814
|
+
* a PENDING state too, so crediting it would delete a live function under
|
|
815
|
+
* `--replace`. Every name here is the opposite: the service declares it for the
|
|
816
|
+
* duplicate-name condition and for nothing else, so there is no second reading
|
|
817
|
+
* to be wrong about. A name may join this list only on that test.
|
|
818
|
+
*
|
|
819
|
+
* It exists because ELBv2 states the condition in prose that the message
|
|
820
|
+
* matcher above cannot see, and must not be widened to see. MEASURED against
|
|
821
|
+
* the real API (us-east-1, 2026-09-16, `@aws-sdk/client-elastic-load-balancing-v2`
|
|
822
|
+
* 3.1126.0), creating a second target group under a live name:
|
|
823
|
+
*
|
|
824
|
+
* name = 'DuplicateTargetGroupNameException'
|
|
825
|
+
* message = "A target group with the same name 'x' exists, but with
|
|
826
|
+
* different settings"
|
|
827
|
+
* cause = none
|
|
828
|
+
*
|
|
829
|
+
* The message carries no code and never says "already exists", so
|
|
830
|
+
* `isNameCollisionError` misses it — and the consequence is not cosmetic: the
|
|
831
|
+
* `--replace` delete-first fallback and the rollback executor's
|
|
832
|
+
* delete-new-first arm both gate on that predicate, so BOTH recovery paths went
|
|
833
|
+
* inert and a create-only change to a cdkd-named target group could not be
|
|
834
|
+
* deployed at all. Widening the prose matcher to a bare `exists` was rejected:
|
|
835
|
+
* it is substring-matched against every service's text, and the direction of a
|
|
836
|
+
* false positive here is a DELETE.
|
|
837
|
+
*
|
|
838
|
+
* The SET is complete rather than illustrative: `Duplicate*NameException` over
|
|
839
|
+
* every installed `@aws-sdk/client-*` model yields exactly these three, all
|
|
840
|
+
* ELBv2. Two ELBv2 siblings are deliberately EXCLUDED, and the reasons are the
|
|
841
|
+
* membership test in action — `DuplicateListenerException` reports a listener
|
|
842
|
+
* already bound to that PORT, which is not a name, and
|
|
843
|
+
* `DuplicateTagKeysException` reports repeated keys WITHIN one request, which
|
|
844
|
+
* is not an existence condition at all. Crediting either would hand a
|
|
845
|
+
* destructive path a collision that no delete can clear.
|
|
846
|
+
*/
|
|
847
|
+
const NAME_COLLISION_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
848
|
+
"DuplicateTargetGroupNameException",
|
|
849
|
+
"DuplicateLoadBalancerNameException",
|
|
850
|
+
"DuplicateTrustStoreNameException"
|
|
851
|
+
]);
|
|
852
|
+
/**
|
|
853
|
+
* {@link isNameCollisionError}, but reading the ERROR rather than a rendered
|
|
854
|
+
* message — which is the only way to see an exception NAME (issue #3208).
|
|
855
|
+
*
|
|
856
|
+
* Providers wrap an AWS failure as `Failed to create X: ${err.message}`, so the
|
|
857
|
+
* name is dropped before any caller could match it. This walks the bounded
|
|
858
|
+
* `cause` chain (the same {@link MAX_CAUSE_CHAIN_DEPTH} as every other
|
|
859
|
+
* classifier in this file), checking each link's `name` against
|
|
860
|
+
* {@link NAME_COLLISION_ERROR_NAMES} and each link's `message` through
|
|
861
|
+
* {@link isNameCollisionError}. A provider is required to thread the caught
|
|
862
|
+
* value as `cause` (`scripts/check-provider-error-cause.ts` enforces it across
|
|
863
|
+
* `src/provisioning/providers/**`), which is what makes the walk reach the SDK
|
|
864
|
+
* error at all.
|
|
865
|
+
*
|
|
866
|
+
* Prefer this at any site holding the error object. The string form stays for
|
|
867
|
+
* callers that genuinely have only text, and its behaviour is unchanged — this
|
|
868
|
+
* is strictly additive, so nothing that matched before stops matching.
|
|
869
|
+
*/
|
|
870
|
+
/**
|
|
871
|
+
* `String(value)` that cannot itself throw — a thrown `Object.create(null)` has
|
|
872
|
+
* no `toString`. Preserves the call sites' pre-#3208 `String(createError)` arm
|
|
873
|
+
* for a non-`Error` throw, which reading `.message` alone would have dropped.
|
|
874
|
+
*/
|
|
875
|
+
function stringifyForMatch(value) {
|
|
876
|
+
try {
|
|
877
|
+
return String(value);
|
|
878
|
+
} catch {
|
|
879
|
+
return "";
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function isNameCollisionErrorFrom(error, logicalId) {
|
|
883
|
+
if (typeof error === "string") return isNameCollisionError(error);
|
|
884
|
+
let current = error;
|
|
885
|
+
for (let depth = 0; depth < MAX_CAUSE_CHAIN_DEPTH && current != null; depth++) {
|
|
886
|
+
const link = current;
|
|
887
|
+
if (typeof link.logicalId === "string" && link.logicalId !== logicalId) return false;
|
|
888
|
+
if (typeof link.name === "string" && NAME_COLLISION_ERROR_NAMES.has(link.name)) return true;
|
|
889
|
+
if (depth === 0) {
|
|
890
|
+
if (isNameCollisionError(error instanceof Error && typeof link.message === "string" ? link.message : stringifyForMatch(error))) return true;
|
|
891
|
+
}
|
|
892
|
+
current = link.cause;
|
|
893
|
+
}
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
807
897
|
* Match a same-name re-creation cooldown — an AWS service still holding a
|
|
808
898
|
* resource's name while its asynchronous delete finishes. Every recognised
|
|
809
899
|
* spelling lives in {@link NAME_COOLDOWN_ERROR_MESSAGE_PATTERNS}; add new ones
|
|
@@ -24617,6 +24707,16 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
24617
24707
|
* one.
|
|
24618
24708
|
*/
|
|
24619
24709
|
producerRegionGuest = false;
|
|
24710
|
+
/**
|
|
24711
|
+
* How a producer-region guest PRINTS its own `explicitRegion` (issue
|
|
24712
|
+
* [#3150](https://github.com/go-to-k/cdkd/issues/3150)): the masked log text
|
|
24713
|
+
* its creator held for that region, which a template can assemble around a
|
|
24714
|
+
* short secret, or `***` once a later spelling of the same region masks
|
|
24715
|
+
* differently. Display only; `undefined` on an ordinary resolver, whose
|
|
24716
|
+
* region its command built (the stack's synthesized or recorded region,
|
|
24717
|
+
* `--region`, or a region read out of a literal token).
|
|
24718
|
+
*/
|
|
24719
|
+
explicitRegionLogText;
|
|
24620
24720
|
strictGetAtt;
|
|
24621
24721
|
cfnFallback;
|
|
24622
24722
|
/**
|
|
@@ -24868,18 +24968,19 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
24868
24968
|
* uppercase spelling would build a second client for the same physical
|
|
24869
24969
|
* region — benign, but wasteful and confusing in a debug log.
|
|
24870
24970
|
*/
|
|
24871
|
-
clientsForRegion(targetRegion) {
|
|
24971
|
+
clientsForRegion(targetRegion, targetLogText) {
|
|
24872
24972
|
const ambient = getAwsClients();
|
|
24873
24973
|
if (!targetRegion) return ambient;
|
|
24874
24974
|
const target = canonicalizeRegion(targetRegion);
|
|
24875
|
-
|
|
24975
|
+
const loggedTarget = targetLogText ?? (targetRegion === this.explicitRegion ? this.explicitRegionLogText : void 0) ?? target;
|
|
24976
|
+
if (!isClientSafeRegion(target)) throw new Error(`Refusing to build AWS clients for the region '${stripControlChars(loggedTarget).slice(0, 64)}': it is not a valid AWS region name, and a region is substituted into the AWS service hostname.`);
|
|
24876
24977
|
if (typeof ambient.withRegion !== "function") return ambient;
|
|
24877
24978
|
const cached = this.regionScopedClients.get(target);
|
|
24878
24979
|
if (cached) return cached;
|
|
24879
24980
|
if (canonicalizeRegion(ambient.configuredRegion) === target) return ambient;
|
|
24880
24981
|
const scoped = ambient.withRegion(target);
|
|
24881
24982
|
this.regionScopedClients.set(target, scoped);
|
|
24882
|
-
this.logger.debug(`Using region-scoped AWS clients for ${
|
|
24983
|
+
this.logger.debug(`Using region-scoped AWS clients for ${loggedTarget}`);
|
|
24883
24984
|
return scoped;
|
|
24884
24985
|
}
|
|
24885
24986
|
/**
|
|
@@ -25469,7 +25570,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25469
25570
|
return this.noteAttributeSecrecy(logicalId, attributeName, nameServers, context);
|
|
25470
25571
|
}
|
|
25471
25572
|
this.logger.debug(`Resolved Fn::GetAtt from attributes: ${logicalId}.${this.maskSecretsForLog(attributeName, context)} -> ${this.maskSecretsForLog(stringifyAttributeForLog(attributeName, this.maskValueLeaves(flatValue, context)), context)}`);
|
|
25472
|
-
if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE$1 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX) && carriesDynamicReference(flatValue)) return await this.reresolveCrossStackValue(flatValue, nestedStackChildRegionFromLocalArn(resource.physicalId), context, `nested stack ${logicalId} ${attributeName}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
|
|
25573
|
+
if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE$1 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX) && carriesDynamicReference(flatValue)) return await this.reresolveCrossStackValue(flatValue, nestedStackChildRegionFromLocalArn(resource.physicalId), context, `nested stack ${logicalId} ${this.logTextOfLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
|
|
25473
25574
|
return this.noteAttributeSecrecy(logicalId, attributeName, flatValue, context);
|
|
25474
25575
|
}
|
|
25475
25576
|
if (attributeName.includes(".")) {
|
|
@@ -25487,8 +25588,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25487
25588
|
}
|
|
25488
25589
|
}
|
|
25489
25590
|
if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE$1 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX)) {
|
|
25490
|
-
const declared = Object.keys(resource.attributes ?? {}).filter((k) => k.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX)).map((k) =>
|
|
25491
|
-
|
|
25591
|
+
const declared = Object.keys(resource.attributes ?? {}).filter((k) => k.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX)).sort().map((k) => this.maskSecretsForLog(this.outputNameLogText(k, context), context));
|
|
25592
|
+
const declaredText = declared.length > 0 ? declared.join(", ") : "(none)";
|
|
25593
|
+
throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}]: the nested stack '${logicalId}' declares no output named '${this.maskSecretsForLog(this.outputNameLogText(attributeName, context), context)}'. Its outputs are ${this.maskSecretsForLog(declaredText, context)}. Check the output name in the nested stack's template, and deploy the child stack again if you have just added it.`));
|
|
25492
25594
|
}
|
|
25493
25595
|
const value = await this.constructGuardedAttribute(resource, attributeName, context, logicalId);
|
|
25494
25596
|
this.logger.debug(`Resolved Fn::GetAtt: ${logicalId}.${this.maskSecretsForLog(attributeName, context)} -> ${this.maskSecretsForLog(stringifyAttributeForLog(attributeName, this.maskValueLeaves(value, context)), context)}`);
|
|
@@ -26775,7 +26877,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26775
26877
|
* the producer's rather than the caller's — which is exactly what issue #2057
|
|
26776
26878
|
* says the other two copies get wrong.
|
|
26777
26879
|
*/
|
|
26778
|
-
async reresolveCrossStackValue(value, producerRegion, context, origin, sourceKey, producerOutput) {
|
|
26880
|
+
async reresolveCrossStackValue(value, producerRegion, context, origin, sourceKey, producerOutput, producerRegionLogText) {
|
|
26779
26881
|
if (carriesSecretMask(value)) {
|
|
26780
26882
|
const recovered = producerOutput === void 0 || producerOutput.crossAccount === true ? void 0 : recoverMaskedOutput(producerOutput.stackName, producerOutput.region, producerOutput.outputKey);
|
|
26781
26883
|
if (recovered !== void 0) {
|
|
@@ -26791,7 +26893,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26791
26893
|
}
|
|
26792
26894
|
}
|
|
26793
26895
|
if (!carriesDynamicReference(value)) return value;
|
|
26794
|
-
const resolver = this.resolverForProducerRegion(producerRegion);
|
|
26896
|
+
const resolver = this.resolverForProducerRegion(producerRegion, context, producerRegionLogText);
|
|
26795
26897
|
const pinnedContext = producerRegion ? withoutProducerRegions(context) : context;
|
|
26796
26898
|
const walk = async (v) => {
|
|
26797
26899
|
if (typeof v === "string") return v.includes("{{resolve:") ? await resolver.resolveDynamicReferences(v, pinnedContext) : v;
|
|
@@ -26872,19 +26974,25 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26872
26974
|
if (secret) recordedSecretExpressions.add(expression);
|
|
26873
26975
|
else recordedSecretExpressions.delete(expression);
|
|
26874
26976
|
}
|
|
26875
|
-
resolverForProducerRegion(producerRegion) {
|
|
26977
|
+
resolverForProducerRegion(producerRegion, context, producerRegionLogText) {
|
|
26876
26978
|
if (!producerRegion) return this;
|
|
26877
26979
|
const target = canonicalizeRegion(producerRegion);
|
|
26878
26980
|
if (target === canonicalizeRegion(this.explicitRegion)) return this;
|
|
26981
|
+
const regionText = producerRegionLogText !== void 0 ? canonicalizeRegion(producerRegionLogText) : this.regionLogText(producerRegion, context);
|
|
26982
|
+
const guestRegionText = this.maskThenStripThenMask(regionText, context);
|
|
26879
26983
|
const cached = this.producerRegionResolvers.get(target);
|
|
26880
|
-
if (cached)
|
|
26984
|
+
if (cached) {
|
|
26985
|
+
if (cached.explicitRegionLogText !== guestRegionText) cached.explicitRegionLogText = "***";
|
|
26986
|
+
return cached;
|
|
26987
|
+
}
|
|
26881
26988
|
const scoped = new IntrinsicFunctionResolver(target, {
|
|
26882
26989
|
strictGetAtt: this.strictGetAtt,
|
|
26883
26990
|
cfnFallback: this.cfnFallback
|
|
26884
26991
|
});
|
|
26885
26992
|
scoped.producerRegionGuest = true;
|
|
26993
|
+
scoped.explicitRegionLogText = guestRegionText;
|
|
26886
26994
|
this.producerRegionResolvers.set(target, scoped);
|
|
26887
|
-
this.logger.debug(`Using a producer-region resolver for ${
|
|
26995
|
+
this.logger.debug(`Using a producer-region resolver for ${guestRegionText}`);
|
|
26888
26996
|
return scoped;
|
|
26889
26997
|
}
|
|
26890
26998
|
/**
|
|
@@ -26909,8 +27017,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26909
27017
|
}
|
|
26910
27018
|
if (entry && (!context.stackName || entry.producerStack !== context.stackName)) {
|
|
26911
27019
|
this.recordImport(context, exportName, entry.producerStack, entry.producerRegion);
|
|
26912
|
-
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from index: ${this.maskSecretsForLog(entry.producerStack, context)} / ${entry.producerRegion}; ${carriesDynamicReference(entry.value) ? "redacted dynamic reference" : "literal value"})`);
|
|
26913
|
-
return await this.reresolveCrossStackValue(entry.value, entry.producerRegion, context, `Fn::ImportValue '${exportName}' (producer ${entry.producerStack} / ${entry.producerRegion})`, sourceKey, {
|
|
27020
|
+
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from index: ${this.maskSecretsForLog(entry.producerStack, context)} / ${this.maskSecretsForLog(entry.producerRegion, context)}; ${carriesDynamicReference(entry.value) ? "redacted dynamic reference" : "literal value"})`);
|
|
27021
|
+
return await this.reresolveCrossStackValue(entry.value, entry.producerRegion, context, `Fn::ImportValue '${this.logTextOfLeaf(exportName, context)}' (producer ${this.logTextOfLeaf(entry.producerStack, context)} / ${this.logTextOfLeaf(entry.producerRegion, context)})`, sourceKey, {
|
|
26914
27022
|
stackName: entry.producerStack,
|
|
26915
27023
|
region: entry.producerRegion,
|
|
26916
27024
|
outputKey: exportName
|
|
@@ -26934,13 +27042,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26934
27042
|
}
|
|
26935
27043
|
const stateData = await context.stateBackend.getState(refStack, lookupRegion);
|
|
26936
27044
|
if (!stateData) {
|
|
26937
|
-
this.logger.debug(`No state found for stack: ${this.maskSecretsForLog(refStack, context)} (${lookupRegion})`);
|
|
27045
|
+
this.logger.debug(`No state found for stack: ${this.maskSecretsForLog(refStack, context)} (${this.maskSecretsForLog(lookupRegion, context)})`);
|
|
26938
27046
|
continue;
|
|
26939
27047
|
}
|
|
26940
27048
|
const { state } = stateData;
|
|
26941
27049
|
if (importableOutputKeys(state).includes(exportName)) {
|
|
26942
27050
|
const value = state.outputs[exportName];
|
|
26943
|
-
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from stack: ${this.maskSecretsForLog(refStack, context)} / ${lookupRegion}; ${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
27051
|
+
this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from stack: ${this.maskSecretsForLog(refStack, context)} / ${this.maskSecretsForLog(lookupRegion, context)}; ${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
26944
27052
|
if (context.exportIndex) context.exportIndex.patchEntry(exportName, {
|
|
26945
27053
|
value,
|
|
26946
27054
|
producerStack: refStack,
|
|
@@ -26961,7 +27069,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26961
27069
|
continue;
|
|
26962
27070
|
}
|
|
26963
27071
|
}
|
|
26964
|
-
if (found) return await this.reresolveCrossStackValue(found.value, found.lookupRegion, context, `Fn::ImportValue '${exportName}' (producer ${found.refStack} / ${found.lookupRegion})`, sourceKey, {
|
|
27072
|
+
if (found) return await this.reresolveCrossStackValue(found.value, found.lookupRegion, context, `Fn::ImportValue '${this.logTextOfLeaf(exportName, context)}' (producer ${this.logTextOfLeaf(found.refStack, context)} / ${this.logTextOfLeaf(found.lookupRegion, context)})`, sourceKey, {
|
|
26965
27073
|
stackName: found.refStack,
|
|
26966
27074
|
region: found.lookupRegion,
|
|
26967
27075
|
outputKey: exportName
|
|
@@ -27026,9 +27134,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27026
27134
|
* `OutputName` is the overwhelmingly common cause, and the list is what makes
|
|
27027
27135
|
* the error actionable.
|
|
27028
27136
|
*
|
|
27029
|
-
*
|
|
27030
|
-
*
|
|
27031
|
-
*
|
|
27137
|
+
* `maskSecretsForLog` reads the consumer pass's log twin first (issue #3150),
|
|
27138
|
+
* so a key equal to a name this pass assembled around a short secret is
|
|
27139
|
+
* masked. Residual, stated rather than hidden: the needles and twins belong to the
|
|
27140
|
+
* CONSUMER's resolution, so a plaintext sitting in a PRODUCER key that this
|
|
27141
|
+
* consumer never resolved is not maskable from here. The cap is what bounds that case;
|
|
27032
27142
|
* `cdkd scrub` reporting the producer's own `secretBearingKeys` is the remedy.
|
|
27033
27143
|
*/
|
|
27034
27144
|
describeAvailableOutputs(keys, context) {
|
|
@@ -27060,7 +27170,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27060
27170
|
* logged for non-not-found failures). Same graceful-degradation
|
|
27061
27171
|
* contract as {@link lookupCfnExport}.
|
|
27062
27172
|
*/
|
|
27063
|
-
async lookupCfnStackOutputs(stackName, region, context) {
|
|
27173
|
+
async lookupCfnStackOutputs(stackName, region, context, loggedRegionText) {
|
|
27064
27174
|
const cacheKey = `${region}\0${stackName}`;
|
|
27065
27175
|
let fetch = this.cfnStackOutputsCache.get(cacheKey);
|
|
27066
27176
|
if (!fetch) {
|
|
@@ -27074,7 +27184,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27074
27184
|
return await fetch;
|
|
27075
27185
|
} catch (error) {
|
|
27076
27186
|
const message = error instanceof Error ? error.message : String(error);
|
|
27077
|
-
this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${this.maskSecretsForLog(stackName, context)}' (${this.maskSecretsForLog(
|
|
27187
|
+
this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${this.maskSecretsForLog(stackName, context)}' (${this.maskSecretsForLog(loggedRegionText, context)}): ${this.maskSecretsForLog(message, context)}. Grant cloudformation:DescribeStacks to resolve outputs from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
|
|
27078
27188
|
return;
|
|
27079
27189
|
}
|
|
27080
27190
|
}
|
|
@@ -27179,12 +27289,14 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27179
27289
|
const outputName = await this.resolveValue(args["OutputName"], context);
|
|
27180
27290
|
if (typeof outputName !== "string" || outputName === "") throw new Error(`Fn::GetStackOutput: OutputName must resolve to a non-empty string, got ${typeof outputName}`);
|
|
27181
27291
|
let region = this.resolverRegion;
|
|
27292
|
+
let loggedRegionText = this.logTextOfLeaf(region, context);
|
|
27182
27293
|
if ("Region" in args && args["Region"] !== void 0 && args["Region"] !== null) {
|
|
27183
27294
|
const resolvedRegion = await this.resolveValue(args["Region"], context);
|
|
27184
27295
|
if (typeof resolvedRegion !== "string" || resolvedRegion === "") throw new Error(`Fn::GetStackOutput: Region must resolve to a non-empty string, got ${typeof resolvedRegion}`);
|
|
27185
27296
|
const requestedRegion = canonicalizeRegion(resolvedRegion);
|
|
27186
|
-
if (!isClientSafeRegion(requestedRegion)) throw new Error(`Fn::GetStackOutput: '${this.maskThenStripThenMask(resolvedRegion, context).slice(0, 64)}' is not a valid AWS region name. The region selects both the AWS endpoint and the state-file key, so cdkd will not use it.`);
|
|
27297
|
+
if (!isClientSafeRegion(requestedRegion)) throw new Error(`Fn::GetStackOutput: '${this.maskThenStripThenMask(this.logTextOfLeaf(resolvedRegion, context) !== resolvedRegion ? "***" : resolvedRegion, context).slice(0, 64)}' is not a valid AWS region name. The region selects both the AWS endpoint and the state-file key, so cdkd will not use it.`);
|
|
27187
27298
|
region = requestedRegion;
|
|
27299
|
+
loggedRegionText = this.regionLogText(resolvedRegion, context);
|
|
27188
27300
|
}
|
|
27189
27301
|
let roleArn;
|
|
27190
27302
|
if ("RoleArn" in args && args["RoleArn"] !== void 0 && args["RoleArn"] !== null) {
|
|
@@ -27192,15 +27304,15 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27192
27304
|
if (typeof raw !== "string" || raw === "") throw new Error(`Fn::GetStackOutput: RoleArn must be a literal string in the template (no Ref / Fn::GetAtt / Fn::Sub allowed for cross-account references). Got ${raw === null ? "null" : Array.isArray(raw) ? "array" : typeof raw}${typeof raw === "object" ? ` (intrinsic shape: ${JSON.stringify(raw).slice(0, 80)})` : ""}.`);
|
|
27193
27305
|
roleArn = raw;
|
|
27194
27306
|
}
|
|
27195
|
-
if (!roleArn && context.stackName && context.stackName === stackName && canonicalizeRegion(region) === canonicalizeRegion(this.resolverRegion)) throw new Error(`Fn::GetStackOutput: cannot reference own stack '${this.maskSecretsForLog(stackName, context)}' in the same region '${this.maskSecretsForLog(
|
|
27307
|
+
if (!roleArn && context.stackName && context.stackName === stackName && canonicalizeRegion(region) === canonicalizeRegion(this.resolverRegion)) throw new Error(`Fn::GetStackOutput: cannot reference own stack '${this.maskSecretsForLog(stackName, context)}' in the same region '${this.maskSecretsForLog(loggedRegionText, context)}'`);
|
|
27196
27308
|
const loggedStackName = this.maskSecretsForLog(stackName, context);
|
|
27197
27309
|
const loggedOutputName = this.maskSecretsForLog(outputName, context);
|
|
27198
|
-
const loggedRegion = this.maskSecretsForLog(
|
|
27310
|
+
const loggedRegion = this.maskSecretsForLog(loggedRegionText, context);
|
|
27199
27311
|
this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${roleArn}` : ""}`);
|
|
27200
27312
|
const stateData = roleArn ? await this.getCrossAccountStackState(roleArn, stackName, region, context) : await this.getSameAccountStackState(stackName, region, context);
|
|
27201
27313
|
if (!stateData) {
|
|
27202
27314
|
if (!roleArn && this.cfnFallback) {
|
|
27203
|
-
const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region, context);
|
|
27315
|
+
const cfnOutputs = await this.lookupCfnStackOutputs(stackName, region, context, loggedRegionText);
|
|
27204
27316
|
if (cfnOutputs) {
|
|
27205
27317
|
if (!Object.hasOwn(cfnOutputs, outputName)) {
|
|
27206
27318
|
const available = this.describeAvailableOutputs(Object.keys(cfnOutputs), context);
|
|
@@ -27222,12 +27334,12 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27222
27334
|
this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${roleArn}` : ""} (${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
|
|
27223
27335
|
if (!roleArn) this.recordOutputRead(context, stackName, region, outputName);
|
|
27224
27336
|
if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new CrossAccountSecretRefusalError(`Fn::GetStackOutput: output '${loggedOutputName}' of stack '${loggedStackName}' (${loggedRegion}) 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.`));
|
|
27225
|
-
return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput '${outputName}' (producer ${stackName} / ${
|
|
27337
|
+
return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput '${this.logTextOfLeaf(outputName, context)}' (producer ${this.logTextOfLeaf(stackName, context)} / ${loggedRegionText})`, sourceKey, {
|
|
27226
27338
|
stackName,
|
|
27227
27339
|
region,
|
|
27228
27340
|
outputKey: outputName,
|
|
27229
27341
|
...roleArn ? { crossAccount: true } : {}
|
|
27230
|
-
});
|
|
27342
|
+
}, loggedRegionText);
|
|
27231
27343
|
}
|
|
27232
27344
|
/**
|
|
27233
27345
|
* Push a resolved `Fn::GetStackOutput` into the consumer's
|
|
@@ -27365,7 +27477,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27365
27477
|
if (typeof resolvedValue !== "string") throw new Error(`Fn::Base64: value must resolve to a string, got ${typeof resolvedValue}`);
|
|
27366
27478
|
const result = Buffer.from(resolvedValue).toString("base64");
|
|
27367
27479
|
const inputLogText = this.logTextOfLeaf(resolvedValue, context);
|
|
27368
|
-
if (context.recordedSecretValues && (inputLogText !== resolvedValue || this.
|
|
27480
|
+
if (context.recordedSecretValues && (inputLogText !== resolvedValue || this.maskNeedlesForLog(resolvedValue, context) !== resolvedValue)) recordMaskOnlyValue(context.recordedSecretValues, result);
|
|
27369
27481
|
this.logger.debug(`Resolved Fn::Base64: ${this.maskSecretsForLog(inputLogText, context)} -> ${this.maskSecretsForLog(inputLogText !== resolvedValue ? "***" : result, context)}`);
|
|
27370
27482
|
return result;
|
|
27371
27483
|
}
|
|
@@ -27395,21 +27507,23 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27395
27507
|
* given explicitly (see {@link explicitRegion}).
|
|
27396
27508
|
*/
|
|
27397
27509
|
let clientRegion;
|
|
27510
|
+
let loggedRegionText;
|
|
27398
27511
|
if (typeof resolvedValue === "string" && resolvedValue !== "") {
|
|
27399
27512
|
const requested = canonicalizeRegion(resolvedValue);
|
|
27400
|
-
if (!isClientSafeRegion(requested)) throw new Error(`Fn::GetAZs: '${this.maskThenStripThenMask(resolvedValue, context).slice(0, 64)}' is not a valid AWS region name. A region is substituted into the AWS service hostname, so cdkd will not build a client from it.`);
|
|
27513
|
+
if (!isClientSafeRegion(requested)) throw new Error(`Fn::GetAZs: '${this.maskThenStripThenMask(this.logTextOfLeaf(resolvedValue, context) !== resolvedValue ? "***" : resolvedValue, context).slice(0, 64)}' is not a valid AWS region name. A region is substituted into the AWS service hostname, so cdkd will not build a client from it.`);
|
|
27401
27514
|
region = requested;
|
|
27402
27515
|
clientRegion = requested;
|
|
27516
|
+
loggedRegionText = this.regionLogText(resolvedValue, context);
|
|
27403
27517
|
} else {
|
|
27404
27518
|
region = (await getAccountInfo(this.resolverRegion)).region;
|
|
27405
27519
|
clientRegion = this.explicitRegion;
|
|
27406
27520
|
}
|
|
27407
27521
|
const cached = cachedAvailabilityZones[region];
|
|
27408
27522
|
if (cached) {
|
|
27409
|
-
this.logger.debug(`Resolved Fn::GetAZs from cache: ${this.maskSecretsForLog(region, context)} -> ${JSON.stringify(this.maskValueLeaves(cached, context))}`);
|
|
27523
|
+
this.logger.debug(`Resolved Fn::GetAZs from cache: ${this.maskSecretsForLog(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(cached, context))}`);
|
|
27410
27524
|
return cached;
|
|
27411
27525
|
}
|
|
27412
|
-
const ec2Client = this.clientsForRegion(clientRegion).ec2;
|
|
27526
|
+
const ec2Client = this.clientsForRegion(clientRegion, loggedRegionText === void 0 ? void 0 : this.maskSecretsForLog(loggedRegionText, context)).ec2;
|
|
27413
27527
|
let azNames;
|
|
27414
27528
|
try {
|
|
27415
27529
|
azNames = ((await ec2Client.send(new DescribeAvailabilityZonesCommand({ Filters: [{
|
|
@@ -27420,11 +27534,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27420
27534
|
Values: ["available"]
|
|
27421
27535
|
}] }))).AvailabilityZones || []).map((az) => az.ZoneName).filter((name) => name !== void 0).sort();
|
|
27422
27536
|
} catch (error) {
|
|
27423
|
-
throw new Error(`Fn::GetAZs: failed to describe availability zones for region '${this.maskSecretsForLog(region, context)}': ${this.maskSecretsForLog(error instanceof Error ? error.message : String(error), context)}`);
|
|
27537
|
+
throw new Error(`Fn::GetAZs: failed to describe availability zones for region '${this.maskSecretsForLog(loggedRegionText ?? region, context)}': ${this.maskSecretsForLog(error instanceof Error ? error.message : String(error), context)}`);
|
|
27424
27538
|
}
|
|
27425
|
-
if (azNames.length === 0) throw new Error(`Fn::GetAZs: no availability zones returned for region '${this.maskSecretsForLog(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.`);
|
|
27539
|
+
if (azNames.length === 0) throw new Error(`Fn::GetAZs: no availability zones returned for region '${this.maskSecretsForLog(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.`);
|
|
27426
27540
|
cachedAvailabilityZones[region] = azNames;
|
|
27427
|
-
this.logger.debug(`Resolved Fn::GetAZs: ${this.maskSecretsForLog(region, context)} -> ${JSON.stringify(this.maskValueLeaves(azNames, context))}`);
|
|
27541
|
+
this.logger.debug(`Resolved Fn::GetAZs: ${this.maskSecretsForLog(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(azNames, context))}`);
|
|
27428
27542
|
return azNames;
|
|
27429
27543
|
}
|
|
27430
27544
|
/**
|
|
@@ -27461,8 +27575,37 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27461
27575
|
* Mask any resolved secret value out of a string bound for a log line, using
|
|
27462
27576
|
* the secrets recorded on the resolution pass (GHSA fix). No-op when the pass
|
|
27463
27577
|
* recorded no secrets.
|
|
27578
|
+
*
|
|
27579
|
+
* A value with a registered LOG TWIN prints as its twin first (issue
|
|
27580
|
+
* [#3150](https://github.com/go-to-k/cdkd/issues/3150)). The needle mask
|
|
27581
|
+
* matches a secret under {@link MIN_NEEDLE_LENGTH} only as the whole text,
|
|
27582
|
+
* so a name an `Fn::Sub` assembled around a 1-3 character secret (a map key,
|
|
27583
|
+
* a stack or output name, an attribute name, the secret id of a dynamic
|
|
27584
|
+
* reference) printed in the clear at every site that handed its RAW value
|
|
27585
|
+
* here, although the pass had registered where the secret sits. Looking the
|
|
27586
|
+
* twin up HERE, rather than at each such site, is what makes the class
|
|
27587
|
+
* closed for raw values: every one of those sites already calls this method.
|
|
27588
|
+
* The twin prints as it is: it is the raw text with masked spans, so it
|
|
27589
|
+
* holds no recorded needle the raw text lacks. When the needle mask ALSO
|
|
27590
|
+
* changes the raw text the whole text is masked instead, the rule
|
|
27591
|
+
* `logTwinText` applies to a Join / Sub line, since the two masks' spans
|
|
27592
|
+
* cannot be merged. What this cannot see is a value TRANSFORMED before it
|
|
27593
|
+
* arrives (a lowercased region, a sliced output name, an assembled
|
|
27594
|
+
* sentence); those sites derive their text from the twin themselves.
|
|
27464
27595
|
*/
|
|
27465
27596
|
maskSecretsForLog(text, context) {
|
|
27597
|
+
const registered = this.registeredLogTwin(text, context);
|
|
27598
|
+
if (registered === void 0) return this.maskNeedlesForLog(text, context);
|
|
27599
|
+
return this.maskNeedlesForLog(text, context) !== text ? "***" : registered;
|
|
27600
|
+
}
|
|
27601
|
+
/**
|
|
27602
|
+
* The needle mask alone: {@link maskSecretsForLog} without the log-twin
|
|
27603
|
+
* lookup. For the two DETECTORS that must ask the needle mask apart from the
|
|
27604
|
+
* position mask: `logTwinText`, which asks it of a value that already has a
|
|
27605
|
+
* twin, and `resolveBase64`, whose other operand is the position mask. A
|
|
27606
|
+
* message masks through `maskSecretsForLog`.
|
|
27607
|
+
*/
|
|
27608
|
+
maskNeedlesForLog(text, context) {
|
|
27466
27609
|
let masked = text;
|
|
27467
27610
|
const inherited = context?.inheritedSecrets;
|
|
27468
27611
|
if (inherited && inherited.size > 0) masked = maskSecretsInText(masked, inherited);
|
|
@@ -27492,7 +27635,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27492
27635
|
* resolver's mask-coverage checker sees a masker at the site.
|
|
27493
27636
|
*/
|
|
27494
27637
|
logTwinText(result, twin, context) {
|
|
27495
|
-
return twin !== result && this.
|
|
27638
|
+
return twin !== result && this.maskNeedlesForLog(result, context) !== result ? "***" : twin;
|
|
27496
27639
|
}
|
|
27497
27640
|
/**
|
|
27498
27641
|
* The log twins of `Fn::Split`'s pieces (issue #3100), each registered for
|
|
@@ -27540,16 +27683,15 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27540
27683
|
* the leaf treated as a resolution product — masked whole when it is a
|
|
27541
27684
|
* recorded secret, otherwise the masked twin this pass registered for it —
|
|
27542
27685
|
* and then `logTwinText`'s whole-line guard. The caller still wraps the
|
|
27543
|
-
* result in `maskSecretsForLog`.
|
|
27544
|
-
*
|
|
27545
|
-
*
|
|
27546
|
-
*
|
|
27547
|
-
*
|
|
27548
|
-
*
|
|
27549
|
-
*
|
|
27550
|
-
*
|
|
27551
|
-
*
|
|
27552
|
-
* already takes for a whole secret.
|
|
27686
|
+
* result in `maskSecretsForLog`. Used where the text is needed BEFORE that
|
|
27687
|
+
* masker, or apart from it: the `Fn::Base64` line and its detector, and the
|
|
27688
|
+
* names issue [#3150](https://github.com/go-to-k/cdkd/issues/3150)
|
|
27689
|
+
* transforms or composes before printing (`regionLogText`,
|
|
27690
|
+
* `outputNameLogText`, the invalid-region refusals, the cross-stack `origin`
|
|
27691
|
+
* strings). A leaf printed as it is needs none of it: `maskSecretsForLog`
|
|
27692
|
+
* looks the twin up itself, which is how `maskValueLeaves` gives its lines
|
|
27693
|
+
* and the THROWN messages it masks (the `Fn::Cidr` argument refusals, for
|
|
27694
|
+
* one) the same position mask.
|
|
27553
27695
|
*/
|
|
27554
27696
|
logTextOfLeaf(value, context) {
|
|
27555
27697
|
return this.logTwinText(value, this.logTwinOfProduct({
|
|
@@ -27557,6 +27699,85 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27557
27699
|
twin: value
|
|
27558
27700
|
}, context).twin, context);
|
|
27559
27701
|
}
|
|
27702
|
+
/**
|
|
27703
|
+
* The log text of a nested stack's OUTPUT name, the part of `attributeName`
|
|
27704
|
+
* after `Outputs.` (issue [#3150](https://github.com/go-to-k/cdkd/issues/3150)).
|
|
27705
|
+
* The twin registry is keyed by the exact string, so the suffix has no twin
|
|
27706
|
+
* of its own: it is sliced from the twin of the WHOLE attribute name. A twin
|
|
27707
|
+
* that no longer starts with the literal prefix has a mask over part of it
|
|
27708
|
+
* (a secret was written into the prefix), so the slice offset no longer
|
|
27709
|
+
* lines up and the suffix prints as `***`.
|
|
27710
|
+
*/
|
|
27711
|
+
outputNameLogText(attributeName, context) {
|
|
27712
|
+
const twin = this.logTextOfLeaf(attributeName, context);
|
|
27713
|
+
return twin.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX) ? twin.slice(8) : "***";
|
|
27714
|
+
}
|
|
27715
|
+
/**
|
|
27716
|
+
* The log text of a template-supplied REGION as the resolver uses it, i.e.
|
|
27717
|
+
* after `canonicalizeRegion` (issue #3150). The twin is taken from the RAW
|
|
27718
|
+
* value, the string a write registered, and lowercased the same way: a
|
|
27719
|
+
* lookup of the canonical form finds no twin once the raw value had an
|
|
27720
|
+
* upper-case part, and lowercasing leaves every `***` span where it was.
|
|
27721
|
+
*/
|
|
27722
|
+
regionLogText(rawRegion, context) {
|
|
27723
|
+
const canonical = canonicalizeRegion(rawRegion);
|
|
27724
|
+
const text = canonicalizeRegion(this.logTextOfLeaf(rawRegion, context));
|
|
27725
|
+
return text !== canonical && this.maskNeedlesForLog(canonical, context) !== canonical ? "***" : text;
|
|
27726
|
+
}
|
|
27727
|
+
/**
|
|
27728
|
+
* The log text of a name or token whose `twin` masks spans of `raw` (issue
|
|
27729
|
+
* [#3150](https://github.com/go-to-k/cdkd/issues/3150)). The twin prints
|
|
27730
|
+
* unless the needle mask ALSO changes `raw`; then the two must agree. When
|
|
27731
|
+
* the needle-masked `raw` IS the twin, both masked the same spans and the
|
|
27732
|
+
* twin is safe (`/probe/***` for a 4+ character secret the name holds
|
|
27733
|
+
* whole). When they differ, a recorded secret straddles a masked span
|
|
27734
|
+
* (`q7ab` across `id-***ab`), no text can honour both, and the name prints
|
|
27735
|
+
* as `***`. Coarser `logTwinText` gives up whenever both masks fire.
|
|
27736
|
+
*/
|
|
27737
|
+
straddleSafeTwin(raw, twin, context) {
|
|
27738
|
+
if (twin === raw) return twin;
|
|
27739
|
+
const needled = this.maskNeedlesForLog(raw, context);
|
|
27740
|
+
if (needled === raw) return twin;
|
|
27741
|
+
return needled === twin ? twin : "***";
|
|
27742
|
+
}
|
|
27743
|
+
/**
|
|
27744
|
+
* The log text of a name parsed out of a dynamic-reference token (issue
|
|
27745
|
+
* [#3150](https://github.com/go-to-k/cdkd/issues/3150)). `resolveSub` /
|
|
27746
|
+
* `resolveJoin` re-enter the dynamic-reference loop with the ASSEMBLED string
|
|
27747
|
+
* and its twin, so a secret id, JSON key, version stage or id, SSM parameter
|
|
27748
|
+
* name, service or ARN region assembled around a short secret has its masked
|
|
27749
|
+
* spelling in `tokenTwin` only. Every such name is a run of the token's
|
|
27750
|
+
* `:`-separated pieces, so its log text is the twin's run over the same
|
|
27751
|
+
* pieces. Nothing is registered: the pass's log-twin registry also decides
|
|
27752
|
+
* what `Fn::Base64` persists, so the mapping lives in the returned function.
|
|
27753
|
+
*
|
|
27754
|
+
* `tokenTwin` is the twin's own `{{resolve:...}}` token paired with this one.
|
|
27755
|
+
* Each run's text goes through `straddleSafeTwin`, so a name whose needle
|
|
27756
|
+
* mask disagrees with its twin prints as `***`. A name whose runs carry different
|
|
27757
|
+
* twins, or a token whose pieces do not pair with the twin's (a mask
|
|
27758
|
+
* covering a `:`), prints as `***` too.
|
|
27759
|
+
*
|
|
27760
|
+
* A name that is no run of the token is a default the caller synthesized
|
|
27761
|
+
* (`AWSCURRENT` for an empty version stage, `''` for an absent version id),
|
|
27762
|
+
* printed as it is. Should the token spell such a non-empty name inside a longer
|
|
27763
|
+
* piece, it prints as `***`: the run rule says nothing about that text.
|
|
27764
|
+
*/
|
|
27765
|
+
dynamicReferenceNameLogText(inner, tokenTwin, context) {
|
|
27766
|
+
const twinPieces = tokenTwin.slice(10, -2).split(":");
|
|
27767
|
+
const pieces = inner.split(":");
|
|
27768
|
+
if (twinPieces.length !== pieces.length) return () => "***";
|
|
27769
|
+
return (name) => {
|
|
27770
|
+
let text;
|
|
27771
|
+
for (let start = 0; start < pieces.length; start++) for (let end = start + 1; end <= pieces.length; end++) {
|
|
27772
|
+
if (pieces.slice(start, end).join(":") !== name) continue;
|
|
27773
|
+
const twin = this.straddleSafeTwin(name, twinPieces.slice(start, end).join(":"), context);
|
|
27774
|
+
if (text !== void 0 && text !== twin) return "***";
|
|
27775
|
+
text = twin;
|
|
27776
|
+
break;
|
|
27777
|
+
}
|
|
27778
|
+
return text ?? (name !== "" && inner.includes(name) ? "***" : name);
|
|
27779
|
+
};
|
|
27780
|
+
}
|
|
27560
27781
|
/** The bag a pass's log twins are keyed by (issue #3100): the recorded one, else the inherited one. */
|
|
27561
27782
|
logTwinBag(context) {
|
|
27562
27783
|
return context?.recordedSecretValues ?? context?.inheritedSecrets;
|
|
@@ -27692,7 +27913,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27692
27913
|
maskValueLeaves(value, context) {
|
|
27693
27914
|
const done = /* @__PURE__ */ new Map();
|
|
27694
27915
|
const walk = (node) => {
|
|
27695
|
-
if (typeof node === "string") return this.maskSecretsForLog(
|
|
27916
|
+
if (typeof node === "string") return this.maskSecretsForLog(node, context);
|
|
27696
27917
|
if (node === null || typeof node !== "object") return node;
|
|
27697
27918
|
const memo = done.get(node);
|
|
27698
27919
|
if (memo !== void 0) return memo;
|
|
@@ -27704,7 +27925,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27704
27925
|
}
|
|
27705
27926
|
const out = Object.create(null);
|
|
27706
27927
|
done.set(node, out);
|
|
27707
|
-
for (const [key, child] of Object.entries(node)) out[this.maskSecretsForLog(
|
|
27928
|
+
for (const [key, child] of Object.entries(node)) out[this.maskSecretsForLog(key, context)] = walk(child);
|
|
27708
27929
|
return out;
|
|
27709
27930
|
};
|
|
27710
27931
|
return walk(value);
|
|
@@ -27731,14 +27952,14 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27731
27952
|
* visible. The FIRST mask is demonstrated by a test: deleting it (masking
|
|
27732
27953
|
* only after the strip) reds the split-needle case, because the recorded
|
|
27733
27954
|
* needle is then the split form and the strip has destroyed it. The SECOND
|
|
27734
|
-
* mask
|
|
27735
|
-
*
|
|
27736
|
-
*
|
|
27737
|
-
*
|
|
27738
|
-
*
|
|
27739
|
-
*
|
|
27740
|
-
*
|
|
27741
|
-
*
|
|
27955
|
+
* mask earns its place when the bag holds a needle that is the STRIPPED form
|
|
27956
|
+
* of the text in hand. A value this resolver resolved cannot be that text
|
|
27957
|
+
* (the split copy is itself recorded, so the first mask catches it), but a
|
|
27958
|
+
* template LITERAL can: issue #3150's region-scoped clients refusal prints
|
|
27959
|
+
* a producer-region guest's region through this helper, and a literal ARN
|
|
27960
|
+
* region spelling a recorded `st-1` as `s` + U+0001 + `t-1` is masked only
|
|
27961
|
+
* by the second pass (`intrinsic-resolver-name-argument-log-twin.test.ts`
|
|
27962
|
+
* pins both halves on that route).
|
|
27742
27963
|
*
|
|
27743
27964
|
* THE BOUND, since this file's job is to state them: this covers a needle
|
|
27744
27965
|
* split by a character `stripControlChars` removes. A needle split by
|
|
@@ -27772,7 +27993,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27772
27993
|
* NEEDLE match that straddles a masked span, which is why the log lines go
|
|
27773
27994
|
* through `logTwinText` rather than masking the twin alone.
|
|
27774
27995
|
*/
|
|
27775
|
-
async resolveDynamicReferencesWithLogTwin(value, logTwin, context) {
|
|
27996
|
+
async resolveDynamicReferencesWithLogTwin(value, logTwin, context, inherited) {
|
|
27776
27997
|
const pattern = /\{\{resolve:([^}]+)\}\}/g;
|
|
27777
27998
|
let result = value;
|
|
27778
27999
|
let twin = logTwin;
|
|
@@ -27782,14 +28003,22 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27782
28003
|
fullMatch: match[0],
|
|
27783
28004
|
inner: match[1]
|
|
27784
28005
|
});
|
|
27785
|
-
|
|
28006
|
+
const twinTokens = dynamicReferenceTokens(logTwin);
|
|
28007
|
+
const tokensAligned = twinTokens.length === matches.length;
|
|
28008
|
+
for (const [index, { fullMatch, inner }] of matches.entries()) {
|
|
27786
28009
|
const service = inner.split(":")[0];
|
|
28010
|
+
const pairedTwin = tokensAligned ? twinTokens[index] : void 0;
|
|
28011
|
+
const tokenLogText = inherited?.tokenLogText ?? (pairedTwin === void 0 ? "***" : this.straddleSafeTwin(fullMatch, pairedTwin, context));
|
|
28012
|
+
const nameLogText = inherited?.nameLogText ?? (pairedTwin === void 0 ? () => "***" : this.dynamicReferenceNameLogText(inner, pairedTwin, context));
|
|
27787
28013
|
const isKnownSecret = service === "secretsmanager" || service === "ssm-secure" || recordedSecretExpressions.has(fullMatch);
|
|
27788
28014
|
if (isKnownSecret && context?.skipDynamicReferences) continue;
|
|
27789
28015
|
const regionVerdict = classifyReplaySecretRegion(fullMatch, this.explicitRegion ?? this.resolverRegion, context?.producerRegions);
|
|
27790
|
-
if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${this.maskSecretsForLog(
|
|
28016
|
+
if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${this.maskSecretsForLog(tokenLogText, context)}: it names '${this.maskSecretsForLog(nameLogText(regionVerdict.secretName), context)}' without a region, and this stack reads from ${this.maskSecretsForLog(regionVerdict.foreignProducerRegions.map((r) => this.maskSecretsForLog(r, context)).join(", "), context)} as well as its own region. cdkd cannot tell which one must answer, and resolving against the wrong one yields a different secret. Spell the reference as a full ARN to say which region owns it.`));
|
|
27791
28017
|
if (regionVerdict.kind === "named-region") {
|
|
27792
|
-
const foreign = await this.resolverForProducerRegion(regionVerdict.region).resolveDynamicReferencesWithLogTwin(fullMatch, fullMatch, withoutProducerRegions(context)
|
|
28018
|
+
const foreign = await this.resolverForProducerRegion(regionVerdict.region, context, nameLogText(regionVerdict.region)).resolveDynamicReferencesWithLogTwin(fullMatch, fullMatch, withoutProducerRegions(context), {
|
|
28019
|
+
tokenLogText,
|
|
28020
|
+
nameLogText
|
|
28021
|
+
});
|
|
27793
28022
|
result = result.replace(fullMatch, () => foreign.result);
|
|
27794
28023
|
twin = twin.replace(fullMatch, () => foreign.twin);
|
|
27795
28024
|
continue;
|
|
@@ -27820,10 +28049,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27820
28049
|
* which caches nothing (issue #1933).
|
|
27821
28050
|
*/
|
|
27822
28051
|
let cacheable = true;
|
|
27823
|
-
if (service === "secretsmanager") resolved = await this.resolveSecretsManagerReference(inner, context);
|
|
28052
|
+
if (service === "secretsmanager") resolved = await this.resolveSecretsManagerReference(inner, context, nameLogText);
|
|
27824
28053
|
else if (service === "ssm") {
|
|
27825
28054
|
const decrypt = context?.skipDynamicReferences !== true;
|
|
27826
|
-
const param = await this.resolveSSMReference(parts, decrypt, "ssm", context);
|
|
28055
|
+
const param = await this.resolveSSMReference(parts, decrypt, "ssm", context, nameLogText);
|
|
27827
28056
|
if (param.type === "SecureString") this.pinSecretVerdict(fullMatch, true);
|
|
27828
28057
|
else if (!param.secure) this.pinSecretVerdict(fullMatch, false);
|
|
27829
28058
|
else cacheable = false;
|
|
@@ -27833,12 +28062,12 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27833
28062
|
}
|
|
27834
28063
|
resolved = param.value;
|
|
27835
28064
|
} else if (service === "ssm-secure") {
|
|
27836
|
-
const param = await this.resolveSSMReference(parts, true, "ssm-secure", context);
|
|
27837
|
-
if (!param.secure) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to resolve ${this.maskSecretsForLog(
|
|
28065
|
+
const param = await this.resolveSSMReference(parts, true, "ssm-secure", context, nameLogText);
|
|
28066
|
+
if (!param.secure) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to resolve ${this.maskSecretsForLog(tokenLogText, context)}: the parameter is a ${param.type} parameter, and the ssm-secure spelling is defined for SecureString parameters only. Reference it as {{resolve:ssm:...}} if it is public configuration.`));
|
|
27838
28067
|
isSecret = true;
|
|
27839
28068
|
resolved = param.value;
|
|
27840
28069
|
} else {
|
|
27841
|
-
this.logger.warn(this.maskSecretsForLog(`Unsupported dynamic reference service: ${service}`, context));
|
|
28070
|
+
this.logger.warn(this.maskSecretsForLog(`Unsupported dynamic reference service: ${this.maskSecretsForLog(nameLogText(String(service)), context)}`, context));
|
|
27842
28071
|
continue;
|
|
27843
28072
|
}
|
|
27844
28073
|
if (cacheable) this.cachedDynamicReferences.set(fullMatch, {
|
|
@@ -27874,7 +28103,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27874
28103
|
* runs when no mid-string ":SecretString:" delimiter is present, so the json-key / version
|
|
27875
28104
|
* forms are unaffected.)
|
|
27876
28105
|
*/
|
|
27877
|
-
async resolveSecretsManagerReference(inner, context) {
|
|
28106
|
+
async resolveSecretsManagerReference(inner, context, nameLogText) {
|
|
27878
28107
|
const afterService = inner.substring(15);
|
|
27879
28108
|
let secretId;
|
|
27880
28109
|
let jsonKey = "";
|
|
@@ -27903,9 +28132,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
27903
28132
|
} else secretId = afterService;
|
|
27904
28133
|
if (!versionStage) versionStage = "AWSCURRENT";
|
|
27905
28134
|
if (!secretId) throw new Error("Dynamic reference: secretsmanager SECRET_ID is required");
|
|
27906
|
-
const loggedSecretId = this.maskSecretsForLog(secretId, context);
|
|
27907
|
-
const loggedJsonKey = this.maskSecretsForLog(jsonKey, context);
|
|
27908
|
-
this.logger.debug(`Resolving dynamic reference: secretsmanager:${loggedSecretId}:SecretString:${loggedJsonKey}:${this.maskSecretsForLog(versionStage, context)}:${this.maskSecretsForLog(versionId, context)}`);
|
|
28135
|
+
const loggedSecretId = this.maskSecretsForLog(nameLogText(secretId), context);
|
|
28136
|
+
const loggedJsonKey = this.maskSecretsForLog(nameLogText(jsonKey), context);
|
|
28137
|
+
this.logger.debug(`Resolving dynamic reference: secretsmanager:${loggedSecretId}:SecretString:${loggedJsonKey}:${this.maskSecretsForLog(nameLogText(versionStage), context)}:${this.maskSecretsForLog(nameLogText(versionId), context)}`);
|
|
27909
28138
|
const client = this.clientsForRegion(this.explicitRegion).secretsManager;
|
|
27910
28139
|
const command = new GetSecretValueCommand({
|
|
27911
28140
|
SecretId: secretId,
|
|
@@ -28066,10 +28295,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
28066
28295
|
* discard the value when `secure` is set — it is ciphertext, not the resolved
|
|
28067
28296
|
* reference.
|
|
28068
28297
|
*/
|
|
28069
|
-
async resolveSSMReference(parts, decrypt
|
|
28298
|
+
async resolveSSMReference(parts, decrypt, service, context, nameLogText) {
|
|
28070
28299
|
const parameterName = parts.slice(1).join(":");
|
|
28071
28300
|
if (!parameterName) throw new Error(`Dynamic reference: ${service} PARAMETER_NAME is required`);
|
|
28072
|
-
const loggedParameterName = this.maskSecretsForLog(parameterName, context);
|
|
28301
|
+
const loggedParameterName = this.maskSecretsForLog(nameLogText(parameterName), context);
|
|
28073
28302
|
this.logger.debug(`Resolving dynamic reference: ${service}:${loggedParameterName}`);
|
|
28074
28303
|
const client = this.clientsForRegion(this.explicitRegion).ssm;
|
|
28075
28304
|
const command = new GetParameterCommand({
|
|
@@ -29421,7 +29650,7 @@ var CloudControlProvider = class {
|
|
|
29421
29650
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
29422
29651
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
29423
29652
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
29424
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
29653
|
+
const { ASGProvider } = await import("./asg-provider-BAYjqZuM.js").then((n) => n.n);
|
|
29425
29654
|
const asgProvider = new ASGProvider();
|
|
29426
29655
|
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
29427
29656
|
}
|
|
@@ -38122,7 +38351,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
38122
38351
|
});
|
|
38123
38352
|
} catch (createError) {
|
|
38124
38353
|
const msg = createError instanceof Error ? createError.message : String(createError);
|
|
38125
|
-
if (!
|
|
38354
|
+
if (!isNameCollisionErrorFrom(createError, op.logicalId)) throw createError;
|
|
38126
38355
|
if (rollbackRetainsNewResource(current)) throw markNonRetryable(new CdkdError(maskSecretsInText(`Cannot reverse the replacement of ${safe(op.logicalId)} (${safe(op.resourceType)}): the re-create of the old resource (${safe(prev.physicalId)}) collided with the name still held by the new one (${safe(current.physicalId)}), and UpdateReplacePolicy: Retain pins that new resource in place, so cdkd will not delete it to free the name. Delete the new resource yourself, or remove UpdateReplacePolicy: Retain, then re-run \`cdkd rollback\` — the journal is kept, so the revert resumes from here. To leave THIS resource alone and let the rest of the rollback proceed, re-run with ` + (typeof op.logicalId === "string" && PASTEABLE_LOGICAL_ID.test(op.logicalId) ? `\`cdkd rollback --orphan ${op.logicalId}\`: one op failure stops the ` : "`cdkd rollback --orphan <id>` (the id is withheld: it is not a plain CloudFormation logical id, so a pasted command could be reshaped by the shell or name a different resource -- read it from `cdkd events`): one op failure stops the ") + `segment loop, so a single pinned resource otherwise halts every OLDER segment too. Underlying collision: ${displaySafe(msg)}`, secrets), "NAMED_REPLACEMENT_COLLISION", maskSecretsInError(createError instanceof Error ? createError : void 0, secrets)));
|
|
38127
38356
|
logger.info(` Rollback: re-create collided with the new resource's name — deleting the new resource (${displaySafe(current.physicalId)}) first...`);
|
|
38128
38357
|
{
|
|
@@ -41259,7 +41488,7 @@ var DeployEngine = class DeployEngine {
|
|
|
41259
41488
|
createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replaceProvider.create(logicalId, resourceType, replaceProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replaceProvider);
|
|
41260
41489
|
} catch (createError) {
|
|
41261
41490
|
const createMsg = createError instanceof Error ? createError.message : String(createError);
|
|
41262
|
-
if (!
|
|
41491
|
+
if (!isNameCollisionErrorFrom(createError, logicalId)) throw createError;
|
|
41263
41492
|
const nameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
|
|
41264
41493
|
if (updateReplacePolicy === "Retain") throw new CdkdError(`${logicalId} (${resourceType}) requires replacement, but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. ${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed.`, "NAMED_REPLACEMENT_COLLISION");
|
|
41265
41494
|
if (this.options.replace !== true) throw new CdkdError(`${logicalId} (${resourceType}) requires replacement, but the create-first attempt collided with the existing resource: ${createMsg}. ${nameOrigin.descriptor}, so the CloudFormation-style safe replacement order (create the new resource before deleting the old) cannot reuse the occupied name — CloudFormation refuses this shape with "cannot update a stack when a custom-named resource requires replacing". ${nameOrigin.remedy}, or re-run with \`cdkd deploy --replace\` to delete the old resource FIRST and recreate it under the same name (the resource is briefly unavailable while it is recreated).`, "NAMED_REPLACEMENT_COLLISION");
|
|
@@ -41395,8 +41624,7 @@ var DeployEngine = class DeployEngine {
|
|
|
41395
41624
|
createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replProvider);
|
|
41396
41625
|
} catch (createError) {
|
|
41397
41626
|
if (!retainOldOnReplace) throw new Error(maskSecretsInText(`Failed to create ${logicalId} after the UPDATE-not-supported replacement: the old resource (${currentResource.physicalId}) is now gone. Cause: ${createError instanceof Error ? createError.message : String(createError)}. Re-run the deploy to create it fresh.`, updateSecrets), { cause: createError instanceof Error ? createError : void 0 });
|
|
41398
|
-
|
|
41399
|
-
if (!isNameCollisionError(createMsg)) throw createError;
|
|
41627
|
+
if (!isNameCollisionErrorFrom(createError, logicalId)) throw createError;
|
|
41400
41628
|
const nameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
|
|
41401
41629
|
throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement because the provisioning layer cannot update it in place — but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. ${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed. Removing UpdateReplacePolicy: Retain lets cdkd delete the old resource first, which destroys it and any data it holds.`, "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
|
|
41402
41630
|
}
|
|
@@ -41680,7 +41908,7 @@ var DeployEngine = class DeployEngine {
|
|
|
41680
41908
|
if (!(error instanceof ProvisioningError)) return void 0;
|
|
41681
41909
|
const physicalId = error.physicalId;
|
|
41682
41910
|
if (!physicalId) return void 0;
|
|
41683
|
-
if (!
|
|
41911
|
+
if (!isNameCollisionErrorFrom(error, logicalId)) return void 0;
|
|
41684
41912
|
const stackName = getCurrentStackName();
|
|
41685
41913
|
if (!looksLikeCdkdGeneratedName(physicalId, logicalId, stackName)) return void 0;
|
|
41686
41914
|
if (!stackName) return void 0;
|
|
@@ -42151,4 +42379,4 @@ var DeployEngine = class DeployEngine {
|
|
|
42151
42379
|
|
|
42152
42380
|
//#endregion
|
|
42153
42381
|
export { secretBearing as $, BOOTSTRAP_MARKER_PREFIX as $n, getAwsClients as $r, s3BucketRegionalDomainName as $t, extractDeploymentEventError as A, markNonRetryable as Ai, buildForceUnlockCommand as An, resolveAutoAssetStorage as Ar, parameterTypeMayLoseSecretIdentity as At, toCfnInteger as B, importableOutputs as Bn, MIGRATE_TMP_PREFIX as Br, configIntegerRefusal as Bt, buildFinalSnapshotIdentifier as C, isCdkdError as Ci, recordMaskOnlyValue as Cn, AssetManifestLoader as Cr, IntrinsicFunctionResolver as Ct, refusesFinalSnapshot as D, isRetryableTransientError as Di, LockManager as Dn, getDefaultStateBucketName as Dr, getAccountInfo as Dt, isFinalSnapshotError as E, isMarkedNonRetryable as Ei, scrubResourceRecord as En, synthesisStatusMessage as Er, coerceParameterTypedValue as Et, isStatefulRecreateTargetSync as F, CUSTOM_RESOURCE_RESPONSE_PREFIX as Fn, resolveUseCdkBootstrapAssets as Fr, resolveExplicitPhysicalId as Ft, gray as G, AssetPublisher as Gn, PARTITION_TABLE as Gr, requireConfigObject as Gt, formatResourceLine as H, orphansAfterRollback as Hn, uploadCfnTemplate as Hr, readConfigString as Ht, renderStatefulReason as I, DEFAULT_STATE_PREFIX as In, stateBucketExistenceConfirmed as Ir, assertRegionMatch as It, yellow as J, buildAssetRedirectMap as Jn, AssemblyReader as Jr, producerRegionsFromState as Jt, green as K, stringifyValue as Kn, canonicalizeRegion as Kr, requireConfigString as Kt, WARM_THROUGHPUT_MEMBERS as L, exportNamesCarriedFrom as Ln, warnDeprecatedNoPrefixCliFlag as Lr, coerceCfnBoolean as Lt, planOrphanAdoption as M, retryClassificationText as Mi, forceQuitRecoveryClause as Mn, resolveSkipPrefix as Mr, isSettledInstanceState as Mt, MULTI_REGION_RECREATE_BLOCKED_TYPES as N, __exportAll as Ni, formatLockExpiry as Nn, resolveStateBucketWithDefault as Nr, WAFv2WebACLProvider as Nt, unsupportedFinalSnapshotError as O, isThrottlingError as Oi, S3StateBackend as On, getLegacyStateBucketName as Or, isImpossibleEmptyStoredAttribute as Ot, isStatefulRecreateTargetForReplace as P, shellQuote as Pn, resolveStateBucketWithDefaultAndSource as Pr, normalizeAwsTagsToCfn as Pt, isExportAliasCollision as Q, AssetModeResolver as Qn, AwsClients as Qr, s3BucketDualStackDomainName as Qt, coerceWarmThroughput as R, hasReadableExportSet as Rn, CFN_TEMPLATE_BODY_LIMIT as Rr, coerceCfnInteger as Rt, PRE_DELETE_SNAPSHOT_TYPES as S, formatError as Si, maskSecretsInText as Sn, stripControlChars as Sr, isTerminationProtectionPropagationError as St, createPreDeleteFinalSnapshot as T, withErrorHandling as Ti, redactSecretsForState as Tn, Synthesizer as Tr, cfnRefValueFromPhysicalId as Tt, bold as U, orphansCarriedFrom as Un, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Ur, replayWarn as Ut, toFiniteNumber as V, isReadableBag as Vn, findLargeInlineResources as Vr, configStringRefusal as Vt, cyan as W, shouldRetainResource as Wn, expectedOwnerParam as Wr, requireConfigArray as Wt, collectPublishedOutputNames as X, loadPublishableAssetManifest as Xn, clearBucketRegionCache as Xr, s3BucketArn as Xt, collectDeclaredOutputNames as Y, createAssetRedirectResolver as Yn, processStackMessages as Yr, withSharedDrainBudget as Yt, exportAliasCollisionScrubWarning as Z, rewriteTemplateAssetReferences as Zn, resolveBucketRegion as Zr, s3BucketDomainName as Zt, isSecretBearingReferenceString as _, ResourceUpdateNotSupportedError as _i, errorCauseChain as _n, partitionSensitiveEnv as _r, slowCcOperationTimeoutMs as _t, DeploymentEventsStore as a, CrossAccountSecretRefusalError as ai, findSilentDropProperties as an, readBootstrapMarkerBody as ar, clearOnUpdateRemoval as at, bindingSkippedOutputs as b, StateError as bi, markSameGenerationBag as bn, runDockerStreaming as br, deleteSkipReason as bt, replayFailedOperations as c, DynamicReferenceRegionAmbiguousError as ci, DagBuilder as cn, buildDenyExternalAccessPolicy as cr, createMaskedRetryLogger as ct, updatePartialReason as d, LocalStartServiceError as di, STATE_SOURCED_CROSS_GENERATION_RULES as dn, describeDockerCapturedOutput as dr, beginCommandInterruptScope as dt, resetAwsClients as ei, s3BucketWebsiteUrl as en, assertAssetBucketRegion as er, secretBearingStateKeyWarning as et, withResourceDeadline as f, LockError as fi, STATE_SOURCED_READBACK_RULES as fn, describeDockerExecFailure as fr, endCommandInterruptScope as ft, bagHoldsSecretExpression as g, ResourceTimeoutError as gi, dynamicReferenceTokens as gn, getDockerCmd as gr, CloudControlProvider as gt, computeImplicitDeleteEdges as h, ProvisioningError as hi, createSecretMasker as hn, formatDockerLoginError as hr, startInterruptWatch as ht, DeploymentEventsReader as i, ConfigError as ii, findActionableSilentDrops as in, parseBootstrapMarker as ir, collectInlinePolicyNamesManagedBySiblings as it, makeSiblingClaimReader as j, markRedactedCause as ji, buildLockContentionMessage as jn, resolveCaptureObservedState as jr, refStateLookupFromResource as jt, makeCanonicalizePropertiesFn as k, isTransientServerError as ki, rebuildClientForBucketRegion as kn, resolveApp as kr, isUnboundTemplateParameter as kt, replayRollback as l, IntrinsicResolutionRefusalError as li, TemplateParser as ln, describeAwsFailure as lr, maskDeep as lt, IMPLICIT_DELETE_DEPENDENCIES as m, PartialFailureError as mi, carriesSecretMask as mn, dockerSpawnEnvWithSensitive as mr, isInterruptedWaitError as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, AssetError as ni, DiffCalculator as nn, getBootstrapMarkerKey as nr, getCurrentResourceSecrets as nt, planFailedOps as o, DependencyError as oi, describeTypeWithThrottleRetry as on, validateAssetBucketName as or, ProviderRegistry as ot, maskingRetryLogger as p, NestedStackChildDirectDestroyError as pi, TEMPLATE_SOURCED_RULES as pn, describeDockerFailure as pr, interruptWatchListenerCount as pt, red as q, WorkGraph as qn, derivePartitionAndUrlSuffix as qr, classifyReplaySecretRegion as qt, DeployEngine as r, CdkdError as ri, INTRINSIC_KEYS as rn, isCrossRegionRedirect as rr, IAMRoleProvider as rt, planRollback as s, DeployCancelledError as si, withRetry as sn, validateContainerRepoName as sr, wouldReturnToSdkProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, setAwsClients as ti, applyRoleArnIfSet as tn, ensureAssetStorage as tr, secretSafeKeyDisplay as tt, updatePartialMessage as u, LocalInvokeBuildError as ui, STATE_SOURCED_BASELINE_RULES as un, buildDockerImage as ur, maskerOrIdentity as ut, keptWholeReasonText as v, StackHasActiveImportsError as vi, identityKeyFor as vn, redactDockerArgvValues as vr, UNSPECIFIED_SKIP_REASON as vt, ccRoutedFinalSnapshotError as w, normalizeAwsError as wi, recoverMaskedOutput as wn, getDockerImageBySourceHash as wr, carriesDynamicReference as wt, ATOMIC_FINAL_SNAPSHOT_TYPES as x, SynthesisError as xi, maskSecretsInError as xn, escapeRegExp$1 as xr, disableInstanceApiTermination as xt, mergeNoChangeOutputs as y, StackTerminationProtectionError as yi, isSingleDynamicReferenceToken as yn, runDockerForeground as yr, deleteIndeterminateGuards as yt, isWarmThroughputDecrease as z, importableOutputKeys as zn, CFN_TEMPLATE_URL_LIMIT as zr, configBooleanRefusal as zt };
|
|
42154
|
-
//# sourceMappingURL=deploy-engine-
|
|
42382
|
+
//# sourceMappingURL=deploy-engine-v7h1H_Ac.js.map
|