@go-to-k/cdkd 0.284.62 → 0.284.64
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-BfX7AwFi.js → asg-provider-DGJz_iFy.js} +2 -2
- package/dist/{asg-provider-BfX7AwFi.js.map → asg-provider-DGJz_iFy.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-D8AIgkwy.js → deploy-engine-BtqjWvh5.js} +383 -32
- package/dist/deploy-engine-BtqjWvh5.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-XLMSMzWe.js → program-I-xR_ceK.js} +167 -32
- package/dist/{program-XLMSMzWe.js.map → program-I-xR_ceK.js.map} +1 -1
- package/dist/{version-DoW7XkO0.js → version-BtSUTHs5.js} +2 -2
- package/dist/{version-DoW7XkO0.js.map → version-BtSUTHs5.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-D8AIgkwy.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { a as getLiveRenderer, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, l as applyDefaultNameForFallback, n as getLogger, p as looksLikeCdkdGeneratedName, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
2
|
-
import { t as getCdkdVersion } from "./version-
|
|
2
|
+
import { t as getCdkdVersion } from "./version-BtSUTHs5.js";
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
5
6
|
import { CloudControlClient, CreateResourceCommand, DeleteResourceCommand, GetResourceCommand, GetResourceRequestStatusCommand, ListResourcesCommand, UpdateResourceCommand } from "@aws-sdk/client-cloudcontrol";
|
|
@@ -11709,6 +11710,10 @@ function literalStringOrUndefined(value) {
|
|
|
11709
11710
|
* (`(producer X / Y)`), so it is neither derivable from the source leaf nor
|
|
11710
11711
|
* stable.
|
|
11711
11712
|
*
|
|
11713
|
+
* THREE arms answer: `Fn::ImportValue`, `Fn::GetStackOutput`, and the
|
|
11714
|
+
* `Fn::GetAtt` on a nested-stack OUTPUT that issue #2055's read site
|
|
11715
|
+
* re-resolves. Every other leaf refuses.
|
|
11716
|
+
*
|
|
11712
11717
|
* `Region` and `RoleArn` are OPTIONAL slots, and an ABSENT one keys as empty
|
|
11713
11718
|
* while a PRESENT-but-non-literal one refuses. Absent has to be its own key
|
|
11714
11719
|
* rather than being filled in with the resolver's own region: the persist path
|
|
@@ -11767,6 +11772,26 @@ function crossStackSourceKey(source) {
|
|
|
11767
11772
|
}
|
|
11768
11773
|
return slots.join(CROSS_STACK_KEY_SEPARATOR);
|
|
11769
11774
|
}
|
|
11775
|
+
if (key === "Fn::GetAtt") {
|
|
11776
|
+
const raw = source[key];
|
|
11777
|
+
let logicalId;
|
|
11778
|
+
let attributeName;
|
|
11779
|
+
if (typeof raw === "string") {
|
|
11780
|
+
const parts = raw.split(".");
|
|
11781
|
+
if (parts.length !== 2) return void 0;
|
|
11782
|
+
logicalId = literalStringOrUndefined(parts[0]);
|
|
11783
|
+
attributeName = literalStringOrUndefined(parts[1]);
|
|
11784
|
+
} else if (Array.isArray(raw) && raw.length === 2) {
|
|
11785
|
+
logicalId = literalStringOrUndefined(raw[0]);
|
|
11786
|
+
attributeName = literalStringOrUndefined(raw[1]);
|
|
11787
|
+
}
|
|
11788
|
+
if (logicalId === void 0 || attributeName === void 0) return void 0;
|
|
11789
|
+
return [
|
|
11790
|
+
"Fn::GetAtt",
|
|
11791
|
+
logicalId,
|
|
11792
|
+
attributeName
|
|
11793
|
+
].join(CROSS_STACK_KEY_SEPARATOR);
|
|
11794
|
+
}
|
|
11770
11795
|
}
|
|
11771
11796
|
/**
|
|
11772
11797
|
* Remember, FOR THE PASS THAT OWNS `secrets`, that the cross-stack source leaf
|
|
@@ -12335,7 +12360,7 @@ function plaintextIndexOf(secrets) {
|
|
|
12335
12360
|
* bag could not be vouched for, because it rewrote a `{Name: '', Value:
|
|
12336
12361
|
* 'an-unrelated-literal'}` pair. Nothing here can do that: the answer is never
|
|
12337
12362
|
* the source subtree, it is an expression a WRITER recorded against this exact
|
|
12338
|
-
* leaf identity; the arm fires for exactly
|
|
12363
|
+
* leaf identity; the arm fires for exactly three intrinsic spellings; and
|
|
12339
12364
|
* condition 1 still demands that the bag leaf be a plaintext this pass
|
|
12340
12365
|
* resolved. Every rejection degrades to {@link positionByIntrinsicSkeleton} and
|
|
12341
12366
|
* then to the value scan, i.e. to today's behavior.
|
|
@@ -14868,6 +14893,36 @@ function carriesDynamicReference(value) {
|
|
|
14868
14893
|
if (value !== null && typeof value === "object") return Object.values(value).some(carriesDynamicReference);
|
|
14869
14894
|
return false;
|
|
14870
14895
|
}
|
|
14896
|
+
/** The nested-stack resource type, whose `Outputs.<Name>` attributes are re-resolved (issue #2055). */
|
|
14897
|
+
const NESTED_STACK_RESOURCE_TYPE = "AWS::CloudFormation::Stack";
|
|
14898
|
+
/** Prefix `NestedStackProvider` records a child stack output under. */
|
|
14899
|
+
const NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX = "Outputs.";
|
|
14900
|
+
/**
|
|
14901
|
+
* `arn:cdkd-local:<childRegion>:<accountId>:nested-stack/<parent>/<logicalId>` —
|
|
14902
|
+
* the synthesized physicalId `NestedStackProvider.synthesizeArn` records on the
|
|
14903
|
+
* parent's `AWS::CloudFormation::Stack` row.
|
|
14904
|
+
*/
|
|
14905
|
+
const NESTED_STACK_LOCAL_ARN = /^arn:cdkd-local:([a-z0-9-]+):[^:]*:nested-stack\//i;
|
|
14906
|
+
/**
|
|
14907
|
+
* The CHILD stack's region, read off the parent row's synthesized physicalId
|
|
14908
|
+
* (issue [#2055](https://github.com/go-to-k/cdkd/issues/2055)).
|
|
14909
|
+
*
|
|
14910
|
+
* WHY THE ARN AND NOT A STATE READ. The child's own record carries `region`,
|
|
14911
|
+
* but its state KEY is `cdkd/<parent>~<logicalId>/<region>/state.json` — the
|
|
14912
|
+
* region is part of the key, so reading the record to learn the region is
|
|
14913
|
+
* circular. The synthesized physicalId is the SAME provider's durable record of
|
|
14914
|
+
* the region it deployed the child into, it sits on the resource row the
|
|
14915
|
+
* resolver already holds, and reading it costs no I/O on a path that is
|
|
14916
|
+
* otherwise hot.
|
|
14917
|
+
*
|
|
14918
|
+
* Returns `undefined` for anything that is not that shape (a hand-edited state
|
|
14919
|
+
* file, a record written before this provider existed), which the caller reads
|
|
14920
|
+
* as "use this resolver's own region".
|
|
14921
|
+
*/
|
|
14922
|
+
function nestedStackChildRegionFromLocalArn(physicalId) {
|
|
14923
|
+
if (typeof physicalId !== "string") return void 0;
|
|
14924
|
+
return NESTED_STACK_LOCAL_ARN.exec(physicalId)?.[1];
|
|
14925
|
+
}
|
|
14871
14926
|
let cachedAccountIdentity = null;
|
|
14872
14927
|
/**
|
|
14873
14928
|
* Cache for availability zones per region
|
|
@@ -15224,6 +15279,79 @@ function collectReferencedParameterNames(template) {
|
|
|
15224
15279
|
return referenced;
|
|
15225
15280
|
}
|
|
15226
15281
|
/**
|
|
15282
|
+
* Does coercing to `type` risk destroying the plaintext cdkd redacts against?
|
|
15283
|
+
*
|
|
15284
|
+
* DERIVED from {@link coerceParameterTypedValue}, never enumerated beside it.
|
|
15285
|
+
* The previous shape was a hand-kept set naming `Number` / `List<Number>`,
|
|
15286
|
+
* whose doc cleared `CommaDelimitedList` as safe because it "produces an array
|
|
15287
|
+
* of strings (both of which the recording scan and the redactor handle)". That
|
|
15288
|
+
* holds only for a comma-FREE secret -- and the dominant Secrets Manager shape
|
|
15289
|
+
* is a JSON blob, which is nothing but commas, so `,`-splitting shreds the
|
|
15290
|
+
* plaintext into fragments matching neither arm of
|
|
15291
|
+
* {@link inheritedSecretsCarriedBy}. An audited allow-list was wrong about one
|
|
15292
|
+
* of its own three entries, which is why this is now measured, not listed.
|
|
15293
|
+
*
|
|
15294
|
+
* Probe the REAL coercion with a canary carrying the separators the arms use --
|
|
15295
|
+
* a comma and surrounding whitespace -- and call the type risky when the canary
|
|
15296
|
+
* does not survive as one string. A `Type` added to the switch is covered the
|
|
15297
|
+
* day it is added, with nothing to keep in sync.
|
|
15298
|
+
*
|
|
15299
|
+
* The DEPLOY path does better: `refuseCoercedInheritedSecret` measures the loss
|
|
15300
|
+
* on the ACTUAL value, so a comma-free secret in a `CommaDelimitedList` still
|
|
15301
|
+
* works. This coarser predicate is for `cdkd diff`, which holds no secrets bag
|
|
15302
|
+
* and therefore cannot measure.
|
|
15303
|
+
*/
|
|
15304
|
+
const SECRET_IDENTITY_CANARY = "a, b";
|
|
15305
|
+
function parameterTypeMayLoseSecretIdentity(type) {
|
|
15306
|
+
return coerceParameterTypedValue(SECRET_IDENTITY_CANARY, type) !== SECRET_IDENTITY_CANARY;
|
|
15307
|
+
}
|
|
15308
|
+
/**
|
|
15309
|
+
* ONE definition of parameter-type coercion, at module scope so
|
|
15310
|
+
* {@link parameterTypeMayLoseSecretIdentity} probes the same code the resolver
|
|
15311
|
+
* runs rather than a copy of it.
|
|
15312
|
+
*/
|
|
15313
|
+
function coerceParameterTypedValue(value, type) {
|
|
15314
|
+
switch (type) {
|
|
15315
|
+
case "Number": return Number(value);
|
|
15316
|
+
case "List<Number>": return value.split(",").map((v) => Number(v.trim()));
|
|
15317
|
+
case "CommaDelimitedList": return value.split(",").map((v) => v.trim());
|
|
15318
|
+
default: return value;
|
|
15319
|
+
}
|
|
15320
|
+
}
|
|
15321
|
+
/**
|
|
15322
|
+
* The inherited `plaintext -> expression` pairs that `value` CARRIES.
|
|
15323
|
+
*
|
|
15324
|
+
* ONE definition, shared by the RECORDING side
|
|
15325
|
+
* (`recordInheritedParameterSecrets`) and the REFUSAL side
|
|
15326
|
+
* (`refuseCoercedInheritedSecret`), because a refusal narrower than the
|
|
15327
|
+
* recording would let exactly the values it exists to catch through — and the
|
|
15328
|
+
* two drifting apart is how this class of bug reappears.
|
|
15329
|
+
*
|
|
15330
|
+
* TWO ARMS, mirroring the two `redactSecretsForState` performs, so the
|
|
15331
|
+
* recording side cannot be narrower than the redaction side:
|
|
15332
|
+
*
|
|
15333
|
+
* - WHOLE VALUE at any length — `{Ref: Param}` returning exactly the secret.
|
|
15334
|
+
* - SUBSTRING at or above {@link MIN_NEEDLE_LENGTH} — the parent built the
|
|
15335
|
+
* parameter with an `Fn::Sub`, so the value is `postgres://u:<secret>@host`
|
|
15336
|
+
* and only part of it is the secret. Short needles are excluded on this arm
|
|
15337
|
+
* for the same reason the redactor excludes them: a 3-character secret
|
|
15338
|
+
* matches half the alphabet's worth of ordinary identifiers.
|
|
15339
|
+
*
|
|
15340
|
+
* A `CommaDelimitedList` parameter arrives as an array, so the scan walks
|
|
15341
|
+
* string elements too.
|
|
15342
|
+
*/
|
|
15343
|
+
function inheritedSecretsCarriedBy(value, inherited) {
|
|
15344
|
+
const candidates = [];
|
|
15345
|
+
if (typeof value === "string") candidates.push(value);
|
|
15346
|
+
else if (Array.isArray(value)) {
|
|
15347
|
+
for (const element of value) if (typeof element === "string") candidates.push(element);
|
|
15348
|
+
}
|
|
15349
|
+
if (candidates.length === 0) return [];
|
|
15350
|
+
const carried = [];
|
|
15351
|
+
for (const [plaintext, expression] of inherited) if (candidates.some((candidate) => candidate === plaintext || plaintext.length >= 4 && candidate.includes(plaintext))) carried.push([plaintext, expression]);
|
|
15352
|
+
return carried;
|
|
15353
|
+
}
|
|
15354
|
+
/**
|
|
15227
15355
|
* Render a parameter VALUE for a debug log line, honoring the definition's
|
|
15228
15356
|
* `NoEcho` flag (issue #1329). `NoEcho: true` is the template author's
|
|
15229
15357
|
* explicit "this value is sensitive" declaration — CloudFormation masks such
|
|
@@ -15669,7 +15797,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15669
15797
|
* @param userParameters User-provided parameter values (e.g., from CLI)
|
|
15670
15798
|
* @returns Record of parameter names to resolved values
|
|
15671
15799
|
*/
|
|
15672
|
-
async resolveParameters(template, userParameters) {
|
|
15800
|
+
async resolveParameters(template, userParameters, options) {
|
|
15801
|
+
const inheritedSecrets = options?.inheritedSecrets;
|
|
15802
|
+
const maskInherited = (text) => inheritedSecrets && inheritedSecrets.size > 0 ? maskSecretsInText(text, inheritedSecrets) : text;
|
|
15673
15803
|
const parameters = {};
|
|
15674
15804
|
const templateParameters = template.Parameters;
|
|
15675
15805
|
if (!templateParameters || typeof templateParameters !== "object") return parameters;
|
|
@@ -15679,8 +15809,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15679
15809
|
if (userParameters && name in userParameters) {
|
|
15680
15810
|
const userValue = userParameters[name];
|
|
15681
15811
|
if (userValue !== void 0) {
|
|
15812
|
+
this.refuseCoercedInheritedSecret(name, paramDef, userValue, inheritedSecrets);
|
|
15682
15813
|
parameters[name] = this.coerceParameterValue(userValue, paramDef.Type);
|
|
15683
|
-
this.logger.debug(`Parameter ${name}: using user-provided value ${stringifyParameterForLog(paramDef, userValue)}`);
|
|
15814
|
+
this.logger.debug(`Parameter ${name}: using user-provided value ${maskInherited(stringifyParameterForLog(paramDef, userValue))}`);
|
|
15684
15815
|
continue;
|
|
15685
15816
|
}
|
|
15686
15817
|
}
|
|
@@ -15695,11 +15826,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15695
15826
|
this.logger.debug(`Parameter ${name}: resolving SSM parameter path ${ssmPath}`);
|
|
15696
15827
|
const resolved = await this.resolveSSMParameter(ssmPath);
|
|
15697
15828
|
parameters[name] = resolved;
|
|
15698
|
-
this.logger.debug(`Parameter ${name}: resolved SSM value ${stringifyParameterForLog(paramDef, resolved)}`);
|
|
15829
|
+
this.logger.debug(`Parameter ${name}: resolved SSM value ${maskInherited(stringifyParameterForLog(paramDef, resolved))}`);
|
|
15699
15830
|
continue;
|
|
15700
15831
|
}
|
|
15701
15832
|
parameters[name] = paramDef.Default;
|
|
15702
|
-
this.logger.debug(`Parameter ${name}: using default value ${stringifyParameterForLog(paramDef, paramDef.Default)}`);
|
|
15833
|
+
this.logger.debug(`Parameter ${name}: using default value ${maskInherited(stringifyParameterForLog(paramDef, paramDef.Default))}`);
|
|
15703
15834
|
continue;
|
|
15704
15835
|
}
|
|
15705
15836
|
throw new Error(`Parameter ${name} is required but no value was provided and no default exists`);
|
|
@@ -15717,12 +15848,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15717
15848
|
* Coerce parameter value to the correct type based on parameter definition
|
|
15718
15849
|
*/
|
|
15719
15850
|
coerceParameterValue(value, type) {
|
|
15720
|
-
|
|
15721
|
-
case "Number": return Number(value);
|
|
15722
|
-
case "List<Number>": return value.split(",").map((v) => Number(v.trim()));
|
|
15723
|
-
case "CommaDelimitedList": return value.split(",").map((v) => v.trim());
|
|
15724
|
-
default: return value;
|
|
15725
|
-
}
|
|
15851
|
+
return coerceParameterTypedValue(value, type);
|
|
15726
15852
|
}
|
|
15727
15853
|
/**
|
|
15728
15854
|
* Resolve all intrinsic functions in a value
|
|
@@ -15812,6 +15938,101 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15812
15938
|
return resolved;
|
|
15813
15939
|
}
|
|
15814
15940
|
/**
|
|
15941
|
+
* Copy any {@link ResolverContext.inheritedSecrets} pair whose PLAINTEXT is
|
|
15942
|
+
* present in a just-resolved parameter value into this context's
|
|
15943
|
+
* `recordedSecretValues` (issues #1903 / #2087).
|
|
15944
|
+
*
|
|
15945
|
+
* WHY AT RESOLUTION TIME. This is the whole of the #2087 fix. The parent
|
|
15946
|
+
* hands a nested child already-resolved plaintext, so the child's own
|
|
15947
|
+
* resolution never sees a `{{resolve:` and cannot record the pair itself; the
|
|
15948
|
+
* first cut pre-SEEDED every child resource's map with the parent's bag,
|
|
15949
|
+
* which restored the redaction but destroyed the per-resource scoping
|
|
15950
|
+
* `perResourceSecrets` exists for. `redactSecretsForState` substring-matches
|
|
15951
|
+
* at or above {@link MIN_NEEDLE_LENGTH}, so a child resource that never
|
|
15952
|
+
* referenced the parameter but happens to spell `my-production-bucket` while
|
|
15953
|
+
* the secret is `production` had its state persisted as
|
|
15954
|
+
* `my-{{resolve:...}}-bucket` — which `redactParametersForDiff` does NOT
|
|
15955
|
+
* mirror on the desired side (it rewrites only the PARAMETERS), so every
|
|
15956
|
+
* later deploy saw a change: a perpetual UPDATE, or a perpetual REPLACEMENT
|
|
15957
|
+
* on a create-only property.
|
|
15958
|
+
*
|
|
15959
|
+
* Recording here binds the pair to exactly the resources whose resolution
|
|
15960
|
+
* consumed the parameter — which are exactly the ones that can carry the
|
|
15961
|
+
* plaintext into their persisted state — so the child gets the SAME scoping
|
|
15962
|
+
* RULE the PARENT already has, where `perResourceSecrets` is keyed by logical
|
|
15963
|
+
* id.
|
|
15964
|
+
*
|
|
15965
|
+
* That is PARITY with the parent, not a claim of exactness. Once a pair is in
|
|
15966
|
+
* a resource's bag, `redactSecretsForState` substring-matches every leaf of
|
|
15967
|
+
* THAT resource, so a resource which both `Ref`s the parameter and carries an
|
|
15968
|
+
* unrelated literal spelling the plaintext has the literal rewritten too. The
|
|
15969
|
+
* parent has precisely this residual for any resource that resolves a
|
|
15970
|
+
* `{{resolve:...}}`; what #2087 removed was the much wider version, where
|
|
15971
|
+
* every resource in the child got the bag whether it consumed the parameter
|
|
15972
|
+
* or not.
|
|
15973
|
+
*
|
|
15974
|
+
* The TWO ARMS of the match live in {@link inheritedSecretsCarriedBy}, shared
|
|
15975
|
+
* with the refusal below so the two can never drift apart.
|
|
15976
|
+
*
|
|
15977
|
+
* Covers every consumption shape, because `Fn::Sub` / `Fn::Join` /
|
|
15978
|
+
* `Fn::Select` / `Fn::FindInMap` all re-enter `resolveValue` and reach the
|
|
15979
|
+
* parameter through this same `Ref` branch.
|
|
15980
|
+
*
|
|
15981
|
+
* Substituting is deliberately NOT done here — the resolved value is what
|
|
15982
|
+
* reaches AWS, and an `Fn::Equals` over a parameter must compare the real
|
|
15983
|
+
* value or the condition flips.
|
|
15984
|
+
*/
|
|
15985
|
+
recordInheritedParameterSecrets(value, context) {
|
|
15986
|
+
const inherited = context.inheritedSecrets;
|
|
15987
|
+
const recorded = context.recordedSecretValues;
|
|
15988
|
+
if (!inherited || inherited.size === 0 || !recorded) return;
|
|
15989
|
+
for (const [plaintext, expression] of inheritedSecretsCarriedBy(value, inherited)) recorded.set(plaintext, expression);
|
|
15990
|
+
}
|
|
15991
|
+
/**
|
|
15992
|
+
* Refuse a child parameter whose declared `Type` would COERCE an inherited
|
|
15993
|
+
* secret out of cdkd's string-keyed secret model (issue #1903, review round
|
|
15994
|
+
* 2).
|
|
15995
|
+
*
|
|
15996
|
+
* THE MODEL IS STRING-KEYED END TO END. `RecordedSecretValues` is keyed by
|
|
15997
|
+
* plaintext STRING, {@link recordInheritedParameterSecrets} scans strings and
|
|
15998
|
+
* string array elements, and `redactSecretsForState` rewrites string LEAVES.
|
|
15999
|
+
* `coerceParameterValue` turns a `Number` / `List<Number>` parameter into a JS
|
|
16000
|
+
* number before any of that runs, so the pair was never recorded, the leaf was
|
|
16001
|
+
* never rewritten, and the child's `state.json` persisted the DECRYPTED value
|
|
16002
|
+
* verbatim — the exact disclosure this issue closes for `String` parameters —
|
|
16003
|
+
* with `cdkd diff --recursive` then reporting a change on every run.
|
|
16004
|
+
*
|
|
16005
|
+
* WHY A REFUSAL RATHER THAN RECORDING ON THE PRE-COERCION STRING. Recording
|
|
16006
|
+
* the pair is not enough on its own: the persisted leaf is a NUMBER, so the
|
|
16007
|
+
* redactor would additionally have to rewrite a number leaf into an
|
|
16008
|
+
* expression STRING, matched by `String(n) === plaintext`. That comparison
|
|
16009
|
+
* both UNDER-covers (`"007"` coerces to `7` and stringifies back to `"7"`, so
|
|
16010
|
+
* a zero-padded secret silently stays plaintext) and OVER-covers (a numeric
|
|
16011
|
+
* secret like `8080` whole-value-matches every unrelated port in the bag —
|
|
16012
|
+
* issue #2087's class, on a path where `MIN_NEEDLE_LENGTH` does not apply).
|
|
16013
|
+
* A remedy that can silently under-cover is the wrong one for a disclosure
|
|
16014
|
+
* path, so this refuses and NAMES the parameter instead.
|
|
16015
|
+
*
|
|
16016
|
+
* The blast radius is nil for CDK-authored apps: CDK synthesizes every
|
|
16017
|
+
* nested-stack cross-reference parameter as `Type: String`. A hand-authored
|
|
16018
|
+
* template that really wants a numeric secret can declare the parameter
|
|
16019
|
+
* `String` and keep the value a string, which is what CloudFormation's own
|
|
16020
|
+
* `NoEcho` / dynamic-reference handling assumes anyway.
|
|
16021
|
+
*
|
|
16022
|
+
* SCOPED TO THE INHERITED BAG, which is non-empty only on a nested-stack
|
|
16023
|
+
* child engine, and only for a value that actually carries a pair the parent
|
|
16024
|
+
* PROVED secret. An ordinary `Type: Number` parameter is untouched.
|
|
16025
|
+
*
|
|
16026
|
+
* The message never quotes the value.
|
|
16027
|
+
*/
|
|
16028
|
+
refuseCoercedInheritedSecret(name, paramDef, userValue, inherited) {
|
|
16029
|
+
if (!inherited || inherited.size === 0) return;
|
|
16030
|
+
const carriedBefore = inheritedSecretsCarriedBy(userValue, inherited).length;
|
|
16031
|
+
if (carriedBefore === 0) return;
|
|
16032
|
+
if (inheritedSecretsCarriedBy(this.coerceParameterValue(userValue, paramDef.Type), inherited).length >= carriedBefore) return;
|
|
16033
|
+
throw markNonRetryable(new IntrinsicResolutionRefusalError(`Nested-stack parameter '${name}' is declared 'Type: ${paramDef.Type}', but the parent stack resolved a SECRET dynamic reference into it. cdkd keeps a resolved secret out of persisted state by rewriting STRING leaves back to their {{resolve:...}} expression; coercing this value to '${paramDef.Type}' destroys the plaintext cdkd would have matched on, so the DECRYPTED secret would be left in the child stack's state.json with nothing to redact it back to. Declare '${name}' as 'Type: String' in the nested stack's template (CDK does this by default for cross-stack references), or stop passing a secret reference into it.`, void 0, "NESTED_STACK_SECRET_PARAMETER_TYPE"));
|
|
16034
|
+
}
|
|
16035
|
+
/**
|
|
15815
16036
|
* Resolve Ref intrinsic function
|
|
15816
16037
|
*
|
|
15817
16038
|
* Ref can reference:
|
|
@@ -15829,7 +16050,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15829
16050
|
if (context.parameters && logicalId in context.parameters) {
|
|
15830
16051
|
const value = context.parameters[logicalId];
|
|
15831
16052
|
const paramDef = context.template.Parameters?.[logicalId];
|
|
15832
|
-
this.logger.debug(`Resolved Ref to parameter: ${logicalId} -> ${stringifyParameterForLog(paramDef, value)}`);
|
|
16053
|
+
this.logger.debug(`Resolved Ref to parameter: ${logicalId} -> ${this.maskSecretsForLog(stringifyParameterForLog(paramDef, value), context)}`);
|
|
16054
|
+
this.recordInheritedParameterSecrets(value, context);
|
|
15833
16055
|
return value;
|
|
15834
16056
|
}
|
|
15835
16057
|
const pseudoValue = await this.resolvePseudoParameter(logicalId, context);
|
|
@@ -15934,6 +16156,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
15934
16156
|
return nameServers;
|
|
15935
16157
|
}
|
|
15936
16158
|
this.logger.debug(`Resolved Fn::GetAtt from attributes: ${logicalId}.${attributeName} -> ${stringifyAttributeForLog(attributeName, flatValue)}`);
|
|
16159
|
+
if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE && 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 }));
|
|
15937
16160
|
return flatValue;
|
|
15938
16161
|
}
|
|
15939
16162
|
if (attributeName.includes(".")) {
|
|
@@ -17453,8 +17676,12 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
17453
17676
|
* recorded no secrets.
|
|
17454
17677
|
*/
|
|
17455
17678
|
maskSecretsForLog(text, context) {
|
|
17679
|
+
let masked = text;
|
|
17680
|
+
const inherited = context?.inheritedSecrets;
|
|
17681
|
+
if (inherited && inherited.size > 0) masked = maskSecretsInText(masked, inherited);
|
|
17456
17682
|
const secrets = context?.recordedSecretValues;
|
|
17457
|
-
|
|
17683
|
+
if (secrets && secrets.size > 0) masked = maskSecretsInText(masked, secrets);
|
|
17684
|
+
return masked;
|
|
17458
17685
|
}
|
|
17459
17686
|
async resolveDynamicReferences(value, context) {
|
|
17460
17687
|
const pattern = /\{\{resolve:([^}]+)\}\}/g;
|
|
@@ -18617,7 +18844,7 @@ var CloudControlProvider = class {
|
|
|
18617
18844
|
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);
|
|
18618
18845
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
18619
18846
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
18620
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
18847
|
+
const { ASGProvider } = await import("./asg-provider-DGJz_iFy.js").then((n) => n.n);
|
|
18621
18848
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
18622
18849
|
}
|
|
18623
18850
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -24609,6 +24836,67 @@ function collectInlinePolicyNamesManagedBySiblings(targetPhysicalId, context, at
|
|
|
24609
24836
|
return result;
|
|
24610
24837
|
}
|
|
24611
24838
|
|
|
24839
|
+
//#endregion
|
|
24840
|
+
//#region src/deployment/resource-secrets-scope.ts
|
|
24841
|
+
/**
|
|
24842
|
+
* The secrets THIS process substituted into the property bag of the resource
|
|
24843
|
+
* currently being provisioned, scoped to that provider call's async chain
|
|
24844
|
+
* (issue [#1903](https://github.com/go-to-k/cdkd/issues/1903)).
|
|
24845
|
+
*
|
|
24846
|
+
* WHY AN ASYNC-LOCAL STORE RATHER THAN A FIELD ON `CreateContext`. Exactly ONE
|
|
24847
|
+
* provider needs the pairs — `NestedStackProvider`, which must SEED them into
|
|
24848
|
+
* the child `DeployEngine` it builds (see
|
|
24849
|
+
* `DeployEngineOptions.inheritedSecrets`) — and a `RecordedSecretValues` is
|
|
24850
|
+
* keyed by PLAINTEXT. `.claude/rules/providers.md` already records the rule
|
|
24851
|
+
* this follows: the reason `SecretMaskingContext` carries a masking FUNCTION
|
|
24852
|
+
* and not the bag is that putting the bag on the shared context makes every one
|
|
24853
|
+
* of the ~130 registered providers a place a `[...secrets.keys()]` can leak
|
|
24854
|
+
* from. A function cannot substitute here — seeding needs the pairs, not the
|
|
24855
|
+
* ability to mask — so the bag is handed through a channel only this one
|
|
24856
|
+
* provider reads, instead of widening the type every provider sees.
|
|
24857
|
+
*
|
|
24858
|
+
* It is also the idiom this particular provider already lives in:
|
|
24859
|
+
* `NestedStackProvider` reads its whole world out of
|
|
24860
|
+
* `getCurrentNestedStackContext()`, another `AsyncLocalStorage`.
|
|
24861
|
+
*
|
|
24862
|
+
* WHY ITS OWN LEAF MODULE rather than living in `deploy-engine.ts`, where it
|
|
24863
|
+
* started. Both BINDERS need it — the deploy engine and
|
|
24864
|
+
* `rollback-executor.ts`, whose replay arms re-resolve the journal's
|
|
24865
|
+
* `{{resolve:...}}` back to plaintext and drive the very same providers (issue
|
|
24866
|
+
* [#2086](https://github.com/go-to-k/cdkd/issues/2086)) — and
|
|
24867
|
+
* `deploy-engine.ts` already imports `rollback-executor.ts`, so keeping the
|
|
24868
|
+
* store there would have made the two modules a cycle. A leaf that imports one
|
|
24869
|
+
* TYPE cannot participate in one.
|
|
24870
|
+
*
|
|
24871
|
+
* SCOPE. {@link withCurrentResourceSecrets} wraps the provider CREATE / UPDATE
|
|
24872
|
+
* call itself, so the store is bound per resource and per retry attempt, and
|
|
24873
|
+
* two resources provisioned concurrently under `--concurrency` cannot see each
|
|
24874
|
+
* other's bag. Absent (every caller that binds nothing — `cdkd drift --revert`,
|
|
24875
|
+
* the import path, tests) reads as `undefined`, which the provider treats as
|
|
24876
|
+
* "no secrets to inherit" — the pre-#1903 behaviour.
|
|
24877
|
+
*/
|
|
24878
|
+
const currentResourceSecretsStore = new AsyncLocalStorage();
|
|
24879
|
+
/**
|
|
24880
|
+
* Run `fn` with `secrets` visible to {@link getCurrentResourceSecrets}. Used by
|
|
24881
|
+
* the deploy engine and the rollback executor around a provider CREATE / UPDATE
|
|
24882
|
+
* call; see the store's own doc for why the bag travels this way rather than on
|
|
24883
|
+
* `CreateContext`.
|
|
24884
|
+
*/
|
|
24885
|
+
function withCurrentResourceSecrets(secrets, fn) {
|
|
24886
|
+
return currentResourceSecretsStore.run(secrets, fn);
|
|
24887
|
+
}
|
|
24888
|
+
/**
|
|
24889
|
+
* The bag {@link withCurrentResourceSecrets} bound for the provider call
|
|
24890
|
+
* currently in flight, or `undefined` when no binder is on the stack.
|
|
24891
|
+
*
|
|
24892
|
+
* Read by `NestedStackProvider` alone. A provider reading this MUST NOT
|
|
24893
|
+
* enumerate or log its KEYS — they are secret plaintext; the only sanctioned
|
|
24894
|
+
* use is handing the map on as a redaction seed.
|
|
24895
|
+
*/
|
|
24896
|
+
function getCurrentResourceSecrets() {
|
|
24897
|
+
return currentResourceSecretsStore.getStore();
|
|
24898
|
+
}
|
|
24899
|
+
|
|
24612
24900
|
//#endregion
|
|
24613
24901
|
//#region src/deployment/outputs-export-alias.ts
|
|
24614
24902
|
/**
|
|
@@ -24860,9 +25148,12 @@ function exportAliasCollisionWarning(outputKey, exportName) {
|
|
|
24860
25148
|
* {@link collectDeclaredOutputNames}.
|
|
24861
25149
|
*/
|
|
24862
25150
|
function exportAliasCollisionScrubWarning(outputKey, exportName, secrets) {
|
|
24863
|
-
const
|
|
24864
|
-
|
|
24865
|
-
|
|
25151
|
+
const mask = (name) => {
|
|
25152
|
+
const exposure = secretsPresentIn(name, secrets);
|
|
25153
|
+
return stripControlChars(exposure ? maskEveryOccurrence(name, exposure) : name);
|
|
25154
|
+
};
|
|
25155
|
+
const shown = mask(exportName);
|
|
25156
|
+
return `Output ${mask(outputKey)} exports as "${shown}", which is also the name of another output in this stack — state cannot say which of the two the stored value under "${shown}" came from, so that key is redacted by value match instead of by template position, and two references resolving to the same value could still collapse there. Rename the export, or the colliding output, and redeploy.`;
|
|
24866
25157
|
}
|
|
24867
25158
|
|
|
24868
25159
|
//#endregion
|
|
@@ -26508,6 +26799,29 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
|
|
|
26508
26799
|
* backoff schedule per op — ~47s on the generic grid, or ~64s if the op
|
|
26509
26800
|
* hits a name cooldown, which rides its own longer grid since issue #2116.
|
|
26510
26801
|
*
|
|
26802
|
+
* A FOURTH thing since issue
|
|
26803
|
+
* [#2086](https://github.com/go-to-k/cdkd/issues/2086): the call is bound in
|
|
26804
|
+
* {@link withCurrentResourceSecrets}, the async-local channel
|
|
26805
|
+
* `NestedStackProvider` reads to seed a nested CHILD engine with the pairs the
|
|
26806
|
+
* parent already resolved (issue #1903). `resolveReplayProps` has just
|
|
26807
|
+
* re-resolved the journal's `{{resolve:...}}` expressions back to PLAINTEXT
|
|
26808
|
+
* into `secrets`, so the bag in hand here is exactly the one the deploy engine
|
|
26809
|
+
* would have bound — and without the binding a rollback that reverts a
|
|
26810
|
+
* nested-stack row calls `NestedStackProvider.update`, the child engine seeds
|
|
26811
|
+
* nothing, and the child's `state.json` is rewritten with the DECRYPTED secret.
|
|
26812
|
+
* A recovery path that restores the pre-fix behaviour re-opens the very
|
|
26813
|
+
* disclosure the fix closes, so "absent reads as undefined, the pre-#1903
|
|
26814
|
+
* baseline" is not an acceptable answer HERE, however it reads elsewhere.
|
|
26815
|
+
*
|
|
26816
|
+
* `NestedStackProvider` is reachable on this path by construction, not in
|
|
26817
|
+
* theory: it is one of the two `disableOuterRetry` providers named above that
|
|
26818
|
+
* also implement `update()`, and `cdkd deploy`'s in-process auto-rollback runs
|
|
26819
|
+
* inside a DEPLOY-mode `withNestedStackContext` (`deploy.ts` passes
|
|
26820
|
+
* `nestedTemplates` / `dagBuilder` / `diffCalculator`). Standalone `cdkd
|
|
26821
|
+
* rollback` is NOT affected — `rollback.ts` builds a destroy-mode context with
|
|
26822
|
+
* none of those three fields, so `requireDeployContext` throws loudly before
|
|
26823
|
+
* any child engine is built.
|
|
26824
|
+
*
|
|
26511
26825
|
* Returns the provider's result so the caller can honour
|
|
26512
26826
|
* `effectiveProperties` (issue #1644) — both revert arms used to write the
|
|
26513
26827
|
* previous state record back verbatim, dropping a narrowing the provider had
|
|
@@ -26740,8 +27054,8 @@ function redactRollbackRecord(record, secrets, journaledProps) {
|
|
|
26740
27054
|
}, secrets);
|
|
26741
27055
|
}
|
|
26742
27056
|
async function updateWithRollbackRetry(provider, args, logicalId, logger, isInterrupted, secrets) {
|
|
26743
|
-
if (provider.disableOuterRetry) return await provider.update(...args);
|
|
26744
|
-
return await withRetry(() => provider.update(...args), logicalId, {
|
|
27057
|
+
if (provider.disableOuterRetry) return await withCurrentResourceSecrets(secrets, () => provider.update(...args));
|
|
27058
|
+
return await withRetry(() => withCurrentResourceSecrets(secrets, () => provider.update(...args)), logicalId, {
|
|
26745
27059
|
logger: maskingRetryLogger(logger, secrets),
|
|
26746
27060
|
...isInterrupted && {
|
|
26747
27061
|
isInterrupted,
|
|
@@ -26819,6 +27133,16 @@ async function updateWithRollbackRetry(provider, args, logicalId, logger, isInte
|
|
|
26819
27133
|
* now earns its place by ALSO covering the late name release that the inner
|
|
26820
27134
|
* default classifier rejects. The two compound — measured at 640s of total
|
|
26821
27135
|
* sleep on a cooldown, inside the 30-minute per-resource deadline.
|
|
27136
|
+
*
|
|
27137
|
+
* ## The secrets scope, on both call sites (issue #2086)
|
|
27138
|
+
*
|
|
27139
|
+
* Each caller's `create` thunk binds {@link withCurrentResourceSecrets} around
|
|
27140
|
+
* `createProvider.create(...)`, for the same reason
|
|
27141
|
+
* {@link updateWithRollbackRetry} does around `update(...)`: a
|
|
27142
|
+
* reverse-replacement replay of an `AWS::CloudFormation::Stack` row re-CREATES
|
|
27143
|
+
* the child, and an unbound store makes the child engine persist the parent's
|
|
27144
|
+
* plaintext. It sits INSIDE the thunk, so it is re-established on every
|
|
27145
|
+
* attempt of both loops rather than once around them.
|
|
26822
27146
|
*/
|
|
26823
27147
|
async function createWithRollbackRetry(provider, create, logicalId, logger, isInterrupted, secrets, outer) {
|
|
26824
27148
|
if (provider.disableOuterRetry) return await create();
|
|
@@ -27039,7 +27363,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
27039
27363
|
let deletedNewFirst = false;
|
|
27040
27364
|
let createResult;
|
|
27041
27365
|
try {
|
|
27042
|
-
createResult = await createWithRollbackRetry(createProvider, () => createProvider.create(op.logicalId, op.resourceType, { ...resolvedPrevProps }, replayingStateCreateContext(secrets)), op.logicalId, logger, isInterrupted, secrets, {
|
|
27366
|
+
createResult = await createWithRollbackRetry(createProvider, () => withCurrentResourceSecrets(secrets, () => createProvider.create(op.logicalId, op.resourceType, { ...resolvedPrevProps }, replayingStateCreateContext(secrets))), op.logicalId, logger, isInterrupted, secrets, {
|
|
27043
27367
|
isRetryable: isNameCooldownError,
|
|
27044
27368
|
interruptedMessage: "Rollback interrupted while waiting out the name cooldown"
|
|
27045
27369
|
});
|
|
@@ -27057,7 +27381,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
27057
27381
|
delete stateResources[op.logicalId];
|
|
27058
27382
|
await afterOp?.(op.logicalId);
|
|
27059
27383
|
try {
|
|
27060
|
-
createResult = await createWithRollbackRetry(createProvider, () => createProvider.create(op.logicalId, op.resourceType, { ...resolvedPrevProps }, replayingStateCreateContext(secrets)), op.logicalId, logger, isInterrupted, secrets, {
|
|
27384
|
+
createResult = await createWithRollbackRetry(createProvider, () => withCurrentResourceSecrets(secrets, () => createProvider.create(op.logicalId, op.resourceType, { ...resolvedPrevProps }, replayingStateCreateContext(secrets))), op.logicalId, logger, isInterrupted, secrets, {
|
|
27061
27385
|
isRetryable: isRecreateRetryableError,
|
|
27062
27386
|
interruptedMessage: "Rollback interrupted while waiting for the old name to release"
|
|
27063
27387
|
});
|
|
@@ -28223,10 +28547,37 @@ var DeployEngine = class {
|
|
|
28223
28547
|
...this.exportIndexStore && { exportIndex: this.exportIndexStore },
|
|
28224
28548
|
recordedImports: this.recordedImports,
|
|
28225
28549
|
recordedOutputReads: this.recordedOutputReads,
|
|
28550
|
+
...this.options.inheritedSecrets && this.options.inheritedSecrets.size > 0 && { inheritedSecrets: this.options.inheritedSecrets },
|
|
28226
28551
|
recordedSecretValues: /* @__PURE__ */ new Map()
|
|
28227
28552
|
};
|
|
28228
28553
|
}
|
|
28229
28554
|
/**
|
|
28555
|
+
* The parameter bag the DIFF resolver context binds, with any inherited
|
|
28556
|
+
* secret plaintext rewritten back to its `{{resolve:...}}` expression (issue
|
|
28557
|
+
* #1903).
|
|
28558
|
+
*
|
|
28559
|
+
* The provisioning pass must keep the REAL values — that is what actually
|
|
28560
|
+
* reaches AWS — but the child's persisted state holds the expression, so the
|
|
28561
|
+
* comparison side has to hold it too or every deploy of a secret-bearing
|
|
28562
|
+
* nested stack reports a spurious UPDATE and re-issues an AWS call that
|
|
28563
|
+
* changes nothing. This is the child-stack twin of the
|
|
28564
|
+
* `skipDynamicReferences` flag the parent's own diff sets: same goal
|
|
28565
|
+
* (expression-vs-expression), reached differently because the child's
|
|
28566
|
+
* template carries `{Ref: Param}` rather than a `{{resolve:` string, so
|
|
28567
|
+
* there is no reference for that flag to decline to resolve.
|
|
28568
|
+
*
|
|
28569
|
+
* `redactSecretsForState` rather than a `Map.get` lookup so an EMBEDDED
|
|
28570
|
+
* secret — a parameter whose value is `postgres://u:<secret>@host` because
|
|
28571
|
+
* the parent built it with `Fn::Sub` — is rewritten the same way the
|
|
28572
|
+
* state-save choke point rewrites it, keeping the two sides byte-identical.
|
|
28573
|
+
* Identity-returns when nothing was inherited.
|
|
28574
|
+
*/
|
|
28575
|
+
redactParametersForDiff(parameterValues) {
|
|
28576
|
+
const inherited = this.options.inheritedSecrets;
|
|
28577
|
+
if (!inherited || inherited.size === 0) return parameterValues;
|
|
28578
|
+
return redactSecretsForState(parameterValues, inherited);
|
|
28579
|
+
}
|
|
28580
|
+
/**
|
|
28230
28581
|
* Redact resolved secret plaintext out of a bag about to be PERSISTED to
|
|
28231
28582
|
* state, replacing each secret value with the unresolved `{{resolve:...}}`
|
|
28232
28583
|
* expression it came from (GHSA fix; see `secret-redaction.ts`). No-op when
|
|
@@ -28546,7 +28897,7 @@ var DeployEngine = class {
|
|
|
28546
28897
|
} catch {}
|
|
28547
28898
|
this.kickOffAutoRefreshObservedProperties(currentState.resources);
|
|
28548
28899
|
this.logger.debug(`Template has ${Object.keys(template.Resources || {}).length} resources`);
|
|
28549
|
-
const parameterValues = await this.resolver.resolveParameters(template, this.options.parameters);
|
|
28900
|
+
const parameterValues = await this.resolver.resolveParameters(template, this.options.parameters, { ...this.options.inheritedSecrets && this.options.inheritedSecrets.size > 0 && { inheritedSecrets: this.options.inheritedSecrets } });
|
|
28550
28901
|
this.logger.debug(`Resolved ${Object.keys(parameterValues).length} parameters: ${Object.keys(parameterValues).join(", ")}`);
|
|
28551
28902
|
const context = this.buildResolverContext({
|
|
28552
28903
|
template,
|
|
@@ -28573,7 +28924,7 @@ var DeployEngine = class {
|
|
|
28573
28924
|
const diffResolverContext = this.buildResolverContext({
|
|
28574
28925
|
template: effectiveTemplate,
|
|
28575
28926
|
resources: currentState.resources,
|
|
28576
|
-
parameters: parameterValues,
|
|
28927
|
+
parameters: this.redactParametersForDiff(parameterValues),
|
|
28577
28928
|
conditions
|
|
28578
28929
|
}, stackName);
|
|
28579
28930
|
diffResolverContext.bestEffort = true;
|
|
@@ -29304,7 +29655,7 @@ var DeployEngine = class {
|
|
|
29304
29655
|
this.logger.info(` ${green("✓")} Old resource deleted`);
|
|
29305
29656
|
this.logger.info(` Re-creating ${logicalId}...`);
|
|
29306
29657
|
try {
|
|
29307
|
-
return await withRetry(() => this.withRetry(() => replaceProvider.create(logicalId, resourceType, replaceProps, createContext), logicalId, void 0, void 0, replaceProvider), logicalId, {
|
|
29658
|
+
return await withRetry(() => this.withRetry(() => withCurrentResourceSecrets(secrets, () => replaceProvider.create(logicalId, resourceType, replaceProps, createContext)), logicalId, void 0, void 0, replaceProvider), logicalId, {
|
|
29308
29659
|
maxRetries: 8,
|
|
29309
29660
|
initialDelayMs: 2e3,
|
|
29310
29661
|
maxDelayMs: 1e4,
|
|
@@ -29348,7 +29699,7 @@ var DeployEngine = class {
|
|
|
29348
29699
|
});
|
|
29349
29700
|
const createProvider = createDecision.provider;
|
|
29350
29701
|
const createProps = createDecision.provisionedBy === "cc-api" ? this.preparePropertiesForCcApi(resourceType, resolvedProps, logicalId) : resolvedProps;
|
|
29351
|
-
const result = await this.withRetry(() => createProvider.create(logicalId, resourceType, createProps, { maskSecrets: createSecretMasker(createSecrets) }), logicalId, void 0, void 0, createProvider);
|
|
29702
|
+
const result = await this.withRetry(() => withCurrentResourceSecrets(createSecrets, () => createProvider.create(logicalId, resourceType, createProps, { maskSecrets: createSecretMasker(createSecrets) })), logicalId, void 0, void 0, createProvider);
|
|
29352
29703
|
const dependencies = this.extractAllDependencies(template, logicalId);
|
|
29353
29704
|
const templateAttrs = this.extractTemplateAttributes(template, logicalId);
|
|
29354
29705
|
stateResources[logicalId] = {
|
|
@@ -29459,7 +29810,7 @@ var DeployEngine = class {
|
|
|
29459
29810
|
this.logger.info(` ${green("✓")} Old resource deleted`);
|
|
29460
29811
|
}
|
|
29461
29812
|
this.logger.info(` Creating new ${logicalId}...`);
|
|
29462
|
-
createResult = await withRetry(() => this.withRetry(() => replaceProvider.create(logicalId, resourceType, replaceProps, { maskSecrets: createSecretMasker(updateSecrets) }), logicalId, void 0, void 0, replaceProvider), logicalId, {
|
|
29813
|
+
createResult = await withRetry(() => this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replaceProvider.create(logicalId, resourceType, replaceProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replaceProvider), logicalId, {
|
|
29463
29814
|
maxRetries: 8,
|
|
29464
29815
|
initialDelayMs: 2e3,
|
|
29465
29816
|
maxDelayMs: 1e4,
|
|
@@ -29473,7 +29824,7 @@ var DeployEngine = class {
|
|
|
29473
29824
|
this.logger.info(` Creating new ${logicalId}...`);
|
|
29474
29825
|
let deletedOldFirst = false;
|
|
29475
29826
|
try {
|
|
29476
|
-
createResult = await this.withRetry(() => replaceProvider.create(logicalId, resourceType, replaceProps, { maskSecrets: createSecretMasker(updateSecrets) }), logicalId, void 0, void 0, replaceProvider);
|
|
29827
|
+
createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replaceProvider.create(logicalId, resourceType, replaceProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replaceProvider);
|
|
29477
29828
|
} catch (createError) {
|
|
29478
29829
|
const createMsg = createError instanceof Error ? createError.message : String(createError);
|
|
29479
29830
|
if (!isNameCollisionError(createMsg)) throw createError;
|
|
@@ -29550,7 +29901,7 @@ var DeployEngine = class {
|
|
|
29550
29901
|
let result;
|
|
29551
29902
|
let resultProvisionedBy = updateDecision.provisionedBy;
|
|
29552
29903
|
try {
|
|
29553
|
-
result = await this.withRetry(() => updateProvider.update(logicalId, currentResource.physicalId, resourceType, updateProps, currentProps, { maskSecrets: createSecretMasker(updateSecrets) }), logicalId, void 0, void 0, updateProvider);
|
|
29904
|
+
result = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => updateProvider.update(logicalId, currentResource.physicalId, resourceType, updateProps, currentProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, updateProvider);
|
|
29554
29905
|
} catch (updateError) {
|
|
29555
29906
|
const msg = updateError instanceof Error ? updateError.message : String(updateError);
|
|
29556
29907
|
const ccUnsupported = msg.includes("UnsupportedActionException") || msg.includes("does not support UPDATE");
|
|
@@ -29582,7 +29933,7 @@ var DeployEngine = class {
|
|
|
29582
29933
|
});
|
|
29583
29934
|
const replProvider = replDecision.provider;
|
|
29584
29935
|
const replProps = replDecision.provisionedBy === "cc-api" ? this.preparePropertiesForCcApi(resourceType, resolvedProps, logicalId) : resolvedProps;
|
|
29585
|
-
const createResult = await this.withRetry(() => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) }), logicalId, void 0, void 0, replProvider);
|
|
29936
|
+
const createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replProvider);
|
|
29586
29937
|
const replacementResult = {
|
|
29587
29938
|
physicalId: createResult.physicalId,
|
|
29588
29939
|
wasReplaced: true,
|
|
@@ -30051,5 +30402,5 @@ var DeployEngine = class {
|
|
|
30051
30402
|
};
|
|
30052
30403
|
|
|
30053
30404
|
//#endregion
|
|
30054
|
-
export {
|
|
30055
|
-
//# sourceMappingURL=deploy-engine-
|
|
30405
|
+
export { beginCommandInterruptScope as $, PARTITION_TABLE as $n, S3StateBackend as $t, renderStatefulReason as A, runDockerForeground as An, SynthesisError as Ar, dynamicReferenceTokens as At, exportAliasCollisionScrubWarning as B, resolveCaptureObservedState as Bn, s3BucketDomainName as Bt, isFinalSnapshotError as C, validateContainerRepoName as Cn, PartialFailureError as Cr, requireConfigArray as Ct, extractDeploymentEventError as D, formatDockerLoginError as Dn, StackHasActiveImportsError as Dr, STATE_SOURCED_READBACK_RULES as Dt, makeCanonicalizePropertiesFn as E, dockerSpawnEnvWithSensitive as En, ResourceUpdateNotSupportedError as Er, STATE_SOURCED_CROSS_GENERATION_RULES as Et, green as F, synthesisStatusMessage as Fn, isMarkedNonRetryable as Fr, redactSecretsForState as Ft, IAMRoleProvider as G, stateBucketExistenceConfirmed as Gn, DiffCalculator as Gt, secretBearingStateKeyWarning as H, resolveStateBucketWithDefault as Hn, s3BucketRegionalDomainName as Ht, red as I, getDefaultStateBucketName as In, isRetryableTransientError as Ir, scrubResourceRecord as It, ProviderRegistry as J, CFN_TEMPLATE_URL_LIMIT as Jn, withRetry as Jt, collectInlinePolicyNamesManagedBySiblings as K, warnDeprecatedNoPrefixCliFlag as Kn, INTRINSIC_KEYS as Kt, yellow as L, getLegacyStateBucketName as Ln, isThrottlingError as Lr, classifyReplaySecretRegion as Lt, bold as M, AssetManifestLoader as Mn, isCdkdError as Mr, isSingleDynamicReferenceToken as Mt, cyan as N, getDockerImageBySourceHash as Nn, normalizeAwsError as Nr, maskSecretsInError as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, getDockerCmd as On, StackTerminationProtectionError as Or, TEMPLATE_SOURCED_RULES as Ot, gray as P, Synthesizer as Pn, withErrorHandling as Pr, maskSecretsInText as Pt, DEFAULT_STATE_PREFIX as Q, expectedOwnerParam as Qn, displaySafe as Qt, collectDeclaredOutputNames as R, resolveApp as Rn, markNonRetryable as Rr, producerRegionsFromState as Rt, createPreDeleteFinalSnapshot as S, validateAssetBucketName as Sn, NestedStackChildDirectDestroyError as Sr, replayWarn as St, unsupportedFinalSnapshotError as T, buildDockerImage as Tn, ResourceTimeoutError as Tr, requireConfigString as Tt, stateKeySecretExposure as U, resolveStateBucketWithDefaultAndSource as Un, s3BucketWebsiteUrl as Ut, isExportAliasCollision as V, resolveSkipPrefix as Vn, s3BucketDualStackDomainName as Vt, getCurrentResourceSecrets as W, resolveUseCdkBootstrapAssets as Wn, applyRoleArnIfSet as Wt, findSilentDropProperties as X, findLargeInlineResources as Xn, TemplateParser as Xt, findActionableSilentDrops as Y, MIGRATE_TMP_PREFIX as Yn, DagBuilder as Yt, CUSTOM_RESOURCE_RESPONSE_PREFIX as Z, uploadCfnTemplate as Zn, LockManager as Zt, computeImplicitDeleteEdges as _, ensureAssetStorage as _n, LocalInvokeBuildError as _r, assertRegionMatch as _t, DeploymentEventsStore as a, AssetPublisher as an, resolveBucketRegion as ar, slowCcOperationTimeoutMs as at, buildFinalSnapshotIdentifier as b, parseBootstrapMarker as bn, LockError as br, configStringRefusal as bt, replayFailedOperations as c, buildAssetRedirectMap as cn, resetAwsClients as cr, IntrinsicFunctionResolver as ct, updatePartialReason as d, rewriteTemplateAssetReferences as dn, CdkdError as dr, getAccountInfo as dt, rebuildClientForBucketRegion as en, canonicalizeRegion as er, endCommandInterruptScope as et, UNSPECIFIED_SKIP_REASON as f, escapeRegExp$1 as fn, ConfigError as fr, parameterTypeMayLoseSecretIdentity as ft, IMPLICIT_DELETE_DEPENDENCIES as g, assertAssetBucketRegion as gn, DynamicReferenceRegionAmbiguousError as gr, resolveExplicitPhysicalId as gt, maskingRetryLogger as h, BOOTSTRAP_MARKER_PREFIX as hn, DeployCancelledError as hr, normalizeAwsTagsToCfn as ht, DeploymentEventsReader as i, shouldRetainResource as in, clearBucketRegionCache as ir, CloudControlProvider as it, formatResourceLine as j, runDockerStreaming as jn, formatError as jr, errorCauseChain as jt, isStatefulRecreateTargetSync as k, partitionSensitiveEnv as kn, StateError as kr, createSecretMasker as kt, replayRollback as l, createAssetRedirectResolver as ln, setAwsClients as lr, carriesDynamicReference as lt, withResourceDeadline as m, AssetModeResolver as mn, DependencyError as mr, WAFv2WebACLProvider as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, importableOutputKeys as nn, AssemblyReader as nr, isInterruptedWaitError as nt, planFailedOps as o, stringifyValue as on, AwsClients as or, disableInstanceApiTermination as ot, deleteSkipReason as p, stripControlChars as pn, CrossAccountSecretRefusalError as pr, refStateLookupFromResource as pt, clearOnUpdateRemoval as q, CFN_TEMPLATE_BODY_LIMIT as qn, describeTypeWithThrottleRetry as qt, DeployEngine as r, importableOutputs as rn, processStackMessages as rr, startInterruptWatch as rt, planRollback as s, WorkGraph as sn, getAwsClients as sr, isTerminationProtectionPropagationError as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, exportNamesCarriedFrom as tn, derivePartitionAndUrlSuffix as tr, interruptWatchListenerCount as tt, updatePartialMessage as u, loadPublishableAssetManifest as un, AssetError as ur, cfnRefValueFromPhysicalId as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, getBootstrapMarkerKey as vn, LocalMigrateError as vr, coerceCfnBoolean as vt, refusesFinalSnapshot as w, buildDenyExternalAccessPolicy as wn, ProvisioningError as wr, requireConfigObject as wt, ccRoutedFinalSnapshotError as x, readBootstrapMarkerBody as xn, MissingCdkCliError as xr, readConfigString as xt, PRE_DELETE_SNAPSHOT_TYPES as y, isCrossRegionRedirect as yn, LocalStartServiceError as yr, configBooleanRefusal as yt, collectPublishedOutputNames as z, resolveAutoAssetStorage as zn, __exportAll as zr, s3BucketArn as zt };
|
|
30406
|
+
//# sourceMappingURL=deploy-engine-BtqjWvh5.js.map
|