@go-to-k/cdkd 0.285.4 → 0.285.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/README.md +10 -0
- package/dist/{asg-provider-sRJzRAe_.js → asg-provider-DsyALMVT.js} +3 -3
- package/dist/{asg-provider-sRJzRAe_.js.map → asg-provider-DsyALMVT.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-3EmPzxSN.js → deploy-engine-BgpCWFvY.js} +240 -99
- package/dist/deploy-engine-BgpCWFvY.js.map +1 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{logger-Dz3Le2Pw.js → logger-DyTk5GeO.js} +81 -17
- package/dist/{logger-Dz3Le2Pw.js.map → logger-DyTk5GeO.js.map} +1 -1
- package/dist/{program-DoauTYs2.js → program-cjSJf49d.js} +59 -19
- package/dist/{program-DoauTYs2.js.map → program-cjSJf49d.js.map} +1 -1
- package/dist/{version-Dlq6xZAQ.js → version-De6foYg3.js} +2 -2
- package/dist/{version-Dlq6xZAQ.js.map → version-De6foYg3.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-3EmPzxSN.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { d as
|
|
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-DyTk5GeO.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-De6foYg3.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -5525,8 +5525,13 @@ var FileAssetPublisher = class {
|
|
|
5525
5525
|
* Output handling: stdout/stderr are collected in memory unconditionally so
|
|
5526
5526
|
* `runDockerStreaming` can return them to the caller for error wrapping.
|
|
5527
5527
|
* When the logger is at debug level (i.e. the user passed `--verbose`),
|
|
5528
|
-
* the chunks are ALSO mirrored
|
|
5529
|
-
*
|
|
5528
|
+
* the chunks are ALSO mirrored live so the user sees build progress —
|
|
5529
|
+
* stderr always to `process.stderr`, and stdout to `process.stdout` EXCEPT
|
|
5530
|
+
* while a command holds a payload reservation
|
|
5531
|
+
* ({@link isStdoutReservedForPayload}), where it joins the logger on stderr
|
|
5532
|
+
* so a child's diagnostics cannot land in the payload
|
|
5533
|
+
* ([#2410](https://github.com/go-to-k/cdkd/issues/2410)). The same
|
|
5534
|
+
* reservation redirects `spawnForeground`'s inherited fd 1 to fd 2.
|
|
5530
5535
|
*/
|
|
5531
5536
|
/**
|
|
5532
5537
|
* Return the docker-compatible CLI binary to invoke. Matches CDK CLI:
|
|
@@ -5573,7 +5578,8 @@ async function spawnStreaming(cmd, args, options = {}) {
|
|
|
5573
5578
|
const stderrChunks = [];
|
|
5574
5579
|
child.stdout.on("data", (chunk) => {
|
|
5575
5580
|
stdoutChunks.push(chunk);
|
|
5576
|
-
if (streamLive) process.
|
|
5581
|
+
if (streamLive) if (isStdoutReservedForPayload()) process.stderr.write(chunk);
|
|
5582
|
+
else process.stdout.write(chunk);
|
|
5577
5583
|
});
|
|
5578
5584
|
child.stderr.on("data", (chunk) => {
|
|
5579
5585
|
stderrChunks.push(chunk);
|
|
@@ -5617,25 +5623,42 @@ async function spawnStreaming(cmd, args, options = {}) {
|
|
|
5617
5623
|
* exit, so the caller can wrap with its own error class.
|
|
5618
5624
|
*
|
|
5619
5625
|
* Differs from {@link runDockerStreaming} in two ways:
|
|
5620
|
-
* 1.
|
|
5621
|
-
* (color, progress bar overwrites) flow through
|
|
5622
|
-
* load-bearing reason for the split:
|
|
5623
|
-
*
|
|
5626
|
+
* 1. The child INHERITS descriptors — output is NOT captured, so terminal
|
|
5627
|
+
* control codes (color, progress bar overwrites) flow through
|
|
5628
|
+
* unchanged. That is the load-bearing reason for the split:
|
|
5629
|
+
* `docker pull`'s progress bars only animate when the child writes to a
|
|
5630
|
+
* real TTY rather than a pipe. Under a payload reservation the child's
|
|
5631
|
+
* fd 1 is redirected to the parent's fd 2 rather than piped, precisely
|
|
5632
|
+
* so it keeps a descriptor and not a pipe — though the animation then
|
|
5633
|
+
* depends on STDERR being a terminal, and degrades to plain lines under
|
|
5634
|
+
* `2> file` (issue
|
|
5635
|
+
* [#2410](https://github.com/go-to-k/cdkd/issues/2410)).
|
|
5624
5636
|
* 2. No `input` / `streamLive` options — inherit-mode has nothing to
|
|
5625
5637
|
* capture and nothing to mirror.
|
|
5626
5638
|
*
|
|
5627
|
-
* Used by the
|
|
5628
|
-
*
|
|
5629
|
-
*
|
|
5639
|
+
* Used by the `docker pull` plumbing in `docker-runner.ts` and
|
|
5640
|
+
* `ecr-puller.ts`. Those two callers differ, and the difference matters
|
|
5641
|
+
* enough to state: `docker-runner.ts` reaches this only under `--verbose`,
|
|
5642
|
+
* while `ecr-puller.ts` runs it UNCONDITIONALLY, which is what made the
|
|
5643
|
+
* pre-#2410 stdout leak reachable with no flag at all. Non-verbose pulls in
|
|
5644
|
+
* `docker-runner.ts` go through {@link runDockerStreaming} instead, so
|
|
5645
|
+
* stderr can be folded into the error message.
|
|
5630
5646
|
*/
|
|
5631
5647
|
async function runDockerForeground(args, options = {}) {
|
|
5632
5648
|
return spawnForeground(getDockerCmd(), args, options);
|
|
5633
5649
|
}
|
|
5634
5650
|
/**
|
|
5635
|
-
* Foreground (
|
|
5651
|
+
* Foreground (descriptor-inheriting) spawn — the inherit-mode counterpart to
|
|
5636
5652
|
* {@link spawnStreaming}. Used by {@link runDockerForeground} for docker-CLI
|
|
5637
5653
|
* subprocesses.
|
|
5638
5654
|
*
|
|
5655
|
+
* "inherit" is not unqualified, and THIS is the function that qualifies it:
|
|
5656
|
+
* while a command holds a payload reservation
|
|
5657
|
+
* ({@link isStdoutReservedForPayload}) the child's fd 1 is redirected to the
|
|
5658
|
+
* parent's fd 2, so its output cannot land in the payload
|
|
5659
|
+
* ([#2410](https://github.com/go-to-k/cdkd/issues/2410)). stdin and stderr
|
|
5660
|
+
* are inherited either way. See the inline note at the `spawn` call.
|
|
5661
|
+
*
|
|
5639
5662
|
* The ENOENT branch crafts a docker-specific install hint ("Install Docker
|
|
5640
5663
|
* (or set CDK_DOCKER ...)"), so non-docker callers reusing this helper
|
|
5641
5664
|
* would see a misleading error on missing-binary failures. Keep the binary
|
|
@@ -5648,7 +5671,11 @@ async function spawnForeground(cmd, args, options = {}) {
|
|
|
5648
5671
|
const child = spawn(cmd, args, {
|
|
5649
5672
|
cwd: options.cwd,
|
|
5650
5673
|
env,
|
|
5651
|
-
stdio:
|
|
5674
|
+
stdio: isStdoutReservedForPayload() ? [
|
|
5675
|
+
"inherit",
|
|
5676
|
+
2,
|
|
5677
|
+
"inherit"
|
|
5678
|
+
] : "inherit"
|
|
5652
5679
|
});
|
|
5653
5680
|
child.once("error", (err) => {
|
|
5654
5681
|
if (err.code === "ENOENT") {
|
|
@@ -20218,6 +20245,151 @@ function isTerminationProtectionPropagationError(message) {
|
|
|
20218
20245
|
return /may not be terminated|disableApiTermination/i.test(message);
|
|
20219
20246
|
}
|
|
20220
20247
|
|
|
20248
|
+
//#endregion
|
|
20249
|
+
//#region src/deployment/delete-outcome.ts
|
|
20250
|
+
/**
|
|
20251
|
+
* Shared helpers over {@link ResourceDeleteResult} — originally the deploy-side
|
|
20252
|
+
* consumption of it (issue
|
|
20253
|
+
* [#1762](https://github.com/go-to-k/cdkd/issues/1762)), the twin of what
|
|
20254
|
+
* `src/cli/commands/destroy-runner.ts` does for `cdkd destroy`, and since issue
|
|
20255
|
+
* [#2301](https://github.com/go-to-k/cdkd/issues/2301) also the PRODUCER-side
|
|
20256
|
+
* `indeterminateGuards` constructor. Write and read live in one file on
|
|
20257
|
+
* purpose: the field's whole job is to survive a hop from a provider to a
|
|
20258
|
+
* recorder, and a sanitizer that does not sit beside its constructor is how
|
|
20259
|
+
* the two drift.
|
|
20260
|
+
*
|
|
20261
|
+
* Issue [#1752](https://github.com/go-to-k/cdkd/issues/1752) gave
|
|
20262
|
+
* `ResourceProvider.delete` an optional return value whose `'skipped'` arm
|
|
20263
|
+
* means **the resource this result names was NOT destroyed and may still be
|
|
20264
|
+
* ALIVE**, and taught the destroy runner to report it. Every OTHER
|
|
20265
|
+
* `provider.delete(...)` call site — the deploy engine's template-DELETE
|
|
20266
|
+
* branch, its four replacement / recreate delete sites, and the five
|
|
20267
|
+
* `rollback-executor.ts` delete arms — discarded the value, so the same skip
|
|
20268
|
+
* printed as `deleted`, counted as `deleted`, and dropped the state record.
|
|
20269
|
+
*
|
|
20270
|
+
* **The module must stay a LEAF — no imports beyond the type, ever.** Same
|
|
20271
|
+
* reason as `src/provisioning/nested-stack-messages.ts`: both the deploy
|
|
20272
|
+
* engine and the rollback executor consume it, and those two already sit on a
|
|
20273
|
+
* dense import ring (engine -> executor -> provider registry -> every
|
|
20274
|
+
* provider). A helper that pulled anything else in would close it.
|
|
20275
|
+
*/
|
|
20276
|
+
/**
|
|
20277
|
+
* The `reason` of a `'skipped'` delete outcome, or `undefined` when the
|
|
20278
|
+
* provider reported a delete (`{ outcome: 'deleted' }` or the back-compat
|
|
20279
|
+
* `void` return ~80 providers still use).
|
|
20280
|
+
*
|
|
20281
|
+
* A function rather than an inline `result?.outcome === 'skipped'` test at
|
|
20282
|
+
* ten call sites so the back-compat `void` reading lives in ONE place: the
|
|
20283
|
+
* signature is `Promise<void | ResourceDeleteResult>`, so a caller that awaits
|
|
20284
|
+
* it holds `void | ResourceDeleteResult`, which TypeScript will happily let
|
|
20285
|
+
* you compare against nothing useful.
|
|
20286
|
+
*/
|
|
20287
|
+
function deleteSkipReason(result) {
|
|
20288
|
+
if (!result || result.outcome !== "skipped") return void 0;
|
|
20289
|
+
if (typeof result.reason !== "string") return UNSPECIFIED_SKIP_REASON;
|
|
20290
|
+
const trimmed = result.reason.trim();
|
|
20291
|
+
return trimmed === "" ? UNSPECIFIED_SKIP_REASON : trimmed;
|
|
20292
|
+
}
|
|
20293
|
+
/**
|
|
20294
|
+
* Stand-in for a `'skipped'` outcome whose producer supplied no `reason`.
|
|
20295
|
+
*
|
|
20296
|
+
* Deliberately says the cause is unknown rather than inventing one: the line
|
|
20297
|
+
* it renders on is the user's only signal that the resource survived, and a
|
|
20298
|
+
* fabricated cause would send them looking in the wrong place.
|
|
20299
|
+
*/
|
|
20300
|
+
const UNSPECIFIED_SKIP_REASON = "no reason reported by the provider";
|
|
20301
|
+
/**
|
|
20302
|
+
* The sentence every deploy-side skip renders, in the log line AND in the
|
|
20303
|
+
* `Error` the sites that must FAIL the resource throw.
|
|
20304
|
+
*
|
|
20305
|
+
* Wording rules, both load-bearing:
|
|
20306
|
+
*
|
|
20307
|
+
* 1. It says the resource was NOT deleted and MAY STILL EXIST. A skip issued
|
|
20308
|
+
* no AWS call at every producer but `NestedStackProvider.delete`, so the
|
|
20309
|
+
* old resource is presumed alive — which is the whole reason a replacement
|
|
20310
|
+
* site cannot proceed to create its replacement beside it.
|
|
20311
|
+
* 2. It must NOT contain any phrase the callers' already-deleted classifiers
|
|
20312
|
+
* substring-match (`does not exist` / `was not found` / `not found` /
|
|
20313
|
+
* `No policy found` / `NoSuchEntity` / `NotFoundException` /
|
|
20314
|
+
* `ResourceNotFoundException`). Reading a skip as "already gone" is exactly
|
|
20315
|
+
* the mis-accounting this change exists to remove, and the deploy engine's
|
|
20316
|
+
* DELETE branch and its update-not-supported fallback each carry such a
|
|
20317
|
+
* classifier. The call sites additionally handle the skip OUTSIDE their
|
|
20318
|
+
* `catch`, so a future `reason` carrying one of those phrases still cannot
|
|
20319
|
+
* reach a classifier — belt and braces, because `reason` is provider text.
|
|
20320
|
+
*/
|
|
20321
|
+
function deleteSkippedMessage(logicalId, physicalId, reason, duringClause) {
|
|
20322
|
+
return `cdkd could not address ${logicalId} (${physicalId}) ${duringClause}, so it was NOT deleted and may still exist: ${reason}`;
|
|
20323
|
+
}
|
|
20324
|
+
/**
|
|
20325
|
+
* Attach an {@link IndeterminateGuard} to whatever a delete arm was about to
|
|
20326
|
+
* return (issue [#2301](https://github.com/go-to-k/cdkd/issues/2301)).
|
|
20327
|
+
*
|
|
20328
|
+
* `undefined` in, `undefined` out when there is no guard to carry — so a
|
|
20329
|
+
* provider whose guard reached a verdict keeps returning the back-compat
|
|
20330
|
+
* `void` the ~80 providers that return it use, and nothing about the
|
|
20331
|
+
* existing shape changes on the hot path.
|
|
20332
|
+
*
|
|
20333
|
+
* A `'skipped'` result keeps its outcome and its `reason`: a guard that could
|
|
20334
|
+
* not answer and a delete that could not be addressed are independent facts,
|
|
20335
|
+
* and collapsing either into the other loses one of them.
|
|
20336
|
+
*/
|
|
20337
|
+
function withIndeterminateGuard(result, guard) {
|
|
20338
|
+
if (!guard) return result;
|
|
20339
|
+
const indeterminateGuards = [...Array.isArray(result?.indeterminateGuards) ? result.indeterminateGuards : [], guard];
|
|
20340
|
+
if (result && result.outcome === "skipped") return {
|
|
20341
|
+
...result,
|
|
20342
|
+
indeterminateGuards
|
|
20343
|
+
};
|
|
20344
|
+
return {
|
|
20345
|
+
...result ?? {},
|
|
20346
|
+
outcome: "deleted",
|
|
20347
|
+
indeterminateGuards
|
|
20348
|
+
};
|
|
20349
|
+
}
|
|
20350
|
+
/**
|
|
20351
|
+
* The guards a delete result reports as INDETERMINATE — those that ran, could
|
|
20352
|
+
* not reach a verdict, and were therefore not enforced while cdkd proceeded
|
|
20353
|
+
* (issue [#2301](https://github.com/go-to-k/cdkd/issues/2301)). Empty for the
|
|
20354
|
+
* overwhelmingly common case, including the back-compat `void` return.
|
|
20355
|
+
*
|
|
20356
|
+
* Defensive in the same shape and for the same reason as
|
|
20357
|
+
* {@link deleteSkipReason}: the value crosses into a DURABLE record
|
|
20358
|
+
* (`deployments/*.jsonl`), providers are the least type-checked layer in the
|
|
20359
|
+
* repo (a hand-built test double, a future arm, a JS provider), and a
|
|
20360
|
+
* malformed entry must degrade to "not reported" rather than crash the delete
|
|
20361
|
+
* path or persist `guard: undefined`. `typeof` rather than `?.trim()` for the
|
|
20362
|
+
* same reason `deleteSkipReason` uses it — a non-string makes `.trim` itself
|
|
20363
|
+
* `undefined`, i.e. a TypeError thrown out of the very path this hardens.
|
|
20364
|
+
*
|
|
20365
|
+
* Entries whose `guard` or `reason` is missing / non-string / blank are
|
|
20366
|
+
* DROPPED rather than defaulted, which is the opposite of `deleteSkipReason`'s
|
|
20367
|
+
* choice and deliberately so: there a default is the user's only signal that a
|
|
20368
|
+
* live resource survived, so inventing `UNSPECIFIED_SKIP_REASON` beats
|
|
20369
|
+
* silence. Here a guard row with no guard id and no cause says only "something
|
|
20370
|
+
* somewhere was not checked", which cannot be acted on — and it would count
|
|
20371
|
+
* toward the destroy summary's tally, turning an unactionable row into a
|
|
20372
|
+
* number the operator has to chase.
|
|
20373
|
+
*/
|
|
20374
|
+
function deleteIndeterminateGuards(result) {
|
|
20375
|
+
const raw = result?.indeterminateGuards;
|
|
20376
|
+
if (!Array.isArray(raw)) return [];
|
|
20377
|
+
const out = [];
|
|
20378
|
+
for (const entry of raw) {
|
|
20379
|
+
if (!entry || typeof entry !== "object") continue;
|
|
20380
|
+
const { guard, reason } = entry;
|
|
20381
|
+
if (typeof guard !== "string" || typeof reason !== "string") continue;
|
|
20382
|
+
const trimmedGuard = guard.trim();
|
|
20383
|
+
const trimmedReason = reason.trim();
|
|
20384
|
+
if (trimmedGuard === "" || trimmedReason === "") continue;
|
|
20385
|
+
out.push({
|
|
20386
|
+
guard: trimmedGuard,
|
|
20387
|
+
reason: trimmedReason
|
|
20388
|
+
});
|
|
20389
|
+
}
|
|
20390
|
+
return out;
|
|
20391
|
+
}
|
|
20392
|
+
|
|
20221
20393
|
//#endregion
|
|
20222
20394
|
//#region src/provisioning/json-patch-generator.ts
|
|
20223
20395
|
/**
|
|
@@ -20941,6 +21113,19 @@ function requiresCcDeleteIdentityCheck(resourceType) {
|
|
|
20941
21113
|
return CC_DELETE_IDENTITY_CHECKED_TYPES.has(resourceType);
|
|
20942
21114
|
}
|
|
20943
21115
|
/**
|
|
21116
|
+
* `IndeterminateGuard.guard` for the pre-flight identity confirmation above
|
|
21117
|
+
* (issue [#2301](https://github.com/go-to-k/cdkd/issues/2301)).
|
|
21118
|
+
*
|
|
21119
|
+
* Named for the GUARD, not for the type or the API it happens to probe today:
|
|
21120
|
+
* the value is persisted into `deployments/*.jsonl` and is therefore a user
|
|
21121
|
+
* contract, and the set it fires for is
|
|
21122
|
+
* {@link CC_DELETE_IDENTITY_CHECKED_TYPES} — a set that is expected to grow to
|
|
21123
|
+
* any type whose physical id is globally unique while its resource is
|
|
21124
|
+
* regional. `s3` / `get-bucket-location` in the id would go stale on the first
|
|
21125
|
+
* such addition, and a stale id cannot be corrected without breaking readers.
|
|
21126
|
+
*/
|
|
21127
|
+
const CC_DELETE_REGION_IDENTITY_GUARD = "cc-delete-region-identity";
|
|
21128
|
+
/**
|
|
20944
21129
|
* The region a `GetBucketLocation` answer denotes, canonicalized.
|
|
20945
21130
|
*
|
|
20946
21131
|
* Two legacy wire shapes, both still returned, which is why this is a function
|
|
@@ -21152,11 +21337,11 @@ var CloudControlProvider = class {
|
|
|
21152
21337
|
this.logger.debug(`Deleting resource ${logicalId} (${resourceType}), physical ID: ${physicalId}`);
|
|
21153
21338
|
if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
|
|
21154
21339
|
await this.assertRecordedRegionAgainstClient("pre-delete", context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
21155
|
-
await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
21340
|
+
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
21156
21341
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
21157
21342
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
21158
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
21159
|
-
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
21343
|
+
const { ASGProvider } = await import("./asg-provider-DsyALMVT.js").then((n) => n.n);
|
|
21344
|
+
return withIndeterminateGuard(await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
21160
21345
|
}
|
|
21161
21346
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
21162
21347
|
if (isProtectedEc2Instance) await disableInstanceApiTermination(getAwsClients().ec2, physicalId, this.logger);
|
|
@@ -21174,13 +21359,13 @@ var CloudControlProvider = class {
|
|
|
21174
21359
|
this.logger.debug(`Delete request submitted for ${logicalId}, token: ${deleteResponse.ProgressEvent.RequestToken}`);
|
|
21175
21360
|
await this.waitForOperation(deleteResponse.ProgressEvent.RequestToken, logicalId, "DELETE", resourceType);
|
|
21176
21361
|
this.logger.debug(`Deleted resource ${logicalId}`);
|
|
21177
|
-
return;
|
|
21362
|
+
return withIndeterminateGuard(void 0, indeterminateGuard);
|
|
21178
21363
|
} catch (error) {
|
|
21179
21364
|
const err = error;
|
|
21180
21365
|
if (error instanceof CloudControlOperationFailedError && error.ccOperation === "DELETE" && error.ccErrorCode === "NotFound" || err.name === "ResourceNotFoundException" || err.message?.includes("does not exist") || err.message?.includes("not found") || err.message?.includes("NotFound")) {
|
|
21181
21366
|
await this.assertRecordedRegionAgainstClient("not-found", context?.expectedRegion, resourceType, logicalId, physicalId);
|
|
21182
21367
|
this.logger.debug(`Resource ${logicalId} already deleted (not found), treating as success`);
|
|
21183
|
-
return;
|
|
21368
|
+
return withIndeterminateGuard(void 0, indeterminateGuard);
|
|
21184
21369
|
}
|
|
21185
21370
|
if (isProtectedEc2Instance && isTerminationProtectionPropagationError(err.message ?? "") && attempt < maxAttempts) {
|
|
21186
21371
|
this.logger.debug(`Cloud Control delete of ${logicalId} raced the DisableApiTermination flip-off (attempt ${attempt}/${maxAttempts}); re-flipping and retrying`);
|
|
@@ -21316,21 +21501,43 @@ var CloudControlProvider = class {
|
|
|
21316
21501
|
* indeterminate arm, which PROCEEDS. `src/utils/aws-region-resolver.ts`
|
|
21317
21502
|
* records the same finding, and the SDK-side guard re-learned it the
|
|
21318
21503
|
* expensive way.
|
|
21504
|
+
*
|
|
21505
|
+
* RETURN VALUE (issue #2301 item 3). `undefined` means the guard reached a
|
|
21506
|
+
* verdict — it confirmed the region, or the type is unguarded, or the bucket
|
|
21507
|
+
* is absent (a fourth outcome, not an indeterminate one, per the paragraph
|
|
21508
|
+
* above). An {@link IndeterminateGuard} means it could NOT, and the caller
|
|
21509
|
+
* must carry it out through `ResourceDeleteResult` so the destroy runner can
|
|
21510
|
+
* persist a `RESOURCE_GUARD_INDETERMINATE` event. A MISMATCH still throws.
|
|
21511
|
+
*
|
|
21512
|
+
* The two indeterminate arms below produce THREE distinct `reason` texts,
|
|
21513
|
+
* not two, and that is deliberate: the region-resolution arm falls THROUGH
|
|
21514
|
+
* into the no-region warn, so before this change a client whose SDK region
|
|
21515
|
+
* chain REJECTED was reported identically to one that was never asked. The
|
|
21516
|
+
* remedies differ (fix the credential chain / pass `--region` vs. repair the
|
|
21517
|
+
* state record), so the durable record — and the warn beside it — names
|
|
21518
|
+
* which happened.
|
|
21319
21519
|
*/
|
|
21320
21520
|
async confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context) {
|
|
21321
|
-
if (!requiresCcDeleteIdentityCheck(resourceType)) return;
|
|
21521
|
+
if (!requiresCcDeleteIdentityCheck(resourceType)) return void 0;
|
|
21322
21522
|
const recordedRegion = context?.expectedRegion?.trim();
|
|
21323
21523
|
let expectedRegion = recordedRegion === void 0 || recordedRegion === "" ? void 0 : recordedRegion;
|
|
21524
|
+
let clientRegionError;
|
|
21324
21525
|
if (expectedRegion === void 0) try {
|
|
21325
21526
|
const clientRegion = (await this.cloudControlClient.config.region())?.trim();
|
|
21326
21527
|
expectedRegion = clientRegion === void 0 || clientRegion === "" ? void 0 : clientRegion;
|
|
21327
21528
|
} catch (error) {
|
|
21328
|
-
|
|
21529
|
+
const clientRegionFailure = describeAwsFailure(error);
|
|
21530
|
+
clientRegionError = clientRegionFailure.summary;
|
|
21531
|
+
this.logger.debug(`Could not resolve the Cloud Control client region while confirming ${physicalId}: ${clientRegionFailure.detail}`);
|
|
21329
21532
|
expectedRegion = void 0;
|
|
21330
21533
|
}
|
|
21331
21534
|
if (expectedRegion === void 0) {
|
|
21332
|
-
|
|
21333
|
-
|
|
21535
|
+
const reason = clientRegionError === void 0 ? `neither the stack state nor the AWS client reports a region` : `the stack state records no region and the AWS client's region could not be resolved: ${clientRegionError}`;
|
|
21536
|
+
this.logger.warn(`Could not confirm that ${resourceType} ${physicalId} (${logicalId}) is the resource this destroy targets: ${reason.replace(/[.\s]+$/, "")}. Proceeding with the delete.`);
|
|
21537
|
+
return {
|
|
21538
|
+
guard: CC_DELETE_REGION_IDENTITY_GUARD,
|
|
21539
|
+
reason
|
|
21540
|
+
};
|
|
21334
21541
|
}
|
|
21335
21542
|
const wantRegion = canonicalizeRegion(expectedRegion);
|
|
21336
21543
|
let actualRegion;
|
|
@@ -21341,9 +21548,14 @@ var CloudControlProvider = class {
|
|
|
21341
21548
|
this.logger.debug(`Bucket ${physicalId} (${logicalId}) is already absent; leaving the delete to the Cloud Control idempotency path`);
|
|
21342
21549
|
return;
|
|
21343
21550
|
}
|
|
21344
|
-
const
|
|
21345
|
-
this.logger.
|
|
21346
|
-
|
|
21551
|
+
const failure = describeAwsFailure(error);
|
|
21552
|
+
this.logger.debug(`s3:GetBucketLocation on ${physicalId} (${logicalId}) failed: ${failure.detail}`);
|
|
21553
|
+
const summarySentence = failure.summary.replace(/[.\s]+$/, "");
|
|
21554
|
+
this.logger.warn(`Could not confirm which region S3 bucket ${physicalId} (${logicalId}) lives in before deleting it: ${summarySentence}. S3 bucket names are globally unique, so cdkd cannot rule out that this name denotes a bucket in another region. Grant s3:GetBucketLocation on the bucket to enable the check. Proceeding with the delete.`);
|
|
21555
|
+
return {
|
|
21556
|
+
guard: CC_DELETE_REGION_IDENTITY_GUARD,
|
|
21557
|
+
reason: `s3:GetBucketLocation on ${physicalId} could not be answered: ${failure.summary}`
|
|
21558
|
+
};
|
|
21347
21559
|
}
|
|
21348
21560
|
if (actualRegion === wantRegion) {
|
|
21349
21561
|
this.logger.debug(`Confirmed S3 bucket ${physicalId} (${logicalId}) lives in ${wantRegion} before deleting it`);
|
|
@@ -29019,77 +29231,6 @@ async function withResourceDeadline(operation, opts) {
|
|
|
29019
29231
|
});
|
|
29020
29232
|
}
|
|
29021
29233
|
|
|
29022
|
-
//#endregion
|
|
29023
|
-
//#region src/deployment/delete-outcome.ts
|
|
29024
|
-
/**
|
|
29025
|
-
* Deploy-side consumption of {@link ResourceDeleteResult} (issue
|
|
29026
|
-
* [#1762](https://github.com/go-to-k/cdkd/issues/1762)) — the twin of what
|
|
29027
|
-
* `src/cli/commands/destroy-runner.ts` does for `cdkd destroy`.
|
|
29028
|
-
*
|
|
29029
|
-
* Issue [#1752](https://github.com/go-to-k/cdkd/issues/1752) gave
|
|
29030
|
-
* `ResourceProvider.delete` an optional return value whose `'skipped'` arm
|
|
29031
|
-
* means **the resource this result names was NOT destroyed and may still be
|
|
29032
|
-
* ALIVE**, and taught the destroy runner to report it. Every OTHER
|
|
29033
|
-
* `provider.delete(...)` call site — the deploy engine's template-DELETE
|
|
29034
|
-
* branch, its four replacement / recreate delete sites, and the five
|
|
29035
|
-
* `rollback-executor.ts` delete arms — discarded the value, so the same skip
|
|
29036
|
-
* printed as `deleted`, counted as `deleted`, and dropped the state record.
|
|
29037
|
-
*
|
|
29038
|
-
* **The module must stay a LEAF — no imports beyond the type, ever.** Same
|
|
29039
|
-
* reason as `src/provisioning/nested-stack-messages.ts`: both the deploy
|
|
29040
|
-
* engine and the rollback executor consume it, and those two already sit on a
|
|
29041
|
-
* dense import ring (engine -> executor -> provider registry -> every
|
|
29042
|
-
* provider). A helper that pulled anything else in would close it.
|
|
29043
|
-
*/
|
|
29044
|
-
/**
|
|
29045
|
-
* The `reason` of a `'skipped'` delete outcome, or `undefined` when the
|
|
29046
|
-
* provider reported a delete (`{ outcome: 'deleted' }` or the back-compat
|
|
29047
|
-
* `void` return ~80 providers still use).
|
|
29048
|
-
*
|
|
29049
|
-
* A function rather than an inline `result?.outcome === 'skipped'` test at
|
|
29050
|
-
* ten call sites so the back-compat `void` reading lives in ONE place: the
|
|
29051
|
-
* signature is `Promise<void | ResourceDeleteResult>`, so a caller that awaits
|
|
29052
|
-
* it holds `void | ResourceDeleteResult`, which TypeScript will happily let
|
|
29053
|
-
* you compare against nothing useful.
|
|
29054
|
-
*/
|
|
29055
|
-
function deleteSkipReason(result) {
|
|
29056
|
-
if (!result || result.outcome !== "skipped") return void 0;
|
|
29057
|
-
if (typeof result.reason !== "string") return UNSPECIFIED_SKIP_REASON;
|
|
29058
|
-
const trimmed = result.reason.trim();
|
|
29059
|
-
return trimmed === "" ? UNSPECIFIED_SKIP_REASON : trimmed;
|
|
29060
|
-
}
|
|
29061
|
-
/**
|
|
29062
|
-
* Stand-in for a `'skipped'` outcome whose producer supplied no `reason`.
|
|
29063
|
-
*
|
|
29064
|
-
* Deliberately says the cause is unknown rather than inventing one: the line
|
|
29065
|
-
* it renders on is the user's only signal that the resource survived, and a
|
|
29066
|
-
* fabricated cause would send them looking in the wrong place.
|
|
29067
|
-
*/
|
|
29068
|
-
const UNSPECIFIED_SKIP_REASON = "no reason reported by the provider";
|
|
29069
|
-
/**
|
|
29070
|
-
* The sentence every deploy-side skip renders, in the log line AND in the
|
|
29071
|
-
* `Error` the sites that must FAIL the resource throw.
|
|
29072
|
-
*
|
|
29073
|
-
* Wording rules, both load-bearing:
|
|
29074
|
-
*
|
|
29075
|
-
* 1. It says the resource was NOT deleted and MAY STILL EXIST. A skip issued
|
|
29076
|
-
* no AWS call at every producer but `NestedStackProvider.delete`, so the
|
|
29077
|
-
* old resource is presumed alive — which is the whole reason a replacement
|
|
29078
|
-
* site cannot proceed to create its replacement beside it.
|
|
29079
|
-
* 2. It must NOT contain any phrase the callers' already-deleted classifiers
|
|
29080
|
-
* substring-match (`does not exist` / `was not found` / `not found` /
|
|
29081
|
-
* `No policy found` / `NoSuchEntity` / `NotFoundException` /
|
|
29082
|
-
* `ResourceNotFoundException`). Reading a skip as "already gone" is exactly
|
|
29083
|
-
* the mis-accounting this change exists to remove, and the deploy engine's
|
|
29084
|
-
* DELETE branch and its update-not-supported fallback each carry such a
|
|
29085
|
-
* classifier. The call sites additionally handle the skip OUTSIDE their
|
|
29086
|
-
* `catch`, so a future `reason` carrying one of those phrases still cannot
|
|
29087
|
-
* reach a classifier — belt and braces, because `reason` is provider text.
|
|
29088
|
-
*/
|
|
29089
|
-
function deleteSkippedMessage(logicalId, physicalId, reason, duringClause) {
|
|
29090
|
-
return `cdkd could not address ${logicalId} (${physicalId}) ${duringClause}, so it was NOT deleted and may still exist: ${reason}`;
|
|
29091
|
-
}
|
|
29092
|
-
|
|
29093
29234
|
//#endregion
|
|
29094
29235
|
//#region src/deployment/update-outcome.ts
|
|
29095
29236
|
/**
|
|
@@ -33143,5 +33284,5 @@ var DeployEngine = class {
|
|
|
33143
33284
|
};
|
|
33144
33285
|
|
|
33145
33286
|
//#endregion
|
|
33146
|
-
export {
|
|
33147
|
-
//# sourceMappingURL=deploy-engine-
|
|
33287
|
+
export { DEFAULT_STATE_PREFIX as $, warnDeprecatedNoPrefixCliFlag as $n, maskSecretsInError as $t, bold as A, buildDenyExternalAccessPolicy as An, NestedStackChildDirectDestroyError as Ar, requireConfigObject as At, secretBearingStateKeyWarning as B, getDockerImageBySourceHash as Bn, isCdkdError as Br, DiffCalculator as Bt, unsupportedFinalSnapshotError as C, ensureAssetStorage as Cn, DeployCancelledError as Cr, assertRegionMatch as Ct, isStatefulRecreateTargetSync as D, readBootstrapMarkerBody as Dn, LocalStartServiceError as Dr, readConfigString as Dt, MULTI_REGION_RECREATE_BLOCKED_TYPES as E, parseBootstrapMarker as En, LocalMigrateError as Er, configStringRefusal as Et, yellow as F, getDockerCmd as Fn, StackHasActiveImportsError as Fr, s3BucketDomainName as Ft, clearOnUpdateRemoval as G, resolveApp as Gn, isThrottlingError as Gr, TemplateParser as Gt, getCurrentResourceSecrets as H, synthesisStatusMessage as Hn, withErrorHandling as Hr, describeTypeWithThrottleRetry as Ht, collectDeclaredOutputNames as I, partitionSensitiveEnv as In, StackTerminationProtectionError as Ir, s3BucketDualStackDomainName as It, findSilentDropProperties as J, resolveSkipPrefix as Jn, markRedactedCause as Jr, TEMPLATE_SOURCED_RULES as Jt, ProviderRegistry as K, resolveAutoAssetStorage as Kn, isTransientServerError as Kr, STATE_SOURCED_CROSS_GENERATION_RULES as Kt, collectPublishedOutputNames as L, runDockerForeground as Ln, StateError as Lr, s3BucketRegionalDomainName as Lt, gray as M, buildDockerImage as Mn, ProvisioningError as Mr, classifyReplaySecretRegion as Mt, green as N, dockerSpawnEnvWithSensitive as Nn, ResourceTimeoutError as Nr, producerRegionsFromState as Nt, renderStatefulReason as O, validateAssetBucketName as On, LockError as Or, replayWarn as Ot, red as P, formatDockerLoginError as Pn, ResourceUpdateNotSupportedError as Pr, s3BucketArn as Pt, CUSTOM_RESOURCE_RESPONSE_PREFIX as Q, stateBucketExistenceConfirmed as Qn, isSingleDynamicReferenceToken as Qt, exportAliasCollisionScrubWarning as R, runDockerStreaming as Rn, SynthesisError as Rr, s3BucketWebsiteUrl as Rt, refusesFinalSnapshot as S, assertAssetBucketRegion as Sn, DependencyError as Sr, resolveExplicitPhysicalId as St, extractDeploymentEventError as T, isCrossRegionRedirect as Tn, LocalInvokeBuildError as Tr, configBooleanRefusal as Tt, IAMRoleProvider as U, getDefaultStateBucketName as Un, isMarkedNonRetryable as Ur, withRetry as Ut, stateKeySecretExposure as V, Synthesizer as Vn, normalizeAwsError as Vr, INTRINSIC_KEYS as Vt, collectInlinePolicyNamesManagedBySiblings as W, getLegacyStateBucketName as Wn, isRetryableTransientError as Wr, DagBuilder as Wt, maskDeep as X, resolveStateBucketWithDefaultAndSource as Xn, __exportAll as Xr, dynamicReferenceTokens as Xt, createMaskedRetryLogger as Y, resolveStateBucketWithDefault as Yn, retryClassificationText as Yr, createSecretMasker as Yt, maskerOrIdentity as Z, resolveUseCdkBootstrapAssets as Zn, errorCauseChain as Zt, PRE_DELETE_SNAPSHOT_TYPES as _, rewriteTemplateAssetReferences as _n, setAwsClients as _r, isUnboundTemplateParameter as _t, DeploymentEventsStore as a, S3StateBackend as an, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as ar, CloudControlProvider as at, createPreDeleteFinalSnapshot as b, AssetModeResolver as bn, ConfigError as br, WAFv2WebACLProvider as bt, replayFailedOperations as c, importableOutputKeys as cn, canonicalizeRegion as cr, deleteIndeterminateGuards as ct, updatePartialReason as d, AssetPublisher as dn, processStackMessages as dr, isTerminationProtectionPropagationError as dt, maskSecretsInText as en, CFN_TEMPLATE_BODY_LIMIT as er, beginCommandInterruptScope as et, withResourceDeadline as f, stringifyValue as fn, clearBucketRegionCache as fr, IntrinsicFunctionResolver as ft, ATOMIC_FINAL_SNAPSHOT_TYPES as g, loadPublishableAssetManifest as gn, resetAwsClients as gr, getAccountInfo as gt, computeImplicitDeleteEdges as h, createAssetRedirectResolver as hn, getAwsClients as hr, coerceParameterTypedValue as ht, DeploymentEventsReader as i, displaySafe as in, uploadCfnTemplate as ir, startInterruptWatch as it, cyan as j, describeAwsFailure as jn, PartialFailureError as jr, requireConfigString as jt, formatResourceLine as k, validateContainerRepoName as kn, MissingCdkCliError as kr, requireConfigArray as kt, replayRollback as l, importableOutputs as ln, derivePartitionAndUrlSuffix as lr, deleteSkipReason as lt, IMPLICIT_DELETE_DEPENDENCIES as m, buildAssetRedirectMap as mn, AwsClients as mr, cfnRefValueFromPhysicalId as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, scrubResourceRecord as nn, MIGRATE_TMP_PREFIX as nr, interruptWatchListenerCount as nt, planFailedOps as o, rebuildClientForBucketRegion as on, expectedOwnerParam as or, slowCcOperationTimeoutMs as ot, maskingRetryLogger as p, WorkGraph as pn, resolveBucketRegion as pr, carriesDynamicReference as pt, findActionableSilentDrops as q, resolveCaptureObservedState as qn, markNonRetryable as qr, STATE_SOURCED_READBACK_RULES as qt, DeployEngine as r, LockManager as rn, findLargeInlineResources as rr, isInterruptedWaitError as rt, planRollback as s, exportNamesCarriedFrom as sn, PARTITION_TABLE as sr, UNSPECIFIED_SKIP_REASON as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, redactSecretsForState as tn, CFN_TEMPLATE_URL_LIMIT as tr, endCommandInterruptScope as tt, updatePartialMessage as u, shouldRetainResource as un, AssemblyReader as ur, disableInstanceApiTermination as ut, buildFinalSnapshotIdentifier as v, escapeRegExp$1 as vn, AssetError as vr, parameterTypeMayLoseSecretIdentity as vt, makeCanonicalizePropertiesFn as w, getBootstrapMarkerKey as wn, DynamicReferenceRegionAmbiguousError as wr, coerceCfnBoolean as wt, isFinalSnapshotError as x, BOOTSTRAP_MARKER_PREFIX as xn, CrossAccountSecretRefusalError as xr, normalizeAwsTagsToCfn as xt, ccRoutedFinalSnapshotError as y, stripControlChars as yn, CdkdError as yr, refStateLookupFromResource as yt, isExportAliasCollision as z, AssetManifestLoader as zn, formatError as zr, applyRoleArnIfSet as zt };
|
|
33288
|
+
//# sourceMappingURL=deploy-engine-BgpCWFvY.js.map
|