@go-to-k/cdkd 0.288.0 → 0.288.2
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-DQCVYO5-.js → asg-provider-DUlRn84u.js} +16 -12
- package/dist/{asg-provider-DQCVYO5-.js.map → asg-provider-DUlRn84u.js.map} +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-DF3fAY6q.js → deploy-engine-Cxt3gn8N.js} +277 -95
- package/dist/deploy-engine-Cxt3gn8N.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{program-CizHCByV.js → program-BRon74Fc.js} +756 -493
- package/dist/{program-CizHCByV.js.map → program-BRon74Fc.js.map} +1 -1
- package/dist/{version-BQMDIEQY.js → version-BRByznpy.js} +2 -2
- package/dist/{version-BQMDIEQY.js.map → version-BRByznpy.js.map} +1 -1
- package/package.json +9 -9
- package/dist/deploy-engine-DF3fAY6q.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as withStackName, d as applyDefaultNameForFallback, f as generateResourceName, h as looksLikeCdkdGeneratedName, m as getCurrentStackName, n as getLogger, p as generateResourceNameWithFallback, r as isStdoutReservedForPayload, s as getLiveRenderer } from "./logger-Dw-3y48G.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-BRByznpy.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { 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";
|
|
@@ -2337,7 +2337,7 @@ async function resolveCrossAccountStateBucket(accountId, credentials) {
|
|
|
2337
2337
|
/** Cloud assembly schema version compatible with CDK v2 */
|
|
2338
2338
|
const CDK_ASM_VERSION = "38.0.0";
|
|
2339
2339
|
/** Maximum context size before overflow to temp file (32KB) */
|
|
2340
|
-
const CONTEXT_OVERFLOW_LIMIT =
|
|
2340
|
+
const CONTEXT_OVERFLOW_LIMIT = 32768;
|
|
2341
2341
|
/**
|
|
2342
2342
|
* Remove one matched pair of surrounding quotes from a shell token, so a quoted
|
|
2343
2343
|
* entrypoint (`"bin/app.js"`) is recognized as a .js file and re-quoted cleanly.
|
|
@@ -2551,7 +2551,6 @@ function processStackMessages(stacks, logger, options = {}) {
|
|
|
2551
2551
|
case "error":
|
|
2552
2552
|
hasErrors = true;
|
|
2553
2553
|
logger.error(`[Error at ${msg.path}] ${msg.message}`);
|
|
2554
|
-
break;
|
|
2555
2554
|
}
|
|
2556
2555
|
const failAt = options.strict ? "warn" : options.ignoreErrors ? "none" : "error";
|
|
2557
2556
|
if (hasErrors && failAt !== "none") throw new SynthesisError("Found errors");
|
|
@@ -3174,10 +3173,7 @@ var CcApiContextProvider = class {
|
|
|
3174
3173
|
case "at-least-one":
|
|
3175
3174
|
if (count < 1) throw new Error(`Expected at least one ${typeName}${context}, found none`);
|
|
3176
3175
|
break;
|
|
3177
|
-
case "at-most-one":
|
|
3178
|
-
if (count > 1) throw new Error(`Expected at most one ${typeName}${context}, found ${count}`);
|
|
3179
|
-
break;
|
|
3180
|
-
case "any": break;
|
|
3176
|
+
case "at-most-one": if (count > 1) throw new Error(`Expected at most one ${typeName}${context}, found ${count}`);
|
|
3181
3177
|
}
|
|
3182
3178
|
}
|
|
3183
3179
|
/**
|
|
@@ -4514,7 +4510,8 @@ async function purgeNoncurrentKeyVersions(s3Client, bucket, keys, options = {})
|
|
|
4514
4510
|
const elided = failed.size - named.length;
|
|
4515
4511
|
logger.warn(`Could not purge noncurrent versions of ${failed.size} key(s) in s3://${displaySafe(bucket, { asciiOnly: true })}. Their previous versions survive and remain readable via GetObject with a VersionId (${options.objectDescription ?? "the body of an object cdkd has just reported as removed"}). Grant s3:ListBucketVersions and s3:DeleteObjectVersion on the state bucket, or purge the key(s) by hand. Failures: ${named.join(", ")}` + (elided > 0 ? ` (and ${elided} more)` : ""));
|
|
4516
4512
|
}
|
|
4517
|
-
|
|
4513
|
+
const replicationKeys = [.../* @__PURE__ */ new Set([...purged, ...unsettledBodies])];
|
|
4514
|
+
await warnIfPurgeIsReplicated(s3Client, bucket, replicationKeys, {
|
|
4518
4515
|
requestFields,
|
|
4519
4516
|
logger,
|
|
4520
4517
|
...options.objectDescription !== void 0 && { objectDescription: options.objectDescription }
|
|
@@ -5114,7 +5111,8 @@ async function expandMacrosAttempt(template, opts, logger) {
|
|
|
5114
5111
|
ChangeSetName: changeSetName
|
|
5115
5112
|
})).catch(() => void 0);
|
|
5116
5113
|
const reason = desc?.StatusReason ?? "unknown (DescribeChangeSet failed)";
|
|
5117
|
-
|
|
5114
|
+
const status = desc?.Status ?? "UNKNOWN";
|
|
5115
|
+
throw new MacroExpansionError(`CloudFormation macro expansion failed (status=${status}): ${reason}`, waiterError instanceof Error ? waiterError : void 0);
|
|
5118
5116
|
}
|
|
5119
5117
|
const tpl = await cfn.send(new GetTemplateCommand({
|
|
5120
5118
|
StackName: transientStackName,
|
|
@@ -5123,7 +5121,10 @@ async function expandMacrosAttempt(template, opts, logger) {
|
|
|
5123
5121
|
}));
|
|
5124
5122
|
if (tpl.TemplateBody === void 0 || tpl.TemplateBody === null) throw new MacroExpansionError(`CloudFormation returned no Processed-stage template body for the macro-expansion changeset. This typically indicates a CFn-side regression — re-run, and if the failure persists open an issue with the transforms involved: [${macros.join(", ")}].`);
|
|
5125
5123
|
const expanded = parseTemplateBody(tpl.TemplateBody);
|
|
5126
|
-
if (containsMacro(expanded))
|
|
5124
|
+
if (containsMacro(expanded)) {
|
|
5125
|
+
const inner = enumerateMacros(expanded);
|
|
5126
|
+
throw new MacroExpansionError(`Macro expansion produced a template that still contains macros [${inner.join(", ")}]. Multi-stage macros (a macro whose expansion emits another macro reference) are intentionally out of scope in cdkd v1 — see https://github.com/go-to-k/cdkd/issues/463. If you need this pattern, manually pre-expand the template and deploy the result.`);
|
|
5127
|
+
}
|
|
5127
5128
|
logger.debug(`Macro expansion: success — ${Object.keys(expanded.Resources ?? {}).length} resources after expansion.`);
|
|
5128
5129
|
return expanded;
|
|
5129
5130
|
} finally {
|
|
@@ -5245,7 +5246,8 @@ function loadJsonConfig(filePath) {
|
|
|
5245
5246
|
* Load cdk.json from the current working directory
|
|
5246
5247
|
*/
|
|
5247
5248
|
function loadCdkJson(cwd) {
|
|
5248
|
-
|
|
5249
|
+
const dir = cwd || process.cwd();
|
|
5250
|
+
return loadJsonConfig(resolve(dir, "cdk.json"));
|
|
5249
5251
|
}
|
|
5250
5252
|
/**
|
|
5251
5253
|
* Load user-level defaults from ~/.cdk.json
|
|
@@ -6200,8 +6202,10 @@ async function spawnStreaming(cmd, args, options = {}) {
|
|
|
6200
6202
|
const stderrChunks = [];
|
|
6201
6203
|
child.stdout.on("data", (chunk) => {
|
|
6202
6204
|
stdoutChunks.push(chunk);
|
|
6203
|
-
if (streamLive)
|
|
6204
|
-
|
|
6205
|
+
if (streamLive) {
|
|
6206
|
+
if (isStdoutReservedForPayload()) process.stderr.write(chunk);
|
|
6207
|
+
else process.stdout.write(chunk);
|
|
6208
|
+
}
|
|
6205
6209
|
});
|
|
6206
6210
|
child.stderr.on("data", (chunk) => {
|
|
6207
6211
|
stderrChunks.push(chunk);
|
|
@@ -7831,10 +7835,11 @@ async function assertAssetBucketRegion(s3Client, bucketName, expectedRegion, acc
|
|
|
7831
7835
|
const fromHeader = readBucketRegionHeader(cause);
|
|
7832
7836
|
if (fromHeader) actual = canonicalizeRegion(fromHeader);
|
|
7833
7837
|
else try {
|
|
7834
|
-
|
|
7838
|
+
const location = await s3Client.send(new GetBucketLocationCommand({
|
|
7835
7839
|
Bucket: bucketName,
|
|
7836
7840
|
ExpectedBucketOwner: accountId
|
|
7837
|
-
}))
|
|
7841
|
+
}));
|
|
7842
|
+
actual = canonicalizeRegion(bucketLocationToRegion$1(location.LocationConstraint));
|
|
7838
7843
|
} catch (probeError) {
|
|
7839
7844
|
const fromProbe = readBucketRegionHeader(probeError);
|
|
7840
7845
|
if (fromProbe) actual = canonicalizeRegion(fromProbe);
|
|
@@ -9000,7 +9005,8 @@ var AssetPublisher = class {
|
|
|
9000
9005
|
const err = error;
|
|
9001
9006
|
const message = stringifyValue(err["message"] || err["name"] || error);
|
|
9002
9007
|
const code = stringifyValue(err["Code"] || err["code"] || err["name"] || "");
|
|
9003
|
-
|
|
9008
|
+
const detail = code ? `${code}: ${message}` : message;
|
|
9009
|
+
throw new AssetError(`Asset publishing failed: ${detail}`, error instanceof Error ? error : void 0);
|
|
9004
9010
|
}
|
|
9005
9011
|
}
|
|
9006
9012
|
/**
|
|
@@ -10184,9 +10190,10 @@ var S3StateBackend = class {
|
|
|
10184
10190
|
if (isNoSuchKey(error)) return { kind: "absent" };
|
|
10185
10191
|
const { detail } = describeAwsFailure(error);
|
|
10186
10192
|
this.logger.debug(`Could not read legacy state region for '${this.displayName(stackName)}': ${displaySafe(detail, { asciiOnly: true }) || "<unrenderable>"}`);
|
|
10193
|
+
const cls = error instanceof Error && error.name ? error.name : "an unknown error";
|
|
10187
10194
|
return {
|
|
10188
10195
|
kind: "unreadable",
|
|
10189
|
-
reason: displaySafe(
|
|
10196
|
+
reason: displaySafe(cls, { asciiOnly: true }) || "<unrenderable>"
|
|
10190
10197
|
};
|
|
10191
10198
|
}
|
|
10192
10199
|
}
|
|
@@ -10289,7 +10296,7 @@ function isNoSuchKey(error) {
|
|
|
10289
10296
|
* tolerates FOURTEEN consecutive missed renewals before it lapses, and an
|
|
10290
10297
|
* ordinary broad-set integ (~8 min) performs three.
|
|
10291
10298
|
*/
|
|
10292
|
-
const MAX_RENEWAL_INTERVAL_MS =
|
|
10299
|
+
const MAX_RENEWAL_INTERVAL_MS = 12e4;
|
|
10293
10300
|
/**
|
|
10294
10301
|
* Renew after at most a quarter of the TTL, so a short TTL still gets three
|
|
10295
10302
|
* chances to renew before it lapses. This is what binds the two numbers
|
|
@@ -11093,7 +11100,9 @@ var LockManager = class {
|
|
|
11093
11100
|
const expiresIn = lockInfo ? this.formatDuration(lockInfo.expiresAt - Date.now()) : "unknown";
|
|
11094
11101
|
const forceUnlockCommand = buildForceUnlockCommand(stackName, region);
|
|
11095
11102
|
const recovery = forceUnlockCommand ? `If you are certain no other process is active, run: ${forceUnlockCommand}` : `If you are certain no other process is active, ${UNREPRODUCIBLE_LOCK_CLAUSE.charAt(0).toLowerCase()}${UNREPRODUCIBLE_LOCK_CLAUSE.slice(1)}`;
|
|
11096
|
-
|
|
11103
|
+
const safeStack = displaySafe(stackName, { asciiOnly: true }) || "<unrenderable>";
|
|
11104
|
+
const safeRegion = displaySafe(region, { asciiOnly: true }) || "<unrenderable>";
|
|
11105
|
+
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}`));
|
|
11097
11106
|
}
|
|
11098
11107
|
};
|
|
11099
11108
|
|
|
@@ -11197,6 +11206,102 @@ function resolvedPlaintextOf(secrets, expression) {
|
|
|
11197
11206
|
return typeof recorded === "string" ? recorded : void 0;
|
|
11198
11207
|
}
|
|
11199
11208
|
/**
|
|
11209
|
+
* The bag OBJECTS a deploy pass produced ITSELF and installed on a success
|
|
11210
|
+
* path — the fact the resolved-pair evidence above cannot state (issue
|
|
11211
|
+
* [#2516](https://github.com/go-to-k/cdkd/issues/2516)).
|
|
11212
|
+
*
|
|
11213
|
+
* A pair proves that THIS pass resolved a token to a plaintext; it says nothing
|
|
11214
|
+
* about which bag is being walked. The deploy engine's persist choke point
|
|
11215
|
+
* walks EVERY record in the state map against today's template, and a record
|
|
11216
|
+
* that merely ENTERED the create/update arm is still the PREVIOUS generation
|
|
11217
|
+
* until its provider call succeeds (an intermediate save, a pre/post-rollback
|
|
11218
|
+
* save, Ctrl-C — the same population the `sourceIsSameGeneration` note on
|
|
11219
|
+
* {@link PathSourceRules} names). One record also carries two bags of
|
|
11220
|
+
* different provenance: `properties`, this pass's resolved bag once the
|
|
11221
|
+
* provider succeeded, and `observedProperties`, an AWS readback installed
|
|
11222
|
+
* separately. So the fact is BAG-specific, not caller- or record-level, and it
|
|
11223
|
+
* is carried on the object: {@link markSameGenerationBag} at the moment the
|
|
11224
|
+
* successful result is installed, consulted by {@link redactSecretsForState}
|
|
11225
|
+
* for the object it is handed. A copy of the bag, a derived needle map, a
|
|
11226
|
+
* previous generation's record, a scrub / import / drift walk and a bag the
|
|
11227
|
+
* engine did not mark all answer `false` and keep the fall-through.
|
|
11228
|
+
*
|
|
11229
|
+
* A `WeakSet` for the reason {@link resolvedPairsOf} is a `WeakMap`: the mark
|
|
11230
|
+
* dies with the object it is on, and nothing has to clear it.
|
|
11231
|
+
*/
|
|
11232
|
+
const sameGenerationBags = /* @__PURE__ */ new WeakSet();
|
|
11233
|
+
/**
|
|
11234
|
+
* Mark `bag` as an object THIS pass is entitled to speak for, and return it.
|
|
11235
|
+
* The one evidence {@link positionByEmbeddedSpan} needs beyond a resolved pair
|
|
11236
|
+
* to write a middle SHORTER than {@link MIN_NEEDLE_LENGTH} — see the arm.
|
|
11237
|
+
*
|
|
11238
|
+
* Deliberately NOT "produced by resolving today's template, read back from a
|
|
11239
|
+
* resource it just wrote, and about to be installed on a success path": each
|
|
11240
|
+
* of those three was in this sentence and each is false at one site (an
|
|
11241
|
+
* unchanged resource's auto-refresh resolves nothing; the no-change re-check
|
|
11242
|
+
* and the journal are never installed on the record). The conditions are per
|
|
11243
|
+
* site and are listed below.
|
|
11244
|
+
*
|
|
11245
|
+
* WHAT THE MARK CLAIMS, which is the only thing every site shares: the object
|
|
11246
|
+
* is one THIS PASS is entitled to speak for, so a sub-floor middle in it may
|
|
11247
|
+
* be written as the token this pass recorded. What never qualifies is a bag of
|
|
11248
|
+
* MIXED provenance: a provider's `effectiveProperties` replacement may carry
|
|
11249
|
+
* previous-state values IN, so an object-level mark on it would prove nothing
|
|
11250
|
+
* for those leaves — it stays unmarked and keeps the residual. Nor does the
|
|
11251
|
+
* object the resolver produced, marked at resolution time: it is not
|
|
11252
|
+
* necessarily the object state ends up holding.
|
|
11253
|
+
*
|
|
11254
|
+
* The CONDITIONS are per SITE, not global, and stating them globally is what
|
|
11255
|
+
* this paragraph kept getting wrong (PR 2753, rounds 3 and 4). "After the
|
|
11256
|
+
* provider call" is false for the no-change re-check, which marks BEFORE it
|
|
11257
|
+
* and may skip it entirely. "Every leaf this pass produced" is false for the
|
|
11258
|
+
* auto-refresh readback of an UNCHANGED resource, where nothing was resolved
|
|
11259
|
+
* at all — there the safety comes from the empty secrets map, not from the
|
|
11260
|
+
* mark. Read the per-site list below rather than a rule over all five.
|
|
11261
|
+
*
|
|
11262
|
+
* The five call sites, and which of them the record HOLDS, because the earlier
|
|
11263
|
+
* "two never-installed copies" reading of this paragraph was false once the
|
|
11264
|
+
* third copy arrived:
|
|
11265
|
+
* - `propertiesToRecord` — the record's `properties`, installed. The resolved
|
|
11266
|
+
* bag itself when the route drops nothing, a narrowed copy of it when it
|
|
11267
|
+
* does, and `withoutSilentDropProperties` returns its input by reference in
|
|
11268
|
+
* the first case, which is why the mark must be taken AFTER the narrowing
|
|
11269
|
+
* and not before.
|
|
11270
|
+
* - `drainObservedCaptures` — the `observedProperties` readback it installs,
|
|
11271
|
+
* and a COPY: the object a provider returned is never the marked one, so a
|
|
11272
|
+
* provider that hands back its own `properties` argument cannot get a
|
|
11273
|
+
* previous generation marked. It marks EVERY capture it drains, which is
|
|
11274
|
+
* wider than "a resource this pass wrote" — the schema-upgrade auto-refresh
|
|
11275
|
+
* of an UNCHANGED resource is marked too. What keeps that safe is the map,
|
|
11276
|
+
* not the mark: `perResourceSecrets` is populated only in the create /
|
|
11277
|
+
* update arms, so an unchanged resource's walk carries an empty one and the
|
|
11278
|
+
* span arm cannot fire whatever the object is marked.
|
|
11279
|
+
* - `resolveOutputs` — the `outputs` bag this pass resolved. What every site
|
|
11280
|
+
* shares is that the marked object is the redaction INPUT; whether the
|
|
11281
|
+
* record then holds that same object varies, and here it depends on whether
|
|
11282
|
+
* this pass recorded any output secret: with one,
|
|
11283
|
+
* `redactOutputs` returns a fresh redacted bag and that return value is
|
|
11284
|
+
* installed; with none — the ordinary deploy — it returns its input
|
|
11285
|
+
* unchanged and the marked object IS the one
|
|
11286
|
+
* stored. On the no-change path the newly redacted bag is installed when
|
|
11287
|
+
* the outputs CHANGED, and the previous `persistedOutputs` is kept
|
|
11288
|
+
* otherwise; that previous bag is unmarked, which is the answer that arm
|
|
11289
|
+
* wants.
|
|
11290
|
+
* - the update arm's no-change re-check — a marked `{ ...resolvedProps }`
|
|
11291
|
+
* compared against the stored record so a stored token reads as a no-op.
|
|
11292
|
+
* NOT installed; the object the provider is handed is the unmarked original.
|
|
11293
|
+
* - the rollback journal's FAILED-op `attemptedProperties` — a marked copy, so
|
|
11294
|
+
* that persisted artifact does not carry the plaintext on exactly the
|
|
11295
|
+
* failure path. NOT installed on the record.
|
|
11296
|
+
*/
|
|
11297
|
+
function markSameGenerationBag(bag) {
|
|
11298
|
+
sameGenerationBags.add(bag);
|
|
11299
|
+
return bag;
|
|
11300
|
+
}
|
|
11301
|
+
function isSameGenerationBag(bag) {
|
|
11302
|
+
return sameGenerationBags.has(bag);
|
|
11303
|
+
}
|
|
11304
|
+
/**
|
|
11200
11305
|
* Every `{{resolve:...}}` expression this process has PROVEN resolves to a
|
|
11201
11306
|
* secret, as a SET — uncollapsed by resolved value (issue #1910).
|
|
11202
11307
|
*
|
|
@@ -12847,15 +12952,78 @@ function singleSpanFrame(bag, source) {
|
|
|
12847
12952
|
* not create is the whole-token arm's: a middle that is ALREADY an expression
|
|
12848
12953
|
* (a persisted answer from another generation), which the token refusal below
|
|
12849
12954
|
* keeps out — and, by the same argument, any leaf the value scan would NOT
|
|
12850
|
-
* rewrite to exactly `prefix + survivor + suffix`: a
|
|
12851
|
-
*
|
|
12852
|
-
*
|
|
12853
|
-
*
|
|
12854
|
-
*
|
|
12855
|
-
*
|
|
12856
|
-
*
|
|
12857
|
-
*
|
|
12858
|
-
*
|
|
12955
|
+
* rewrite to exactly `prefix + survivor + suffix`: a whole leaf that is itself
|
|
12956
|
+
* another recorded plaintext, a needle starting in the prefix and overlapping
|
|
12957
|
+
* the middle, and — on a bag whose generation is NOT proven — a middle shorter
|
|
12958
|
+
* than the scan's needle floor. The arm checks that equivalence against the
|
|
12959
|
+
* scan's own answer rather than re-deriving the scan's rules. Pinned by the
|
|
12960
|
+
* cross-generation cases in `secret-redaction-embedded-span.test.ts`.
|
|
12961
|
+
*
|
|
12962
|
+
* BELOW THE NEEDLE FLOOR the scan makes no claim at all (issue
|
|
12963
|
+
* [#2516](https://github.com/go-to-k/cdkd/issues/2516)): {@link buildNeedleRegex}
|
|
12964
|
+
* drops every plaintext shorter than {@link MIN_NEEDLE_LENGTH} from its
|
|
12965
|
+
* alternation, so an embedded 1-3 character secret is left in plaintext by
|
|
12966
|
+
* the scan, with or without a same-plaintext sibling. Accepting the scan's
|
|
12967
|
+
* silence (`scanned === bag`) as equivalence would therefore be a NEW claim
|
|
12968
|
+
* rather than a choice within the scan's class, and on a previous
|
|
12969
|
+
* generation's bag it would fabricate: a 1-3 character readback or old
|
|
12970
|
+
* record that COINCIDES with today's plaintext (`port:0` where AWS returns a
|
|
12971
|
+
* default and today's secret resolved to `0`) would be persisted as today's
|
|
12972
|
+
* expression, which round-trips today and, after a rotation, reports a drift
|
|
12973
|
+
* that never happened. So that arm is admitted only for a bag whose
|
|
12974
|
+
* generation IS proven: `bagIsSameGeneration`, the object-level mark
|
|
12975
|
+
* {@link markSameGenerationBag} puts on the bags the deploy engine hands to
|
|
12976
|
+
* redaction on a success path (the record's `properties`, which are the
|
|
12977
|
+
* resolved bag or the subset of it the SDK route writes; EVERY
|
|
12978
|
+
* `observedProperties` readback `drainObservedCaptures` drains, an unchanged
|
|
12979
|
+
* resource's auto-refresh included, where the empty secrets map rather than
|
|
12980
|
+
* the mark is what keeps it safe; and the `outputs` bag this pass resolved,
|
|
12981
|
+
* whose redacted RETURN VALUE is usually what the record holds) and on two
|
|
12982
|
+
* copies of the resolver's own output that the record never holds. That
|
|
12983
|
+
* function's contract is the authority — the conditions differ per site and
|
|
12984
|
+
* do not survive being stated once. Threaded down from
|
|
12985
|
+
* {@link redactSecretsForState} for exactly the object it was handed. With
|
|
12986
|
+
* the mark AND the pair, `recorded === middle` says this pass resolved the
|
|
12987
|
+
* source token to the middle and the bag is this pass's own, so
|
|
12988
|
+
* `prefix + token + suffix` is what the template says at that leaf and what
|
|
12989
|
+
* the resource holds. Without the mark the sub-floor middle keeps today's
|
|
12990
|
+
* bound, which is the scan's answer: the plaintext, unchanged.
|
|
12991
|
+
*
|
|
12992
|
+
* What stays, stated here rather than papered over. A provider that
|
|
12993
|
+
* substituted `effectiveProperties` built a bag of MIXED provenance, so that
|
|
12994
|
+
* object is never marked and a sub-floor middle in it keeps the scan's
|
|
12995
|
+
* answer. A readback AWS rewrote at that offset to a value that coincides
|
|
12996
|
+
* with the 1-3 character secret is persisted as the expression: value-equal
|
|
12997
|
+
* until the secret rotates, and the same residual the value scan already has
|
|
12998
|
+
* for a 4+ character coincidence in a readback. Every refusal of this arm
|
|
12999
|
+
* returns the scan's answer, so a leaf refused for interference (a frame
|
|
13000
|
+
* that is itself a recorded plaintext, say) has its frame rewritten and its
|
|
13001
|
+
* sub-floor middle left in plaintext. And this arm positions a LITERAL
|
|
13002
|
+
* source leaf only: an `Fn::Join` / `Fn::Sub` source rendering the same
|
|
13003
|
+
* `port:` + token goes to {@link positionByIntrinsicSkeleton}, which refuses
|
|
13004
|
+
* unless the WHOLE bag is a recorded plaintext, so a sub-floor secret
|
|
13005
|
+
* embedded through an intrinsic — the dominant CDK shape — still falls to
|
|
13006
|
+
* the value scan and persists in plaintext. `cdkd scrub`, the documented
|
|
13007
|
+
* repair tool for a pre-GHSA record, cannot repair a sub-floor embedded leaf
|
|
13008
|
+
* either: it walks a STORED bag, which no deploy marked, so the arm is
|
|
13009
|
+
* unreachable from it by construction and the leaf keeps the scan's answer.
|
|
13010
|
+
* The MASKING channel keeps the residual whole: `maskSecretsInText`'s
|
|
13011
|
+
* substring arm carries the same four-character floor, so once this arm has
|
|
13012
|
+
* put `port:{{resolve:...}}` in state, a warn line quoting an AWS message can
|
|
13013
|
+
* still print `port:q7`. Pre-existing and not a regression -- the #2453 class,
|
|
13014
|
+
* and the reason the list would otherwise read as complete when it is not
|
|
13015
|
+
* (maintainer review of PR 2753, round 2).
|
|
13016
|
+
*
|
|
13017
|
+
* The next DEPLOY of that resource repairs the leaves this arm is eligible
|
|
13018
|
+
* for — a LITERAL source leaf on a bag the engine marks — because the
|
|
13019
|
+
* re-check compares unequal against a record holding the plaintext and the
|
|
13020
|
+
* resource is written again from a bag this pass produced. The residuals
|
|
13021
|
+
* named above (an `effectiveProperties` substitution, an intrinsic source
|
|
13022
|
+
* shape) are not repaired by that deploy either; they stay tracked by
|
|
13023
|
+
* #2745. Tracked, with the sub-floor
|
|
13024
|
+
* residuals of a nested-stack child's inherited parameter and of `cdkd
|
|
13025
|
+
* import`'s own resolution, by issue
|
|
13026
|
+
* [#2745](https://github.com/go-to-k/cdkd/issues/2745).
|
|
12859
13027
|
*
|
|
12860
13028
|
* One shape reaches this arm that a reader may not expect: a WHOLE-token
|
|
12861
13029
|
* source that FAILED the whole-token arm's `isKnownSecretExpression` gate (an
|
|
@@ -12883,7 +13051,7 @@ function singleSpanFrame(bag, source) {
|
|
|
12883
13051
|
* the scan as a parameter, which left the bound one wrong caller away from
|
|
12884
13052
|
* comparing against a scan of some other bag with no type error.
|
|
12885
13053
|
*/
|
|
12886
|
-
function positionByEmbeddedSpan(bag, source, secrets) {
|
|
13054
|
+
function positionByEmbeddedSpan(bag, source, secrets, bagIsSameGeneration) {
|
|
12887
13055
|
const scanned = redactSecretsForState(bag, secrets);
|
|
12888
13056
|
const frame = singleSpanFrame(bag, source);
|
|
12889
13057
|
if (frame === void 0) return scanned;
|
|
@@ -12892,8 +13060,9 @@ function positionByEmbeddedSpan(bag, source, secrets) {
|
|
|
12892
13060
|
if (recorded === void 0 || recorded !== middle) return scanned;
|
|
12893
13061
|
const survivor = secrets.get(middle);
|
|
12894
13062
|
if (survivor === void 0) return scanned;
|
|
12895
|
-
if (scanned
|
|
12896
|
-
return prefix + token + suffix;
|
|
13063
|
+
if (scanned === prefix + survivor + suffix) return prefix + token + suffix;
|
|
13064
|
+
if (bagIsSameGeneration && scanned === bag) return prefix + token + suffix;
|
|
13065
|
+
return scanned;
|
|
12897
13066
|
}
|
|
12898
13067
|
/**
|
|
12899
13068
|
* Keys tried, in order, when pairing two arrays whose ORDER cannot be trusted
|
|
@@ -13089,13 +13258,13 @@ function positionListByCrossStackSource(bag, source, secrets) {
|
|
|
13089
13258
|
* association where the position is a cross-stack read, skeleton where it is a
|
|
13090
13259
|
* describable intrinsic, value where none is.
|
|
13091
13260
|
*/
|
|
13092
|
-
function redactByPath(bag, source, secrets, rules, secretExpressions) {
|
|
13261
|
+
function redactByPath(bag, source, secrets, rules, secretExpressions, bagIsSameGeneration) {
|
|
13093
13262
|
if (isDynamicReferenceString(source) && typeof bag === "string") {
|
|
13094
13263
|
if (isSingleDynamicReferenceToken(source) && (rules.trustAnyExpression || isKnownSecretExpression(source, secretExpressions))) {
|
|
13095
13264
|
if (!rules.sourceIsSameGeneration && isSingleDynamicReferenceToken(bag)) return secrets.get(bag) ?? bag;
|
|
13096
13265
|
return source;
|
|
13097
13266
|
}
|
|
13098
|
-
return positionByEmbeddedSpan(bag, source, secrets);
|
|
13267
|
+
return positionByEmbeddedSpan(bag, source, secrets, bagIsSameGeneration);
|
|
13099
13268
|
}
|
|
13100
13269
|
if (typeof bag === "string" && isPlainObject$2(source)) {
|
|
13101
13270
|
const certified = positionByCrossStackSource(bag, source, secrets);
|
|
@@ -13124,16 +13293,16 @@ function redactByPath(bag, source, secrets, rules, secretExpressions) {
|
|
|
13124
13293
|
const positionalIsExact = rules.descendArrays && bag.length === source.length && orderPreserved;
|
|
13125
13294
|
return bag.map((item, i) => {
|
|
13126
13295
|
const j = partnerIndex[i];
|
|
13127
|
-
if (j >= 0) return redactByPath(item, source[j], secrets, rules, secretExpressions);
|
|
13128
|
-
if (positionalIsExact) return redactByPath(item, source[i], secrets, rules, secretExpressions);
|
|
13296
|
+
if (j >= 0) return redactByPath(item, source[j], secrets, rules, secretExpressions, bagIsSameGeneration);
|
|
13297
|
+
if (positionalIsExact) return redactByPath(item, source[i], secrets, rules, secretExpressions, bagIsSameGeneration);
|
|
13129
13298
|
return redactSecretsForState(item, secrets);
|
|
13130
13299
|
});
|
|
13131
13300
|
}
|
|
13132
|
-
if (rules.descendArrays && bag.length === source.length) return bag.map((item, i) => redactByPath(item, source[i], secrets, rules, secretExpressions));
|
|
13301
|
+
if (rules.descendArrays && bag.length === source.length) return bag.map((item, i) => redactByPath(item, source[i], secrets, rules, secretExpressions, bagIsSameGeneration));
|
|
13133
13302
|
}
|
|
13134
13303
|
if (isPlainObject$2(bag) && isPlainObject$2(source)) {
|
|
13135
13304
|
const out = Object.create(null);
|
|
13136
|
-
for (const [k, v] of Object.entries(bag)) out[k] = Object.hasOwn(source, k) ? redactByPath(v, source[k], secrets, rules, secretExpressions) : redactSecretsForState(v, secrets);
|
|
13305
|
+
for (const [k, v] of Object.entries(bag)) out[k] = Object.hasOwn(source, k) ? redactByPath(v, source[k], secrets, rules, secretExpressions, bagIsSameGeneration) : redactSecretsForState(v, secrets);
|
|
13137
13306
|
return out;
|
|
13138
13307
|
}
|
|
13139
13308
|
return redactSecretsForState(bag, secrets);
|
|
@@ -14151,7 +14320,7 @@ function refuseUncertifiedReadbackPositions(bag, source, secrets, learn, mark) {
|
|
|
14151
14320
|
function redactSecretsForState(bag, secrets, source, rules = TEMPLATE_DERIVED_RULES) {
|
|
14152
14321
|
if (secrets.size === 0 && source === void 0) return bag;
|
|
14153
14322
|
if (source !== void 0) {
|
|
14154
|
-
const positioned = redactByPath(bag, source, secrets, rules, recordedExpressionsOf(secrets));
|
|
14323
|
+
const positioned = redactByPath(bag, source, secrets, rules, recordedExpressionsOf(secrets), isSameGenerationBag(bag));
|
|
14155
14324
|
if (!isReadbackProjectedFromState(rules)) return positioned;
|
|
14156
14325
|
const refused = refuseUncertifiedReadbackPositions(positioned, source, secrets);
|
|
14157
14326
|
const derived = deriveReadbackNeedles(bag, source, secrets, rules);
|
|
@@ -14991,7 +15160,10 @@ var DagBuilder = class {
|
|
|
14991
15160
|
this.logger.debug(`Dependency graph built: ${resourceIds.length} nodes, ${edgeCount} edges`);
|
|
14992
15161
|
edgeCount += this.addCustomResourcePolicyEdges(graph, template);
|
|
14993
15162
|
edgeCount += this.addLambdaVpcEdges(graph, template);
|
|
14994
|
-
if (!alg.isAcyclic(graph))
|
|
15163
|
+
if (!alg.isAcyclic(graph)) {
|
|
15164
|
+
const cycles = this.findCycles(graph);
|
|
15165
|
+
throw new DependencyError(`Circular dependency detected in template. Cycles: ${cycles.map((c) => c.join(" -> ")).join("; ")}`);
|
|
15166
|
+
}
|
|
14995
15167
|
return graph;
|
|
14996
15168
|
}
|
|
14997
15169
|
/**
|
|
@@ -15020,7 +15192,10 @@ var DagBuilder = class {
|
|
|
15020
15192
|
const predecessors = graphCopy.predecessors(node);
|
|
15021
15193
|
return !predecessors || predecessors.length === 0;
|
|
15022
15194
|
});
|
|
15023
|
-
if (readyNodes.length === 0)
|
|
15195
|
+
if (readyNodes.length === 0) {
|
|
15196
|
+
const remaining = graphCopy.nodes();
|
|
15197
|
+
throw new DependencyError(`Circular dependency detected. Remaining nodes: ${remaining.join(", ")}`);
|
|
15198
|
+
}
|
|
15024
15199
|
this.logger.debug(`Level ${levelNum}: ${readyNodes.length} resources - ${readyNodes.join(", ")}`);
|
|
15025
15200
|
levels.push(readyNodes);
|
|
15026
15201
|
readyNodes.forEach((node) => {
|
|
@@ -15826,9 +16001,10 @@ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
15826
16001
|
* 4s/8s steps overshoot it. The dense schedule applies ONLY when the caller
|
|
15827
16002
|
* left the schedule at its defaults — a caller that passed its own
|
|
15828
16003
|
* `maxRetries` / `initialDelayMs` / `maxDelayMs` / `isRetryable` picked that
|
|
15829
|
-
* schedule deliberately (e.g. the DELETE path's 3
|
|
15830
|
-
*
|
|
15831
|
-
*
|
|
16004
|
+
* schedule deliberately (e.g. the DELETE path's 3 retries from 5s — 5s/8s/8s,
|
|
16005
|
+
* since it passes `initialDelayMs` but leaves `maxDelayMs` at the 8s default —
|
|
16006
|
+
* or the delete-then-re-create sites' ~64s budget covering SQS's 60s name
|
|
16007
|
+
* cooldown) and gets it verbatim.
|
|
15832
16008
|
*
|
|
15833
16009
|
* A THIRD class rides its own grid on the default schedule since issue
|
|
15834
16010
|
* [#2116](https://github.com/go-to-k/cdkd/issues/2116): a NAME COOLDOWN (a
|
|
@@ -19370,9 +19546,7 @@ var DiffCalculator = class DiffCalculator {
|
|
|
19370
19546
|
case "DELETE":
|
|
19371
19547
|
summary.delete++;
|
|
19372
19548
|
break;
|
|
19373
|
-
case "NO_CHANGE":
|
|
19374
|
-
summary.noChange++;
|
|
19375
|
-
break;
|
|
19549
|
+
case "NO_CHANGE": summary.noChange++;
|
|
19376
19550
|
}
|
|
19377
19551
|
return summary;
|
|
19378
19552
|
}
|
|
@@ -21122,7 +21296,8 @@ var WAFv2WebACLProvider = class {
|
|
|
21122
21296
|
this.logger.debug(`Successfully deleted WAFv2 WebACL ${logicalId}`);
|
|
21123
21297
|
} catch (error) {
|
|
21124
21298
|
if (error instanceof WAFNonexistentItemException) {
|
|
21125
|
-
|
|
21299
|
+
const clientRegion = await this.getClient().config.region();
|
|
21300
|
+
assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
21126
21301
|
this.logger.debug(`WAFv2 WebACL ${physicalId} does not exist, skipping deletion`);
|
|
21127
21302
|
return;
|
|
21128
21303
|
}
|
|
@@ -21224,7 +21399,8 @@ var WAFv2WebACLProvider = class {
|
|
|
21224
21399
|
result["TokenDomains"] = webACL.TokenDomains ? [...webACL.TokenDomains] : [];
|
|
21225
21400
|
if (webACL.AssociationConfig) result["AssociationConfig"] = webACL.AssociationConfig;
|
|
21226
21401
|
try {
|
|
21227
|
-
|
|
21402
|
+
const tagsResp = await this.getClient().send(new ListTagsForResourceCommand$11({ ResourceARN: physicalId }));
|
|
21403
|
+
result["Tags"] = normalizeAwsTagsToCfn(tagsResp.TagInfoForResource?.TagList);
|
|
21228
21404
|
} catch (err) {
|
|
21229
21405
|
this.logger.debug(`WAFv2 ListTagsForResource(${physicalId}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
21230
21406
|
}
|
|
@@ -22929,14 +23105,15 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
22929
23105
|
const resolved = {};
|
|
22930
23106
|
for (const [key, val] of Object.entries(obj)) {
|
|
22931
23107
|
const resolvedVal = await this.resolveValue(val, context);
|
|
22932
|
-
if (resolvedVal !== AWS_NO_VALUE)
|
|
22933
|
-
|
|
22934
|
-
|
|
22935
|
-
|
|
22936
|
-
|
|
22937
|
-
|
|
22938
|
-
|
|
22939
|
-
|
|
23108
|
+
if (resolvedVal !== AWS_NO_VALUE) {
|
|
23109
|
+
if (key === "__proto__") Object.defineProperty(resolved, key, {
|
|
23110
|
+
value: resolvedVal,
|
|
23111
|
+
enumerable: true,
|
|
23112
|
+
writable: true,
|
|
23113
|
+
configurable: true
|
|
23114
|
+
});
|
|
23115
|
+
else resolved[key] = resolvedVal;
|
|
23116
|
+
} else this.logger.debug(`Property ${key} resolved to AWS::NoValue, omitting from object`);
|
|
22940
23117
|
}
|
|
22941
23118
|
return resolved;
|
|
22942
23119
|
}
|
|
@@ -23649,9 +23826,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
23649
23826
|
case "PublicDnsName":
|
|
23650
23827
|
value = instance?.PublicDnsName;
|
|
23651
23828
|
break;
|
|
23652
|
-
case "AvailabilityZone":
|
|
23653
|
-
value = instance?.Placement?.AvailabilityZone;
|
|
23654
|
-
break;
|
|
23829
|
+
case "AvailabilityZone": value = instance?.Placement?.AvailabilityZone;
|
|
23655
23830
|
}
|
|
23656
23831
|
if (value !== void 0 && value !== null && value !== "") {
|
|
23657
23832
|
cachedEc2InstanceAttributes[cacheKey] = value;
|
|
@@ -24775,7 +24950,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
24775
24950
|
const credentials = await assumeRoleForCrossAccountStateRead(roleArn);
|
|
24776
24951
|
const { bucket, region: bucketRegion } = await resolveCrossAccountStateBucket(parsed.accountId, credentials);
|
|
24777
24952
|
const prefix = context.stateBackend?.prefix ?? "cdkd";
|
|
24778
|
-
|
|
24953
|
+
const s3 = new S3Client({
|
|
24779
24954
|
...awsClientDefaults(),
|
|
24780
24955
|
region: bucketRegion,
|
|
24781
24956
|
credentials: {
|
|
@@ -24789,7 +24964,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
24789
24964
|
warn: () => {},
|
|
24790
24965
|
error: () => {}
|
|
24791
24966
|
}
|
|
24792
|
-
})
|
|
24967
|
+
});
|
|
24968
|
+
return new S3StateBackend(s3, {
|
|
24793
24969
|
bucket,
|
|
24794
24970
|
prefix
|
|
24795
24971
|
}, {
|
|
@@ -25984,7 +26160,7 @@ function unsupportedTypeIssueUrl(resourceType) {
|
|
|
25984
26160
|
|
|
25985
26161
|
//#endregion
|
|
25986
26162
|
//#region src/provisioning/slow-cc-operation-timeouts.ts
|
|
25987
|
-
const MINUTE_MS =
|
|
26163
|
+
const MINUTE_MS = 6e4;
|
|
25988
26164
|
/**
|
|
25989
26165
|
* 60 min covers the worst-case observed for each type with headroom over the
|
|
25990
26166
|
* 15-30 min typical range. Keyed by CloudFormation type name. RDS / ElastiCache
|
|
@@ -26307,7 +26483,7 @@ var CloudControlProvider = class {
|
|
|
26307
26483
|
cloudControlClient;
|
|
26308
26484
|
logger = getLogger().child("CloudControlProvider");
|
|
26309
26485
|
patchGenerator = new JsonPatchGenerator();
|
|
26310
|
-
MAX_WAIT_TIME_MS =
|
|
26486
|
+
MAX_WAIT_TIME_MS = 9e5;
|
|
26311
26487
|
INITIAL_POLL_INTERVAL_MS = 1e3;
|
|
26312
26488
|
MAX_POLL_INTERVAL_MS = 1e4;
|
|
26313
26489
|
constructor() {
|
|
@@ -26466,8 +26642,9 @@ var CloudControlProvider = class {
|
|
|
26466
26642
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
26467
26643
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
26468
26644
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
26469
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
26470
|
-
|
|
26645
|
+
const { ASGProvider } = await import("./asg-provider-DUlRn84u.js").then((n) => n.n);
|
|
26646
|
+
const asgProvider = new ASGProvider();
|
|
26647
|
+
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
26471
26648
|
}
|
|
26472
26649
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
26473
26650
|
if (isProtectedEc2Instance) await disableInstanceApiTermination(getAwsClients().ec2, physicalId, this.logger);
|
|
@@ -27119,16 +27296,13 @@ var CloudControlProvider = class {
|
|
|
27119
27296
|
}
|
|
27120
27297
|
}
|
|
27121
27298
|
break;
|
|
27122
|
-
case "AWS::ResourceGroups::Group":
|
|
27123
|
-
|
|
27124
|
-
|
|
27125
|
-
if (model)
|
|
27126
|
-
|
|
27127
|
-
this.logger.debug(`Enriched ResourceGroups Group ${physicalId} with Arn from CC GetResource`);
|
|
27128
|
-
}
|
|
27299
|
+
case "AWS::ResourceGroups::Group": if (!enriched["Arn"]) {
|
|
27300
|
+
const model = await this.readCcResourceModel(resourceType, physicalId);
|
|
27301
|
+
if (model) {
|
|
27302
|
+
if (typeof model["Arn"] === "string") enriched["Arn"] = model["Arn"];
|
|
27303
|
+
this.logger.debug(`Enriched ResourceGroups Group ${physicalId} with Arn from CC GetResource`);
|
|
27129
27304
|
}
|
|
27130
|
-
|
|
27131
|
-
default: break;
|
|
27305
|
+
}
|
|
27132
27306
|
}
|
|
27133
27307
|
return enriched;
|
|
27134
27308
|
}
|
|
@@ -30321,7 +30495,8 @@ var IAMRoleProvider = class {
|
|
|
30321
30495
|
await this.iamClient.send(new GetRoleCommand({ RoleName: physicalId }));
|
|
30322
30496
|
} catch (error) {
|
|
30323
30497
|
if (error instanceof NoSuchEntityException) {
|
|
30324
|
-
|
|
30498
|
+
const clientRegion = await this.iamClient.config.region();
|
|
30499
|
+
assertRegionMatch(clientRegion, context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
30325
30500
|
this.logger.debug(`Role ${physicalId} does not exist, skipping deletion`);
|
|
30326
30501
|
return;
|
|
30327
30502
|
}
|
|
@@ -32121,9 +32296,9 @@ const EBS_FINAL_SNAPSHOT_TAG_KEY = "cdkd:final-snapshot-of";
|
|
|
32121
32296
|
/** Test seam (matches the `describe-type.ts` / macro-expander pattern). */
|
|
32122
32297
|
const finalSnapshotDelays = { sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)) };
|
|
32123
32298
|
const PRE_DELETE_SNAPSHOT_POLL_INTERVAL_MS = 5e3;
|
|
32124
|
-
const PRE_DELETE_SNAPSHOT_TIMEOUT_MS =
|
|
32299
|
+
const PRE_DELETE_SNAPSHOT_TIMEOUT_MS = 36e5;
|
|
32125
32300
|
/** Post-snapshot settle budget for a Redshift cluster before its delete. */
|
|
32126
|
-
const REDSHIFT_CLUSTER_SETTLE_TIMEOUT_MS =
|
|
32301
|
+
const REDSHIFT_CLUSTER_SETTLE_TIMEOUT_MS = 12e5;
|
|
32127
32302
|
function errMsg(error) {
|
|
32128
32303
|
return error instanceof Error ? error.message : String(error);
|
|
32129
32304
|
}
|
|
@@ -33432,7 +33607,8 @@ var ReplayResolvers = class {
|
|
|
33432
33607
|
* `state.json` already stores in the clear.
|
|
33433
33608
|
*/
|
|
33434
33609
|
function regionAmbiguousReplaySecretError(logicalId, propertyPath, secretName, foreignProducerRegions, consumerRegion) {
|
|
33435
|
-
|
|
33610
|
+
const where = propertyPath === "" ? "" : ` property '${propertyPath}'`;
|
|
33611
|
+
return new CdkdError(`Rollback of ${logicalId}${where} cannot re-resolve the secret reference '${secretName}': the reference carries no region of its own, and this stack read across a region boundary (producer region(s) on record: ${foreignProducerRegions.join(", ")}), so it may have been resolved in one of those rather than in '${consumerRegion}'. A secret of the same name in two regions is two independent values, so replaying this would write the WRONG secret to a live resource. Refusing instead. Resolve the reference in its own region and set the property directly (or spell it as a full ARN, which names its region and is resolved there), then re-run 'cdkd rollback'.`, "ROLLBACK_SECRET_REGION_AMBIGUOUS");
|
|
33436
33612
|
}
|
|
33437
33613
|
/**
|
|
33438
33614
|
* Re-resolve one LEAF string, sending each `{{resolve:...}}` reference in it to
|
|
@@ -33535,10 +33711,11 @@ async function resolveLeafByRegion(leaf, propertyPath, logicalId, execCtx, resol
|
|
|
33535
33711
|
*/
|
|
33536
33712
|
function redactRollbackRecord(record, secrets, journaledProps) {
|
|
33537
33713
|
if (secrets.size === 0) return record;
|
|
33538
|
-
|
|
33714
|
+
const positioned = journaledProps === void 0 ? record : {
|
|
33539
33715
|
...record,
|
|
33540
33716
|
properties: redactSecretsForState(record.properties, secrets, journaledProps, STATE_DERIVED_RULES)
|
|
33541
|
-
}
|
|
33717
|
+
};
|
|
33718
|
+
return scrubResourceRecord(positioned, secrets);
|
|
33542
33719
|
}
|
|
33543
33720
|
async function updateWithRollbackRetry(provider, args, logicalId, logger, isInterrupted, secrets) {
|
|
33544
33721
|
if (provider.disableOuterRetry) return await withCurrentResourceSecrets(secrets, () => provider.update(...args));
|
|
@@ -34759,13 +34936,13 @@ const EMPTY_SECRETS = /* @__PURE__ */ new Map();
|
|
|
34759
34936
|
* resource has been in flight for 5 minutes. Most CC API resources
|
|
34760
34937
|
* complete in under a minute; 5m is the agreed elbow.
|
|
34761
34938
|
*/
|
|
34762
|
-
const DEFAULT_RESOURCE_WARN_AFTER_MS =
|
|
34939
|
+
const DEFAULT_RESOURCE_WARN_AFTER_MS = 3e5;
|
|
34763
34940
|
/**
|
|
34764
34941
|
* Default per-resource hard timeout: abort after 30 minutes. Matches the
|
|
34765
34942
|
* design doc — Custom-Resource-heavy stacks should pass `--resource-timeout 1h`
|
|
34766
34943
|
* explicitly because the Custom Resource provider's polling cap is 1h.
|
|
34767
34944
|
*/
|
|
34768
|
-
const DEFAULT_RESOURCE_TIMEOUT_MS =
|
|
34945
|
+
const DEFAULT_RESOURCE_TIMEOUT_MS = 18e5;
|
|
34769
34946
|
var InterruptedError = class extends Error {
|
|
34770
34947
|
constructor(reason = "user") {
|
|
34771
34948
|
super(reason === "user" ? "Deployment interrupted by user (Ctrl+C)" : "Deployment aborted after another resource failed");
|
|
@@ -35104,7 +35281,7 @@ var DeployEngine = class {
|
|
|
35104
35281
|
});
|
|
35105
35282
|
this.options.concurrency = options.concurrency ?? 10;
|
|
35106
35283
|
this.options.dryRun = options.dryRun ?? false;
|
|
35107
|
-
this.options.lockTimeout = options.lockTimeout ??
|
|
35284
|
+
this.options.lockTimeout = options.lockTimeout ?? 3e5;
|
|
35108
35285
|
this.options.noRollback = options.noRollback ?? false;
|
|
35109
35286
|
this.options.resourceWarnAfterMs = options.resourceWarnAfterMs ?? 3e5;
|
|
35110
35287
|
this.options.resourceTimeoutMs = options.resourceTimeoutMs ?? 18e5;
|
|
@@ -35119,6 +35296,7 @@ var DeployEngine = class {
|
|
|
35119
35296
|
this.perResourceSecrets = /* @__PURE__ */ new Map();
|
|
35120
35297
|
this.noEchoAttributeResources = /* @__PURE__ */ new Map();
|
|
35121
35298
|
this.perResourceTemplateProps = /* @__PURE__ */ new Map();
|
|
35299
|
+
this.attemptedResolvedProps = /* @__PURE__ */ new Map();
|
|
35122
35300
|
this.outputSecrets = /* @__PURE__ */ new Map();
|
|
35123
35301
|
this.outputsTemplateSource = {};
|
|
35124
35302
|
this.outputsSourceUsable = true;
|
|
@@ -35339,7 +35517,7 @@ var DeployEngine = class {
|
|
|
35339
35517
|
const ownSecrets = secrets ?? /* @__PURE__ */ new Map();
|
|
35340
35518
|
const next = { ...op };
|
|
35341
35519
|
if (next.properties) next.properties = redactSecretsForState(next.properties, ownSecrets, templateProps);
|
|
35342
|
-
if (next.attemptedProperties) next.attemptedProperties = redactSecretsForState(next.attemptedProperties, ownSecrets, templateProps);
|
|
35520
|
+
if (next.attemptedProperties) next.attemptedProperties = redactSecretsForState(markSameGenerationBag({ ...next.attemptedProperties }), ownSecrets, templateProps);
|
|
35343
35521
|
if (next.previousState) next.previousState = scrubResourceRecord(next.previousState, ownSecrets);
|
|
35344
35522
|
return next;
|
|
35345
35523
|
});
|
|
@@ -35427,7 +35605,7 @@ var DeployEngine = class {
|
|
|
35427
35605
|
const logicalId = entries[i][0];
|
|
35428
35606
|
const observed = resolved[i];
|
|
35429
35607
|
const target = stateResources[logicalId];
|
|
35430
|
-
if (target && observed !== void 0) target.observedProperties = observed;
|
|
35608
|
+
if (target && observed !== void 0) target.observedProperties = markSameGenerationBag({ ...observed });
|
|
35431
35609
|
}
|
|
35432
35610
|
}
|
|
35433
35611
|
/**
|
|
@@ -36361,7 +36539,8 @@ var DeployEngine = class {
|
|
|
36361
36539
|
if (!redirect) return;
|
|
36362
36540
|
const findings = findUnrewrittenAssetReferences(resolvedProps, redirect);
|
|
36363
36541
|
if (findings.length === 0) return;
|
|
36364
|
-
|
|
36542
|
+
const detail = findings.map((f) => ` - ${f.path}: still references '${f.source}'`).join("\n");
|
|
36543
|
+
throw new ProvisioningError(`Unrewritten asset reference on '${logicalId}' (${resourceType}): this region uses cdkd-owned asset storage, but the following resolved properties still point at the CDK bootstrap storage that 'cdk gc' may garbage-collect:\n${detail}\nThis is a template shape cdkd's asset-reference rewrite did not cover — deploying it would split-brain the stack (assets in cdkd storage, properties reading the CDK bucket). Please report this at https://github.com/go-to-k/cdkd/issues with the property shape. Workaround: deploy with --use-cdk-bootstrap-assets to pin the legacy destinations for this app.`, resourceType, logicalId);
|
|
36365
36544
|
}
|
|
36366
36545
|
/**
|
|
36367
36546
|
* The `Snapshot`-policy gate every engine delete site runs BEFORE its
|
|
@@ -36503,7 +36682,7 @@ var DeployEngine = class {
|
|
|
36503
36682
|
recordNestedStackParameterExpressions(updateSecrets, resourceType, resolvedProps, desiredProps);
|
|
36504
36683
|
this.auditResolvedAssetReferences(logicalId, resourceType, resolvedProps);
|
|
36505
36684
|
this.attemptedResolvedProps.set(logicalId, resolvedProps);
|
|
36506
|
-
if (JSON.stringify(redactSecretsForState(resolvedProps, updateSecrets, desiredProps)) === JSON.stringify(currentPropsAsWritten)) {
|
|
36685
|
+
if (JSON.stringify(redactSecretsForState(markSameGenerationBag({ ...resolvedProps }), updateSecrets, desiredProps)) === JSON.stringify(currentPropsAsWritten)) {
|
|
36507
36686
|
if (change.attributeChanges && change.attributeChanges.length > 0) {
|
|
36508
36687
|
const attrSummary = change.attributeChanges.map((a) => `${a.attribute}: ${a.oldValue ?? "(unset)"} → ${a.newValue ?? "(unset)"}`).join(", ");
|
|
36509
36688
|
this.logger.info(` ↻ ${logicalId} (${resourceType}) attribute update: ${attrSummary}`);
|
|
@@ -36733,7 +36912,8 @@ var DeployEngine = class {
|
|
|
36733
36912
|
createResult = await this.withRetry(() => withCurrentResourceSecrets(updateSecrets, () => replProvider.create(logicalId, resourceType, replProps, { maskSecrets: createSecretMasker(updateSecrets) })), logicalId, void 0, void 0, replProvider);
|
|
36734
36913
|
} catch (createError) {
|
|
36735
36914
|
if (!retainOldOnReplace) throw new Error(maskSecretsInText(`Failed to create ${logicalId} after the UPDATE-not-supported replacement: the old resource (${currentResource.physicalId}) is now gone. Cause: ${createError instanceof Error ? createError.message : String(createError)}. Re-run the deploy to create it fresh.`, updateSecrets), { cause: createError instanceof Error ? createError : void 0 });
|
|
36736
|
-
|
|
36915
|
+
const createMsg = createError instanceof Error ? createError.message : String(createError);
|
|
36916
|
+
if (!isNameCollisionError(createMsg)) throw createError;
|
|
36737
36917
|
const nameOrigin = this.replacementNameOrigin(logicalId, currentResource.physicalId);
|
|
36738
36918
|
throw markNonRetryable(new CdkdError(`${logicalId} (${resourceType}) requires replacement because the provisioning layer cannot update it in place — but its physical name is still held by the existing resource AND UpdateReplacePolicy: Retain pins that resource in place. ${nameOrigin.descriptor}. ${nameOrigin.remedy} — with Retain, the old resource keeps the name, so a same-name replacement can never proceed. Removing UpdateReplacePolicy: Retain lets cdkd delete the old resource first, which destroys it and any data it holds.`, "NAMED_REPLACEMENT_COLLISION", createError instanceof Error ? createError : void 0));
|
|
36739
36919
|
}
|
|
@@ -36782,8 +36962,10 @@ var DeployEngine = class {
|
|
|
36782
36962
|
const updateCaptureSiblings = await this.buildObservedCaptureSiblings(resourceType, logicalId, result.physicalId, template, stateResources, stackName, parameterValues, conditions);
|
|
36783
36963
|
this.kickOffObservedCapture(captureProvider, logicalId, result.physicalId, resourceType, resolvedProps, updateCaptureSiblings);
|
|
36784
36964
|
const updatePartial = updatePartialReason(result);
|
|
36785
|
-
if (counts)
|
|
36786
|
-
|
|
36965
|
+
if (counts) {
|
|
36966
|
+
if (updatePartial !== void 0) counts.updatePartial++;
|
|
36967
|
+
else counts.updated++;
|
|
36968
|
+
}
|
|
36787
36969
|
if (progress) progress.current++;
|
|
36788
36970
|
const updatePrefix = progress ? `[${progress.current}/${progress.total}] ` : " ";
|
|
36789
36971
|
renderer.removeTask(logicalId);
|
|
@@ -36903,9 +37085,9 @@ var DeployEngine = class {
|
|
|
36903
37085
|
* `cdkd export`, `cdkd state`.
|
|
36904
37086
|
*/
|
|
36905
37087
|
propertiesToRecord(desiredProperties, result, resourceType, provisionedBy) {
|
|
36906
|
-
|
|
36907
|
-
|
|
36908
|
-
return
|
|
37088
|
+
if (result.effectiveProperties) return provisionedBy === "sdk" ? withoutSilentDropProperties(resourceType, result.effectiveProperties) : result.effectiveProperties;
|
|
37089
|
+
const written = provisionedBy === "sdk" ? withoutSilentDropProperties(resourceType, desiredProperties) : desiredProperties;
|
|
37090
|
+
return markSameGenerationBag(written);
|
|
36909
37091
|
}
|
|
36910
37092
|
/**
|
|
36911
37093
|
* The name-origin half of the replacement-collision messages (issue #1636).
|
|
@@ -37285,7 +37467,7 @@ var DeployEngine = class {
|
|
|
37285
37467
|
if (!publishedOutputNames.has(outputKey)) continue;
|
|
37286
37468
|
this.outputsTemplateSource[outputKey] = output.Value;
|
|
37287
37469
|
}
|
|
37288
|
-
return outputs;
|
|
37470
|
+
return markSameGenerationBag(outputs);
|
|
37289
37471
|
}
|
|
37290
37472
|
buildDisplayOutputs(template, resolvedOutputs) {
|
|
37291
37473
|
const display = {};
|
|
@@ -37300,4 +37482,4 @@ var DeployEngine = class {
|
|
|
37300
37482
|
|
|
37301
37483
|
//#endregion
|
|
37302
37484
|
export { createMaskedRetryLogger as $, runDockerStreaming as $n, StackTerminationProtectionError as $r, carriesSecretMask as $t, WARM_THROUGHPUT_MEMBERS as A, rewriteTemplateAssetReferences as An, clearBucketRegionCache as Ar, replayWarn as At, yellow as B, validateContainerRepoName as Bn, DependencyError as Br, s3BucketWebsiteUrl as Bt, unsupportedFinalSnapshotError as C, shouldRetainResource as Cn, displaySafe as Cr, normalizeAwsTagsToCfn as Ct, isStatefulRecreateTargetForReplace as D, buildAssetRedirectMap as Dn, derivePartitionAndUrlSuffix as Dr, configBooleanRefusal as Dt, MULTI_REGION_RECREATE_BLOCKED_TYPES as E, WorkGraph as En, canonicalizeRegion as Er, coerceCfnBoolean as Et, bold as F, getBootstrapMarkerKey as Fn, setAwsClients as Fr, producerRegionsFromState as Ft, secretBearingStateKeyWarning as G, describeDockerExecFailure as Gn, LocalStartServiceError as Gr, findSilentDropProperties as Gt, collectPublishedOutputNames as H, describeAwsFailure as Hn, DynamicReferenceRegionAmbiguousError as Hr, DiffCalculator as Ht, cyan as I, isCrossRegionRedirect as In, AssetError as Ir, s3BucketArn as It, IAMRoleProvider as J, formatDockerLoginError as Jn, PartialFailureError as Jr, DagBuilder as Jt, stateKeySecretExposure as K, describeDockerFailure as Kn, LockError as Kr, describeTypeWithThrottleRetry as Kt, gray as L, parseBootstrapMarker as Ln, CdkdError as Lr, s3BucketDomainName as Lt, isWarmThroughputDecrease as M, BOOTSTRAP_MARKER_PREFIX as Mn, AwsClients as Mr, requireConfigObject as Mt, toFiniteNumber as N, assertAssetBucketRegion as Nn, getAwsClients as Nr, requireConfigString as Nt, isStatefulRecreateTargetSync as O, createAssetRedirectResolver as On, AssemblyReader as Or, configStringRefusal as Ot, formatResourceLine as P, ensureAssetStorage as Pn, resetAwsClients as Pr, classifyReplaySecretRegion as Pt, wouldReturnToSdkProvider as Q, runDockerForeground as Qn, StackHasActiveImportsError as Qr, TEMPLATE_SOURCED_RULES as Qt, green as R, readBootstrapMarkerBody as Rn, ConfigError as Rr, s3BucketDualStackDomainName as Rt, refusesFinalSnapshot as S, importableOutputs as Sn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Sr, WAFv2WebACLProvider as St, extractDeploymentEventError as T, stringifyValue as Tn, PARTITION_TABLE as Tr, assertRegionMatch as Tt, exportAliasCollisionScrubWarning as U, buildDockerImage as Un, IntrinsicResolutionRefusalError as Ur, INTRINSIC_KEYS as Ut, collectDeclaredOutputNames as V, buildDenyExternalAccessPolicy as Vn, DeployCancelledError as Vr, applyRoleArnIfSet as Vt, isExportAliasCollision as W, describeDockerCapturedOutput as Wn, LocalInvokeBuildError as Wr, findActionableSilentDrops as Wt, clearOnUpdateRemoval as X, partitionSensitiveEnv as Xn, ResourceTimeoutError as Xr, STATE_SOURCED_CROSS_GENERATION_RULES as Xt, collectInlinePolicyNamesManagedBySiblings as Y, getDockerCmd as Yn, ProvisioningError as Yr, TemplateParser as Yt, ProviderRegistry as Z, redactDockerArgvValues as Zn, ResourceUpdateNotSupportedError as Zr, STATE_SOURCED_READBACK_RULES as Zt, PRE_DELETE_SNAPSHOT_TYPES as _, shellQuote as _n, CFN_TEMPLATE_BODY_LIMIT as _r, coerceParameterTypedValue as _t, DeploymentEventsStore as a, withErrorHandling as ai, maskSecretsInText as an, synthesisStatusMessage as ar, isInterruptedWaitError as at, createPreDeleteFinalSnapshot as b, exportNamesCarriedFrom as bn, findLargeInlineResources as br, parameterTypeMayLoseSecretIdentity as bt, replayFailedOperations as c, isThrottlingError as ci, redactSecretsForState as cn, resolveApp as cr, slowCcOperationTimeoutMs as ct, updatePartialReason as d, markRedactedCause as di, S3StateBackend as dn, resolveSkipPrefix as dr, deleteSkipReason as dt, StateError as ei, createSecretMasker as en, escapeRegExp$1 as er, maskDeep as et, withResourceDeadline as f, retryClassificationText as fi, rebuildClientForBucketRegion as fn, resolveStateBucketWithDefault as fr, disableInstanceApiTermination as ft, ATOMIC_FINAL_SNAPSHOT_TYPES as g, forceQuitRecoveryClause as gn, warnDeprecatedNoPrefixCliFlag as gr, cfnRefValueFromPhysicalId as gt, computeImplicitDeleteEdges as h, buildLockContentionMessage as hn, stateBucketExistenceConfirmed as hr, carriesDynamicReference as ht, DeploymentEventsReader as i, normalizeAwsError as ii, maskSecretsInError as in, Synthesizer as ir, interruptWatchListenerCount as it, coerceWarmThroughput as j, AssetModeResolver as jn, resolveBucketRegion as jr, requireConfigArray as jt, renderStatefulReason as k, loadPublishableAssetManifest as kn, processStackMessages as kr, readConfigString as kt, replayRollback as l, isTransientServerError as li, scrubResourceRecord as ln, resolveAutoAssetStorage as lr, UNSPECIFIED_SKIP_REASON as lt, IMPLICIT_DELETE_DEPENDENCIES as m, buildForceUnlockCommand as mn, resolveUseCdkBootstrapAssets as mr, IntrinsicFunctionResolver as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, formatError as ni, errorCauseChain as nn, AssetManifestLoader as nr, beginCommandInterruptScope as nt, planFailedOps as o, isMarkedNonRetryable as oi, recordMaskOnlyValue as on, getDefaultStateBucketName as or, startInterruptWatch as ot, maskingRetryLogger as p, __exportAll as pi, UNRENDERABLE as pn, resolveStateBucketWithDefaultAndSource as pr, isTerminationProtectionPropagationError as pt, getCurrentResourceSecrets as q, dockerSpawnEnvWithSensitive as qn, NestedStackChildDirectDestroyError as qr, withRetry as qt, DeployEngine as r, isCdkdError as ri, isSingleDynamicReferenceToken as rn, getDockerImageBySourceHash as rr, endCommandInterruptScope as rt, planRollback as s, isRetryableTransientError as si, recoverMaskedOutput as sn, getLegacyStateBucketName as sr, CloudControlProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, SynthesisError as ti, dynamicReferenceTokens as tn, stripControlChars as tr, maskerOrIdentity as tt, updatePartialMessage as u, markNonRetryable as ui, LockManager as un, resolveCaptureObservedState as ur, deleteIndeterminateGuards as ut, buildFinalSnapshotIdentifier as v, CUSTOM_RESOURCE_RESPONSE_PREFIX as vn, CFN_TEMPLATE_URL_LIMIT as vr, getAccountInfo as vt, makeCanonicalizePropertiesFn as w, AssetPublisher as wn, expectedOwnerParam as wr, resolveExplicitPhysicalId as wt, isFinalSnapshotError as x, importableOutputKeys as xn, uploadCfnTemplate as xr, refStateLookupFromResource as xt, ccRoutedFinalSnapshotError as y, DEFAULT_STATE_PREFIX as yn, MIGRATE_TMP_PREFIX as yr, isUnboundTemplateParameter as yt, red as z, validateAssetBucketName as zn, CrossAccountSecretRefusalError as zr, s3BucketRegionalDomainName as zt };
|
|
37303
|
-
//# sourceMappingURL=deploy-engine-
|
|
37485
|
+
//# sourceMappingURL=deploy-engine-Cxt3gn8N.js.map
|