@go-to-k/cdkd 0.289.4 → 0.289.6
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-CpxZ9sVH.js → asg-provider-eIVYMrmW.js} +3 -3
- package/dist/{asg-provider-CpxZ9sVH.js.map → asg-provider-eIVYMrmW.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-BEpYvI14.js → deploy-engine-CpmvgRtm.js} +304 -20
- package/dist/deploy-engine-CpmvgRtm.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{logger-CecsQ1UT.js → logger-BK-B0slT.js} +33 -3
- package/dist/logger-BK-B0slT.js.map +1 -0
- package/dist/{program-CyIOIvtX.js → program-B3I46yaG.js} +133 -51
- package/dist/{program-CyIOIvtX.js.map → program-B3I46yaG.js.map} +1 -1
- package/dist/{version-C3wRsCF2.js → version-DCxqZhgp.js} +2 -2
- package/dist/{version-C3wRsCF2.js.map → version-DCxqZhgp.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-BEpYvI14.js.map +0 -1
- package/dist/logger-CecsQ1UT.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as isVersionOnlyInvocation, t as getCdkdVersion } from "./version-
|
|
2
|
+
import { n as isVersionOnlyInvocation, t as getCdkdVersion } from "./version-DCxqZhgp.js";
|
|
3
3
|
|
|
4
4
|
//#region src/cli/pipe-close-handler.ts
|
|
5
5
|
/**
|
|
@@ -74,7 +74,7 @@ async function main() {
|
|
|
74
74
|
console.log(getCdkdVersion());
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
-
const { buildProgram } = await import("./program-
|
|
77
|
+
const { buildProgram } = await import("./program-B3I46yaG.js");
|
|
78
78
|
const program = buildProgram();
|
|
79
79
|
const args = reorderArgs(process.argv);
|
|
80
80
|
await program.parseAsync(args);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { 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, y as displaySafe } from "./logger-
|
|
1
|
+
import { 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, y as displaySafe } from "./logger-BK-B0slT.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-DCxqZhgp.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";
|
|
@@ -10286,17 +10286,23 @@ var S3StateBackend = class {
|
|
|
10286
10286
|
* silently lose data on the next save.
|
|
10287
10287
|
*/
|
|
10288
10288
|
parseStateBody(bodyString, stackName) {
|
|
10289
|
-
let
|
|
10289
|
+
let root;
|
|
10290
10290
|
try {
|
|
10291
|
-
|
|
10291
|
+
root = JSON.parse(bodyString);
|
|
10292
10292
|
} catch (error) {
|
|
10293
10293
|
const raw = error instanceof Error ? error.message : String(error);
|
|
10294
10294
|
const detail = displaySafe(raw, { asciiOnly: true }) || "<unrenderable>";
|
|
10295
10295
|
throw new StateError(`State file for stack '${this.displayName(stackName)}' is not valid JSON: ${detail}`, error instanceof Error ? error : void 0);
|
|
10296
10296
|
}
|
|
10297
|
+
if (root === null || typeof root !== "object" || Array.isArray(root)) {
|
|
10298
|
+
const got = root === null ? "null" : Array.isArray(root) ? "an array" : `a ${typeof root}`;
|
|
10299
|
+
throw new StateError(`State file for stack '${this.displayName(stackName)}' is not a JSON object (it parses to ${got}), so cdkd cannot read it as a state record.`);
|
|
10300
|
+
}
|
|
10301
|
+
const parsed = root;
|
|
10297
10302
|
const v = parsed.version;
|
|
10298
10303
|
if (v !== void 0 && !STATE_SCHEMA_VERSIONS_READABLE.includes(v)) {
|
|
10299
|
-
const
|
|
10304
|
+
const vShown = v;
|
|
10305
|
+
const shown = displaySafe(vShown === null ? "null" : vShown, { asciiOnly: true }) || "<unrenderable>";
|
|
10300
10306
|
throw new StateError(`Unsupported state schema version ${shown} for stack '${this.displayName(stackName)}'. This cdkd binary supports versions ${STATE_SCHEMA_VERSIONS_READABLE.join(", ")}. Upgrade cdkd to a version that supports schema ${shown}.`);
|
|
10301
10307
|
}
|
|
10302
10308
|
return parsed;
|
|
@@ -10624,7 +10630,8 @@ var LockManager = class {
|
|
|
10624
10630
|
const lockInfo = {
|
|
10625
10631
|
...parsed,
|
|
10626
10632
|
owner: displaySafe(parsed.owner),
|
|
10627
|
-
...parsed.operation !== void 0 && { operation: displaySafe(parsed.operation) }
|
|
10633
|
+
...parsed.operation !== void 0 && { operation: displaySafe(parsed.operation) },
|
|
10634
|
+
expiresAt: nanIfUncoercible(parsed.expiresAt)
|
|
10628
10635
|
};
|
|
10629
10636
|
this.logger.debug(`Lock info for stack: ${shownStack}:`, lockInfo);
|
|
10630
10637
|
return {
|
|
@@ -11150,6 +11157,21 @@ var LockManager = class {
|
|
|
11150
11157
|
throw new LockError(`Failed to acquire lock for stack '${safeStack}' (${safeRegion}) after ${maxRetries + 1} attempts. ` + (lockInfo ? `Locked by: ${lockInfo.owner}${lockInfo.operation ? `, operation: ${lockInfo.operation}` : ""}, expires in: ${expiresIn}. ` + recovery : `Lock exists but could not read lock info. ${recovery}`));
|
|
11151
11158
|
}
|
|
11152
11159
|
};
|
|
11160
|
+
/**
|
|
11161
|
+
* `value` itself, unless coercing it to a number THROWS — then `NaN`.
|
|
11162
|
+
*
|
|
11163
|
+
* Deliberately not a conversion: see the `expiresAt` note in `getLockRecord`.
|
|
11164
|
+
* The call is the probe — `Number` throws on exactly the values the readers'
|
|
11165
|
+
* arithmetic would throw on, and on nothing else.
|
|
11166
|
+
*/
|
|
11167
|
+
function nanIfUncoercible(value) {
|
|
11168
|
+
try {
|
|
11169
|
+
Number(value);
|
|
11170
|
+
return value;
|
|
11171
|
+
} catch {
|
|
11172
|
+
return NaN;
|
|
11173
|
+
}
|
|
11174
|
+
}
|
|
11153
11175
|
|
|
11154
11176
|
//#endregion
|
|
11155
11177
|
//#region src/deployment/secret-redaction.ts
|
|
@@ -11279,7 +11301,8 @@ function resolvedExpressionsOf(secrets) {
|
|
|
11279
11301
|
* for the object it is handed. A copy of the bag, a derived needle map, a
|
|
11280
11302
|
* previous generation's record, a scrub / drift walk and a bag nobody marked
|
|
11281
11303
|
* all answer `false` and keep the fall-through. `cdkd import` marks the one
|
|
11282
|
-
* bag its own resolver produced (the sixth site below, issue #2745)
|
|
11304
|
+
* bag its own resolver produced (the sixth site below, issue #2745), and the
|
|
11305
|
+
* nested-stack recorder marks the COPY it positions (the seventh, same issue).
|
|
11283
11306
|
*
|
|
11284
11307
|
* A `WeakSet` for the reason {@link resolvedPairsOf} is a `WeakMap`: the mark
|
|
11285
11308
|
* dies with the object it is on, and nothing has to clear it.
|
|
@@ -11314,9 +11337,9 @@ const sameGenerationBags = /* @__PURE__ */ new WeakSet();
|
|
|
11314
11337
|
* and may skip it entirely. "Every leaf this pass produced" is false for the
|
|
11315
11338
|
* auto-refresh readback of an UNCHANGED resource, where nothing was resolved
|
|
11316
11339
|
* at all — there the safety comes from the empty secrets map, not from the
|
|
11317
|
-
* mark. Read the per-site list below rather than a rule over all
|
|
11340
|
+
* mark. Read the per-site list below rather than a rule over all seven.
|
|
11318
11341
|
*
|
|
11319
|
-
* The
|
|
11342
|
+
* The seven call sites, and which of them the record HOLDS, because the earlier
|
|
11320
11343
|
* "two never-installed copies" reading of this paragraph was false once the
|
|
11321
11344
|
* third copy arrived:
|
|
11322
11345
|
* - `propertiesToRecord` — the record's `properties`, installed. The resolved
|
|
@@ -11361,6 +11384,20 @@ const sameGenerationBags = /* @__PURE__ */ new WeakSet();
|
|
|
11361
11384
|
* it does NOT claim is that AWS holds the value: `observedProperties` is
|
|
11362
11385
|
* captured separately, against the redacted record, and is never marked
|
|
11363
11386
|
* here.
|
|
11387
|
+
* - `recordNestedStackParameterExpressions` (issue #2745) — a shallow COPY of
|
|
11388
|
+
* a nested-stack row's resolved `Parameters` sub-bag, marked as the
|
|
11389
|
+
* position pass's input so a sub-floor middle a literal frame embeds is
|
|
11390
|
+
* written as its token there, which is what the recorder's sub-floor
|
|
11391
|
+
* carry reads. NOT installed: the caller's own object is untouched, and
|
|
11392
|
+
* whether THAT gets marked is decided at the caller (the deploy engine's
|
|
11393
|
+
* two sites mark it later, in `propertiesToRecord`; the replay's three
|
|
11394
|
+
* never do). Pair provenance holds at all five callers: the engine's two
|
|
11395
|
+
* resolve the row in the pass that recorded the pairs, and the replay's
|
|
11396
|
+
* three hand it the bag `resolveReplayProps` filled through
|
|
11397
|
+
* `recordResolvedPair` from the journal rows it resolved just before -- the
|
|
11398
|
+
* desired row, and on the update and failed-op arms the current or
|
|
11399
|
+
* attempted row as well -- all within one replay, so every pair in it is
|
|
11400
|
+
* that pass's own.
|
|
11364
11401
|
*/
|
|
11365
11402
|
function markSameGenerationBag(bag) {
|
|
11366
11403
|
sameGenerationBags.add(bag);
|
|
@@ -11691,6 +11728,21 @@ function substringNeedlesOf(secrets) {
|
|
|
11691
11728
|
* documented as "the expressions this pass recorded" must not silently contain
|
|
11692
11729
|
* something that is not one: the day a candidate test stops requiring token
|
|
11693
11730
|
* SHAPE, the sentinel would be live in it.
|
|
11731
|
+
*
|
|
11732
|
+
* A SECOND non-token class passes the filter, and is meant to: the FRAMED
|
|
11733
|
+
* whole-value entry `recordNestedStackParameterExpressions` writes for a
|
|
11734
|
+
* sub-floor carry (issue #2745) has a `port:{{resolve:...}}` value. It
|
|
11735
|
+
* enters the skeleton and frame candidate unions. The frame pattern is
|
|
11736
|
+
* anchored to the source's token and cannot match it; the SKELETON pattern of
|
|
11737
|
+
* an `Fn::Join` / `Fn::Sub` spelling the same frame around the same token
|
|
11738
|
+
* CAN, and then names that leaf's own frame around this pass's token -- the
|
|
11739
|
+
* correct expression for it, and one `isKnownSecretExpression` reads as
|
|
11740
|
+
* secret anyway, since the value is a map entry. What it DOES cost is the
|
|
11741
|
+
* length cap -- a framed value longer than
|
|
11742
|
+
* `MAX_SKELETON_CANDIDATE_LENGTH` makes both intrinsic arms refuse every
|
|
11743
|
+
* INTRINSIC-sourced leaf of the resource whose bag holds it; a literal-source
|
|
11744
|
+
* leaf keeps the span arm, which reads no candidate list (the recorder's doc
|
|
11745
|
+
* lists it).
|
|
11694
11746
|
*/
|
|
11695
11747
|
function recordedExpressionsOf(secrets) {
|
|
11696
11748
|
const expressions = /* @__PURE__ */ new Set();
|
|
@@ -12060,6 +12112,14 @@ const NESTED_STACK_RESOURCE_TYPE$2 = "AWS::CloudFormation::Stack";
|
|
|
12060
12112
|
*/
|
|
12061
12113
|
const nestedStackParameterExpressions = /* @__PURE__ */ new WeakMap();
|
|
12062
12114
|
/**
|
|
12115
|
+
* Condition (iv)'s key (see {@link recordNestedStackParameterExpressions}) for
|
|
12116
|
+
* a `Parameters` spelling that is not a single-span literal frame of its
|
|
12117
|
+
* resolved value carrying this pass's pair for its token: an object source, a
|
|
12118
|
+
* plain literal, a two-span literal, a bag equal to its source, and a frame
|
|
12119
|
+
* whose token this pass never resolved to the middle (a PUBLIC sibling).
|
|
12120
|
+
*/
|
|
12121
|
+
const UNFRAMED_SPELLING = Symbol("cdkd.nested-parameter.unframed-spelling");
|
|
12122
|
+
/**
|
|
12063
12123
|
* Record, for the pass that owns `secrets`, which `{{resolve:...}}` expression
|
|
12064
12124
|
* each `Parameters` entry of a nested-stack row was resolved FROM (issue
|
|
12065
12125
|
* #2291). No-op for every other resource type.
|
|
@@ -12133,6 +12193,127 @@ const nestedStackParameterExpressions = /* @__PURE__ */ new WeakMap();
|
|
|
12133
12193
|
* `return source`, which is the same string again), so both callers reach it.
|
|
12134
12194
|
* Fenced by the self-referential case in
|
|
12135
12195
|
* `secret-redaction-nested-parameter-source.test.ts`.
|
|
12196
|
+
*
|
|
12197
|
+
* THE SUB-FLOOR CARRY (issue #2745, its nested-stack site). A parameter the
|
|
12198
|
+
* parent spelled as a LITERAL frame around one token -- `Pin:
|
|
12199
|
+
* 'port:{{resolve:secretsmanager:S:SecretString:pin::}}'` -- resolves to
|
|
12200
|
+
* `port:q7`: not a key of the map (refusal 1), with a middle below
|
|
12201
|
+
* `MIN_NEEDLE_LENGTH`, so the child's carry (`inheritedSecretsCarriedBy`:
|
|
12202
|
+
* whole value at any length, substring at or above the floor) misses it both
|
|
12203
|
+
* ways and the child persisted `port:q7`. This recorder is the only point
|
|
12204
|
+
* holding the literal frame beside the pair, so the carry is written HERE:
|
|
12205
|
+
* the position pass runs over a MARKED shallow copy, on which
|
|
12206
|
+
* {@link positionByEmbeddedSpan} writes the frame on pair evidence, and a
|
|
12207
|
+
* second walk records `resolvedValue -> sourceLeaf`
|
|
12208
|
+
* (`'port:q7' -> 'port:{{resolve:...}}'`) as an ordinary WHOLE-VALUE entry of
|
|
12209
|
+
* the parent's own bag, under five conditions:
|
|
12210
|
+
*
|
|
12211
|
+
* (i) `positioned[name] === sourceLeaf` -- the pass CERTIFIED the leaf.
|
|
12212
|
+
* On a literal source the span arm returns the source verbatim, so a
|
|
12213
|
+
* mismatch proves it did not fire -- refusal 2b's test, applied to
|
|
12214
|
+
* a literal source; pinned by the "map NO RESOLVER populated" case,
|
|
12215
|
+
* where (ii) and (iii) both pass and only the missing pair refuses.
|
|
12216
|
+
* (ii) `redactSecretsForState(resolvedValue, secrets) === resolvedValue`
|
|
12217
|
+
* -- the value scan is SILENT on it: the sub-floor gate, byte-for-byte
|
|
12218
|
+
* the bound the span arm accepted. What it refuses is a middle at or
|
|
12219
|
+
* above the floor, whose substring carry the child already has (the
|
|
12220
|
+
* only refusal a test can see: the others coincide with (i) or with
|
|
12221
|
+
* the map's own entry, as a whole-token source's would).
|
|
12222
|
+
* (iii) `secrets.get(middle) === token` -- the token IS the map's survivor
|
|
12223
|
+
* for the middle. Load-bearing: two framed parameters over ONE middle
|
|
12224
|
+
* (`pin::` and `pin:AWSCURRENT:`) keep their own tokens on this row's
|
|
12225
|
+
* record today because each reaches the span arm with the scan
|
|
12226
|
+
* silent; once a `'port:q7'` entry exists the scan answers for the
|
|
12227
|
+
* whole leaf and the arm's bound (`scanned === prefix + survivor +
|
|
12228
|
+
* suffix`) decides. Recording only the frame whose token is the
|
|
12229
|
+
* middle's survivor makes every parent leaf keep its own token by
|
|
12230
|
+
* construction rather than by recording order.
|
|
12231
|
+
* (iv) ONE FRAME per VALUE, across the whole row. Once the entry exists
|
|
12232
|
+
* the scan is no longer silent on the value, so on the parent's
|
|
12233
|
+
* record every leaf holding it answers against the entry through the
|
|
12234
|
+
* span arm's bound (`scanned === prefix + survivor + suffix`). The
|
|
12235
|
+
* SAME frame around another token -- the (iii) shape, `port:` + A
|
|
12236
|
+
* beside `port:` + B -- passes that bound and keeps its own token. A
|
|
12237
|
+
* DIFFERENT frame (`port:` + `q7` beside `port` + `:q7`, each passing
|
|
12238
|
+
* (i)-(iii) on its own), a leaf (iii) refused under a different
|
|
12239
|
+
* frame, an object spelling and a plain literal equal to the value
|
|
12240
|
+
* all fail it and would take the entry's frame -- and so would a
|
|
12241
|
+
* same-frame sibling whose token this pass never resolved to the
|
|
12242
|
+
* middle: a PUBLIC `ssm` reference in the same `port:` frame holding
|
|
12243
|
+
* the same two characters is kept RESOLVED on the record, and the
|
|
12244
|
+
* entry would rewrite it to the secret sibling's expression. So the
|
|
12245
|
+
* frames (prefix + suffix) of every spelling of every string value in
|
|
12246
|
+
* the row are gathered BEFORE the conditions run, a spelling that is
|
|
12247
|
+
* not a single-span literal frame with this pass's pair for its token
|
|
12248
|
+
* (`resolvedPlaintextOf`) counting as its own, and a value is
|
|
12249
|
+
* recorded only when its certified frame is the row's only one.
|
|
12250
|
+
* (v) No OTHER string leaf of the ROW would be rewritten by the entry,
|
|
12251
|
+
* read over every leaf of the resolved row since the bag is per
|
|
12252
|
+
* resource, not per `Parameters`. Two arms of the persist walk read
|
|
12253
|
+
* a map entry. The WHOLE-VALUE arm is floorless, so a leaf EQUAL to
|
|
12254
|
+
* the value OUTSIDE `Parameters` (a `TemplateURL` that happens to
|
|
12255
|
+
* equal it has no frame of its own and escapes (iv)) or inside a
|
|
12256
|
+
* LIST-valued sibling parameter (an array here; `extractParameters`
|
|
12257
|
+
* joins it back for the wire) refuses at any length; equality
|
|
12258
|
+
* between string parameters is (iv)'s frame identity. The SUBSTRING
|
|
12259
|
+
* arm is reached only by a value at or above `MIN_NEEDLE_LENGTH`
|
|
12260
|
+
* (`port:q7` clears the floor its bare middle sits under), so a
|
|
12261
|
+
* sibling merely CONTAINING the value -- `x-port` + `:q7` from
|
|
12262
|
+
* another token, a plain literal `literal-port:q7-end` -- refuses
|
|
12263
|
+
* only then, or it would be spliced with this frame on the parent's
|
|
12264
|
+
* record, exactly the #2087 splice the child side is scoped against;
|
|
12265
|
+
* a 3-character `pq7` beside such a sibling is carried, since no
|
|
12266
|
+
* needle exists for it.
|
|
12267
|
+
*
|
|
12268
|
+
* Written AFTER the walk, so no iteration reads the recorder's own write --
|
|
12269
|
+
* a statement of intent rather than a pinned behaviour: under (iv) and (v)
|
|
12270
|
+
* an in-loop write is EQUIVALENT (a later value the entry would rewrite is
|
|
12271
|
+
* refused by (v), an equal one by (iv) or as the same entry), so no test can
|
|
12272
|
+
* red on the order, and it is kept so (ii)'s reading of the map cannot come
|
|
12273
|
+
* to depend on iteration order. No pair and no pin are recorded for the
|
|
12274
|
+
* entry: it is not a token
|
|
12275
|
+
* ({@link recordedExpressionsOf} names the class), and no consumer needs one
|
|
12276
|
+
* -- the child's carry, the child's persist (the floorless whole-value arm),
|
|
12277
|
+
* the diff side (`redactParametersForDiff`'s fallback) and the parent's
|
|
12278
|
+
* rollback record all read the map by whole value. Refusal 3's
|
|
12279
|
+
* self-referential shape cannot reach the write: {@link singleSpanFrame}
|
|
12280
|
+
* refuses a middle that is itself a token, which is what a bag equal to its
|
|
12281
|
+
* source has.
|
|
12282
|
+
*
|
|
12283
|
+
* WHAT STAYS OPEN, weighed against the three live consumers named on
|
|
12284
|
+
* {@link positionByIntrinsicFrame} (`cdkd rollback`, `drift --revert`, a
|
|
12285
|
+
* consumer's cross-stack read). (a) Over one middle with TWO tokens, (iii)
|
|
12286
|
+
* records the survivor's frames only, never a loser's, so the loser's child
|
|
12287
|
+
* leaf takes the survivor's frame when the two frames MATCH (`port:` + either
|
|
12288
|
+
* token: the survivor's entry is the loser's whole value too) and stays
|
|
12289
|
+
* PLAINTEXT when they differ (`port:` + A beside `url:` + B: no entry names
|
|
12290
|
+
* `port:q7`). Either is the pre-#2291 answer for this shape; on a match it is
|
|
12291
|
+
* the wrong reference those consumers re-resolve -- after the sibling
|
|
12292
|
+
* rotates, a rollback or `--revert` of the child hands the sibling's
|
|
12293
|
+
* plaintext to the loser's live property. The PARENT's record stays per leaf
|
|
12294
|
+
* by (iii) and (iv). One token framed two ways (`port:` + T and `url:` + T)
|
|
12295
|
+
* is two values and two entries, not this shape. (b) The framed
|
|
12296
|
+
* value is a SUBSTRING needle (7 characters here) in every child resource
|
|
12297
|
+
* that consumed the parameter, so an unrelated literal there containing it
|
|
12298
|
+
* is spliced -- the #2087 class, bounded to resources whose own resolution
|
|
12299
|
+
* consumed the parameter; on the parent's own row (v) refuses the entry
|
|
12300
|
+
* instead, over the leaves visible at record time -- a readback leaf AWS
|
|
12301
|
+
* rewrote to contain the value is spliced like any 4+ character needle's.
|
|
12302
|
+
* (c) A frame longer than
|
|
12303
|
+
* `MAX_SKELETON_CANDIDATE_LENGTH` makes both intrinsic arms refuse every
|
|
12304
|
+
* INTRINSIC-sourced leaf of that child resource, which then falls to the
|
|
12305
|
+
* value scan (a literal-source leaf keeps the span arm). (d) A child
|
|
12306
|
+
* OUTPUT carrying the framed value re-resolves in the parent to `port:q7`,
|
|
12307
|
+
* where the cross-stack seam refuses a non-token and the consumer's leaf
|
|
12308
|
+
* persists the plaintext -- the same class as the nonliteral-frame deferral.
|
|
12309
|
+
* (e) An OBJECT-spelled parameter source (`Fn::Join` / `Fn::Sub` in the
|
|
12310
|
+
* parent's own `Parameters` block) is out of this arm's reach -- (i) cannot
|
|
12311
|
+
* hold for one. #2745 scopes this site to the literal spelling; the object
|
|
12312
|
+
* spelling is issue #3062. (f) A child record persisted BEFORE this carry
|
|
12313
|
+
* keeps `port:q7` until the child is next redeployed: the parent's own row
|
|
12314
|
+
* already held the frame (the literal arm), so a parent deploy whose child
|
|
12315
|
+
* row is unchanged never re-runs the child, and `cdkd scrub` cannot repair
|
|
12316
|
+
* it either -- it walks the child's stored bag with no inherited bag.
|
|
12136
12317
|
*/
|
|
12137
12318
|
function recordNestedStackParameterExpressions(secrets, resourceType, resolvedProperties, sourceProperties, rules = TEMPLATE_DERIVED_RULES) {
|
|
12138
12319
|
if (resourceType !== NESTED_STACK_RESOURCE_TYPE$2) return;
|
|
@@ -12143,7 +12324,7 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
|
|
|
12143
12324
|
const resolvedParameters = resolvedProperties["Parameters"];
|
|
12144
12325
|
const sourceParameters = sourceProperties["Parameters"];
|
|
12145
12326
|
if (!isPlainObject$2(resolvedParameters) || !isPlainObject$2(sourceParameters)) return;
|
|
12146
|
-
const positioned = redactSecretsForState(resolvedParameters, secrets, sourceParameters, rules);
|
|
12327
|
+
const positioned = redactSecretsForState(markSameGenerationBag({ ...resolvedParameters }), secrets, sourceParameters, rules);
|
|
12147
12328
|
let table = nestedStackParameterExpressions.get(secrets);
|
|
12148
12329
|
for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
|
|
12149
12330
|
if (typeof resolvedValue !== "string" || !secrets.has(resolvedValue)) continue;
|
|
@@ -12161,6 +12342,49 @@ function recordNestedStackParameterExpressions(secrets, resourceType, resolvedPr
|
|
|
12161
12342
|
}
|
|
12162
12343
|
storeAssociation(table, name, expression, resolvedValue);
|
|
12163
12344
|
}
|
|
12345
|
+
const framesByValue = /* @__PURE__ */ new Map();
|
|
12346
|
+
for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
|
|
12347
|
+
if (typeof resolvedValue !== "string") continue;
|
|
12348
|
+
const sourceLeaf = sourceParameters[name];
|
|
12349
|
+
const frame = typeof sourceLeaf === "string" ? singleSpanFrame(resolvedValue, sourceLeaf) : void 0;
|
|
12350
|
+
const frames = framesByValue.get(resolvedValue) ?? /* @__PURE__ */ new Set();
|
|
12351
|
+
frames.add(frame === void 0 || resolvedPlaintextOf(secrets, frame.token) !== frame.middle ? UNFRAMED_SPELLING : `${frame.prefix.length}:${frame.prefix}${frame.suffix}`);
|
|
12352
|
+
framesByValue.set(resolvedValue, frames);
|
|
12353
|
+
}
|
|
12354
|
+
const rowWithoutParameters = {};
|
|
12355
|
+
for (const [key, value] of Object.entries(resolvedProperties)) if (key !== "Parameters") rowWithoutParameters[key] = value;
|
|
12356
|
+
const outsideLeaves = wholeStringLeavesOf(rowWithoutParameters);
|
|
12357
|
+
const framed = /* @__PURE__ */ new Map();
|
|
12358
|
+
for (const [name, resolvedValue] of Object.entries(resolvedParameters)) {
|
|
12359
|
+
const sourceLeaf = sourceParameters[name];
|
|
12360
|
+
if (typeof resolvedValue !== "string" || typeof sourceLeaf !== "string") continue;
|
|
12361
|
+
if (positioned[name] !== sourceLeaf) continue;
|
|
12362
|
+
if (redactSecretsForState(resolvedValue, secrets) !== resolvedValue) continue;
|
|
12363
|
+
const frame = singleSpanFrame(resolvedValue, sourceLeaf);
|
|
12364
|
+
if (frame === void 0 || secrets.get(frame.middle) !== frame.token) continue;
|
|
12365
|
+
if (framesByValue.get(resolvedValue)?.size !== 1) continue;
|
|
12366
|
+
const isNeedle = resolvedValue.length >= 4;
|
|
12367
|
+
const rewrites = (leaf) => leaf === resolvedValue || isNeedle && leaf.includes(resolvedValue);
|
|
12368
|
+
let embedded = false;
|
|
12369
|
+
for (const leaf of outsideLeaves) if (rewrites(leaf)) {
|
|
12370
|
+
embedded = true;
|
|
12371
|
+
break;
|
|
12372
|
+
}
|
|
12373
|
+
for (const other of Object.values(resolvedParameters)) {
|
|
12374
|
+
if (embedded) break;
|
|
12375
|
+
if (typeof other === "string") {
|
|
12376
|
+
if (other !== resolvedValue && rewrites(other)) embedded = true;
|
|
12377
|
+
continue;
|
|
12378
|
+
}
|
|
12379
|
+
for (const leaf of wholeStringLeavesOf(other)) if (rewrites(leaf)) {
|
|
12380
|
+
embedded = true;
|
|
12381
|
+
break;
|
|
12382
|
+
}
|
|
12383
|
+
}
|
|
12384
|
+
if (embedded) continue;
|
|
12385
|
+
framed.set(resolvedValue, sourceLeaf);
|
|
12386
|
+
}
|
|
12387
|
+
for (const [plaintext, expression] of framed) secrets.set(plaintext, expression);
|
|
12164
12388
|
}
|
|
12165
12389
|
/**
|
|
12166
12390
|
* Copy a parent pass's per-PARAMETER associations onto a nested-stack CHILD
|
|
@@ -13026,10 +13250,14 @@ function positionByCrossStackSource(bag, source, secrets) {
|
|
|
13026
13250
|
* template text, which genuinely can be a PUBLIC ssm reference that must stay
|
|
13027
13251
|
* resolved in state (issue #1901), so it has to be tested. Here the candidates
|
|
13028
13252
|
* come only from {@link recordedSecretExpressions} and from the values of a
|
|
13029
|
-
* {@link RecordedSecretValues} map,
|
|
13030
|
-
*
|
|
13031
|
-
*
|
|
13032
|
-
*
|
|
13253
|
+
* {@link RecordedSecretValues} map, which the resolver populates ONLY on a
|
|
13254
|
+
* proven-secret verdict — and, since issue #2745, the nested-stack recorder's
|
|
13255
|
+
* framed carry entries ({@link recordedExpressionsOf}), which are not
|
|
13256
|
+
* references but ARE map values, so the same membership test reads them as
|
|
13257
|
+
* secret too. So the test could never answer `false`, and an
|
|
13258
|
+
* unfalsifiable guard reads as protection while fencing nothing. Widening the
|
|
13259
|
+
* candidate sources to a reference that can be public is what would make it
|
|
13260
|
+
* necessary again.
|
|
13033
13261
|
*/
|
|
13034
13262
|
function positionByIntrinsicSkeleton(bag, source, secrets, secretExpressions) {
|
|
13035
13263
|
if (bag === "" || !secrets.has(bag)) return void 0;
|
|
@@ -21280,6 +21508,61 @@ function configBooleanRefusal(container, key, containerPath) {
|
|
|
21280
21508
|
if (coerceCfnBoolean(value) !== void 0) return void 0;
|
|
21281
21509
|
return `${containerPath}.${key} must be a boolean ${malformedShapeDetail(value)}`;
|
|
21282
21510
|
}
|
|
21511
|
+
/**
|
|
21512
|
+
* Coerce a CFn integer, which may arrive as the string `"32"`.
|
|
21513
|
+
*
|
|
21514
|
+
* Same reason as {@link coerceCfnBoolean}: CloudFormation is stringly typed, so
|
|
21515
|
+
* an imported or hand-written template legitimately spells `PasswordLength:
|
|
21516
|
+
* "32"`. A safe whole number, or a string that is a DECIMAL INTEGER LITERAL
|
|
21517
|
+
* (optional sign, then digits, nothing else), is the value; anything else —
|
|
21518
|
+
* `null`, `''`, `'abc'`, `3.5`, `'1e2'`, `'0x10'`, `' 32 '`, an object,
|
|
21519
|
+
* an unresolved intrinsic — is `undefined`, so a caller that indexed
|
|
21520
|
+
* `(x as number) || 32` cannot read a malformed member as its default. The
|
|
21521
|
+
* string grammar is exactly what CloudFormation's own validator accepts,
|
|
21522
|
+
* MEASURED (us-east-1, 2026-09-13, `AWS::SecretsManager::Secret
|
|
21523
|
+
* GenerateSecretString.PasswordLength`): `"+12"` and `"007"` pass, `" 12 "` fails
|
|
21524
|
+
* `expected type: Integer, found: String`, `"1e1"` fails `found: Float` —
|
|
21525
|
+
* so a padded string is refused HERE rather than minted from a template the
|
|
21526
|
+
* service rejects, and a signed one is accepted. Both branches use
|
|
21527
|
+
* `Number.isSafeInteger`, so one value gets one verdict whatever its
|
|
21528
|
+
* spelling.
|
|
21529
|
+
*
|
|
21530
|
+
* @returns the integer, or `undefined` when the value is not one.
|
|
21531
|
+
*/
|
|
21532
|
+
function coerceCfnInteger(value) {
|
|
21533
|
+
if (typeof value === "number") return Number.isSafeInteger(value) ? value : void 0;
|
|
21534
|
+
if (typeof value !== "string" || !/^[+-]?\d+$/.test(value)) return void 0;
|
|
21535
|
+
const n = Number(value);
|
|
21536
|
+
return Number.isSafeInteger(n) ? n : void 0;
|
|
21537
|
+
}
|
|
21538
|
+
/**
|
|
21539
|
+
* The integer twin of {@link configBooleanRefusal} (issue #3056): the same
|
|
21540
|
+
* CONTAINER-then-FIELD halves, the FIELD half being {@link coerceCfnInteger} —
|
|
21541
|
+
* the function the wire read calls. Exists for the member shape neither
|
|
21542
|
+
* sibling sees: `(config['PasswordLength'] as number) || 32` read a
|
|
21543
|
+
* malformed length as the default, and a non-numeric STRING (truthy) reached
|
|
21544
|
+
* `new Uint8Array('abc')` and minted an EMPTY password with no warning.
|
|
21545
|
+
*
|
|
21546
|
+
* @param min the smallest integer that is usable (a generated-password length
|
|
21547
|
+
* of `0` is a value, not a refusal, to `Number.isInteger`, and it mints an
|
|
21548
|
+
* empty secret); pass `1` for a count, `0` where zero is legitimate.
|
|
21549
|
+
* @param max the largest, when the API documents one — a value the service
|
|
21550
|
+
* would reject is refused HERE, before a local consumer spends the work
|
|
21551
|
+
* (`new Uint8Array(1e9)` allocates and spins before AWS ever sees the
|
|
21552
|
+
* length). Omit when the API states no cap.
|
|
21553
|
+
* @returns The refusal sentence (`<path> must be …`), or `undefined` when the
|
|
21554
|
+
* value is usable — including the ABSENT container / ABSENT key cases, which
|
|
21555
|
+
* legitimately take the caller's default.
|
|
21556
|
+
*/
|
|
21557
|
+
function configIntegerRefusal(container, key, containerPath, min, max) {
|
|
21558
|
+
if (container === void 0 || container === null) return void 0;
|
|
21559
|
+
if (!isPlainObject$1(container) || isUnresolvedIntrinsicContainer(container)) return `${containerPath} must be an object ${malformedShapeDetail(container)}`;
|
|
21560
|
+
const value = container[key];
|
|
21561
|
+
if (value === void 0) return void 0;
|
|
21562
|
+
const n = coerceCfnInteger(value);
|
|
21563
|
+
if (n !== void 0 && n >= min && (max === void 0 || n <= max)) return void 0;
|
|
21564
|
+
return `${containerPath}.${key} must be an integer ${max === void 0 ? `>= ${min}` : `between ${min} and ${max}`} ${malformedShapeDetail(value)}`;
|
|
21565
|
+
}
|
|
21283
21566
|
/** The FIELD half of {@link configStringRefusal}, shared with {@link requireConfigString}. */
|
|
21284
21567
|
function configValueRefusal(value, fallback, path, options) {
|
|
21285
21568
|
if (value === void 0) return void 0;
|
|
@@ -21359,9 +21642,10 @@ const NAMEABLE_INTRINSIC_KEYS = /* @__PURE__ */ new Set([
|
|
|
21359
21642
|
* (`DeploymentController`) and `codebuild-provider.ts` (reached from `update()`
|
|
21360
21643
|
* through `mapProperties`). `secretsmanager-secret-provider.ts` was on this
|
|
21361
21644
|
* list until issue #3048 moved its update path to a SKIP (the container is
|
|
21362
|
-
* refused by `requireConfigObject` before `generateSecretString` reads it
|
|
21363
|
-
*
|
|
21364
|
-
*
|
|
21645
|
+
* refused by `requireConfigObject` before `generateSecretString` reads it,
|
|
21646
|
+
* and since issue #3056 every MEMBER read inside it takes the same skip
|
|
21647
|
+
* through an `onUnusable` callback; `create()` still throws on both). Not a
|
|
21648
|
+
* count, for the same
|
|
21365
21649
|
* reason as the near-copy list below: two successive reviews each found
|
|
21366
21650
|
* another. Re-derive with
|
|
21367
21651
|
* `grep -rn 'readConfigString(' src/provisioning/providers/`.
|
|
@@ -28041,7 +28325,7 @@ var CloudControlProvider = class {
|
|
|
28041
28325
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
28042
28326
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
28043
28327
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
28044
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
28328
|
+
const { ASGProvider } = await import("./asg-provider-eIVYMrmW.js").then((n) => n.n);
|
|
28045
28329
|
const asgProvider = new ASGProvider();
|
|
28046
28330
|
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
28047
28331
|
}
|
|
@@ -40487,5 +40771,5 @@ var DeployEngine = class DeployEngine {
|
|
|
40487
40771
|
};
|
|
40488
40772
|
|
|
40489
40773
|
//#endregion
|
|
40490
|
-
export { collectInlinePolicyNamesManagedBySiblings as $,
|
|
40491
|
-
//# sourceMappingURL=deploy-engine-
|
|
40774
|
+
export { collectInlinePolicyNamesManagedBySiblings as $, buildDenyExternalAccessPolicy as $n, DynamicReferenceRegionAmbiguousError as $r, describeTypeWithThrottleRetry as $t, isStatefulRecreateTargetForReplace as A, exportNamesCarriedFrom as An, CFN_TEMPLATE_URL_LIMIT as Ar, coerceCfnBoolean as At, gray as B, createAssetRedirectResolver as Bn, processStackMessages as Br, classifyReplaySecretRegion as Bt, refusesFinalSnapshot as C, retryClassificationText as Ci, UNRENDERABLE as Cn, resolveSkipPrefix as Cr, isUnboundTemplateParameter as Ct, makeSiblingClaimReader as D, shellQuote as Dn, stateBucketExistenceConfirmed as Dr, normalizeAwsTagsToCfn as Dt, extractDeploymentEventError as E, forceQuitRecoveryClause as En, resolveUseCdkBootstrapAssets as Er, WAFv2WebACLProvider as Et, isWarmThroughputDecrease as F, shouldRetainResource as Fn, expectedOwnerParam as Fr, readConfigString as Ft, collectPublishedOutputNames as G, assertAssetBucketRegion as Gn, resetAwsClients as Gr, s3BucketDualStackDomainName as Gt, red as H, rewriteTemplateAssetReferences as Hn, resolveBucketRegion as Hr, withSharedDrainBudget as Ht, toFiniteNumber as I, AssetPublisher as In, PARTITION_TABLE as Ir, replayWarn as It, secretBearing as J, isCrossRegionRedirect as Jn, CdkdError as Jr, applyRoleArnIfSet as Jt, exportAliasCollisionScrubWarning as K, ensureAssetStorage as Kn, setAwsClients as Kr, s3BucketRegionalDomainName as Kt, formatResourceLine as L, stringifyValue as Ln, canonicalizeRegion as Lr, requireConfigArray as Lt, renderStatefulReason as M, importableOutputs as Mn, findLargeInlineResources as Mr, configBooleanRefusal as Mt, WARM_THROUGHPUT_MEMBERS as N, orphansAfterRollback as Nn, uploadCfnTemplate as Nr, configIntegerRefusal as Nt, planOrphanAdoption as O, CUSTOM_RESOURCE_RESPONSE_PREFIX as On, warnDeprecatedNoPrefixCliFlag as Or, resolveExplicitPhysicalId as Ot, coerceWarmThroughput as P, orphansCarriedFrom as Pn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Pr, configStringRefusal as Pt, IAMRoleProvider as Q, validateContainerRepoName as Qn, DeployCancelledError as Qr, findSilentDropProperties as Qt, bold as R, WorkGraph as Rn, derivePartitionAndUrlSuffix as Rr, requireConfigObject as Rt, isFinalSnapshotError as S, markRedactedCause as Si, rebuildClientForBucketRegion as Sn, resolveCaptureObservedState as Sr, getAccountInfo as St, makeCanonicalizePropertiesFn as T, buildLockContentionMessage as Tn, resolveStateBucketWithDefaultAndSource as Tr, refStateLookupFromResource as Tt, yellow as U, AssetModeResolver as Un, AwsClients as Ur, s3BucketArn as Ut, green as V, loadPublishableAssetManifest as Vn, clearBucketRegionCache as Vr, producerRegionsFromState as Vt, collectDeclaredOutputNames as W, BOOTSTRAP_MARKER_PREFIX as Wn, getAwsClients as Wr, s3BucketDomainName as Wt, secretSafeKeyDisplay as X, readBootstrapMarkerBody as Xn, CrossAccountSecretRefusalError as Xr, INTRINSIC_KEYS as Xt, secretBearingStateKeyWarning as Y, parseBootstrapMarker as Yn, ConfigError as Yr, DiffCalculator as Yt, getCurrentResourceSecrets as Z, validateAssetBucketName as Zn, DependencyError as Zr, findActionableSilentDrops as Zt, ATOMIC_FINAL_SNAPSHOT_TYPES as _, isMarkedNonRetryable as _i, recoverMaskedOutput as _n, synthesisStatusMessage as _r, isTerminationProtectionPropagationError as _t, DeploymentEventsStore as a, PartialFailureError as ai, STATE_SOURCED_READBACK_RULES as an, dockerSpawnEnvWithSensitive as ar, maskerOrIdentity as at, ccRoutedFinalSnapshotError as b, isTransientServerError as bi, LockManager as bn, resolveApp as br, cfnRefValueFromPhysicalId as bt, replayFailedOperations as c, ResourceUpdateNotSupportedError as ci, createSecretMasker as cn, partitionSensitiveEnv as cr, interruptWatchListenerCount as ct, updatePartialReason as d, StateError as di, identityKeyFor as dn, runDockerStreaming as dr, CloudControlProvider as dt, IntrinsicResolutionRefusalError as ei, withRetry as en, describeAwsFailure as er, clearOnUpdateRemoval as et, withResourceDeadline as f, SynthesisError as fi, isSingleDynamicReferenceToken as fn, escapeRegExp$1 as fr, slowCcOperationTimeoutMs as ft, bindingSkippedOutputs as g, withErrorHandling as gi, recordMaskOnlyValue as gn, Synthesizer as gr, disableInstanceApiTermination as gt, computeImplicitDeleteEdges as h, normalizeAwsError as hi, maskSecretsInText as hn, getDockerImageBySourceHash as hr, deleteSkipReason as ht, DeploymentEventsReader as i, NestedStackChildDirectDestroyError as ii, STATE_SOURCED_CROSS_GENERATION_RULES as in, describeDockerFailure as ir, maskDeep as it, isStatefulRecreateTargetSync as j, importableOutputKeys as jn, MIGRATE_TMP_PREFIX as jr, coerceCfnInteger as jt, MULTI_REGION_RECREATE_BLOCKED_TYPES as k, DEFAULT_STATE_PREFIX as kn, CFN_TEMPLATE_BODY_LIMIT as kr, assertRegionMatch as kt, replayRollback as l, StackHasActiveImportsError as li, dynamicReferenceTokens as ln, redactDockerArgvValues as lr, isInterruptedWaitError as lt, IMPLICIT_DELETE_DEPENDENCIES as m, isCdkdError as mi, maskSecretsInError as mn, AssetManifestLoader as mr, deleteIndeterminateGuards as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, LocalStartServiceError as ni, TemplateParser as nn, describeDockerCapturedOutput as nr, wouldReturnToSdkProvider as nt, planFailedOps as o, ProvisioningError as oi, TEMPLATE_SOURCED_RULES as on, formatDockerLoginError as or, beginCommandInterruptScope as ot, maskingRetryLogger as p, formatError as pi, markSameGenerationBag as pn, stripControlChars as pr, UNSPECIFIED_SKIP_REASON as pt, isExportAliasCollision as q, getBootstrapMarkerKey as qn, AssetError as qr, s3BucketWebsiteUrl as qt, DeployEngine as r, LockError as ri, STATE_SOURCED_BASELINE_RULES as rn, describeDockerExecFailure as rr, createMaskedRetryLogger as rt, planRollback as s, ResourceTimeoutError as si, carriesSecretMask as sn, getDockerCmd as sr, endCommandInterruptScope as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, LocalInvokeBuildError as ti, DagBuilder as tn, buildDockerImage as tr, ProviderRegistry as tt, updatePartialMessage as u, StackTerminationProtectionError as ui, errorCauseChain as un, runDockerForeground as ur, startInterruptWatch as ut, PRE_DELETE_SNAPSHOT_TYPES as v, isRetryableTransientError as vi, redactSecretsForState as vn, getDefaultStateBucketName as vr, IntrinsicFunctionResolver as vt, unsupportedFinalSnapshotError as w, __exportAll as wi, buildForceUnlockCommand as wn, resolveStateBucketWithDefault as wr, parameterTypeMayLoseSecretIdentity as wt, createPreDeleteFinalSnapshot as x, markNonRetryable as xi, S3StateBackend as xn, resolveAutoAssetStorage as xr, coerceParameterTypedValue as xt, buildFinalSnapshotIdentifier as y, isThrottlingError as yi, scrubResourceRecord as yn, getLegacyStateBucketName as yr, carriesDynamicReference as yt, cyan as z, buildAssetRedirectMap as zn, AssemblyReader as zr, requireConfigString as zt };
|
|
40775
|
+
//# sourceMappingURL=deploy-engine-CpmvgRtm.js.map
|