@go-to-k/cdkd 0.290.1 → 0.290.3
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-e05iqtU_.js → asg-provider-RLnpBIKj.js} +20 -15
- package/dist/asg-provider-RLnpBIKj.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-aYUEGRRl.js → deploy-engine-0Wg4MwP2.js} +693 -103
- package/dist/deploy-engine-0Wg4MwP2.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{logger-DTEUzYP_.js → logger-th1myfgh.js} +63 -2
- package/dist/logger-th1myfgh.js.map +1 -0
- package/dist/{program-CnTfNj2k.js → program-CoRRfEe_.js} +397 -117
- package/dist/{program-CnTfNj2k.js.map → program-CoRRfEe_.js.map} +1 -1
- package/dist/{version-DTli1mA9.js → version-BTao4oxo.js} +2 -2
- package/dist/{version-DTli1mA9.js.map → version-BTao4oxo.js.map} +1 -1
- package/package.json +1 -1
- package/dist/asg-provider-e05iqtU_.js.map +0 -1
- package/dist/deploy-engine-aYUEGRRl.js.map +0 -1
- package/dist/logger-DTEUzYP_.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { b as
|
|
1
|
+
import { b as displayIdent, d as applyDefaultNameForFallback, f as explicitNamePropertyFor, g as looksLikeCdkdGeneratedName, h as getCurrentStackName, m as generateResourceNameWithFallback, n as getLogger, p as generateResourceName, r as isStdoutReservedForPayload, s as getLiveRenderer, v as withStackName, x as displaySafe, y as UNRENDERABLE } from "./logger-th1myfgh.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-BTao4oxo.js";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetBucketReplicationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -17,7 +17,7 @@ import { APIGatewayClient, GetRestApiCommand } from "@aws-sdk/client-api-gateway
|
|
|
17
17
|
import { DescribeApiDestinationCommand, DescribeConnectionCommand, EventBridgeClient } from "@aws-sdk/client-eventbridge";
|
|
18
18
|
import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";
|
|
19
19
|
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
20
|
-
import { CloudFrontClient, GetCloudFrontOriginAccessIdentityCommand } from "@aws-sdk/client-cloudfront";
|
|
20
|
+
import { CloudFrontClient, GetCloudFrontOriginAccessIdentityCommand, GetDistributionCommand } from "@aws-sdk/client-cloudfront";
|
|
21
21
|
import { CloudWatchClient } from "@aws-sdk/client-cloudwatch";
|
|
22
22
|
import { CloudWatchLogsClient } from "@aws-sdk/client-cloudwatch-logs";
|
|
23
23
|
import { BedrockAgentCoreControlClient } from "@aws-sdk/client-bedrock-agentcore-control";
|
|
@@ -1148,7 +1148,15 @@ function formatDuration$1(ms) {
|
|
|
1148
1148
|
* `Outputs.<Key>` the child does not declare rather than letting
|
|
1149
1149
|
* `guardedPhysicalIdFallback` serve the synthetic
|
|
1150
1150
|
* `arn:cdkd-local:...` physical id — that id starts with `arn:`, so the
|
|
1151
|
-
* #1103 ARN-shape guard passes it
|
|
1151
|
+
* #1103 ARN-shape guard passes it; and the LIVE-READ refusals of issue
|
|
1152
|
+
* [#3096](https://github.com/go-to-k/cdkd/issues/3096)
|
|
1153
|
+
* (`refuseUnservedAttribute`, raised by the `AWS::EC2::Instance` address /
|
|
1154
|
+
* DNS / zone arm, the `AWS::EC2::VPC` `DefaultSecurityGroup` arm and the
|
|
1155
|
+
* `AWS::CloudFront::Distribution` `DomainName` arm when the record omits
|
|
1156
|
+
* the attribute and the live read finds nothing or fails), plus the
|
|
1157
|
+
* read-less `AWS::RDS::DBProxy` / `DBProxyEndpoint` `VpcId` refusal beside
|
|
1158
|
+
* them — each replacing a physical id the attribute's value type can never
|
|
1159
|
+
* accept.
|
|
1152
1160
|
* 2. NOT reachable from it, and thrown as this class only so that "deliberate
|
|
1153
1161
|
* refusal" is a property of the THROW rather than of the one catch that
|
|
1154
1162
|
* inspects it: `resolveSplit`'s two refusals of a non-string value (#1874),
|
|
@@ -1177,11 +1185,17 @@ function formatDuration$1(ms) {
|
|
|
1177
1185
|
* subclass, never on this class.
|
|
1178
1186
|
*
|
|
1179
1187
|
* The class is deliberately NOT `markNonRetryable` at construction, unlike
|
|
1180
|
-
* {@link ResourceUpdateNotSupportedError}:
|
|
1188
|
+
* {@link ResourceUpdateNotSupportedError}: two kinds of throw site are
|
|
1181
1189
|
* genuinely time-dependent — the fabricated-account guard, where
|
|
1182
1190
|
* `getAccountInfo` caches a fabricated answer for only 10s precisely so a
|
|
1183
|
-
* later attempt can heal
|
|
1184
|
-
*
|
|
1191
|
+
* later attempt can heal, and since issue #3096 the LIVE-READ refusals
|
|
1192
|
+
* (`refuseUnservedAttribute`), where a `pending` instance settles seconds
|
|
1193
|
+
* later and a failed describe can succeed on the next attempt — so a
|
|
1194
|
+
* constructor-level marker would wrongly DECLARE those terminal (whether
|
|
1195
|
+
* `withRetry` then retries one is the classifiers' call, and that helper's
|
|
1196
|
+
* doc comment says what they actually see). Every OTHER
|
|
1197
|
+
* site marks at its own `throw` (the #3096 `DBProxy` `VpcId` refusal
|
|
1198
|
+
* included — it has no live read, so it decides from the record alone): each
|
|
1185
1199
|
* decides from inputs a retry cannot change (a persisted state record, an
|
|
1186
1200
|
* attribute-name suffix, a CLI flag, an already-resolved value's type, a
|
|
1187
1201
|
* template's literal `RoleArn`, a child stack's declared output names), and
|
|
@@ -12731,7 +12745,13 @@ const STATE_SOURCED_READBACK_RULES = {
|
|
|
12731
12745
|
* `observedProperties`, where a mask is a REGRESSION rather than a refusal
|
|
12732
12746
|
* (`cdkd export` blocks such a record and the rollback replay refuses the
|
|
12733
12747
|
* operation). A caller declares this constant when it knows its bag becomes a
|
|
12734
|
-
* drift baseline and nothing else
|
|
12748
|
+
* drift baseline and nothing else — and since issue
|
|
12749
|
+
* [#2939](https://github.com/go-to-k/cdkd/issues/2939) the two `cdkd drift`
|
|
12750
|
+
* writers make that call per record: `--accept`'s new baseline and
|
|
12751
|
+
* `--revert`'s narrowed delta take THIS constant when the record carries
|
|
12752
|
+
* `observedProperties` (the bag lands there) and
|
|
12753
|
+
* {@link STATE_SOURCED_READBACK_RULES} otherwise (the bag lands in
|
|
12754
|
+
* `properties`), the *** rows of the write-site table above.
|
|
12735
12755
|
*/
|
|
12736
12756
|
const STATE_SOURCED_BASELINE_RULES = {
|
|
12737
12757
|
descendArrays: false,
|
|
@@ -16981,6 +17001,7 @@ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
16981
17001
|
* releases. Neither counter feeds a control decision; they are reporting only.
|
|
16982
17002
|
*/
|
|
16983
17003
|
async function withRetry(operation, logicalId, opts = {}) {
|
|
17004
|
+
const shownId = displaySafe(logicalId, { asciiOnly: true }) || "<unrenderable>";
|
|
16984
17005
|
const maxRetries = opts.maxRetries ?? 8;
|
|
16985
17006
|
const initialDelayMs = opts.initialDelayMs ?? 1e3;
|
|
16986
17007
|
const maxDelayMs = opts.maxDelayMs ?? 8e3;
|
|
@@ -17014,7 +17035,7 @@ async function withRetry(operation, logicalId, opts = {}) {
|
|
|
17014
17035
|
if (propagationRetries > 0) spent.push(`${propagationRetries} IAM-propagation ${propagationRetries === 1 ? "retry" : "retries"} over ${(propagationSleptMs / 1e3).toFixed(2)}s of propagation backoff${budgetExhausted ? " (the full propagation budget)" : ""}`);
|
|
17015
17036
|
if (nameCooldownRetries > 0) spent.push(`${nameCooldownRetries} name-cooldown ${nameCooldownRetries === 1 ? "retry" : "retries"} over ${(nameCooldownSleptMs / 1e3).toFixed(2)}s waiting for the name to be released${nameCooldownBudgetExhausted ? " (the full name-cooldown budget)" : ""}`);
|
|
17016
17037
|
if (serverErrorRetries > 0) spent.push(`${serverErrorRetries} transient server-error ${serverErrorRetries === 1 ? "retry" : "retries"} (HTTP 5xx)`);
|
|
17017
|
-
const summary = () => `${
|
|
17038
|
+
const summary = () => `${shownId}: gave up after ${spent.join(" and ")} - ${message}` + formatRetryClassificationSignals(error);
|
|
17018
17039
|
try {
|
|
17019
17040
|
opts.logger?.warn?.(summary());
|
|
17020
17041
|
} catch {}
|
|
@@ -17023,7 +17044,7 @@ async function withRetry(operation, logicalId, opts = {}) {
|
|
|
17023
17044
|
}
|
|
17024
17045
|
const delay = propagation ? Math.min(250 * Math.pow(2, attempt), IAM_PROPAGATION_MAX_DELAY_MS) : nameCooldown ? Math.min(NAME_COOLDOWN_INITIAL_DELAY_MS * Math.pow(2, attempt), NAME_COOLDOWN_MAX_DELAY_MS) : Math.min(initialDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
17025
17046
|
const backoffThroughThisAttemptMs = propagation ? propagationSleptMs + delay : propagationSleptMs;
|
|
17026
|
-
opts.logger?.debug(` ⏳ Retrying ${
|
|
17047
|
+
opts.logger?.debug(` ⏳ Retrying ${shownId} in ${delay / 1e3}s (attempt ${attempt + 1}/${attemptLimit}${propagation ? `, ${(backoffThroughThisAttemptMs / 1e3).toFixed(2)}s backoff through this attempt` : ""}) - ${message}`);
|
|
17027
17048
|
for (let waited = 0; waited < delay; waited += 1e3) {
|
|
17028
17049
|
if (opts.isInterrupted?.()) throw opts.onInterrupted ? opts.onInterrupted() : /* @__PURE__ */ new Error("Interrupted");
|
|
17029
17050
|
await sleep(Math.min(1e3, delay - waited));
|
|
@@ -20675,14 +20696,17 @@ async function assumeRoleForCrossAccountStateRead(roleArn) {
|
|
|
20675
20696
|
* up the assumed-role credentials automatically without touching the
|
|
20676
20697
|
* client construction sites.
|
|
20677
20698
|
*
|
|
20678
|
-
* **
|
|
20679
|
-
*
|
|
20680
|
-
*
|
|
20681
|
-
*
|
|
20682
|
-
*
|
|
20683
|
-
*
|
|
20684
|
-
*
|
|
20685
|
-
*
|
|
20699
|
+
* **What the assumed role must carry.** Unlike `cdk deploy`, cdkd does
|
|
20700
|
+
* NOT route through CloudFormation. There is no cfn-exec-role to
|
|
20701
|
+
* delegate to. Every IAM / EC2 / Lambda / etc. API call is issued from
|
|
20702
|
+
* the cdkd process directly. The role you pass to `--role-arn` (or set
|
|
20703
|
+
* in `CDKD_ROLE_ARN`) must therefore carry the actions for the resource
|
|
20704
|
+
* types being deployed plus cdkd's own bookkeeping set (Cloud Control,
|
|
20705
|
+
* `cloudformation:DescribeType` / `ListExports` / `DescribeStacks`,
|
|
20706
|
+
* `sts:GetCallerIdentity`, the state and asset storage) — i.e. exactly what the
|
|
20707
|
+
* caller's own principal would otherwise have needed, not
|
|
20708
|
+
* `AdministratorAccess`. CDK CLI's `cdk-hnb659fds-deploy-role-*` is NOT
|
|
20709
|
+
* sufficient — that role only carries CFn + asset-publish permissions.
|
|
20686
20710
|
*
|
|
20687
20711
|
* Default session duration is 1 hour. For longer-running deploys, the
|
|
20688
20712
|
* caller should re-issue the cdkd command (the in-flight credentials
|
|
@@ -22663,6 +22687,36 @@ var WAFv2WebACLProvider = class {
|
|
|
22663
22687
|
}
|
|
22664
22688
|
};
|
|
22665
22689
|
|
|
22690
|
+
//#endregion
|
|
22691
|
+
//#region src/provisioning/ec2-instance-state.ts
|
|
22692
|
+
/**
|
|
22693
|
+
* The ONE spelling of "has this EC2 instance SETTLED?" (issue
|
|
22694
|
+
* [#3096](https://github.com/go-to-k/cdkd/issues/3096) review).
|
|
22695
|
+
*
|
|
22696
|
+
* Two readers must agree on it or a record and a resolution disagree about
|
|
22697
|
+
* the same instance: `EC2Provider`'s `describedInstanceAttributes` decides
|
|
22698
|
+
* whether a missing public member is RECORDED as the known `''` (settled) or
|
|
22699
|
+
* OMITTED (still `pending`, issue #3077), and the resolver's
|
|
22700
|
+
* `AWS::EC2::Instance` live arm decides, for an omitted member, whether to
|
|
22701
|
+
* SERVE that same `''` or REFUSE. Each carried the comparison inline; this
|
|
22702
|
+
* module is the shared predicate so a change to one side cannot leave the
|
|
22703
|
+
* other on the old rule.
|
|
22704
|
+
*
|
|
22705
|
+
* `pending` is the only state in which EC2 has not finished assigning the
|
|
22706
|
+
* launch-time members; every other reported state — `running`, `stopping`,
|
|
22707
|
+
* `stopped`, `shutting-down`, `terminated` — is a settled one whose public
|
|
22708
|
+
* pair, when absent, is genuinely absent (a private-subnet instance, or a
|
|
22709
|
+
* stopped one whose address was released). NO state at all is treated like
|
|
22710
|
+
* `pending`: a read-back that returned no instance, or a shape without one,
|
|
22711
|
+
* says nothing about having settled.
|
|
22712
|
+
*
|
|
22713
|
+
* A LEAF: no imports, so both `src/provisioning/**` and `src/deployment/**`
|
|
22714
|
+
* can take it without adding an edge between the two layers.
|
|
22715
|
+
*/
|
|
22716
|
+
function isSettledInstanceState(stateName) {
|
|
22717
|
+
return stateName !== void 0 && stateName !== "pending";
|
|
22718
|
+
}
|
|
22719
|
+
|
|
22666
22720
|
//#endregion
|
|
22667
22721
|
//#region src/deployment/intrinsic-function-resolver.ts
|
|
22668
22722
|
/**
|
|
@@ -23195,6 +23249,19 @@ function withoutProducerRegions(context) {
|
|
|
23195
23249
|
return rest;
|
|
23196
23250
|
}
|
|
23197
23251
|
/**
|
|
23252
|
+
* Masked log twins registered this pass, per pass bag (issue #3100;
|
|
23253
|
+
* `rememberLogTwin` / `logTwinOfProduct`). Log-only: nothing that resolves or
|
|
23254
|
+
* persists a value reads it.
|
|
23255
|
+
*
|
|
23256
|
+
* MODULE scope, not instance scope: a region-pinned sibling resolver
|
|
23257
|
+
* (`resolverForProducerRegion`) resolves on behalf of the consumer with the
|
|
23258
|
+
* consumer's bag, so an instance-local registry left the sibling's twin where
|
|
23259
|
+
* the consumer's `Fn::Join` / `Fn::Sub` never looked. The key is still the
|
|
23260
|
+
* pass's own bag object, so scope does not widen: another pass holds another
|
|
23261
|
+
* bag and cannot reach these entries, and they die with the bag.
|
|
23262
|
+
*/
|
|
23263
|
+
const LOG_TWINS_BY_PASS = /* @__PURE__ */ new WeakMap();
|
|
23264
|
+
/**
|
|
23198
23265
|
* Does `value` carry a CloudFormation dynamic reference anywhere inside it?
|
|
23199
23266
|
*
|
|
23200
23267
|
* Used as the identity fast path of {@link
|
|
@@ -23313,10 +23380,37 @@ const recordedSecretExpressions = {
|
|
|
23313
23380
|
* lookup (PrivateIp / PublicIp / PrivateDnsName / PublicDnsName /
|
|
23314
23381
|
* AvailabilityZone). Keyed by `${physicalId}#${attributeName}`. The IP /
|
|
23315
23382
|
* DNS attributes are not derivable from the instance id, so they are read
|
|
23316
|
-
* back from AWS once per (instance, attribute) and memoized for the
|
|
23317
|
-
* lifetime
|
|
23318
|
-
|
|
23319
|
-
|
|
23383
|
+
* back from AWS once per (instance, attribute) and memoized for the PROCESS
|
|
23384
|
+
* lifetime — one `cdkd deploy` per CLI process, so "the deploy" in practice;
|
|
23385
|
+
* nothing in `src/` calls `resetAccountInfoCache`, tests do. Only a VALUE is cached — a settled instance's address, or the
|
|
23386
|
+
* known-empty `''` a settled instance reports for a public member it has
|
|
23387
|
+
* none of — never a refusal: a `pending` instance is re-described on the
|
|
23388
|
+
* next resolution, when it may have settled (issue #3096).
|
|
23389
|
+
*/
|
|
23390
|
+
const cachedEc2InstanceAttributes = Object.create(null);
|
|
23391
|
+
/**
|
|
23392
|
+
* The two sibling caches of {@link cachedEc2InstanceAttributes} (issue
|
|
23393
|
+
* #3096), each holding a value the resolver read LIVE because the state
|
|
23394
|
+
* record omitted it — `definedAttributes` drops a member the provider could
|
|
23395
|
+
* not read back (issue #3077), so the `Fn::GetAtt` falls out of the flat
|
|
23396
|
+
* lookup and into `constructAttribute`'s per-type arm. Keyed by physical id
|
|
23397
|
+
* (AWS-minted, unique across accounts and regions, and the value — a default
|
|
23398
|
+
* security group id, a distribution hostname — never changes); like the
|
|
23399
|
+
* instance cache, a refusal caches nothing. Same process lifetime, cleared
|
|
23400
|
+
* together with it by {@link resetAccountInfoCache}. The RDS `DBProxy` / `DBProxyEndpoint`
|
|
23401
|
+
* `VpcId` arms have no cache because they have no live read: `AwsClients`
|
|
23402
|
+
* exposes no RDS client and this file imports none, so those two arms refuse
|
|
23403
|
+
* outright (see `refuseUnservedAttribute`'s callers).
|
|
23404
|
+
*
|
|
23405
|
+
* All three are NULL-PROTOTYPE objects (#3096 delta review, measured): the
|
|
23406
|
+
* key is a state-record physical id, and on a plain `{}` a record holding
|
|
23407
|
+
* `constructor` / `__proto__` / `hasOwnProperty` read a FUNCTION out of
|
|
23408
|
+
* `Object.prototype` as the cached value — served with zero AWS calls, ahead
|
|
23409
|
+
* of every shape guard below. `Object.create(null)` has nothing to read; the
|
|
23410
|
+
* `delete`-based clears in `resetAccountInfoCache` keep the prototype.
|
|
23411
|
+
*/
|
|
23412
|
+
const cachedVpcDefaultSecurityGroups = Object.create(null);
|
|
23413
|
+
const cachedCloudFrontDomainNames = Object.create(null);
|
|
23320
23414
|
/**
|
|
23321
23415
|
* The region this call answers for: the caller's override, else the ambient one.
|
|
23322
23416
|
*
|
|
@@ -25228,7 +25322,44 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25228
25322
|
this.logger.warn(`Failed to fetch VPC Ipv6CidrBlocks for ${physicalId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
25229
25323
|
return [];
|
|
25230
25324
|
}
|
|
25231
|
-
case "DefaultSecurityGroup":
|
|
25325
|
+
case "DefaultSecurityGroup": {
|
|
25326
|
+
if (!/^vpc-[0-9a-f]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, DefaultSecurityGroup] for AWS::EC2::VPC: the state record's physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context)).slice(0, 64)}" is not a VPC id (vpc-<hex>), so cdkd will not use it as an EC2 filter value. Repair the record (cdkd import, or re-create the VPC) and deploy again.`));
|
|
25327
|
+
const cachedGroupId = cachedVpcDefaultSecurityGroups[physicalId];
|
|
25328
|
+
if (cachedGroupId !== void 0) return cachedGroupId;
|
|
25329
|
+
let groupId;
|
|
25330
|
+
try {
|
|
25331
|
+
groupId = (await this.clientsForRegion(this.explicitRegion).ec2.send(new DescribeSecurityGroupsCommand({ Filters: [{
|
|
25332
|
+
Name: "vpc-id",
|
|
25333
|
+
Values: [physicalId]
|
|
25334
|
+
}, {
|
|
25335
|
+
Name: "group-name",
|
|
25336
|
+
Values: ["default"]
|
|
25337
|
+
}] }))).SecurityGroups?.[0]?.GroupId;
|
|
25338
|
+
} catch (err) {
|
|
25339
|
+
this.refuseUnservedAttribute({
|
|
25340
|
+
logicalId,
|
|
25341
|
+
attributeName,
|
|
25342
|
+
resourceType,
|
|
25343
|
+
physicalId,
|
|
25344
|
+
context,
|
|
25345
|
+
observed: this.describeFailureObserved("DescribeSecurityGroups", err, context),
|
|
25346
|
+
remedy: "Fix the read (the vpc-id / group-name filtered DescribeSecurityGroups permission, or the region) and deploy again."
|
|
25347
|
+
});
|
|
25348
|
+
}
|
|
25349
|
+
if (groupId) {
|
|
25350
|
+
cachedVpcDefaultSecurityGroups[physicalId] = groupId;
|
|
25351
|
+
return groupId;
|
|
25352
|
+
}
|
|
25353
|
+
this.refuseUnservedAttribute({
|
|
25354
|
+
logicalId,
|
|
25355
|
+
attributeName,
|
|
25356
|
+
resourceType,
|
|
25357
|
+
physicalId,
|
|
25358
|
+
context,
|
|
25359
|
+
observed: "DescribeSecurityGroups found no group named \"default\" in the VPC",
|
|
25360
|
+
remedy: "Check the VPC in the console, or reference the attribute from a later deploy."
|
|
25361
|
+
});
|
|
25362
|
+
}
|
|
25232
25363
|
default: return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
|
|
25233
25364
|
}
|
|
25234
25365
|
if (resourceType === "AWS::IAM::Policy") switch (attributeName) {
|
|
@@ -25423,9 +25554,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25423
25554
|
const cacheKey = `${physicalId}#${attributeName}`;
|
|
25424
25555
|
const cached = cachedEc2InstanceAttributes[cacheKey];
|
|
25425
25556
|
if (cached !== void 0) return cached;
|
|
25557
|
+
let value;
|
|
25558
|
+
let stateName;
|
|
25426
25559
|
try {
|
|
25427
25560
|
const instance = (await this.clientsForRegion(this.explicitRegion).ec2.send(new DescribeInstancesCommand({ InstanceIds: [physicalId] }))).Reservations?.[0]?.Instances?.[0];
|
|
25428
|
-
|
|
25561
|
+
stateName = instance?.State?.Name;
|
|
25429
25562
|
switch (attributeName) {
|
|
25430
25563
|
case "PrivateIp":
|
|
25431
25564
|
value = instance?.PrivateIpAddress;
|
|
@@ -25441,15 +25574,36 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25441
25574
|
break;
|
|
25442
25575
|
case "AvailabilityZone": value = instance?.Placement?.AvailabilityZone;
|
|
25443
25576
|
}
|
|
25444
|
-
if (value !== void 0 && value !== null && value !== "") {
|
|
25445
|
-
cachedEc2InstanceAttributes[cacheKey] = value;
|
|
25446
|
-
return value;
|
|
25447
|
-
}
|
|
25448
|
-
this.logger.warn(`DescribeInstances(${physicalId}) returned no ${this.maskSecretsForLog(attributeName, context)}; returning physical ID`);
|
|
25449
25577
|
} catch (err) {
|
|
25450
|
-
this.
|
|
25578
|
+
this.refuseUnservedAttribute({
|
|
25579
|
+
logicalId,
|
|
25580
|
+
attributeName,
|
|
25581
|
+
resourceType,
|
|
25582
|
+
physicalId,
|
|
25583
|
+
context,
|
|
25584
|
+
observed: this.describeFailureObserved("DescribeInstances", err, context),
|
|
25585
|
+
remedy: "Fix the read (the ec2:DescribeInstances permission, or the region) and deploy again."
|
|
25586
|
+
});
|
|
25451
25587
|
}
|
|
25452
|
-
|
|
25588
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
25589
|
+
cachedEc2InstanceAttributes[cacheKey] = value;
|
|
25590
|
+
return value;
|
|
25591
|
+
}
|
|
25592
|
+
const settled = isSettledInstanceState(stateName);
|
|
25593
|
+
if (settled && (attributeName === "PublicIp" || attributeName === "PublicDnsName")) {
|
|
25594
|
+
cachedEc2InstanceAttributes[cacheKey] = "";
|
|
25595
|
+
return "";
|
|
25596
|
+
}
|
|
25597
|
+
const observedState = stateName === void 0 ? "no instance state" : `state ${stateName}`;
|
|
25598
|
+
this.refuseUnservedAttribute({
|
|
25599
|
+
logicalId,
|
|
25600
|
+
attributeName,
|
|
25601
|
+
resourceType,
|
|
25602
|
+
physicalId,
|
|
25603
|
+
context,
|
|
25604
|
+
observed: `DescribeInstances reports no ${this.maskSecretsForLog(attributeName, context)} yet (${observedState})`,
|
|
25605
|
+
remedy: settled ? "Check the instance in the console; a terminated or stopped instance has no such attribute to serve." : "Deploy without --no-wait so the instance is running before its attributes are read, or reference the attribute from a later deploy once it is."
|
|
25606
|
+
});
|
|
25453
25607
|
}
|
|
25454
25608
|
default: return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
|
|
25455
25609
|
}
|
|
@@ -25467,9 +25621,115 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25467
25621
|
if (attributeName === "LaunchTemplateId") return physicalId;
|
|
25468
25622
|
return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
|
|
25469
25623
|
}
|
|
25624
|
+
if (resourceType === "AWS::CloudFront::Distribution") switch (attributeName) {
|
|
25625
|
+
case "Id": return physicalId;
|
|
25626
|
+
case "DomainName": {
|
|
25627
|
+
if (!/^[A-Z0-9]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, DomainName] for AWS::CloudFront::Distribution: the state record's physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context)).slice(0, 64)}" is not a distribution id (upper-case alphanumerics), so cdkd will not look it up. Repair the record (cdkd import, or re-create the distribution) and deploy again.`));
|
|
25628
|
+
const cachedDomainName = cachedCloudFrontDomainNames[physicalId];
|
|
25629
|
+
if (cachedDomainName !== void 0) return cachedDomainName;
|
|
25630
|
+
let domainName;
|
|
25631
|
+
try {
|
|
25632
|
+
domainName = (await this.clientsForRegion(this.explicitRegion).cloudFront.send(new GetDistributionCommand({ Id: physicalId }))).Distribution?.DomainName;
|
|
25633
|
+
} catch (err) {
|
|
25634
|
+
this.refuseUnservedAttribute({
|
|
25635
|
+
logicalId,
|
|
25636
|
+
attributeName,
|
|
25637
|
+
resourceType,
|
|
25638
|
+
physicalId,
|
|
25639
|
+
context,
|
|
25640
|
+
observed: this.describeFailureObserved("GetDistribution", err, context),
|
|
25641
|
+
remedy: "Fix the read (the cloudfront:GetDistribution permission) and deploy again."
|
|
25642
|
+
});
|
|
25643
|
+
}
|
|
25644
|
+
if (domainName) {
|
|
25645
|
+
cachedCloudFrontDomainNames[physicalId] = domainName;
|
|
25646
|
+
return domainName;
|
|
25647
|
+
}
|
|
25648
|
+
this.refuseUnservedAttribute({
|
|
25649
|
+
logicalId,
|
|
25650
|
+
attributeName,
|
|
25651
|
+
resourceType,
|
|
25652
|
+
physicalId,
|
|
25653
|
+
context,
|
|
25654
|
+
observed: "GetDistribution reports no DomainName",
|
|
25655
|
+
remedy: "Check the distribution in the console, or reference the attribute from a later deploy."
|
|
25656
|
+
});
|
|
25657
|
+
}
|
|
25658
|
+
default: return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
|
|
25659
|
+
}
|
|
25660
|
+
if (resourceType === "AWS::RDS::DBProxy" || resourceType === "AWS::RDS::DBProxyEndpoint") {
|
|
25661
|
+
if (attributeName === "VpcId") throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: the state record holds no VpcId for it (the read-back that would have recorded it reported none), and the physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" is a name, not a VPC id, so cdkd refuses to substitute it. Update the resource so its next deploy records the value, or reference the VPC directly.`));
|
|
25662
|
+
return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
|
|
25663
|
+
}
|
|
25470
25664
|
return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
|
|
25471
25665
|
}
|
|
25472
25666
|
/**
|
|
25667
|
+
* Refuse an attribute the state record omits and a live read could not
|
|
25668
|
+
* serve (issue [#3096](https://github.com/go-to-k/cdkd/issues/3096)).
|
|
25669
|
+
*
|
|
25670
|
+
* The arms that call this all share one shape: the provider recorded no
|
|
25671
|
+
* value because AWS had not assigned one yet or the read-back failed (issue
|
|
25672
|
+
* #3077 made the key ABSENT rather than `''`), the resolver re-reads it
|
|
25673
|
+
* live, and the read finds nothing — or fails. Before #3096 every such arm
|
|
25674
|
+
* answered the PHYSICAL ID: an `i-...` where an IP address or a DNS name
|
|
25675
|
+
* belongs, a `vpc-...` in a security-group slot, a distribution id where a
|
|
25676
|
+
* hostname belongs, a proxy name in a `VpcId` position. Loud only where AWS
|
|
25677
|
+
* rejects the shape; an Output, an export or a free-text property carried it
|
|
25678
|
+
* silently. The physical id can never be the value for these attributes,
|
|
25679
|
+
* so the honest answer is a refusal naming the resource, the attribute, what
|
|
25680
|
+
* was observed and the remedy.
|
|
25681
|
+
*
|
|
25682
|
+
* DELIBERATELY NOT `markNonRetryable`, unlike every other refusal in this
|
|
25683
|
+
* file but the fabricated-account guard: the verdict is TIME-DEPENDENT. A
|
|
25684
|
+
* `pending` instance settles seconds later, and a failed describe can
|
|
25685
|
+
* succeed on the next attempt, so cdkd must not DECLARE it terminal — the
|
|
25686
|
+
* marker is that declaration, and `withRetry` honours it ahead of every
|
|
25687
|
+
* classifier. Leaving it off promises no retry: `isRetryableTransientError`
|
|
25688
|
+
* reads throttle names and HTTP statuses off the `cause` chain — which this
|
|
25689
|
+
* refusal deliberately does not carry, see below — and everything else by
|
|
25690
|
+
* message substring, and this message matches nothing on its own. So the
|
|
25691
|
+
* nested-stack replay (`NestedStackProvider.create` runs the child deploy
|
|
25692
|
+
* inside the parent's `withRetry`) re-runs the child only when an
|
|
25693
|
+
* interpolated hole happens to carry a pattern — the `logicalId` (the #1838
|
|
25694
|
+
* hazard: `DependencyViolation` and two other bare words), or the error
|
|
25695
|
+
* CLASS name `describeFailureObserved` puts in `observed`, which none of
|
|
25696
|
+
* these three reads raises — and then re-describes and can heal.
|
|
25697
|
+
* Measured, not designed: the fabricated-account guard sits in exactly the
|
|
25698
|
+
* same place. Threading a sanitized SDK error as `cause` so a throttled
|
|
25699
|
+
* describe classifies as transient was considered and left out — a
|
|
25700
|
+
* `CdkdError`'s `cause` is rendered at default verbosity by `formatError`
|
|
25701
|
+
* (`Caused by:`), so the clone would need its own fence. What the
|
|
25702
|
+
* refusal does at each consumer: a resource property fails the resource; a
|
|
25703
|
+
* stack Output is caught per-output by `DeployEngine.
|
|
25704
|
+
* handleOutputResolutionFailure`, skipped and recorded in `skippedOutputs`
|
|
25705
|
+
* (#2740), then re-resolved on the next deploy; an `Fn::Sub` re-raises it
|
|
25706
|
+
* (#1740); a `Conditions` entry still absorbs it to `false`
|
|
25707
|
+
* (`evaluateConditions`).
|
|
25708
|
+
*
|
|
25709
|
+
* `observed` and `remedy` are cdkd-authored sentences built by the caller
|
|
25710
|
+
* from an instance STATE name, an error CLASS name or a fixed phrase — never
|
|
25711
|
+
* AWS's raw message, which `describeFailureObserved` keeps at debug (the
|
|
25712
|
+
* per-reader rule in `.claude/rules/provider-resource-identity.md`: a
|
|
25713
|
+
* denied describe quotes the caller's account, role and session).
|
|
25714
|
+
*/
|
|
25715
|
+
refuseUnservedAttribute(site) {
|
|
25716
|
+
const { logicalId, attributeName, resourceType, physicalId, context, observed, remedy } = site;
|
|
25717
|
+
throw new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: ${observed}. The physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" is not a usable ${this.maskSecretsForLog(attributeName, context)}, so cdkd refuses to substitute it. ${remedy}`);
|
|
25718
|
+
}
|
|
25719
|
+
/**
|
|
25720
|
+
* The `observed` clause of {@link refuseUnservedAttribute} for a live read
|
|
25721
|
+
* that THREW: names the read and the error's CLASS at default verbosity and
|
|
25722
|
+
* puts AWS's own text behind `--verbose`, since a denied describe quotes the
|
|
25723
|
+
* caller's account, role and session into its message.
|
|
25724
|
+
*/
|
|
25725
|
+
describeFailureObserved(read, err, context) {
|
|
25726
|
+
const name = displaySafe(err instanceof Error && err.name ? err.name : "Error", { asciiOnly: true }).slice(0, 64).trim() || "Error";
|
|
25727
|
+
const status = err?.$metadata?.httpStatusCode;
|
|
25728
|
+
const errorClass = typeof status === "number" && Number.isInteger(status) ? `${name}, HTTP ${status}` : name;
|
|
25729
|
+
this.logger.debug(`${read} failed (${errorClass}): ${this.maskSecretsForLog(err instanceof Error ? err.message : String(err), context)}`);
|
|
25730
|
+
return `${read} failed (${errorClass}); re-run with --verbose for the AWS error text`;
|
|
25731
|
+
}
|
|
25732
|
+
/**
|
|
25473
25733
|
* Shared unknown-attribute physicalId fallback (issues #1106 / #1111).
|
|
25474
25734
|
*
|
|
25475
25735
|
* Applied by BOTH the final unknown-type fallback of
|
|
@@ -25501,9 +25761,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25501
25761
|
const expectsUrlShape = attributeName.endsWith("Url") && !/^https?:\/\//.test(physicalId);
|
|
25502
25762
|
if (expectsArnShape || expectsUrlShape) {
|
|
25503
25763
|
const expectedShape = expectsArnShape ? "an ARN (arn:...)" : "a URL (http(s)://...)";
|
|
25504
|
-
throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and the physical ID fallback "${this.
|
|
25764
|
+
throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and the physical ID fallback "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" is not ${expectedShape}. CloudFormation would return a different value here, so falling back to the physical ID would silently produce a wrong value (e.g. in stack Outputs). Avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${this.maskSecretsForLog(attributeName, context)}.`));
|
|
25505
25765
|
}
|
|
25506
|
-
if (this.strictGetAtt) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and --strict-getatt rejects the physical ID fallback "${this.
|
|
25766
|
+
if (this.strictGetAtt) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and --strict-getatt rejects the physical ID fallback "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" (which may not be the value CloudFormation would return). Drop --strict-getatt to fall back with a warning, avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${this.maskSecretsForLog(attributeName, context)}.`));
|
|
25507
25767
|
this.physicalIdFallbackCount++;
|
|
25508
25768
|
this.logger.warn(`Unknown attribute ${this.maskSecretsForLog(attributeName, context)} for resource type ${resourceType}, returning physical ID`);
|
|
25509
25769
|
return physicalId;
|
|
@@ -25518,12 +25778,36 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25518
25778
|
let values = rawValues;
|
|
25519
25779
|
if (!Array.isArray(values)) values = await this.resolveValue(values, context);
|
|
25520
25780
|
if (!Array.isArray(values)) throw new Error(`Fn::Join's second argument must be a list (an array literal or a list-returning intrinsic such as Fn::Cidr / Fn::GetAZs / Fn::Split / a Ref to a list-typed parameter — any List<...> type or CommaDelimitedList), but resolved to ${typeof values}`);
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25524
|
-
|
|
25525
|
-
|
|
25526
|
-
|
|
25781
|
+
const literalList = Array.isArray(rawValues);
|
|
25782
|
+
const parts = (await allSettledKeepingFirstRejection(values.map(async (v) => {
|
|
25783
|
+
if (typeof v === "string") return {
|
|
25784
|
+
...v.includes("{{resolve:") ? await this.resolveDynamicReferencesWithLogTwin(v, v, context) : {
|
|
25785
|
+
result: v,
|
|
25786
|
+
twin: v
|
|
25787
|
+
},
|
|
25788
|
+
product: !literalList
|
|
25789
|
+
};
|
|
25790
|
+
const raw = await this.resolveValue(v, context);
|
|
25791
|
+
const resolved = String(raw);
|
|
25792
|
+
return {
|
|
25793
|
+
result: resolved,
|
|
25794
|
+
twin: resolved,
|
|
25795
|
+
product: true,
|
|
25796
|
+
raw: { value: raw }
|
|
25797
|
+
};
|
|
25798
|
+
}), (pending) => this.warnAbandonedParts(pending))).map((part) => {
|
|
25799
|
+
if (!part.product) return part;
|
|
25800
|
+
if (part.raw) return {
|
|
25801
|
+
result: part.result,
|
|
25802
|
+
twin: this.productLogTwin(part.raw.value, context)
|
|
25803
|
+
};
|
|
25804
|
+
return this.logTwinOfProduct(part, context);
|
|
25805
|
+
});
|
|
25806
|
+
let result = parts.map((part) => part.result).join(delimiter);
|
|
25807
|
+
let twin = parts.map((part) => part.twin).join(delimiter);
|
|
25808
|
+
if (result.includes("{{resolve:")) ({result, twin} = await this.resolveDynamicReferencesWithLogTwin(result, twin, context));
|
|
25809
|
+
this.rememberLogTwin(context, result, twin);
|
|
25810
|
+
this.logger.debug(`Resolved Fn::Join: ${this.maskSecretsForLog(this.logTwinText(result, twin, context), context)}`);
|
|
25527
25811
|
return result;
|
|
25528
25812
|
}
|
|
25529
25813
|
/**
|
|
@@ -25666,11 +25950,19 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25666
25950
|
async resolveSub(subArgs, context) {
|
|
25667
25951
|
let template;
|
|
25668
25952
|
const variables = Object.create(null);
|
|
25953
|
+
const variableTwins = Object.create(null);
|
|
25669
25954
|
if (Array.isArray(subArgs)) {
|
|
25670
25955
|
const [templateString, variableMap] = subArgs;
|
|
25671
25956
|
template = templateString;
|
|
25672
25957
|
if (typeof variableMap !== "object" || variableMap === null) throw markNonRetryable(/* @__PURE__ */ new Error(`Fn::Sub: the second element must be a variable map, got ${variableMap === null ? "null" : typeof variableMap}`));
|
|
25673
|
-
for (const [key, val] of Object.entries(variableMap))
|
|
25958
|
+
for (const [key, val] of Object.entries(variableMap)) if (typeof val === "string") {
|
|
25959
|
+
const resolved = val.includes("{{resolve:") ? await this.resolveDynamicReferencesWithLogTwin(val, val, context) : {
|
|
25960
|
+
result: val,
|
|
25961
|
+
twin: val
|
|
25962
|
+
};
|
|
25963
|
+
variables[key] = resolved.result;
|
|
25964
|
+
variableTwins[key] = resolved.twin;
|
|
25965
|
+
} else variables[key] = await this.resolveValue(val, context);
|
|
25674
25966
|
} else template = subArgs;
|
|
25675
25967
|
const replacements = [];
|
|
25676
25968
|
const matches = template.matchAll(/\$\{(!)?([^}]*)\}/g);
|
|
@@ -25678,31 +25970,39 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25678
25970
|
const isEscaped = match[1] === "!";
|
|
25679
25971
|
const varNameStr = match[2];
|
|
25680
25972
|
if (isEscaped) {
|
|
25973
|
+
const escapedLiteral = `\${${varNameStr ?? ""}}`;
|
|
25681
25974
|
replacements.push({
|
|
25682
25975
|
match: match[0],
|
|
25683
|
-
replacement:
|
|
25976
|
+
replacement: escapedLiteral,
|
|
25977
|
+
twin: escapedLiteral
|
|
25684
25978
|
});
|
|
25685
25979
|
continue;
|
|
25686
25980
|
}
|
|
25687
25981
|
if (!varNameStr) {
|
|
25688
25982
|
replacements.push({
|
|
25689
25983
|
match: match[0],
|
|
25690
|
-
replacement: match[0]
|
|
25984
|
+
replacement: match[0],
|
|
25985
|
+
twin: match[0]
|
|
25691
25986
|
});
|
|
25692
25987
|
continue;
|
|
25693
25988
|
}
|
|
25694
25989
|
let replacement;
|
|
25695
|
-
|
|
25696
|
-
|
|
25990
|
+
let twinReplacement;
|
|
25991
|
+
if (varNameStr in variables) {
|
|
25992
|
+
replacement = String(variables[varNameStr]);
|
|
25993
|
+
twinReplacement = varNameStr in variableTwins ? variableTwins[varNameStr] : this.productLogTwin(variables[varNameStr], context);
|
|
25994
|
+
} else {
|
|
25697
25995
|
const pseudoValue = await this.resolvePseudoParameter(varNameStr, context);
|
|
25698
25996
|
if (pseudoValue !== void 0) replacement = String(pseudoValue);
|
|
25699
25997
|
else try {
|
|
25700
25998
|
const value = await this.resolveRef(varNameStr, context);
|
|
25701
25999
|
replacement = String(value);
|
|
26000
|
+
twinReplacement = this.productLogTwin(value, context);
|
|
25702
26001
|
} catch (refError) {
|
|
25703
26002
|
if (varNameStr.includes(".")) try {
|
|
25704
26003
|
const value = await this.resolveGetAtt(varNameStr, context);
|
|
25705
26004
|
replacement = String(value);
|
|
26005
|
+
twinReplacement = this.productLogTwin(value, context);
|
|
25706
26006
|
} catch (getAttError) {
|
|
25707
26007
|
if (getAttError instanceof IntrinsicResolutionRefusalError) throw getAttError;
|
|
25708
26008
|
this.rethrowStructuralSubFailure(varNameStr, getAttError, context);
|
|
@@ -25719,7 +26019,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25719
26019
|
}
|
|
25720
26020
|
replacements.push({
|
|
25721
26021
|
match: match[0],
|
|
25722
|
-
replacement
|
|
26022
|
+
replacement,
|
|
26023
|
+
twin: twinReplacement ?? replacement
|
|
25723
26024
|
});
|
|
25724
26025
|
}
|
|
25725
26026
|
let cursor = 0;
|
|
@@ -25727,8 +26028,14 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25727
26028
|
const entry = replacements[cursor++];
|
|
25728
26029
|
return entry ? entry.replacement : whole;
|
|
25729
26030
|
});
|
|
25730
|
-
|
|
25731
|
-
|
|
26031
|
+
let twinCursor = 0;
|
|
26032
|
+
let twin = template.replace(/\$\{(!)?([^}]*)\}/g, (whole) => {
|
|
26033
|
+
const entry = replacements[twinCursor++];
|
|
26034
|
+
return entry ? entry.twin : whole;
|
|
26035
|
+
});
|
|
26036
|
+
if (result.includes("{{resolve:")) ({result, twin} = await this.resolveDynamicReferencesWithLogTwin(result, twin, context));
|
|
26037
|
+
this.rememberLogTwin(context, result, twin);
|
|
26038
|
+
this.logger.debug(`Resolved Fn::Sub: ${this.maskSecretsForLog(this.logTwinText(result, twin, context), context)}`);
|
|
25732
26039
|
return result;
|
|
25733
26040
|
}
|
|
25734
26041
|
/**
|
|
@@ -25890,7 +26197,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
25890
26197
|
throw markNonRetryable(new IntrinsicResolutionRefusalError(`Fn::Split: the value to split${sourceClause} must be a string, got ${resolvedValue === null ? "null" : typeof resolvedValue}. Fn::Split accepts only a string; check the value or the intrinsic that produced it.`));
|
|
25891
26198
|
}
|
|
25892
26199
|
const result = resolvedValue.split(delimiter);
|
|
25893
|
-
this.
|
|
26200
|
+
const pieceTwins = this.splitLogTwins(resolvedValue, delimiter, result, context);
|
|
26201
|
+
this.logger.debug(`Resolved Fn::Split: split by "${delimiter}" -> ${JSON.stringify(this.maskValueLeaves(pieceTwins, context))}`);
|
|
25894
26202
|
return result;
|
|
25895
26203
|
}
|
|
25896
26204
|
/**
|
|
@@ -26651,8 +26959,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26651
26959
|
const resolvedValue = await this.resolveValue(value, context);
|
|
26652
26960
|
if (typeof resolvedValue !== "string") throw new Error(`Fn::Base64: value must resolve to a string, got ${typeof resolvedValue}`);
|
|
26653
26961
|
const result = Buffer.from(resolvedValue).toString("base64");
|
|
26654
|
-
|
|
26655
|
-
|
|
26962
|
+
const inputLogText = this.logTextOfLeaf(resolvedValue, context);
|
|
26963
|
+
if (context.recordedSecretValues && (inputLogText !== resolvedValue || this.maskSecretsForLog(resolvedValue, context) !== resolvedValue)) recordMaskOnlyValue(context.recordedSecretValues, result);
|
|
26964
|
+
this.logger.debug(`Resolved Fn::Base64: ${this.maskSecretsForLog(inputLogText, context)} -> ${this.maskSecretsForLog(inputLogText !== resolvedValue ? "***" : result, context)}`);
|
|
26656
26965
|
return result;
|
|
26657
26966
|
}
|
|
26658
26967
|
/**
|
|
@@ -26757,6 +27066,155 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26757
27066
|
return masked;
|
|
26758
27067
|
}
|
|
26759
27068
|
/**
|
|
27069
|
+
* Is `value` WHOLE a secret either bag holds (issue #3100)? Asked of a
|
|
27070
|
+
* resolution PRODUCT only — never of a template literal — so an exact match
|
|
27071
|
+
* at any length is a verdict about what was written, not a floorless needle.
|
|
27072
|
+
*/
|
|
27073
|
+
isRecordedSecretForLog(value, context) {
|
|
27074
|
+
return context?.recordedSecretValues?.has(value) === true || context?.inheritedSecrets?.has(value) === true;
|
|
27075
|
+
}
|
|
27076
|
+
/**
|
|
27077
|
+
* The text a `Resolved Fn::Join:` / `Resolved Fn::Sub:` line prints (issue
|
|
27078
|
+
* #3100): the twin through the needle mask — unless the needle mask ALSO
|
|
27079
|
+
* fires on the value itself, in which case the whole line is masked. The
|
|
27080
|
+
* twin splits the text at the spans it masked, so a 4+ character recorded
|
|
27081
|
+
* secret that overlaps one of them (or IS the whole value) is no longer a
|
|
27082
|
+
* contiguous needle in the twin, and masking the twin alone would print the
|
|
27083
|
+
* part of it outside the span. The value's own needle mask cannot be merged
|
|
27084
|
+
* with the twin's positions, so the line gives both up for `***`: never
|
|
27085
|
+
* more text than either mask alone would print. Returns the text BEFORE the
|
|
27086
|
+
* needle mask; each log line wraps it in `maskSecretsForLog` itself, so the
|
|
27087
|
+
* resolver's mask-coverage checker sees a masker at the site.
|
|
27088
|
+
*/
|
|
27089
|
+
logTwinText(result, twin, context) {
|
|
27090
|
+
return twin !== result && this.maskSecretsForLog(result, context) !== result ? "***" : twin;
|
|
27091
|
+
}
|
|
27092
|
+
/**
|
|
27093
|
+
* The log twins of `Fn::Split`'s pieces (issue #3100), each registered for
|
|
27094
|
+
* the pass so an outer `Fn::Join` over the pieces keeps the mask. A source
|
|
27095
|
+
* that is itself a recorded or inherited secret counts as a twin of `***`;
|
|
27096
|
+
* a source with neither is its pieces' own twin.
|
|
27097
|
+
*
|
|
27098
|
+
* The source's twin is split by the same delimiter. When both splits give
|
|
27099
|
+
* the same number of pieces they are paired by position; when they do not —
|
|
27100
|
+
* a secret carrying the delimiter, or a delimiter that occurs in the mask
|
|
27101
|
+
* itself — no pairing can be trusted, so every piece is masked whole. Every
|
|
27102
|
+
* masked piece is registered by VALUE, so an equal string elsewhere in the
|
|
27103
|
+
* pass is masked too: the over-masking direction `logTwinOfProduct` accepts.
|
|
27104
|
+
*/
|
|
27105
|
+
splitLogTwins(value, delimiter, pieces, context) {
|
|
27106
|
+
const bag = this.logTwinBag(context);
|
|
27107
|
+
const sourceTwin = this.isRecordedSecretForLog(value, context) ? "***" : bag ? LOG_TWINS_BY_PASS.get(bag)?.get(value) : void 0;
|
|
27108
|
+
if (sourceTwin === void 0) return pieces;
|
|
27109
|
+
const twinPieces = sourceTwin.split(delimiter);
|
|
27110
|
+
const aligned = twinPieces.length === pieces.length && !"***".includes(delimiter);
|
|
27111
|
+
return pieces.map((piece, index) => {
|
|
27112
|
+
const twin = this.logTwinText(piece, aligned ? twinPieces[index] ?? "***" : "***", context);
|
|
27113
|
+
this.rememberLogTwin(context, piece, twin);
|
|
27114
|
+
return twin;
|
|
27115
|
+
});
|
|
27116
|
+
}
|
|
27117
|
+
/**
|
|
27118
|
+
* The log twin of a resolution product as `String(value)` renders it (issue
|
|
27119
|
+
* #3100). A LIST is stringified element by element exactly as
|
|
27120
|
+
* `Array.prototype.join` does (`null` / `undefined` as the empty string,
|
|
27121
|
+
* nested lists recursively, comma-separated), so each element keeps its own
|
|
27122
|
+
* twin: `String()` over the whole list produced a string no registered twin
|
|
27123
|
+
* matched. No cycle guard: a product is JSON-sourced state or a fresh
|
|
27124
|
+
* resolution result, and neither can hold a self-referencing list.
|
|
27125
|
+
*/
|
|
27126
|
+
productLogTwin(value, context) {
|
|
27127
|
+
if (Array.isArray(value)) return value.map((element) => element === null || element === void 0 ? "" : this.productLogTwin(element, context)).join(",");
|
|
27128
|
+
const text = String(value);
|
|
27129
|
+
return this.logTwinOfProduct({
|
|
27130
|
+
result: text,
|
|
27131
|
+
twin: text
|
|
27132
|
+
}, context).twin;
|
|
27133
|
+
}
|
|
27134
|
+
/**
|
|
27135
|
+
* The pre-mask log text of a string LEAF a debug line prints (issue #3100):
|
|
27136
|
+
* the leaf treated as a resolution product — masked whole when it is a
|
|
27137
|
+
* recorded secret, otherwise the masked twin this pass registered for it —
|
|
27138
|
+
* and then `logTwinText`'s whole-line guard. The caller still wraps the
|
|
27139
|
+
* result in `maskSecretsForLog`. Shared by every caller of `maskValueLeaves`
|
|
27140
|
+
* (the `Fn::Select`, `Fn::Split`, `Fn::Equals`, `Fn::FindInMap`,
|
|
27141
|
+
* `Fn::GetAZs` and `Fn::Cidr` lines and the VPC `Ipv6CidrBlocks` line among
|
|
27142
|
+
* them) and by the `Fn::Base64` line, so a string one
|
|
27143
|
+
* write already masked by position is not printed in the clear by the next
|
|
27144
|
+
* intrinsic that logs it. `maskValueLeaves` also masks values interpolated
|
|
27145
|
+
* into THROWN messages (the `Fn::Cidr` argument refusals, for one), so those
|
|
27146
|
+
* messages take the same position mask: a short secret an earlier write put
|
|
27147
|
+
* into the value is `***` there too, the direction the mask at the throw
|
|
27148
|
+
* already takes for a whole secret.
|
|
27149
|
+
*/
|
|
27150
|
+
logTextOfLeaf(value, context) {
|
|
27151
|
+
return this.logTwinText(value, this.logTwinOfProduct({
|
|
27152
|
+
result: value,
|
|
27153
|
+
twin: value
|
|
27154
|
+
}, context).twin, context);
|
|
27155
|
+
}
|
|
27156
|
+
/** The bag a pass's log twins are keyed by (issue #3100): the recorded one, else the inherited one. */
|
|
27157
|
+
logTwinBag(context) {
|
|
27158
|
+
return context?.recordedSecretValues ?? context?.inheritedSecrets;
|
|
27159
|
+
}
|
|
27160
|
+
/**
|
|
27161
|
+
* The log twin of a RESOLUTION PRODUCT — an intrinsic part, variable or
|
|
27162
|
+
* placeholder — for issue #3100. Masked whole when its value is a recorded
|
|
27163
|
+
* secret. Otherwise a part that carries no mask of its own takes the masked
|
|
27164
|
+
* twin an earlier write of this pass registered for that exact string
|
|
27165
|
+
* (`rememberLogTwin`) — how a Join part that is itself an `Fn::Sub`, or a
|
|
27166
|
+
* `Fn::Select` over a reference-bearing string, keeps the inner mask. A part
|
|
27167
|
+
* whose OWN masked twin disagrees with the registered one (a list element
|
|
27168
|
+
* still spelling a reference) is masked whole, since the two span sets
|
|
27169
|
+
* cannot be merged; one that agrees keeps its twin.
|
|
27170
|
+
*
|
|
27171
|
+
* The registry is keyed by VALUE, so a product equal to a registered string
|
|
27172
|
+
* from another provenance takes its mask too. That over-masks a line whose
|
|
27173
|
+
* text holds a recorded secret at a position some write in this pass put
|
|
27174
|
+
* one. The registry holds masked twins only, so a lookup never unmasks.
|
|
27175
|
+
*
|
|
27176
|
+
* The whole-secret check reads the bags as they stand when the product is
|
|
27177
|
+
* placed, before the enclosing Join / Sub runs its final substitution. A
|
|
27178
|
+
* secret that substitution records is therefore not matched against an
|
|
27179
|
+
* earlier product equal to it. Such a product did not come from that secret:
|
|
27180
|
+
* a parameter holding one arrives in the inherited bag before its `Ref`
|
|
27181
|
+
* resolves, so what stays printed is a public value that coincides with it.
|
|
27182
|
+
*/
|
|
27183
|
+
logTwinOfProduct(part, context) {
|
|
27184
|
+
if (this.isRecordedSecretForLog(part.result, context)) return {
|
|
27185
|
+
result: part.result,
|
|
27186
|
+
twin: "***"
|
|
27187
|
+
};
|
|
27188
|
+
const bag = this.logTwinBag(context);
|
|
27189
|
+
const registered = bag ? LOG_TWINS_BY_PASS.get(bag)?.get(part.result) : void 0;
|
|
27190
|
+
if (registered === void 0 || registered === part.twin) return part;
|
|
27191
|
+
return {
|
|
27192
|
+
result: part.result,
|
|
27193
|
+
twin: part.twin === part.result ? registered : "***"
|
|
27194
|
+
};
|
|
27195
|
+
}
|
|
27196
|
+
/**
|
|
27197
|
+
* Register a MASKED `twin` as the log twin of `result` for this pass (issue
|
|
27198
|
+
* #3100). An unmasked twin is not registered, so a later literal that
|
|
27199
|
+
* resolves to the same string cannot replace an earlier write's mask, and
|
|
27200
|
+
* two DIFFERENT masked twins for one string register `***` for the whole
|
|
27201
|
+
* string, since their spans cannot be merged. Scoped to the pass's bag
|
|
27202
|
+
* through a `WeakMap`, like the cross-stack associations, so it dies with
|
|
27203
|
+
* the bag and another pass's strings cannot be reached.
|
|
27204
|
+
*/
|
|
27205
|
+
rememberLogTwin(context, result, twin) {
|
|
27206
|
+
if (twin === result) return;
|
|
27207
|
+
const bag = this.logTwinBag(context);
|
|
27208
|
+
if (!bag) return;
|
|
27209
|
+
let twins = LOG_TWINS_BY_PASS.get(bag);
|
|
27210
|
+
if (!twins) {
|
|
27211
|
+
twins = /* @__PURE__ */ new Map();
|
|
27212
|
+
LOG_TWINS_BY_PASS.set(bag, twins);
|
|
27213
|
+
}
|
|
27214
|
+
const existing = twins.get(result);
|
|
27215
|
+
twins.set(result, existing === void 0 || existing === twin ? twin : "***");
|
|
27216
|
+
}
|
|
27217
|
+
/**
|
|
26760
27218
|
* A copy of `value` with every string LEAF (and every object KEY) masked, for
|
|
26761
27219
|
* a caller about to ENCODE it into a message (issue
|
|
26762
27220
|
* [#2759](https://github.com/go-to-k/cdkd/issues/2759)).
|
|
@@ -26788,7 +27246,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26788
27246
|
maskValueLeaves(value, context) {
|
|
26789
27247
|
const done = /* @__PURE__ */ new Map();
|
|
26790
27248
|
const walk = (node) => {
|
|
26791
|
-
if (typeof node === "string") return this.maskSecretsForLog(node, context);
|
|
27249
|
+
if (typeof node === "string") return this.maskSecretsForLog(this.logTextOfLeaf(node, context), context);
|
|
26792
27250
|
if (node === null || typeof node !== "object") return node;
|
|
26793
27251
|
const memo = done.get(node);
|
|
26794
27252
|
if (memo !== void 0) return memo;
|
|
@@ -26800,7 +27258,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26800
27258
|
}
|
|
26801
27259
|
const out = Object.create(null);
|
|
26802
27260
|
done.set(node, out);
|
|
26803
|
-
for (const [key, child] of Object.entries(node)) out[this.maskSecretsForLog(key, context)] = walk(child);
|
|
27261
|
+
for (const [key, child] of Object.entries(node)) out[this.maskSecretsForLog(this.logTextOfLeaf(key, context), context)] = walk(child);
|
|
26804
27262
|
return out;
|
|
26805
27263
|
};
|
|
26806
27264
|
return walk(value);
|
|
@@ -26846,8 +27304,32 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26846
27304
|
return this.maskSecretsForLog(stripControlChars(this.maskSecretsForLog(value, context)), context);
|
|
26847
27305
|
}
|
|
26848
27306
|
async resolveDynamicReferences(value, context) {
|
|
27307
|
+
return (await this.resolveDynamicReferencesWithLogTwin(value, value, context)).result;
|
|
27308
|
+
}
|
|
27309
|
+
/**
|
|
27310
|
+
* {@link resolveDynamicReferences}, also returning the LOG TWIN of the result
|
|
27311
|
+
* (issue [#3100](https://github.com/go-to-k/cdkd/issues/3100), see
|
|
27312
|
+
* `LogTwin`). `logTwin` is the caller's twin of `value`, which may already
|
|
27313
|
+
* mask spans an earlier write put there.
|
|
27314
|
+
*
|
|
27315
|
+
* Every arm that writes into `result` writes into the twin too, replacing
|
|
27316
|
+
* the SAME token: a secret verdict writes {@link SECRET_MASK}, anything else
|
|
27317
|
+
* the value itself. The verdict is the one each arm already holds — the
|
|
27318
|
+
* fresh lookup's `isSecret`, the cache entry's own `secret` (never the
|
|
27319
|
+
* process-wide store, for the #1933 reason the cache-hit arm states), and
|
|
27320
|
+
* for a region-pinned sibling the twin the sibling itself returns. An arm
|
|
27321
|
+
* that `continue`s without writing leaves the token in both.
|
|
27322
|
+
*
|
|
27323
|
+
* A token whose text an earlier write masked (`{{resolve:${Pw}}}` over a
|
|
27324
|
+
* secret `Pw`) is not found in the twin, so the twin keeps the masked token
|
|
27325
|
+
* where the value holds its resolution. What the twin cannot carry is a
|
|
27326
|
+
* NEEDLE match that straddles a masked span, which is why the log lines go
|
|
27327
|
+
* through `logTwinText` rather than masking the twin alone.
|
|
27328
|
+
*/
|
|
27329
|
+
async resolveDynamicReferencesWithLogTwin(value, logTwin, context) {
|
|
26849
27330
|
const pattern = /\{\{resolve:([^}]+)\}\}/g;
|
|
26850
27331
|
let result = value;
|
|
27332
|
+
let twin = logTwin;
|
|
26851
27333
|
let match;
|
|
26852
27334
|
const matches = [];
|
|
26853
27335
|
while ((match = pattern.exec(value)) !== null) matches.push({
|
|
@@ -26861,8 +27343,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26861
27343
|
const regionVerdict = classifyReplaySecretRegion(fullMatch, this.explicitRegion ?? this.resolverRegion, context?.producerRegions);
|
|
26862
27344
|
if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${this.maskSecretsForLog(fullMatch, context)}: it names '${this.maskSecretsForLog(regionVerdict.secretName, context)}' without a region, and this stack reads from ${regionVerdict.foreignProducerRegions.join(", ")} as well as its own region. cdkd cannot tell which one must answer, and resolving against the wrong one yields a different secret. Spell the reference as a full ARN to say which region owns it.`));
|
|
26863
27345
|
if (regionVerdict.kind === "named-region") {
|
|
26864
|
-
const foreign = await this.resolverForProducerRegion(regionVerdict.region).
|
|
26865
|
-
result = result.replace(fullMatch, () => foreign);
|
|
27346
|
+
const foreign = await this.resolverForProducerRegion(regionVerdict.region).resolveDynamicReferencesWithLogTwin(fullMatch, fullMatch, withoutProducerRegions(context));
|
|
27347
|
+
result = result.replace(fullMatch, () => foreign.result);
|
|
27348
|
+
twin = twin.replace(fullMatch, () => foreign.twin);
|
|
26866
27349
|
continue;
|
|
26867
27350
|
}
|
|
26868
27351
|
const cached = this.cachedDynamicReferences.get(fullMatch);
|
|
@@ -26872,6 +27355,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26872
27355
|
if (context?.recordedSecretValues) recordResolvedPair(context.recordedSecretValues, fullMatch, cached.value);
|
|
26873
27356
|
}
|
|
26874
27357
|
result = result.replace(fullMatch, () => cached.value);
|
|
27358
|
+
twin = twin.replace(fullMatch, () => cached.secret && cached.value ? "***" : cached.value);
|
|
26875
27359
|
continue;
|
|
26876
27360
|
}
|
|
26877
27361
|
const parts = inner.split(":");
|
|
@@ -26921,8 +27405,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
26921
27405
|
if (service === "secretsmanager" || service === "ssm-secure") this.pinSecretVerdict(fullMatch, true);
|
|
26922
27406
|
}
|
|
26923
27407
|
result = result.replace(fullMatch, () => resolved);
|
|
27408
|
+
twin = twin.replace(fullMatch, () => isSecret && resolved ? "***" : resolved);
|
|
26924
27409
|
}
|
|
26925
|
-
|
|
27410
|
+
if (context) this.rememberLogTwin(context, result, twin);
|
|
27411
|
+
return {
|
|
27412
|
+
result,
|
|
27413
|
+
twin
|
|
27414
|
+
};
|
|
26926
27415
|
}
|
|
26927
27416
|
/**
|
|
26928
27417
|
* Resolve a Secrets Manager dynamic reference
|
|
@@ -28486,7 +28975,7 @@ var CloudControlProvider = class {
|
|
|
28486
28975
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
28487
28976
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
28488
28977
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
28489
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
28978
|
+
const { ASGProvider } = await import("./asg-provider-RLnpBIKj.js").then((n) => n.n);
|
|
28490
28979
|
const asgProvider = new ASGProvider();
|
|
28491
28980
|
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
28492
28981
|
}
|
|
@@ -33684,12 +34173,20 @@ const WARM_THROUGHPUT_MEMBERS = ["ReadUnitsPerSecond", "WriteUnitsPerSecond"];
|
|
|
33684
34173
|
*
|
|
33685
34174
|
* The accepted STRING set is `Number()`'s, which is WIDER than a decimal
|
|
33686
34175
|
* integer: `'0x1e'`, `'0o36'`, `'1e3'`, `'30.5'` and `' 30 '` all coerce.
|
|
33687
|
-
*
|
|
33688
|
-
*
|
|
33689
|
-
*
|
|
33690
|
-
*
|
|
33691
|
-
*
|
|
33692
|
-
*
|
|
34176
|
+
* CloudFormation accepts only the LAST of those for an `Integer`-typed
|
|
34177
|
+
* property — measured on `AWS::Logs::LogGroup.RetentionInDays`, issue
|
|
34178
|
+
* [#2698](https://github.com/go-to-k/cdkd/issues/2698) — and
|
|
34179
|
+
* {@link toCfnInteger} is the reader that matches that measurement. It matters
|
|
34180
|
+
* at the CALLERS that FORWARD the result to AWS rather than merely compare it:
|
|
34181
|
+
* the log-group provider switched; the DynamoDB capacity / throughput
|
|
34182
|
+
* forwarders (`coerceWarmThroughput` below, and the `GlobalTable` provider's
|
|
34183
|
+
* `ProvisionedThroughput` / `OnDemandThroughput` readers) still read through
|
|
34184
|
+
* THIS helper, because the measurement covers one resource handler and
|
|
34185
|
+
* DynamoDB's has not been A/B'd — issue
|
|
34186
|
+
* [#3135](https://github.com/go-to-k/cdkd/issues/3135) holds that pass. A
|
|
34187
|
+
* GUARD caller (`stateful-types.ts`'s `has-retention`, the DynamoDB
|
|
34188
|
+
* already-matches / decrease tests) is safe on the wider set: over-acceptance
|
|
34189
|
+
* there can only produce MORE refusals or skip fewer calls.
|
|
33693
34190
|
*
|
|
33694
34191
|
* EXPORTED, and not because warm throughput needs it exported. This exact rule
|
|
33695
34192
|
* was hand-written three times — here, as `dynamodb-table-provider.ts`'s
|
|
@@ -33710,6 +34207,59 @@ function toFiniteNumber(value) {
|
|
|
33710
34207
|
}
|
|
33711
34208
|
}
|
|
33712
34209
|
/**
|
|
34210
|
+
* A CloudFormation-borne `Integer` property, read the way CloudFormation reads
|
|
34211
|
+
* it, or `undefined` when CloudFormation would REJECT the value.
|
|
34212
|
+
*
|
|
34213
|
+
* The sibling of {@link toFiniteNumber} for the callers that FORWARD the number
|
|
34214
|
+
* to AWS. That helper is `Number()`, which accepts hex, octal, binary,
|
|
34215
|
+
* exponent and decimal-point spellings; CloudFormation does not, and a
|
|
34216
|
+
* provider forwarding `Number('0x1e')` sends `30` for a template CloudFormation
|
|
34217
|
+
* would have refused outright. Measured live on
|
|
34218
|
+
* `AWS::Logs::LogGroup.RetentionInDays` (us-east-1, 2026-09-14, issue
|
|
34219
|
+
* [#2698](https://github.com/go-to-k/cdkd/issues/2698); a one-resource stack
|
|
34220
|
+
* updated per spelling, live value read back with `logs describe-log-groups`):
|
|
34221
|
+
*
|
|
34222
|
+
* ```
|
|
34223
|
+
* template spelling CloudFormation live retention after
|
|
34224
|
+
* 30 (JSON number) accepted 30
|
|
34225
|
+
* "60" accepted 60
|
|
34226
|
+
* "+30" accepted 30
|
|
34227
|
+
* " 30 " (padded) accepted 30
|
|
34228
|
+
* " " (whitespace only) accepted, treated as ABSENT none (policy REMOVED)
|
|
34229
|
+
* "" (empty string) accepted, treated as ABSENT none (policy REMOVED)
|
|
34230
|
+
* property absent accepted none (policy REMOVED)
|
|
34231
|
+
* "0x1e" REJECTED (handler) unchanged
|
|
34232
|
+
* "1e3" REJECTED (handler) unchanged
|
|
34233
|
+
* "30.5" REJECTED (handler) unchanged
|
|
34234
|
+
* "30.0" REJECTED (handler) unchanged
|
|
34235
|
+
* "abc" REJECTED (handler) unchanged
|
|
34236
|
+
* true / false REJECTED (handler) unchanged
|
|
34237
|
+
* 0 / "0" REJECTED (handler: enum) unchanged
|
|
34238
|
+
* null REJECTED at update-stack unchanged
|
|
34239
|
+
* ```
|
|
34240
|
+
*
|
|
34241
|
+
* So the accepted string grammar is `optional sign + decimal digits`, with
|
|
34242
|
+
* surrounding whitespace TRIMMED — `/^\s*[+-]?\d+\s*$/`, then `Number()`. The
|
|
34243
|
+
* digits grammar is `config-shape.ts`'s {@link coerceCfnInteger}, reused rather
|
|
34244
|
+
* than respelled so the two cannot drift on it; the ONE difference is the
|
|
34245
|
+
* trim, and it is a measured difference, not a relaxation: that helper's own
|
|
34246
|
+
* measurement (a NESTED `GenerateSecretString.PasswordLength`, 2026-09-13)
|
|
34247
|
+
* saw `" 12 "` REJECTED where this one saw `" 30 "` accepted. Per-handler
|
|
34248
|
+
* behaviour varies on padding, so each helper carries its own measurement and
|
|
34249
|
+
* a caller picks by the property it forwards.
|
|
34250
|
+
*
|
|
34251
|
+
* What this helper does NOT decide: the empty / whitespace-only strings above
|
|
34252
|
+
* are CloudFormation's spelling of "property absent", which is a statement
|
|
34253
|
+
* about the PROPERTY, not about the number — they answer `undefined` here, and
|
|
34254
|
+
* the caller decides whether `undefined` means "absent" or "unusable" from the
|
|
34255
|
+
* raw value (`logs-loggroup-provider.ts`'s `assertUsableRetention` is the
|
|
34256
|
+
* reference). `0` / `'0'` parse to `0` here; whether zero is usable is again the
|
|
34257
|
+
* property's question (the log-group handler rejects it by enum).
|
|
34258
|
+
*/
|
|
34259
|
+
function toCfnInteger(value) {
|
|
34260
|
+
return coerceCfnInteger(typeof value === "string" ? value.trim() : value);
|
|
34261
|
+
}
|
|
34262
|
+
/**
|
|
33713
34263
|
* Coerce a CFn `WarmThroughput` block to the numeric shape the SDK's `Long`
|
|
33714
34264
|
* fields accept, PER MEMBER.
|
|
33715
34265
|
*
|
|
@@ -36008,6 +36558,45 @@ function effectiveProvisionedBy(record, fallbackProvisionedBy) {
|
|
|
36008
36558
|
return record?.provisionedBy ?? fallbackProvisionedBy;
|
|
36009
36559
|
}
|
|
36010
36560
|
/**
|
|
36561
|
+
* One spelling of "this value came from a rollback-journal record, and is
|
|
36562
|
+
* about to be interpolated into a message a terminal will render" (issue
|
|
36563
|
+
* #3092). The journal is a sibling of `state.json` in the same bucket,
|
|
36564
|
+
* writable by anyone with `s3:PutObject` and validated no more than an
|
|
36565
|
+
* unchecked cast; cdkd's output is line-oriented, so an injected newline
|
|
36566
|
+
* invents a line that reads like a real one. This executor runs under the
|
|
36567
|
+
* standalone `cdkd rollback` AND under the deploy engine's automatic
|
|
36568
|
+
* rollback, so its lines print on every failed deploy.
|
|
36569
|
+
*
|
|
36570
|
+
* `displayIdent`: the ASCII allowlist with `UNRENDERABLE` for a value that
|
|
36571
|
+
* sanitizes to nothing, a length cap, and a visible boundary (a JSON-quoted
|
|
36572
|
+
* rendering) for a value that is not a plain identifier -- the all-ASCII
|
|
36573
|
+
* `X (AWS::RDS::DBInstance) -- already reverted` the allowlist lets through.
|
|
36574
|
+
* A logical id, a CFn resource type and a change type all have known
|
|
36575
|
+
* charsets. Call it for those; `grep safe(` answers the scope.
|
|
36576
|
+
*
|
|
36577
|
+
* NOT for a value that is USED rather than shown -- the ids passed to a
|
|
36578
|
+
* provider call, the keys into `stateResources`, the `msg` a classifier reads.
|
|
36579
|
+
* NOT for the `reason` / `survivorReason` strings handed to `ctx.recordEvent`:
|
|
36580
|
+
* those are PERSISTED into `deployments/*.jsonl` raw and `cdkd events`
|
|
36581
|
+
* sanitizes them on the way out, so sanitizing here would put a display
|
|
36582
|
+
* transform on a stored value and double it at render (the go-to-k/cdkd#2170
|
|
36583
|
+
* direction). NOT for free-form error text either: an SDK message legitimately
|
|
36584
|
+
* carries non-ASCII, so a site rendering one calls `displaySafe()` directly and
|
|
36585
|
+
* takes the DENYLIST, as `formatError` does for a `cause`.
|
|
36586
|
+
*/
|
|
36587
|
+
function safe(value) {
|
|
36588
|
+
return displayIdent(value);
|
|
36589
|
+
}
|
|
36590
|
+
/**
|
|
36591
|
+
* The one shape of `op.logicalId` this executor will print INSIDE a command it
|
|
36592
|
+
* invites the user to paste (`cdkd rollback --orphan <id>`): CloudFormation's
|
|
36593
|
+
* own logical-id charset and length. Stricter than "`safe()` is the identity
|
|
36594
|
+
* on it" on purpose -- `~user` and `=x` are plain identifiers the shell
|
|
36595
|
+
* expands before cdkd sees them (issue #3092 review). Not a display rule: a
|
|
36596
|
+
* legitimate id the executor merely SHOWS still goes through `safe()`.
|
|
36597
|
+
*/
|
|
36598
|
+
const PASTEABLE_LOGICAL_ID = /^[A-Za-z0-9]{1,255}$/;
|
|
36599
|
+
/**
|
|
36011
36600
|
* `UpdateReplacePolicy: Snapshot` on a rollback's delete-of-the-NEW-resource
|
|
36012
36601
|
* (issue #1354): honor it where it costs nothing — an atomic-final-snapshot
|
|
36013
36602
|
* type on the SDK route gets a generated identifier threaded into the delete
|
|
@@ -36104,7 +36693,7 @@ function rollbackRetainsNewResource(record) {
|
|
|
36104
36693
|
*/
|
|
36105
36694
|
function retainedSurvivorMessages(logicalId, resourceType, survivorPhysicalId, stateClause) {
|
|
36106
36695
|
return {
|
|
36107
|
-
warn: ` ⚠ ${logicalId} (${resourceType}) has UpdateReplacePolicy: Retain — the replacement's new physical resource (${survivorPhysicalId}) is RETAINED by this rollback and is no longer tracked by cdkd: it keeps running and incurring cost, and \`cdkd destroy\` will not remove it. Delete it yourself once you no longer need it. ${stateClause}`,
|
|
36696
|
+
warn: ` ⚠ ${safe(logicalId)} (${safe(resourceType)}) has UpdateReplacePolicy: Retain — the replacement's new physical resource (${displaySafe(survivorPhysicalId)}) is RETAINED by this rollback and is no longer tracked by cdkd: it keeps running and incurring cost, and \`cdkd destroy\` will not remove it. Delete it yourself once you no longer need it. ${displaySafe(stateClause)}`,
|
|
36108
36697
|
reason: `UpdateReplacePolicy: Retain kept the replacement's new ${resourceType} (${survivorPhysicalId}); it is live, still billing, and no longer tracked by cdkd. ${stateClause}`
|
|
36109
36698
|
};
|
|
36110
36699
|
}
|
|
@@ -36655,7 +37244,7 @@ function redactRollbackRecord(record, secrets, journaledProps) {
|
|
|
36655
37244
|
}
|
|
36656
37245
|
async function updateWithRollbackRetry(provider, args, logicalId, logger, isInterrupted, secrets) {
|
|
36657
37246
|
if (provider.disableOuterRetry) return await withCurrentResourceSecrets(secrets, () => provider.update(...args));
|
|
36658
|
-
return await withRetry(() => withCurrentResourceSecrets(secrets, () => provider.update(...args)), logicalId, {
|
|
37247
|
+
return await withRetry(() => withCurrentResourceSecrets(secrets, () => provider.update(...args)), safe(logicalId), {
|
|
36659
37248
|
logger: maskingRetryLogger(logger, secrets),
|
|
36660
37249
|
...isInterrupted && {
|
|
36661
37250
|
isInterrupted,
|
|
@@ -36747,13 +37336,14 @@ async function updateWithRollbackRetry(provider, args, logicalId, logger, isInte
|
|
|
36747
37336
|
async function createWithRollbackRetry(provider, create, logicalId, logger, isInterrupted, secrets, outer) {
|
|
36748
37337
|
if (provider.disableOuterRetry) return await create();
|
|
36749
37338
|
const maskedLogger = maskingRetryLogger(logger, secrets);
|
|
36750
|
-
|
|
37339
|
+
const shownId = safe(logicalId);
|
|
37340
|
+
return await withRetry(() => withRetry(create, shownId, {
|
|
36751
37341
|
logger: maskedLogger,
|
|
36752
37342
|
...isInterrupted && {
|
|
36753
37343
|
isInterrupted,
|
|
36754
37344
|
onInterrupted: () => /* @__PURE__ */ new Error("Rollback interrupted while retrying the replay re-create")
|
|
36755
37345
|
}
|
|
36756
|
-
}),
|
|
37346
|
+
}), shownId, {
|
|
36757
37347
|
...RECREATE_RETRY_SCHEDULE,
|
|
36758
37348
|
logger: maskedLogger,
|
|
36759
37349
|
...isInterrupted && {
|
|
@@ -36836,18 +37426,18 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36836
37426
|
try {
|
|
36837
37427
|
switch (action) {
|
|
36838
37428
|
case "unrecoverable-delete":
|
|
36839
|
-
logger.warn(` Rollback: Cannot restore deleted resource ${op.logicalId} (${op.resourceType}) — resource has already been deleted`);
|
|
37429
|
+
logger.warn(` Rollback: Cannot restore deleted resource ${safe(op.logicalId)} (${safe(op.resourceType)}) — resource has already been deleted`);
|
|
36840
37430
|
result.warnings++;
|
|
36841
37431
|
return;
|
|
36842
37432
|
case "skip-already-done":
|
|
36843
|
-
logger.debug(` Rollback: ${op.logicalId} already reverted, skipping`);
|
|
37433
|
+
logger.debug(` Rollback: ${safe(op.logicalId)} already reverted, skipping`);
|
|
36844
37434
|
return;
|
|
36845
37435
|
case "skip-mismatch":
|
|
36846
|
-
logger.warn(` Rollback: Skipping ${op.logicalId} — its physical id changed since the failed deploy (replaced by a later attempt); manual attention may be required`);
|
|
37436
|
+
logger.warn(` Rollback: Skipping ${safe(op.logicalId)} — its physical id changed since the failed deploy (replaced by a later attempt); manual attention may be required`);
|
|
36847
37437
|
result.warnings++;
|
|
36848
37438
|
return;
|
|
36849
37439
|
case "skip-absent":
|
|
36850
|
-
logger.warn(` Rollback: Cannot restore ${op.logicalId} — resource no longer in state, skipping`);
|
|
37440
|
+
logger.warn(` Rollback: Cannot restore ${safe(op.logicalId)} — resource no longer in state, skipping`);
|
|
36851
37441
|
result.warnings++;
|
|
36852
37442
|
return;
|
|
36853
37443
|
case "orphan-flag":
|
|
@@ -36856,7 +37446,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36856
37446
|
const orphanFlagProvisionedBy = effectiveProvisionedBy(record, op.provisionedBy);
|
|
36857
37447
|
createRollbackRoute = orphanFlagProvisionedBy;
|
|
36858
37448
|
delete stateResources[op.logicalId];
|
|
36859
|
-
logger.info(` Rollback: Orphaning created resource ${op.logicalId} (--orphan)`);
|
|
37449
|
+
logger.info(` Rollback: Orphaning created resource ${safe(op.logicalId)} (--orphan)`);
|
|
36860
37450
|
await afterOp?.(op.logicalId);
|
|
36861
37451
|
ctx.recordEvent?.({
|
|
36862
37452
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -36870,7 +37460,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36870
37460
|
reason: `--orphan left ${op.logicalId} (${op.resourceType}) in AWS as ${record.physicalId} and dropped it from state; it is live, still billing, and no longer tracked by cdkd.`
|
|
36871
37461
|
}
|
|
36872
37462
|
});
|
|
36873
|
-
} else logger.info(` Rollback: Leaving ${op.logicalId} at its new state (--orphan)`);
|
|
37463
|
+
} else logger.info(` Rollback: Leaving ${safe(op.logicalId)} at its new state (--orphan)`);
|
|
36874
37464
|
return;
|
|
36875
37465
|
case "orphan-retain": {
|
|
36876
37466
|
const record = stateResources[op.logicalId];
|
|
@@ -36886,7 +37476,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36886
37476
|
onOrphan?.(orphaned);
|
|
36887
37477
|
}
|
|
36888
37478
|
delete stateResources[op.logicalId];
|
|
36889
|
-
logger.info(` Rollback: Leaving ${op.logicalId} (${op.resourceType}) in AWS (DeletionPolicy: Retain) — removed from state`);
|
|
37479
|
+
logger.info(` Rollback: Leaving ${safe(op.logicalId)} (${safe(op.resourceType)}) in AWS (DeletionPolicy: Retain) — removed from state`);
|
|
36890
37480
|
await afterOp?.(op.logicalId);
|
|
36891
37481
|
ctx.recordEvent?.({
|
|
36892
37482
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -36905,7 +37495,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36905
37495
|
case "delete":
|
|
36906
37496
|
case "delete-with-final-snapshot": {
|
|
36907
37497
|
if (!op.physicalId) {
|
|
36908
|
-
logger.warn(` Rollback: Cannot delete ${op.logicalId} — no physical ID recorded`);
|
|
37498
|
+
logger.warn(` Rollback: Cannot delete ${safe(op.logicalId)} — no physical ID recorded`);
|
|
36909
37499
|
result.warnings++;
|
|
36910
37500
|
return;
|
|
36911
37501
|
}
|
|
@@ -36915,7 +37505,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36915
37505
|
const takeFinalSnapshot = snapshotPolicy && ctx.skipFinalSnapshot !== true;
|
|
36916
37506
|
let finalSnapshotIdentifier;
|
|
36917
37507
|
if (takeFinalSnapshot) finalSnapshotIdentifier = await prepareCreateRollbackFinalSnapshot(op, deleteProvisionedBy, ctx);
|
|
36918
|
-
logger.info(` Rollback: Deleting created resource ${op.logicalId} (${op.resourceType})` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
|
|
37508
|
+
logger.info(` Rollback: Deleting created resource ${safe(op.logicalId)} (${safe(op.resourceType)})` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
|
|
36919
37509
|
const { provider } = ctx.providerRegistry.getProviderFor({
|
|
36920
37510
|
resourceType: op.resourceType,
|
|
36921
37511
|
provisionedBy: deleteProvisionedBy
|
|
@@ -36925,7 +37515,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36925
37515
|
...finalSnapshotIdentifier !== void 0 && { finalSnapshotIdentifier }
|
|
36926
37516
|
}), op.logicalId, op.physicalId, "while rolling back its CREATE");
|
|
36927
37517
|
delete stateResources[op.logicalId];
|
|
36928
|
-
logger.info(` Rollback: ${op.logicalId} deleted successfully`);
|
|
37518
|
+
logger.info(` Rollback: ${safe(op.logicalId)} deleted successfully`);
|
|
36929
37519
|
await afterOp?.(op.logicalId);
|
|
36930
37520
|
ctx.recordEvent?.({
|
|
36931
37521
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -36940,7 +37530,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36940
37530
|
case "reverse-replacement-readopt": {
|
|
36941
37531
|
const current = stateResources[op.logicalId];
|
|
36942
37532
|
const prev = op.previousState;
|
|
36943
|
-
logger.info(` Rollback: Reversing replacement of ${op.logicalId} (${op.resourceType}) — deleting the new resource and re-adopting the retained old one (${prev.physicalId})`);
|
|
37533
|
+
logger.info(` Rollback: Reversing replacement of ${safe(op.logicalId)} (${safe(op.resourceType)}) — deleting the new resource and re-adopting the retained old one (${displaySafe(prev.physicalId)})`);
|
|
36944
37534
|
/**
|
|
36945
37535
|
* Set when this arm ORPHANS the replacement's new copy. Read at the
|
|
36946
37536
|
* `ROLLBACK_RESOURCE_SUCCEEDED` event below, which is the only channel
|
|
@@ -36974,7 +37564,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36974
37564
|
}), op.logicalId, current.physicalId, "while reversing its replacement (re-adopting the retained old resource)");
|
|
36975
37565
|
}
|
|
36976
37566
|
stateResources[op.logicalId] = prev;
|
|
36977
|
-
logger.info(` Rollback: ${op.logicalId} restored to the retained old resource`);
|
|
37567
|
+
logger.info(` Rollback: ${safe(op.logicalId)} restored to the retained old resource`);
|
|
36978
37568
|
await afterOp?.(op.logicalId);
|
|
36979
37569
|
const survivorProvisionedBy = current.provisionedBy;
|
|
36980
37570
|
ctx.recordEvent?.({
|
|
@@ -36998,8 +37588,8 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
36998
37588
|
const resolvedPrevProps = await resolveReplayProps(prev.properties, resolver, secrets, ctx, op.logicalId) ?? {};
|
|
36999
37589
|
refuseMaskedReplayBaseline(resolvedPrevProps, op.logicalId);
|
|
37000
37590
|
recordNestedStackParameterExpressions(secrets, op.resourceType, resolvedPrevProps, prev.properties, STATE_DERIVED_RULES);
|
|
37001
|
-
logger.info(` Rollback: Reversing replacement of ${op.logicalId} (${op.resourceType}) — re-creating the old resource and deleting the new one`);
|
|
37002
|
-
if (STATEFUL_TYPES.has(op.resourceType)) logger.warn(` ⚠ ${op.logicalId} (${op.resourceType}) is a stateful type — the old physical resource's data was destroyed by the replacement and is NOT recovered by this rollback; the re-created resource starts empty.`);
|
|
37591
|
+
logger.info(` Rollback: Reversing replacement of ${safe(op.logicalId)} (${safe(op.resourceType)}) — re-creating the old resource and deleting the new one`);
|
|
37592
|
+
if (STATEFUL_TYPES.has(op.resourceType)) logger.warn(` ⚠ ${safe(op.logicalId)} (${safe(op.resourceType)}) is a stateful type — the old physical resource's data was destroyed by the replacement and is NOT recovered by this rollback; the re-created resource starts empty.`);
|
|
37003
37593
|
const { provider: createProvider } = ctx.providerRegistry.getProviderFor({
|
|
37004
37594
|
resourceType: op.resourceType,
|
|
37005
37595
|
provisionedBy: prev.provisionedBy
|
|
@@ -37018,8 +37608,8 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
37018
37608
|
} catch (createError) {
|
|
37019
37609
|
const msg = createError instanceof Error ? createError.message : String(createError);
|
|
37020
37610
|
if (!isNameCollisionError(msg)) throw createError;
|
|
37021
|
-
if (rollbackRetainsNewResource(current)) throw markNonRetryable(new CdkdError(maskSecretsInText(`Cannot reverse the replacement of ${op.logicalId} (${op.resourceType}): the re-create of the old resource (${prev.physicalId}) collided with the name still held by the new one (${current.physicalId}), and UpdateReplacePolicy: Retain pins that new resource in place, so cdkd will not delete it to free the name. Delete the new resource yourself, or remove UpdateReplacePolicy: Retain, then re-run \`cdkd rollback\` — the journal is kept, so the revert resumes from here. To leave THIS resource alone and let the rest of the rollback proceed, re-run with
|
|
37022
|
-
logger.info(` Rollback: re-create collided with the new resource's name — deleting the new resource (${current.physicalId}) first...`);
|
|
37611
|
+
if (rollbackRetainsNewResource(current)) throw markNonRetryable(new CdkdError(maskSecretsInText(`Cannot reverse the replacement of ${safe(op.logicalId)} (${safe(op.resourceType)}): the re-create of the old resource (${safe(prev.physicalId)}) collided with the name still held by the new one (${safe(current.physicalId)}), and UpdateReplacePolicy: Retain pins that new resource in place, so cdkd will not delete it to free the name. Delete the new resource yourself, or remove UpdateReplacePolicy: Retain, then re-run \`cdkd rollback\` — the journal is kept, so the revert resumes from here. To leave THIS resource alone and let the rest of the rollback proceed, re-run with ` + (typeof op.logicalId === "string" && PASTEABLE_LOGICAL_ID.test(op.logicalId) ? `\`cdkd rollback --orphan ${op.logicalId}\`: one op failure stops the ` : "`cdkd rollback --orphan <id>` (the id is withheld: it is not a plain CloudFormation logical id, so a pasted command could be reshaped by the shell or name a different resource -- read it from `cdkd events`): one op failure stops the ") + `segment loop, so a single pinned resource otherwise halts every OLDER segment too. Underlying collision: ${displaySafe(msg)}`, secrets), "NAMED_REPLACEMENT_COLLISION", maskSecretsInError(createError instanceof Error ? createError : void 0, secrets)));
|
|
37612
|
+
logger.info(` Rollback: re-create collided with the new resource's name — deleting the new resource (${displaySafe(current.physicalId)}) first...`);
|
|
37023
37613
|
{
|
|
37024
37614
|
const finalSnapshotIdentifier = rollbackFinalSnapshotId(op.resourceType, current, op.provisionedBy);
|
|
37025
37615
|
throwIfDeleteSkipped(await resolveNewDeleteProvider().delete(op.logicalId, current.physicalId, op.resourceType, current.properties, {
|
|
@@ -37036,12 +37626,12 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
37036
37626
|
interruptedMessage: "Rollback interrupted while waiting for the old name to release"
|
|
37037
37627
|
});
|
|
37038
37628
|
} catch (recreateError) {
|
|
37039
|
-
throw new Error(maskSecretsInText(`Failed to re-create the old ${op.logicalId} after the new resource (${current.physicalId}) was already deleted: ${recreateError instanceof Error ? recreateError.message : String(recreateError)}. The resource is now absent — fix forward with 'cdkd deploy'.`, secrets), { cause: maskSecretsInError(recreateError instanceof Error ? recreateError : void 0, secrets) });
|
|
37629
|
+
throw new Error(maskSecretsInText(`Failed to re-create the old ${safe(op.logicalId)} after the new resource (${current.physicalId}) was already deleted: ${displaySafe(recreateError instanceof Error ? recreateError.message : String(recreateError))}. The resource is now absent — fix forward with 'cdkd deploy'.`, secrets), { cause: maskSecretsInError(recreateError instanceof Error ? recreateError : void 0, secrets) });
|
|
37040
37630
|
}
|
|
37041
37631
|
}
|
|
37042
37632
|
const adoptedLiveNewResource = !deletedNewFirst && createResult.physicalId === current.physicalId;
|
|
37043
37633
|
if (adoptedLiveNewResource) {
|
|
37044
|
-
logger.warn(` ⚠ ${op.logicalId} (${op.resourceType}): the re-create returned the LIVE new resource (${current.physicalId}) instead of re-creating the old one — its Create API is name-idempotent and the new resource still holds the same user-supplied name. Skipping the delete-new step (it would delete that very resource). The old resource's ORIGINAL properties may NOT have been re-applied; state now records the pre-replacement properties, so run 'cdkd drift ${stackName}' to inspect and 'cdkd deploy' to reconcile, or rename the resource to make the replacement reversible.`);
|
|
37634
|
+
logger.warn(` ⚠ ${safe(op.logicalId)} (${safe(op.resourceType)}): the re-create returned the LIVE new resource (${displaySafe(current.physicalId)}) instead of re-creating the old one — its Create API is name-idempotent and the new resource still holds the same user-supplied name. Skipping the delete-new step (it would delete that very resource). The old resource's ORIGINAL properties may NOT have been re-applied; state now records the pre-replacement properties, so run 'cdkd drift ${stackName}' to inspect and 'cdkd deploy' to reconcile, or rename the resource to make the replacement reversible.`);
|
|
37045
37635
|
result.warnings++;
|
|
37046
37636
|
}
|
|
37047
37637
|
const { observedProperties: _staleObserved, ...prevRecord } = prev;
|
|
@@ -37065,11 +37655,11 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
37065
37655
|
...finalSnapshotIdentifier !== void 0 && { finalSnapshotIdentifier }
|
|
37066
37656
|
}), op.logicalId, current.physicalId, "while deleting the new resource after re-creating the old one");
|
|
37067
37657
|
} catch (deleteError) {
|
|
37068
|
-
logger.warn(maskSecretsInText(` Rollback: old ${op.logicalId} re-created, but deleting the new resource (${current.physicalId}) failed: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}. Delete it manually — it is no longer tracked in state.`, secrets));
|
|
37658
|
+
logger.warn(maskSecretsInText(` Rollback: old ${safe(op.logicalId)} re-created, but deleting the new resource (${displaySafe(current.physicalId)}) failed: ${displaySafe(deleteError instanceof Error ? deleteError.message : String(deleteError))}. Delete it manually — it is no longer tracked in state.`, secrets));
|
|
37069
37659
|
survivorReason = `The replacement's new ${op.resourceType} (${current.physicalId}) could not be deleted after the old resource was re-created: ${deleteError instanceof Error ? deleteError.message : String(deleteError)}. It is live, still billing, and no longer tracked by cdkd — delete it yourself.`;
|
|
37070
37660
|
result.warnings++;
|
|
37071
37661
|
}
|
|
37072
|
-
logger.info(adoptedLiveNewResource ? ` Rollback: ${op.logicalId} adopted the live resource (${createResult.physicalId}) — replacement NOT fully reversed (name-idempotent Create API)` : ` Rollback: ${op.logicalId} replacement reversed (old resource re-created as ${createResult.physicalId})`);
|
|
37662
|
+
logger.info(adoptedLiveNewResource ? ` Rollback: ${safe(op.logicalId)} adopted the live resource (${createResult.physicalId}) — replacement NOT fully reversed (name-idempotent Create API)` : ` Rollback: ${safe(op.logicalId)} replacement reversed (old resource re-created as ${createResult.physicalId})`);
|
|
37073
37663
|
const survivorProvisionedBy = current.provisionedBy;
|
|
37074
37664
|
ctx.recordEvent?.({
|
|
37075
37665
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -37088,18 +37678,18 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
37088
37678
|
}
|
|
37089
37679
|
case "revert": {
|
|
37090
37680
|
if (!op.previousState) {
|
|
37091
|
-
logger.warn(` Rollback: Cannot restore ${op.logicalId} — no previous state available`);
|
|
37681
|
+
logger.warn(` Rollback: Cannot restore ${safe(op.logicalId)} — no previous state available`);
|
|
37092
37682
|
result.warnings++;
|
|
37093
37683
|
return;
|
|
37094
37684
|
}
|
|
37095
37685
|
const previousState = op.previousState;
|
|
37096
37686
|
const current = stateResources[op.logicalId];
|
|
37097
37687
|
if (!current) {
|
|
37098
|
-
logger.warn(` Rollback: Cannot restore ${op.logicalId} — resource not found in current state`);
|
|
37688
|
+
logger.warn(` Rollback: Cannot restore ${safe(op.logicalId)} — resource not found in current state`);
|
|
37099
37689
|
result.warnings++;
|
|
37100
37690
|
return;
|
|
37101
37691
|
}
|
|
37102
|
-
logger.info(` Rollback: Restoring ${op.logicalId} (${op.resourceType}) to previous state`);
|
|
37692
|
+
logger.info(` Rollback: Restoring ${safe(op.logicalId)} (${safe(op.resourceType)}) to previous state`);
|
|
37103
37693
|
const { provider } = ctx.providerRegistry.getProviderFor({
|
|
37104
37694
|
resourceType: op.resourceType,
|
|
37105
37695
|
provisionedBy: op.provisionedBy
|
|
@@ -37121,8 +37711,8 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
37121
37711
|
], op.logicalId, logger, isInterrupted, secrets);
|
|
37122
37712
|
stateResources[op.logicalId] = redactRollbackRecord(recordAfterRollbackUpdate(previousState, revertResult), secrets, previousState.properties);
|
|
37123
37713
|
const rollbackPartial = updatePartialReason(revertResult);
|
|
37124
|
-
if (rollbackPartial !== void 0) logger.warn(maskSecretsInText(` Rollback: ${op.logicalId} restored, ${updatePartialMessage(rollbackPartial)}`, secrets));
|
|
37125
|
-
else logger.info(` Rollback: ${op.logicalId} restored successfully`);
|
|
37714
|
+
if (rollbackPartial !== void 0) logger.warn(maskSecretsInText(` Rollback: ${safe(op.logicalId)} restored, ${updatePartialMessage(rollbackPartial)}`, secrets));
|
|
37715
|
+
else logger.info(` Rollback: ${safe(op.logicalId)} restored successfully`);
|
|
37126
37716
|
await afterOp?.(op.logicalId);
|
|
37127
37717
|
ctx.recordEvent?.({
|
|
37128
37718
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -37137,7 +37727,7 @@ async function replaySingle(op, stateResources, stackName, ctx, resolver, orphan
|
|
|
37137
37727
|
}
|
|
37138
37728
|
}
|
|
37139
37729
|
} catch (rollbackError) {
|
|
37140
|
-
logger.warn(maskSecretsInText(` Rollback failed for ${op.logicalId} (${op.changeType}): ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`, secrets));
|
|
37730
|
+
logger.warn(maskSecretsInText(` Rollback failed for ${safe(op.logicalId)} (${safe(op.changeType)}): ${displaySafe(rollbackError instanceof Error ? rollbackError.message : String(rollbackError))}`, secrets));
|
|
37141
37731
|
logger.warn(" Continuing with remaining rollback operations...");
|
|
37142
37732
|
result.failures++;
|
|
37143
37733
|
const failedRoute = createRollbackRoute ?? op.provisionedBy;
|
|
@@ -37199,14 +37789,14 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
|
|
|
37199
37789
|
try {
|
|
37200
37790
|
switch (action) {
|
|
37201
37791
|
case "skip-failed-noop":
|
|
37202
|
-
logger.info(` Rollback: failed ${op.changeType} of ${op.logicalId} (${op.resourceType}) left nothing to revert, skipping`);
|
|
37792
|
+
logger.info(` Rollback: failed ${safe(op.changeType)} of ${safe(op.logicalId)} (${safe(op.resourceType)}) left nothing to revert, skipping`);
|
|
37203
37793
|
break;
|
|
37204
37794
|
case "skip-failed-unknown":
|
|
37205
|
-
logger.warn(` Rollback: failed CREATE of ${op.logicalId} (${op.resourceType}) recorded no physical id — if it was partially created in AWS, delete it manually`);
|
|
37795
|
+
logger.warn(` Rollback: failed CREATE of ${safe(op.logicalId)} (${safe(op.resourceType)}) recorded no physical id — if it was partially created in AWS, delete it manually`);
|
|
37206
37796
|
result.warnings++;
|
|
37207
37797
|
break;
|
|
37208
37798
|
case "skip-failed-absent":
|
|
37209
|
-
logger.warn(` Rollback: cannot revert failed UPDATE of ${op.logicalId} — no previous state available, skipping`);
|
|
37799
|
+
logger.warn(` Rollback: cannot revert failed UPDATE of ${safe(op.logicalId)} — no previous state available, skipping`);
|
|
37210
37800
|
result.warnings++;
|
|
37211
37801
|
break;
|
|
37212
37802
|
case "orphan-failed-create-retain": {
|
|
@@ -37223,7 +37813,7 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
|
|
|
37223
37813
|
options.onOrphan?.(orphaned);
|
|
37224
37814
|
}
|
|
37225
37815
|
delete stateResources[op.logicalId];
|
|
37226
|
-
logger.info(` Rollback: leaving partially-created ${op.logicalId} (${op.resourceType}) in AWS (DeletionPolicy: Retain) — removed from state`);
|
|
37816
|
+
logger.info(` Rollback: leaving partially-created ${safe(op.logicalId)} (${safe(op.resourceType)}) in AWS (DeletionPolicy: Retain) — removed from state`);
|
|
37227
37817
|
await options.afterOp?.(op.logicalId);
|
|
37228
37818
|
ctx.recordEvent?.({
|
|
37229
37819
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -37243,7 +37833,7 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
|
|
|
37243
37833
|
const takeFinalSnapshot = snapshotPolicy && ctx.skipFinalSnapshot !== true;
|
|
37244
37834
|
let finalSnapshotIdentifier;
|
|
37245
37835
|
if (takeFinalSnapshot) finalSnapshotIdentifier = await prepareCreateRollbackFinalSnapshot(op, deleteProvisionedBy, ctx);
|
|
37246
|
-
logger.info(` Rollback: deleting partially-created ${op.logicalId} (${op.resourceType}) (--revert-failed)` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
|
|
37836
|
+
logger.info(` Rollback: deleting partially-created ${safe(op.logicalId)} (${safe(op.resourceType)}) (--revert-failed)` + (takeFinalSnapshot ? " — DeletionPolicy: Snapshot" : "") + (snapshotPolicy && !takeFinalSnapshot ? " — DeletionPolicy: Snapshot NOT taken (--skip-final-snapshot)" : ""));
|
|
37247
37837
|
const { provider } = ctx.providerRegistry.getProviderFor({
|
|
37248
37838
|
resourceType: op.resourceType,
|
|
37249
37839
|
provisionedBy: deleteProvisionedBy
|
|
@@ -37267,7 +37857,7 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
|
|
|
37267
37857
|
case "revert-failed-update": {
|
|
37268
37858
|
const current = stateResources[op.logicalId];
|
|
37269
37859
|
const prev = op.previousState;
|
|
37270
|
-
logger.info(` Rollback: force-reverting failed UPDATE of ${op.logicalId} (${op.resourceType}) to its pre-deploy properties (--revert-failed; remote state is unknown)`);
|
|
37860
|
+
logger.info(` Rollback: force-reverting failed UPDATE of ${safe(op.logicalId)} (${safe(op.resourceType)}) to its pre-deploy properties (--revert-failed; remote state is unknown)`);
|
|
37271
37861
|
const { provider } = ctx.providerRegistry.getProviderFor({
|
|
37272
37862
|
resourceType: op.resourceType,
|
|
37273
37863
|
provisionedBy: op.provisionedBy ?? current.provisionedBy
|
|
@@ -37289,8 +37879,8 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
|
|
|
37289
37879
|
], op.logicalId, logger, options.isInterrupted, secrets);
|
|
37290
37880
|
stateResources[op.logicalId] = redactRollbackRecord(recordAfterRollbackUpdate(prev, revertFailedResult), secrets, prev.properties);
|
|
37291
37881
|
const revertFailedPartial = updatePartialReason(revertFailedResult);
|
|
37292
|
-
if (revertFailedPartial !== void 0) logger.warn(maskSecretsInText(` Rollback: ${op.logicalId} reverted, ${updatePartialMessage(revertFailedPartial)}`, secrets));
|
|
37293
|
-
else logger.info(` Rollback: ${op.logicalId} reverted successfully`);
|
|
37882
|
+
if (revertFailedPartial !== void 0) logger.warn(maskSecretsInText(` Rollback: ${safe(op.logicalId)} reverted, ${updatePartialMessage(revertFailedPartial)}`, secrets));
|
|
37883
|
+
else logger.info(` Rollback: ${safe(op.logicalId)} reverted successfully`);
|
|
37294
37884
|
await options.afterOp?.(op.logicalId);
|
|
37295
37885
|
ctx.recordEvent?.({
|
|
37296
37886
|
eventType: "ROLLBACK_RESOURCE_SUCCEEDED",
|
|
@@ -37305,7 +37895,7 @@ async function replayFailedOperations(failedOps, stateResources, stackName, ctx,
|
|
|
37305
37895
|
}
|
|
37306
37896
|
}
|
|
37307
37897
|
} catch (revertError) {
|
|
37308
|
-
logger.warn(maskSecretsInText(` Rollback failed for failed-op ${op.logicalId} (${op.changeType}): ${revertError instanceof Error ? revertError.message : String(revertError)}`, secrets));
|
|
37898
|
+
logger.warn(maskSecretsInText(` Rollback failed for failed-op ${safe(op.logicalId)} (${safe(op.changeType)}): ${displaySafe(revertError instanceof Error ? revertError.message : String(revertError))}`, secrets));
|
|
37309
37899
|
result.failures++;
|
|
37310
37900
|
pending.add(op);
|
|
37311
37901
|
const failedRoute = createRollbackRoute ?? op.provisionedBy;
|
|
@@ -41041,5 +41631,5 @@ var DeployEngine = class DeployEngine {
|
|
|
41041
41631
|
};
|
|
41042
41632
|
|
|
41043
41633
|
//#endregion
|
|
41044
|
-
export {
|
|
41045
|
-
//# sourceMappingURL=deploy-engine-
|
|
41634
|
+
export { secretSafeKeyDisplay as $, parseBootstrapMarker as $n, ConfigError as $r, DiffCalculator as $t, planOrphanAdoption as A, formatLockExpiry as An, resolveUseCdkBootstrapAssets as Ar, WAFv2WebACLProvider as At, formatResourceLine as B, AssetPublisher as Bn, PARTITION_TABLE as Br, replayWarn as Bt, createPreDeleteFinalSnapshot as C, isThrottlingError as Ci, scrubResourceRecord as Cn, getLegacyStateBucketName as Cr, cfnRefValueFromPhysicalId as Ct, makeCanonicalizePropertiesFn as D, retryClassificationText as Di, buildForceUnlockCommand as Dn, resolveSkipPrefix as Dr, parameterTypeMayLoseSecretIdentity as Dt, unsupportedFinalSnapshotError as E, markRedactedCause as Ei, rebuildClientForBucketRegion as En, resolveCaptureObservedState as Er, isUnboundTemplateParameter as Et, WARM_THROUGHPUT_MEMBERS as F, importableOutputKeys as Fn, MIGRATE_TMP_PREFIX as Fr, coerceCfnInteger as Ft, red as G, loadPublishableAssetManifest as Gn, clearBucketRegionCache as Gr, producerRegionsFromState as Gt, cyan as H, WorkGraph as Hn, derivePartitionAndUrlSuffix as Hr, requireConfigObject as Ht, coerceWarmThroughput as I, importableOutputs as In, findLargeInlineResources as Ir, configBooleanRefusal as It, collectPublishedOutputNames as J, BOOTSTRAP_MARKER_PREFIX as Jn, getAwsClients as Jr, s3BucketDomainName as Jt, yellow as K, rewriteTemplateAssetReferences as Kn, resolveBucketRegion as Kr, withSharedDrainBudget as Kt, isWarmThroughputDecrease as L, orphansAfterRollback as Ln, uploadCfnTemplate as Lr, configIntegerRefusal as Lt, isStatefulRecreateTargetForReplace as M, CUSTOM_RESOURCE_RESPONSE_PREFIX as Mn, warnDeprecatedNoPrefixCliFlag as Mr, resolveExplicitPhysicalId as Mt, isStatefulRecreateTargetSync as N, DEFAULT_STATE_PREFIX as Nn, CFN_TEMPLATE_BODY_LIMIT as Nr, assertRegionMatch as Nt, extractDeploymentEventError as O, __exportAll as Oi, buildLockContentionMessage as On, resolveStateBucketWithDefault as Or, refStateLookupFromResource as Ot, renderStatefulReason as P, exportNamesCarriedFrom as Pn, CFN_TEMPLATE_URL_LIMIT as Pr, coerceCfnBoolean as Pt, secretBearingStateKeyWarning as Q, isCrossRegionRedirect as Qn, CdkdError as Qr, applyRoleArnIfSet as Qt, toCfnInteger as R, orphansCarriedFrom as Rn, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Rr, configStringRefusal as Rt, ccRoutedFinalSnapshotError as S, isRetryableTransientError as Si, redactSecretsForState as Sn, getDefaultStateBucketName as Sr, carriesDynamicReference as St, refusesFinalSnapshot as T, markNonRetryable as Ti, S3StateBackend as Tn, resolveAutoAssetStorage as Tr, getAccountInfo as Tt, gray as U, buildAssetRedirectMap as Un, AssemblyReader as Ur, requireConfigString as Ut, bold as V, stringifyValue as Vn, canonicalizeRegion as Vr, requireConfigArray as Vt, green as W, createAssetRedirectResolver as Wn, processStackMessages as Wr, classifyReplaySecretRegion as Wt, isExportAliasCollision as X, ensureAssetStorage as Xn, setAwsClients as Xr, s3BucketRegionalDomainName as Xt, exportAliasCollisionScrubWarning as Y, assertAssetBucketRegion as Yn, resetAwsClients as Yr, s3BucketDualStackDomainName as Yt, secretBearing as Z, getBootstrapMarkerKey as Zn, AssetError as Zr, s3BucketWebsiteUrl as Zt, isSecretBearingReferenceString as _, formatError as _i, markSameGenerationBag as _n, stripControlChars as _r, deleteIndeterminateGuards as _t, DeploymentEventsStore as a, LocalInvokeBuildError as ai, DagBuilder as an, buildDockerImage as ar, wouldReturnToSdkProvider as at, PRE_DELETE_SNAPSHOT_TYPES as b, withErrorHandling as bi, recordMaskOnlyValue as bn, Synthesizer as br, isTerminationProtectionPropagationError as bt, replayFailedOperations as c, NestedStackChildDirectDestroyError as ci, STATE_SOURCED_CROSS_GENERATION_RULES as cn, describeDockerFailure as cr, maskerOrIdentity as ct, updatePartialReason as d, ResourceTimeoutError as di, carriesSecretMask as dn, getDockerCmd as dr, interruptWatchListenerCount as dt, CrossAccountSecretRefusalError as ei, INTRINSIC_KEYS as en, readBootstrapMarkerBody as er, getCurrentResourceSecrets as et, withResourceDeadline as f, ResourceUpdateNotSupportedError as fi, createSecretMasker as fn, partitionSensitiveEnv as fr, isInterruptedWaitError as ft, bagHoldsSecretExpression as g, SynthesisError as gi, isSingleDynamicReferenceToken as gn, escapeRegExp$1 as gr, UNSPECIFIED_SKIP_REASON as gt, computeImplicitDeleteEdges as h, StateError as hi, identityKeyFor as hn, runDockerStreaming as hr, slowCcOperationTimeoutMs as ht, DeploymentEventsReader as i, IntrinsicResolutionRefusalError as ii, withRetry as in, describeAwsFailure as ir, ProviderRegistry as it, MULTI_REGION_RECREATE_BLOCKED_TYPES as j, shellQuote as jn, stateBucketExistenceConfirmed as jr, normalizeAwsTagsToCfn as jt, makeSiblingClaimReader as k, forceQuitRecoveryClause as kn, resolveStateBucketWithDefaultAndSource as kr, isSettledInstanceState as kt, replayRollback as l, PartialFailureError as li, STATE_SOURCED_READBACK_RULES as ln, dockerSpawnEnvWithSensitive as lr, beginCommandInterruptScope as lt, IMPLICIT_DELETE_DEPENDENCIES as m, StackTerminationProtectionError as mi, errorCauseChain as mn, runDockerForeground as mr, CloudControlProvider as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, DeployCancelledError as ni, findSilentDropProperties as nn, validateContainerRepoName as nr, collectInlinePolicyNamesManagedBySiblings as nt, planFailedOps as o, LocalStartServiceError as oi, TemplateParser as on, describeDockerCapturedOutput as or, createMaskedRetryLogger as ot, maskingRetryLogger as p, StackHasActiveImportsError as pi, dynamicReferenceTokens as pn, redactDockerArgvValues as pr, startInterruptWatch as pt, collectDeclaredOutputNames as q, AssetModeResolver as qn, AwsClients as qr, s3BucketArn as qt, DeployEngine as r, DynamicReferenceRegionAmbiguousError as ri, describeTypeWithThrottleRetry as rn, buildDenyExternalAccessPolicy as rr, clearOnUpdateRemoval as rt, planRollback as s, LockError as si, STATE_SOURCED_BASELINE_RULES as sn, describeDockerExecFailure as sr, maskDeep as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, DependencyError as ti, findActionableSilentDrops as tn, validateAssetBucketName as tr, IAMRoleProvider as tt, updatePartialMessage as u, ProvisioningError as ui, TEMPLATE_SOURCED_RULES as un, formatDockerLoginError as ur, endCommandInterruptScope as ut, bindingSkippedOutputs as v, isCdkdError as vi, maskSecretsInError as vn, AssetManifestLoader as vr, deleteSkipReason as vt, isFinalSnapshotError as w, isTransientServerError as wi, LockManager as wn, resolveApp as wr, coerceParameterTypedValue as wt, buildFinalSnapshotIdentifier as x, isMarkedNonRetryable as xi, recoverMaskedOutput as xn, synthesisStatusMessage as xr, IntrinsicFunctionResolver as xt, ATOMIC_FINAL_SNAPSHOT_TYPES as y, normalizeAwsError as yi, maskSecretsInText as yn, getDockerImageBySourceHash as yr, disableInstanceApiTermination as yt, toFiniteNumber as z, shouldRetainResource as zn, expectedOwnerParam as zr, readConfigString as zt };
|
|
41635
|
+
//# sourceMappingURL=deploy-engine-0Wg4MwP2.js.map
|