@go-to-k/cdkd 0.291.17 → 0.291.19
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-CHM7_WdJ.js → asg-provider-Dpki2-Xd.js} +6 -6
- package/dist/asg-provider-Dpki2-Xd.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-xxVOQPPr.js → deploy-engine-OgrMdBRR.js} +799 -211
- package/dist/deploy-engine-OgrMdBRR.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{logger-GASr9bAF.js → logger-Bt0RGDfb.js} +12 -2
- package/dist/logger-Bt0RGDfb.js.map +1 -0
- package/dist/{program-hXXls0hg.js → program-L-XPPVLA.js} +646 -397
- package/dist/{program-hXXls0hg.js.map → program-L-XPPVLA.js.map} +1 -1
- package/dist/{version-DMRkEtU2.js → version-2QIPw29e.js} +2 -2
- package/dist/{version-DMRkEtU2.js.map → version-2QIPw29e.js.map} +1 -1
- package/package.json +2 -2
- package/dist/asg-provider-CHM7_WdJ.js.map +0 -1
- package/dist/deploy-engine-xxVOQPPr.js.map +0 -1
- package/dist/logger-GASr9bAF.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as displayAwsMessage, D as
|
|
1
|
+
import { C as displayAwsMessage, D as isPasteableIdent, E as displayStackName, O as truncateCodePoints, S as UNRENDERABLE, T as displaySafe, 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, w as displayIdent, x as STACK_REF_MAX_CODE_POINTS, y as withoutGeneratedFallbackName } from "./logger-Bt0RGDfb.js";
|
|
2
2
|
import { a as setAssumedRoleCredentials, c as currentStackAwsScope, i as getPreAssumeEnvCredentials, l as runInStackAwsScope, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, s as ambientRegion, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-jISU4PHo.js";
|
|
3
|
-
import { t as getCdkdVersion } from "./version-
|
|
3
|
+
import { t as getCdkdVersion } from "./version-2QIPw29e.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";
|
|
@@ -35,10 +35,9 @@ import { GetHostedZoneCommand, ListHostedZonesByNameCommand, Route53Client } fro
|
|
|
35
35
|
import { DescribeListenersCommand, DescribeLoadBalancersCommand, ElasticLoadBalancingV2Client } from "@aws-sdk/client-elastic-load-balancing-v2";
|
|
36
36
|
import { KMSClient, ListAliasesCommand } from "@aws-sdk/client-kms";
|
|
37
37
|
import { readFile } from "fs/promises";
|
|
38
|
-
import { isAbsolute as isAbsolute$1,
|
|
38
|
+
import { isAbsolute as isAbsolute$1, resolve as resolve$1 } from "path";
|
|
39
39
|
import { CreateRepositoryCommand, DescribeImagesCommand as DescribeImagesCommand$1, DescribeRepositoriesCommand, ECRClient, GetAuthorizationTokenCommand, PutImageTagMutabilityCommand } from "@aws-sdk/client-ecr";
|
|
40
40
|
import { inspect } from "node:util";
|
|
41
|
-
import { realpathSync as realpathSync$1 } from "fs";
|
|
42
41
|
import { hostname } from "os";
|
|
43
42
|
import graphlib from "graphlib";
|
|
44
43
|
import { DescribeDBClustersCommand, DescribeDBInstancesCommand, RDSClient } from "@aws-sdk/client-rds";
|
|
@@ -3365,7 +3364,9 @@ function assemblyPathEscape(base, bound, candidate) {
|
|
|
3365
3364
|
* Modifier Letters block (U+02BA reads as `"`, U+02BC as `'`) plus the ones
|
|
3366
3365
|
* outside it (U+0374, U+0559, U+07F4-U+07F5, U+A78B-U+A78C, and the halfwidth
|
|
3367
3366
|
* sound marks U+FF9E-U+FF9F). Not all of `\p{Lm}`: U+30FC is in it, and it is
|
|
3368
|
-
* an ordinary character of a Japanese directory name.
|
|
3367
|
+
* an ordinary character of a Japanese directory name. `classify` tests
|
|
3368
|
+
* {@link DEFAULT_IGNORABLE} first, so that carve-out is a backstop here, kept
|
|
3369
|
+
* so the class matches cdk-local's `displayUntrustedValue`.
|
|
3369
3370
|
*/
|
|
3370
3371
|
const VISIBLE_LETTER = new RegExp(String.raw`^(?![\p{Default_Ignorable_Code_Point}\u02b0-\u02ff\u0374\u0559\u07f4\u07f5\ua78b\ua78c\uff9e\uff9f])[\p{L}\p{N}]$`, "u");
|
|
3371
3372
|
/**
|
|
@@ -3375,6 +3376,14 @@ const VISIBLE_LETTER = new RegExp(String.raw`^(?![\p{Default_Ignorable_Code_Poin
|
|
|
3375
3376
|
*/
|
|
3376
3377
|
const COMBINING_MARK = /^\p{M}$/u;
|
|
3377
3378
|
/**
|
|
3379
|
+
* A default-ignorable code point, which draws as NOTHING. Tested before the
|
|
3380
|
+
* mark rule, because some are combining marks (U+034F, U+17B4, U+180B, the
|
|
3381
|
+
* variation selectors U+FE00-U+FE0F and U+E0100-U+E01EF): after a letter they
|
|
3382
|
+
* would otherwise pass as bare, and `/home/me/.ss\u034fh` would print exactly
|
|
3383
|
+
* like `.ssh` while naming a different path (go-to-k/cdkd#3656).
|
|
3384
|
+
*/
|
|
3385
|
+
const DEFAULT_IGNORABLE = /^\p{Default_Ignorable_Code_Point}$/u;
|
|
3386
|
+
/**
|
|
3378
3387
|
* The ASCII a bare path may carry besides letters and digits. Everything else —
|
|
3379
3388
|
* any whitespace, any quote, any other symbol — takes the boundary, which
|
|
3380
3389
|
* costs a legitimate path nothing but a pair of quotes.
|
|
@@ -3394,6 +3403,10 @@ const BARE_PUNCTUATION = /^[/\\._~+@:=-]$/;
|
|
|
3394
3403
|
function classify(chars) {
|
|
3395
3404
|
let afterLetter = false;
|
|
3396
3405
|
return chars.map((ch) => {
|
|
3406
|
+
if (DEFAULT_IGNORABLE.test(ch)) {
|
|
3407
|
+
afterLetter = false;
|
|
3408
|
+
return "escaped";
|
|
3409
|
+
}
|
|
3397
3410
|
if (COMBINING_MARK.test(ch)) return afterLetter ? "bare" : "escaped";
|
|
3398
3411
|
afterLetter = VISIBLE_LETTER.test(ch);
|
|
3399
3412
|
if (afterLetter || BARE_PUNCTUATION.test(ch)) return "bare";
|
|
@@ -3944,7 +3957,7 @@ var AssemblyReader = class {
|
|
|
3944
3957
|
getStack(assemblyDir, manifest, stackName) {
|
|
3945
3958
|
const { stacks, failedStages } = this.readAssembly(assemblyDir, manifest);
|
|
3946
3959
|
const stack = stacks.find((s) => s.stackName === stackName);
|
|
3947
|
-
if (!stack) throw new SynthesisError(`Stack
|
|
3960
|
+
if (!stack) throw new SynthesisError(`Stack ${displayStackName(stackName)} not found in assembly. ` + (stacks.length > 0 ? `Available: ${stacks.map((s) => displayIdent(s.stackName, { maxCodePoints: STACK_REF_MAX_CODE_POINTS })).join(", ")}` : "The assembly has no stacks") + failedStageNote([stackName], failedStages));
|
|
3948
3961
|
return stack;
|
|
3949
3962
|
}
|
|
3950
3963
|
/**
|
|
@@ -3964,7 +3977,7 @@ var AssemblyReader = class {
|
|
|
3964
3977
|
const props = artifact.properties;
|
|
3965
3978
|
if (props?.file) {
|
|
3966
3979
|
const resolved = resolveAssemblyPath(assemblyDir, props.file);
|
|
3967
|
-
if (!resolved.contained) throw new SynthesisError(`Asset manifest artifact
|
|
3980
|
+
if (!resolved.contained) throw new SynthesisError(`Asset manifest artifact ${displayStackName(artifactId)} has file=${displayAssemblyPath(props.file)} which ${renderAssemblyPathEscape(resolved, assemblyDir)}`);
|
|
3968
3981
|
map.set(artifactId, resolved.path);
|
|
3969
3982
|
}
|
|
3970
3983
|
}
|
|
@@ -3977,16 +3990,16 @@ var AssemblyReader = class {
|
|
|
3977
3990
|
const props = artifact.properties;
|
|
3978
3991
|
const stackName = props?.stackName || artifactId;
|
|
3979
3992
|
const templateFile = props?.templateFile;
|
|
3980
|
-
if (!templateFile) throw new SynthesisError(`Stack
|
|
3993
|
+
if (!templateFile) throw new SynthesisError(`Stack ${displayStackName(stackName)} has no templateFile property`);
|
|
3981
3994
|
const resolvedTemplate = resolveAssemblyPath(assemblyDir, templateFile);
|
|
3982
|
-
if (!resolvedTemplate.contained) throw new SynthesisError(`Stack
|
|
3995
|
+
if (!resolvedTemplate.contained) throw new SynthesisError(`Stack ${displayStackName(stackName)} has templateFile=${displayAssemblyPath(templateFile)} which ${renderAssemblyPathEscape(resolvedTemplate, assemblyDir)}`);
|
|
3983
3996
|
const templatePath = resolvedTemplate.path;
|
|
3984
3997
|
let template;
|
|
3985
3998
|
try {
|
|
3986
3999
|
const content = readFileSync(templatePath, "utf-8");
|
|
3987
4000
|
template = JSON.parse(content);
|
|
3988
4001
|
} catch (error) {
|
|
3989
|
-
throw new SynthesisError(`Failed to read template for stack
|
|
4002
|
+
throw new SynthesisError(`Failed to read template for stack ${displayStackName(stackName)}: ${displaySafe(error instanceof Error ? error.message : String(error))}`, error instanceof Error ? error : void 0);
|
|
3990
4003
|
}
|
|
3991
4004
|
this.logger.debug(`Stack: ${displaySafe(stackName)}, Resources: ${Object.keys(template.Resources ?? {}).length}`);
|
|
3992
4005
|
let assetManifestPath;
|
|
@@ -4005,7 +4018,7 @@ var AssemblyReader = class {
|
|
|
4005
4018
|
if (depName !== stackName) dependencyNames.push(depName);
|
|
4006
4019
|
}
|
|
4007
4020
|
}
|
|
4008
|
-
if (dependencyNames.length > 0) this.logger.debug(`Stack
|
|
4021
|
+
if (dependencyNames.length > 0) this.logger.debug(`Stack ${displayStackName(stackName)} depends on: [${dependencyNames.map((n) => displaySafe(n)).join(", ")}]`);
|
|
4009
4022
|
let env;
|
|
4010
4023
|
if (artifact.environment) env = parseEnvironment(artifact.environment);
|
|
4011
4024
|
const nestedTemplates = nullPrototypeRecord();
|
|
@@ -4013,9 +4026,9 @@ var AssemblyReader = class {
|
|
|
4013
4026
|
if (resource?.Type !== "AWS::CloudFormation::Stack") continue;
|
|
4014
4027
|
const assetPath = resource.Metadata?.["aws:asset:path"];
|
|
4015
4028
|
if (typeof assetPath !== "string" || assetPath.length === 0) continue;
|
|
4016
|
-
if (isAbsolute(assetPath) || /^[a-zA-Z]:[\\/]/.test(assetPath) || assetPath.startsWith("\\\\")) throw new SynthesisError(`Stack
|
|
4029
|
+
if (isAbsolute(assetPath) || /^[a-zA-Z]:[\\/]/.test(assetPath) || assetPath.startsWith("\\\\")) throw new SynthesisError(`Stack ${displayStackName(stackName)} nested-stack ${displayIdent(logicalId)} has Metadata['aws:asset:path']=${displayAssemblyPath(assetPath)} which is absolute. CDK emits relative asset paths for nested templates; an absolute path indicates the synth output was hand-modified or generated by a non-CDK toolchain. Refusing to load.`);
|
|
4017
4030
|
const resolvedNested = resolveAssemblyPath(assemblyDir, assetPath);
|
|
4018
|
-
if (!resolvedNested.contained) throw new SynthesisError(`Stack
|
|
4031
|
+
if (!resolvedNested.contained) throw new SynthesisError(`Stack ${displayStackName(stackName)} nested-stack ${displayIdent(logicalId)} has Metadata['aws:asset:path']=${displayAssemblyPath(assetPath)} which ${renderAssemblyPathEscape(resolvedNested, assemblyDir)}`);
|
|
4019
4032
|
nestedTemplates[logicalId] = resolvedNested.path;
|
|
4020
4033
|
}
|
|
4021
4034
|
return {
|
|
@@ -4107,6 +4120,109 @@ var ContextStore = class {
|
|
|
4107
4120
|
}
|
|
4108
4121
|
};
|
|
4109
4122
|
|
|
4123
|
+
//#endregion
|
|
4124
|
+
//#region src/utils/ambient-client-defaults.ts
|
|
4125
|
+
/**
|
|
4126
|
+
* Client config for an SDK client built OUTSIDE `AwsClients` (issue
|
|
4127
|
+
* [#3588](https://github.com/go-to-k/cdkd/issues/3588)).
|
|
4128
|
+
*
|
|
4129
|
+
* `awsClientDefaults()` alone carries the ambient ENVIRONMENT — `AWS_PROFILE`,
|
|
4130
|
+
* a published `--role-arn` role, the proxy handler, a stack scope's region — but
|
|
4131
|
+
* not an explicit `AwsClientConfig.credentials` object, which has no
|
|
4132
|
+
* environment path at all. A LIBRARY caller that installs
|
|
4133
|
+
* `new AwsClients({ credentials })` (`AwsClients` / `setAwsClients` are public
|
|
4134
|
+
* exports) therefore had every client a provider, context provider,
|
|
4135
|
+
* asset publisher or the cross-account STS hop built for itself signing with
|
|
4136
|
+
* the default credential chain: a different identity from the one it
|
|
4137
|
+
* configured. {@link ambientClientDefaults} closes that for every site at once
|
|
4138
|
+
* by reading the ACTIVE clients' {@link AwsClients.credentialConfig}.
|
|
4139
|
+
*
|
|
4140
|
+
* BOUND: a site that caches its client (every SDK provider's lazy
|
|
4141
|
+
* `getClient()`) captures the identity active at its FIRST call. cdkd builds a
|
|
4142
|
+
* provider registry per stack inside that stack's scope, so this is the stack's
|
|
4143
|
+
* identity; a library caller that reuses one registry across `setAwsClients`
|
|
4144
|
+
* switches keeps the first identity's clients.
|
|
4145
|
+
*
|
|
4146
|
+
* SPREAD IT FIRST, exactly where `awsClientDefaults()` was spread:
|
|
4147
|
+
*
|
|
4148
|
+
* `new GlueClient({ ...ambientClientDefaults(), ...(region && { region }) })`
|
|
4149
|
+
*
|
|
4150
|
+
* The site's own keys still win, so a site that names its own `region` or its
|
|
4151
|
+
* own `credentials` keeps them. `scripts/check-aws-client-defaults.ts` accepts
|
|
4152
|
+
* this helper as the defaults spread (it calls `awsClientDefaults` afresh per
|
|
4153
|
+
* call, so each client still gets its own routing agent), and
|
|
4154
|
+
* `tests/unit/utils/ambient-client-defaults-fence.test.ts` refuses a new
|
|
4155
|
+
* `awsClientDefaults()`-only construction under `src/**`.
|
|
4156
|
+
*
|
|
4157
|
+
* Its own module rather than a member of `aws-clients.ts` so that a test which
|
|
4158
|
+
* `vi.mock`s `aws-clients.js` with a `getAwsClients` double still reaches this
|
|
4159
|
+
* code and degrades, instead of losing the export. It is deliberately OUTSIDE
|
|
4160
|
+
* the literal-`.ts` closure `scripts/audit-provider-coverage.ts` resolves
|
|
4161
|
+
* (nothing in that closure imports it), and neither module it imports imports
|
|
4162
|
+
* it back, so there is no cycle.
|
|
4163
|
+
*/
|
|
4164
|
+
/**
|
|
4165
|
+
* The ACTIVE clients' credential configuration: the stack scope's
|
|
4166
|
+
* `AwsClients` inside `runWithStackAwsClients`, else the process-global one.
|
|
4167
|
+
*
|
|
4168
|
+
* `{}` when those clients carry none (every CLI run passes no explicit
|
|
4169
|
+
* `credentials`, and `--profile` alone yields `{ profile }`), and also for a
|
|
4170
|
+
* test double that has no `credentialConfig` getter — degrading to the plain
|
|
4171
|
+
* `awsClientDefaults()` answer rather than throwing.
|
|
4172
|
+
*
|
|
4173
|
+
* Read through `getAwsClients()`, which creates an unconfigured global on first
|
|
4174
|
+
* use when nothing installed one. That is side-effect free here: its service
|
|
4175
|
+
* clients are lazy, no production call passes `getAwsClients(config)` (so no
|
|
4176
|
+
* later configuration is shadowed), and `setAwsClients` replaces it.
|
|
4177
|
+
*/
|
|
4178
|
+
function ambientCredentialConfig() {
|
|
4179
|
+
return getAwsClients()?.credentialConfig ?? {};
|
|
4180
|
+
}
|
|
4181
|
+
/**
|
|
4182
|
+
* `awsClientDefaults(...)` plus `credentialConfig`, in `AwsClients.clientOptions`'
|
|
4183
|
+
* spread order: the defaults FIRST, so an explicit `credentials` outranks a
|
|
4184
|
+
* published `--role-arn` role, then `profile`, then `credentials`.
|
|
4185
|
+
*
|
|
4186
|
+
* Takes the configuration as an argument for the callers that must key a cache
|
|
4187
|
+
* on the SAME reading they build from ({@link credentialFingerprint}); every
|
|
4188
|
+
* other site calls {@link ambientClientDefaults}.
|
|
4189
|
+
*/
|
|
4190
|
+
function clientDefaultsFor(credentialConfig) {
|
|
4191
|
+
return {
|
|
4192
|
+
...awsClientDefaults({ profile: credentialConfig.profile }),
|
|
4193
|
+
...credentialConfig.profile && { profile: credentialConfig.profile },
|
|
4194
|
+
...credentialConfig.credentials && { credentials: { ...credentialConfig.credentials } }
|
|
4195
|
+
};
|
|
4196
|
+
}
|
|
4197
|
+
/**
|
|
4198
|
+
* The config every SDK client built outside `AwsClients` spreads first: the
|
|
4199
|
+
* proxy / role / scope-region defaults plus the ACTIVE clients' profile and
|
|
4200
|
+
* explicit credentials.
|
|
4201
|
+
*/
|
|
4202
|
+
function ambientClientDefaults() {
|
|
4203
|
+
return clientDefaultsFor(ambientCredentialConfig());
|
|
4204
|
+
}
|
|
4205
|
+
/**
|
|
4206
|
+
* A cache-key component naming WHICH identity a credential configuration
|
|
4207
|
+
* selects, for a cache that holds a client (or credentials) built from it.
|
|
4208
|
+
*
|
|
4209
|
+
* `profile` plus the explicit credentials' ACCESS KEY ID — never the secret
|
|
4210
|
+
* key or the session token. The access key id is an identifier rather than a
|
|
4211
|
+
* secret (`expected-bucket-owner.ts` already keys its account cache on it), and
|
|
4212
|
+
* STS issues a distinct one per session, so two different explicit bags are
|
|
4213
|
+
* told apart. The one collision is two bags sharing an access key id with
|
|
4214
|
+
* different secrets, at most one of which can be valid.
|
|
4215
|
+
*
|
|
4216
|
+
* What it does NOT carry, because it is PROCESS-WIDE rather than per
|
|
4217
|
+
* configuration: a published `--role-arn` role (set once, refused a second
|
|
4218
|
+
* time), the proxy, and `AWS_PROFILE` / the environment chain. Two readings
|
|
4219
|
+
* with equal fingerprints within one process therefore resolve to the same
|
|
4220
|
+
* identity. Do not log it.
|
|
4221
|
+
*/
|
|
4222
|
+
function credentialFingerprint(credentialConfig) {
|
|
4223
|
+
return JSON.stringify([credentialConfig.profile ?? null, credentialConfig.credentials?.accessKeyId ?? null]);
|
|
4224
|
+
}
|
|
4225
|
+
|
|
4110
4226
|
//#endregion
|
|
4111
4227
|
//#region src/synthesis/context-providers/az-provider.ts
|
|
4112
4228
|
/**
|
|
@@ -4125,7 +4241,7 @@ var AZContextProvider = class {
|
|
|
4125
4241
|
const region = props["region"] || this.awsConfig?.region;
|
|
4126
4242
|
this.logger.debug(`Fetching availability zones for region: ${region}`);
|
|
4127
4243
|
const client = new EC2Client({
|
|
4128
|
-
...
|
|
4244
|
+
...ambientClientDefaults(),
|
|
4129
4245
|
...region && { region }
|
|
4130
4246
|
});
|
|
4131
4247
|
try {
|
|
@@ -4158,7 +4274,7 @@ var SSMContextProvider = class {
|
|
|
4158
4274
|
if (!parameterName) throw new Error("SSM context provider requires parameterName property");
|
|
4159
4275
|
this.logger.debug(`Reading SSM parameter: ${parameterName} (region: ${region})`);
|
|
4160
4276
|
const client = new SSMClient({
|
|
4161
|
-
...
|
|
4277
|
+
...ambientClientDefaults(),
|
|
4162
4278
|
...region && { region }
|
|
4163
4279
|
});
|
|
4164
4280
|
try {
|
|
@@ -4200,7 +4316,7 @@ var HostedZoneContextProvider = class {
|
|
|
4200
4316
|
if (!domainName) throw new Error("Hosted zone context provider requires domainName property");
|
|
4201
4317
|
this.logger.debug(`Looking up hosted zone: ${domainName} (private: ${privateZone})`);
|
|
4202
4318
|
const client = new Route53Client({
|
|
4203
|
-
...
|
|
4319
|
+
...ambientClientDefaults(),
|
|
4204
4320
|
...region && { region }
|
|
4205
4321
|
});
|
|
4206
4322
|
try {
|
|
@@ -4254,7 +4370,7 @@ var VpcContextProvider = class {
|
|
|
4254
4370
|
const returnVpnGateways = props["returnVpnGateways"];
|
|
4255
4371
|
this.logger.debug(`Looking up VPC (region: ${region}, filter: ${JSON.stringify(filter)})`);
|
|
4256
4372
|
const client = new EC2Client({
|
|
4257
|
-
...
|
|
4373
|
+
...ambientClientDefaults(),
|
|
4258
4374
|
...region && { region }
|
|
4259
4375
|
});
|
|
4260
4376
|
try {
|
|
@@ -4420,7 +4536,7 @@ var CcApiContextProvider = class {
|
|
|
4420
4536
|
if (!typeName) throw new Error("CC API context provider requires typeName property");
|
|
4421
4537
|
this.logger.debug(`CC API lookup: ${typeName}${exactIdentifier ? ` (id: ${exactIdentifier})` : ""} (region: ${region})`);
|
|
4422
4538
|
const client = new CloudControlClient({
|
|
4423
|
-
...
|
|
4539
|
+
...ambientClientDefaults(),
|
|
4424
4540
|
...region && { region }
|
|
4425
4541
|
});
|
|
4426
4542
|
try {
|
|
@@ -4547,7 +4663,7 @@ var AmiContextProvider = class {
|
|
|
4547
4663
|
const filters = props["filters"];
|
|
4548
4664
|
this.logger.debug(`Looking up AMI (region: ${region})`);
|
|
4549
4665
|
const client = new EC2Client({
|
|
4550
|
-
...
|
|
4666
|
+
...ambientClientDefaults(),
|
|
4551
4667
|
...region && { region }
|
|
4552
4668
|
});
|
|
4553
4669
|
try {
|
|
@@ -4590,7 +4706,7 @@ var SecurityGroupContextProvider = class {
|
|
|
4590
4706
|
const vpcId = props["vpcId"];
|
|
4591
4707
|
this.logger.debug(`Looking up security group (id: ${securityGroupId}, name: ${securityGroupName}, region: ${region})`);
|
|
4592
4708
|
const client = new EC2Client({
|
|
4593
|
-
...
|
|
4709
|
+
...ambientClientDefaults(),
|
|
4594
4710
|
...region && { region }
|
|
4595
4711
|
});
|
|
4596
4712
|
try {
|
|
@@ -4644,7 +4760,7 @@ var LoadBalancerContextProvider = class {
|
|
|
4644
4760
|
const loadBalancerType = props["loadBalancerType"];
|
|
4645
4761
|
this.logger.debug(`Looking up load balancer (arn: ${loadBalancerArn}, region: ${region})`);
|
|
4646
4762
|
const client = new ElasticLoadBalancingV2Client({
|
|
4647
|
-
...
|
|
4763
|
+
...ambientClientDefaults(),
|
|
4648
4764
|
...region && { region }
|
|
4649
4765
|
});
|
|
4650
4766
|
try {
|
|
@@ -4686,7 +4802,7 @@ var LoadBalancerListenerContextProvider = class {
|
|
|
4686
4802
|
const listenerProtocol = props["listenerProtocol"];
|
|
4687
4803
|
this.logger.debug(`Looking up load balancer listener (arn: ${listenerArn}, lb: ${loadBalancerArn}, region: ${region})`);
|
|
4688
4804
|
const client = new ElasticLoadBalancingV2Client({
|
|
4689
|
-
...
|
|
4805
|
+
...ambientClientDefaults(),
|
|
4690
4806
|
...region && { region }
|
|
4691
4807
|
});
|
|
4692
4808
|
try {
|
|
@@ -4730,7 +4846,7 @@ var KeyContextProvider = class {
|
|
|
4730
4846
|
if (!aliasName) throw new Error("Key context provider requires aliasName property");
|
|
4731
4847
|
this.logger.debug(`Looking up KMS key by alias: ${aliasName} (region: ${region})`);
|
|
4732
4848
|
const client = new KMSClient({
|
|
4733
|
-
...
|
|
4849
|
+
...ambientClientDefaults(),
|
|
4734
4850
|
...region && { region }
|
|
4735
4851
|
});
|
|
4736
4852
|
try {
|
|
@@ -5115,6 +5231,10 @@ function canonicalizeRegion(region) {
|
|
|
5115
5231
|
* the COMMERCIAL suffix, so `parseEcrRegistryHost` (`src/utils/ecr-uri.ts`)
|
|
5116
5232
|
* rejected it under the strict host check issue #1758 added and the image was
|
|
5117
5233
|
* classified `public` — anonymous pull, no `docker login`, opaque failure.
|
|
5234
|
+
* `parseEcrRegistryHost` is stricter than this fallback (issue #3670): a
|
|
5235
|
+
* region whose PREFIX no partition row knows (`nz-north-1`) is refused there,
|
|
5236
|
+
* and reported by `looksLikeEcrHostWithForeignSuffix`, until its partition's
|
|
5237
|
+
* `regionRegex` is added to `AWS_REGION_ID` in `src/utils/ecr-uri.ts`.
|
|
5118
5238
|
*
|
|
5119
5239
|
* The region is CANONICALIZED through {@link canonicalizeRegion} before the
|
|
5120
5240
|
* prefix tests (issue [#1795](https://github.com/go-to-k/cdkd/issues/1795)),
|
|
@@ -6630,7 +6750,7 @@ async function expandMacrosAttempt(template, opts, logger) {
|
|
|
6630
6750
|
const parameters = buildParameterValues(template, logger);
|
|
6631
6751
|
ownsClient = opts.cfnClient === void 0;
|
|
6632
6752
|
cfn = opts.cfnClient ?? new CloudFormationClient({
|
|
6633
|
-
...
|
|
6753
|
+
...ambientClientDefaults(),
|
|
6634
6754
|
region
|
|
6635
6755
|
});
|
|
6636
6756
|
let templateInput;
|
|
@@ -7378,12 +7498,12 @@ var Synthesizer = class {
|
|
|
7378
7498
|
else if (accountId) stateBucket = `cdkd-state-${accountId}`;
|
|
7379
7499
|
else {
|
|
7380
7500
|
const oversize = stacksWithMacros.find((s) => JSON.stringify(s.template).length > 51200);
|
|
7381
|
-
if (oversize) throw new SynthesisError(`Stack
|
|
7501
|
+
if (oversize) throw new SynthesisError(`Stack ${displayStackName(oversize.stackName)} uses CloudFormation macros AND its serialized template exceeds the 51,200-byte inline TemplateBody limit, so cdkd must upload the template to S3 for the transient expansion changeset. cdkd could not resolve a state bucket: STS GetCallerIdentity failed AND --state-bucket was not provided. Pass --state-bucket <name> (cdkd uses the same bucket as cdkd deploy state storage; typically 'cdkd-state-<accountId>').`);
|
|
7382
7502
|
stateBucket = void 0;
|
|
7383
7503
|
}
|
|
7384
7504
|
for (const stack of stacksWithMacros) {
|
|
7385
7505
|
const macros = enumerateMacros(stack.template);
|
|
7386
|
-
this.logger.info(`[macros] Expanding CloudFormation macros for stack
|
|
7506
|
+
this.logger.info(`[macros] Expanding CloudFormation macros for stack ${displayStackName(stack.stackName)} via CFn round-trip (transforms: ${macros.map((m) => displaySafe(m)).join(", ")}; may take 30-60s)...`);
|
|
7387
7507
|
const before = Date.now();
|
|
7388
7508
|
const expanded = await expandMacros(stack.template, {
|
|
7389
7509
|
region,
|
|
@@ -7536,14 +7656,14 @@ function resolveFileAssetSourcePath(manifestDir, asset, opts) {
|
|
|
7536
7656
|
const absolute = resolve$1(asset.source.path);
|
|
7537
7657
|
const escape = absoluteAssemblyPathEscape(assetOutdir, absolute);
|
|
7538
7658
|
if (escape !== void 0) warnAbsoluteAssetPath({
|
|
7539
|
-
subject: `File asset
|
|
7659
|
+
subject: `File asset ${displayAssemblyPath(asset.displayName)}`,
|
|
7540
7660
|
field: "source.path",
|
|
7541
7661
|
absolute,
|
|
7542
7662
|
escape,
|
|
7543
7663
|
sink
|
|
7544
7664
|
});
|
|
7545
7665
|
else if (namesTheSameDirectory(assetOutdir, absolute)) warnWholeAssemblyAsSource({
|
|
7546
|
-
subject: `File asset
|
|
7666
|
+
subject: `File asset ${displayAssemblyPath(asset.displayName)}`,
|
|
7547
7667
|
field: "source.path",
|
|
7548
7668
|
outdir: absolute,
|
|
7549
7669
|
sink
|
|
@@ -7553,14 +7673,14 @@ function resolveFileAssetSourcePath(manifestDir, asset, opts) {
|
|
|
7553
7673
|
const resolved = resolveAssemblyPath(manifestDir, asset.source.path, { containWithin: assetOutdir });
|
|
7554
7674
|
if (!resolved.contained && namesTheSameDirectory(assetOutdir, resolved.path)) {
|
|
7555
7675
|
warnWholeAssemblyAsSource({
|
|
7556
|
-
subject: `File asset
|
|
7676
|
+
subject: `File asset ${displayAssemblyPath(asset.displayName)}`,
|
|
7557
7677
|
field: "source.path",
|
|
7558
7678
|
outdir: resolved.path,
|
|
7559
7679
|
sink
|
|
7560
7680
|
});
|
|
7561
7681
|
return resolved.path;
|
|
7562
7682
|
}
|
|
7563
|
-
if (!resolved.contained) throw new Error(`File asset
|
|
7683
|
+
if (!resolved.contained) throw new Error(`File asset ${displayAssemblyPath(asset.displayName)} has source.path=${displayAssemblyPath(asset.source.path)} which ${renderAssemblyPathEscape(resolved, assetOutdir, "publish it")}`);
|
|
7564
7684
|
return resolved.path;
|
|
7565
7685
|
}
|
|
7566
7686
|
/**
|
|
@@ -7596,7 +7716,7 @@ var AssetManifestLoader = class {
|
|
|
7596
7716
|
*/
|
|
7597
7717
|
async loadManifest(cdkOutputDir, stackName) {
|
|
7598
7718
|
const resolved = resolveAssemblyPath(cdkOutputDir, `${stackName}.assets.json`);
|
|
7599
|
-
if (!resolved.contained) throw new Error(`Asset manifest for stack
|
|
7719
|
+
if (!resolved.contained) throw new Error(`Asset manifest for stack ${displayStackName(stackName)} ${renderAssemblyPathEscape(resolved, cdkOutputDir)}`);
|
|
7600
7720
|
const manifestPath = resolved.path;
|
|
7601
7721
|
try {
|
|
7602
7722
|
this.logger.debug(`Loading asset manifest from: ${manifestPath}`);
|
|
@@ -7761,7 +7881,7 @@ var FileAssetPublisher = class {
|
|
|
7761
7881
|
const destRegion = dest.region ? this.resolvePlaceholders(dest.region, accountId, region) : region;
|
|
7762
7882
|
this.logger.debug(`Publishing file asset ${asset.displayName || assetHash} → s3://${bucketName}/${objectKey}`);
|
|
7763
7883
|
const client = new S3Client({
|
|
7764
|
-
...
|
|
7884
|
+
...ambientClientDefaults(),
|
|
7765
7885
|
region: destRegion
|
|
7766
7886
|
});
|
|
7767
7887
|
try {
|
|
@@ -9559,65 +9679,7 @@ function resolveDockerContextDirectory(opts) {
|
|
|
9559
9679
|
}
|
|
9560
9680
|
/** One spelling of the warning subject, so the two arms cannot drift. */
|
|
9561
9681
|
function dockerSubject(assetId) {
|
|
9562
|
-
return assetId === void 0 ? "A Docker asset" : `Docker asset
|
|
9563
|
-
}
|
|
9564
|
-
/**
|
|
9565
|
-
* Refuse a Docker asset whose build context the bundled `cdk-local` engine
|
|
9566
|
-
* would take from outside the assembly (issue
|
|
9567
|
-
* [#3503](https://github.com/go-to-k/cdkd/issues/3503)).
|
|
9568
|
-
*
|
|
9569
|
-
* Since cdk-local 0.149.3 the engine's own `buildDockerImage` refuses the same
|
|
9570
|
-
* escapes and opens the path it judged (go-to-k/cdkd#3597). This copy stays in
|
|
9571
|
-
* FRONT of it because the engine's refusal quotes the assembly-chosen value in
|
|
9572
|
-
* a boundary the value can close (go-to-k/cdk-local#758), while this one
|
|
9573
|
-
* renders it through `displayAssemblyPath`; go-to-k/cdkd#3652 removes it once
|
|
9574
|
-
* that ships. It judges the path the engine's `${cdkOutDir}/${source.directory}`
|
|
9575
|
-
* spelling names, before the engine runs, through the same
|
|
9576
|
-
* {@link resolveDockerContextDirectory} cdkd's own build uses.
|
|
9577
|
-
*
|
|
9578
|
-
* An ABSOLUTE value is judged by the engine's spelling, not honoured: the
|
|
9579
|
-
* concatenation folds it UNDER the manifest directory, so its leading
|
|
9580
|
-
* separators are stripped and the remainder takes the relative arm. That
|
|
9581
|
-
* keeps a symlink inside the assembly from becoming an escape through an
|
|
9582
|
-
* absolute spelling, and keeps the honour-and-warn arm, which describes a
|
|
9583
|
-
* build this engine never performs, out of these paths.
|
|
9584
|
-
*/
|
|
9585
|
-
function assertCdkLocalDockerContextContained(opts) {
|
|
9586
|
-
const { manifestDir, source, assetOutdir, wrapError } = opts;
|
|
9587
|
-
const directory = source.directory;
|
|
9588
|
-
if (!directory) return;
|
|
9589
|
-
const asEngineJoinsIt = isAbsolute$1(directory) ? directory.replace(/^[/\\]+/, "") : directory;
|
|
9590
|
-
resolveDockerContextDirectory({
|
|
9591
|
-
manifestDir,
|
|
9592
|
-
directory: asEngineJoinsIt,
|
|
9593
|
-
wrapError,
|
|
9594
|
-
assetOutdir,
|
|
9595
|
-
sink: source.executable && source.executable.length > 0 ? "run this asset's source.executable with that directory as its working directory" : "send that directory to docker build as the context of an image cdkd then runs locally"
|
|
9596
|
-
});
|
|
9597
|
-
const engineSpelled = `${manifestDir}/${asEngineJoinsIt}`;
|
|
9598
|
-
const physical = tryRealpathNative(engineSpelled);
|
|
9599
|
-
if (physical === void 0) return;
|
|
9600
|
-
const bound = tryRealpathNative(assetOutdir) ?? resolve$1(assetOutdir);
|
|
9601
|
-
const rel = relative(bound, physical);
|
|
9602
|
-
if (rel === "" || rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute$1(rel)) return;
|
|
9603
|
-
throw wrapError(`asset source.directory=${displayAssemblyPath(directory)} which ` + renderAssemblyPathEscape({
|
|
9604
|
-
contained: false,
|
|
9605
|
-
escape: "symlink",
|
|
9606
|
-
path: engineSpelled,
|
|
9607
|
-
realPath: physical
|
|
9608
|
-
}, assetOutdir, "build it"));
|
|
9609
|
-
}
|
|
9610
|
-
/**
|
|
9611
|
-
* `realpath(3)`, or `undefined` when the path does not resolve. `.native` is
|
|
9612
|
-
* load-bearing: the JavaScript `realpathSync` folds `..` lexically first,
|
|
9613
|
-
* which is the very reading the check above exists to avoid.
|
|
9614
|
-
*/
|
|
9615
|
-
function tryRealpathNative(p) {
|
|
9616
|
-
try {
|
|
9617
|
-
return realpathSync$1.native(p);
|
|
9618
|
-
} catch {
|
|
9619
|
-
return;
|
|
9620
|
-
}
|
|
9682
|
+
return assetId === void 0 ? "A Docker asset" : `Docker asset ${displayIdent(assetId)}`;
|
|
9621
9683
|
}
|
|
9622
9684
|
/**
|
|
9623
9685
|
* Build a Docker image from a CDK asset source. Returns the local image
|
|
@@ -9781,7 +9843,7 @@ var DockerAssetPublisher = class {
|
|
|
9781
9843
|
const ecrUri = `${accountId}.dkr.ecr.${destRegion}.${ecrUrlSuffix(destRegion)}/${repositoryName}:${imageTag}`;
|
|
9782
9844
|
this.logger.debug(`Publishing Docker image ${asset.displayName || assetHash} → ${ecrUri}`);
|
|
9783
9845
|
const client = new ECRClient({
|
|
9784
|
-
...
|
|
9846
|
+
...ambientClientDefaults(),
|
|
9785
9847
|
region: destRegion
|
|
9786
9848
|
});
|
|
9787
9849
|
try {
|
|
@@ -9820,7 +9882,7 @@ var DockerAssetPublisher = class {
|
|
|
9820
9882
|
const destRegion = dest.region ? this.resolvePlaceholders(dest.region, accountId, region) : region;
|
|
9821
9883
|
const ecrUri = `${accountId}.dkr.ecr.${destRegion}.${ecrUrlSuffix(destRegion)}/${repositoryName}:${imageTag}`;
|
|
9822
9884
|
const client = new ECRClient({
|
|
9823
|
-
...
|
|
9885
|
+
...ambientClientDefaults(),
|
|
9824
9886
|
region: destRegion
|
|
9825
9887
|
});
|
|
9826
9888
|
try {
|
|
@@ -11363,7 +11425,7 @@ var AssetPublisher = class {
|
|
|
11363
11425
|
if (!accountId) {
|
|
11364
11426
|
const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
|
|
11365
11427
|
const stsClient = new STSClient({
|
|
11366
|
-
...
|
|
11428
|
+
...ambientClientDefaults(),
|
|
11367
11429
|
region
|
|
11368
11430
|
});
|
|
11369
11431
|
accountId = (await stsClient.send(new GetCallerIdentityCommand({}))).Account;
|
|
@@ -24507,9 +24569,9 @@ function inspectCommand(stackName, region) {
|
|
|
24507
24569
|
* entries FIRST ({@link repairMalformedResourceEntriesForReadOnly}), so the
|
|
24508
24570
|
* row is reported once, as unreadable, rather than warned about as a preview
|
|
24509
24571
|
* and then dropped. The object test stays here rather than
|
|
24510
|
-
* {@link isReadableResourceEntry}
|
|
24511
|
-
*
|
|
24512
|
-
*
|
|
24572
|
+
* {@link isReadableResourceEntry} so this verdict does not depend on the entry
|
|
24573
|
+
* guard running first: narrowing it would let a typeless object with a torn
|
|
24574
|
+
* map through any caller that takes this predicate alone. Likewise a `resources` bag that is not readable at all
|
|
24513
24575
|
* yields `[]` here rather than ids invented from a string's characters — that
|
|
24514
24576
|
* class is {@link hasReadableResources}'s to report. What a caller must not do
|
|
24515
24577
|
* is take only this one.
|
|
@@ -25167,13 +25229,10 @@ function malformedResourceEntriesWarning(rawStackName, rawRegion, logicalIds) {
|
|
|
25167
25229
|
* `logicalId` is not a string arrives as `''` and renders as the
|
|
25168
25230
|
* `UNRENDERABLE` stand-in.
|
|
25169
25231
|
*/
|
|
25170
|
-
function malformedOrphanRecordsWarning(rawStackName, rawRegion, logicalIds) {
|
|
25232
|
+
function malformedOrphanRecordsWarning(rawStackName, rawRegion, logicalIds, alsoRejectsTornMaps) {
|
|
25171
25233
|
const stackName = absentIfEmpty(rawStackName);
|
|
25172
25234
|
const region = absentIfEmpty(rawRegion);
|
|
25173
|
-
|
|
25174
|
-
const rest = logicalIds.length - NAMED_UNREADABLE_ENTRIES;
|
|
25175
|
-
const more = rest > 0 ? ` and ${rest} more` : "";
|
|
25176
|
-
return `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read as resources — ${named}${more} — because they are not objects, or carry no resource type. Continuing WITHOUT them: they are not previewed for adoption. These ids were read from 'orphans'; the 'resources' map carries its own warning when it is damaged too. See the stored values with: ` + inspectCommand(stackName, region);
|
|
25235
|
+
return `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read as resources — ${namedOrphanRows(logicalIds)} — because they are not objects, have no string 'logicalId' or share it with another row, or their 'state' is not an object, names no resource type${alsoRejectsTornMaps ? ", has no non-empty string 'physicalId', or holds a 'properties' or 'attributes' map that is not an object" : ` or has no non-empty string 'physicalId'`}. Continuing WITHOUT them: ${alsoRejectsTornMaps ? `they are excluded from the secret scan, so nothing this run does can certify them` : "they are not previewed for adoption, and 'cdkd deploy' refuses the record over them rather than dropping them as this command does"}. These ids were read from 'orphans'; the 'resources' map carries its own warning when it is damaged too. See the stored values with: ` + inspectCommand(stackName, region);
|
|
25177
25236
|
}
|
|
25178
25237
|
/**
|
|
25179
25238
|
* The half the refusal and the warning share: what is wrong and which entries.
|
|
@@ -25212,6 +25271,46 @@ function malformedResourceEntriesRefusalMessage(rawStackName, rawRegion, logical
|
|
|
25212
25271
|
return `${namedEntriesClause(stackName, region, logicalIds)} This command can WRITE state, so it refuses rather than skipping them: saving over the record would report a clean run for entries nothing could read, and would leave the next command to fail on them with no more to go on. Nothing was locked, read from AWS or written FOR THIS STACK. Inspect it with: ` + inspectCommand(stackName, region);
|
|
25213
25272
|
}
|
|
25214
25273
|
/**
|
|
25274
|
+
* For `cdkd deploy`: refuse a record whose `resources` map holds a ROW that is
|
|
25275
|
+
* not a readable resource record (go-to-k/cdkd#3314). TWO call sites, one
|
|
25276
|
+
* verdict. `DeployEngine`'s state load is the one a deploy hits: two walks run
|
|
25277
|
+
* between the load and the diff (the CLI's prefix-migration gate and the
|
|
25278
|
+
* observed-state auto-refresh) and each died on a `null` row with a bare
|
|
25279
|
+
* `TypeError`. `DiffCalculator.calculateDiff` also calls it, beside
|
|
25280
|
+
* {@link refuseMalformedResourceProperties}, because that is where the verdict
|
|
25281
|
+
* is made. Any other caller of the diff that forgets gets the refusal.
|
|
25282
|
+
*
|
|
25283
|
+
* The harm is the diff's verdict, not a save. The diff looks up each template
|
|
25284
|
+
* resource by logical id, so a `null` (or any non-object) row reads as "not in
|
|
25285
|
+
* state" and is planned as a CREATE. That either collides with the live
|
|
25286
|
+
* resource's name or creates a SECOND copy and orphans the first. A row with no
|
|
25287
|
+
* `resourceType` compares unequal to the template's type, so it is planned as a
|
|
25288
|
+
* TYPE CHANGE, which is a replacement.
|
|
25289
|
+
*
|
|
25290
|
+
* A third entry point on the ENTRY class rather than a call to
|
|
25291
|
+
* {@link refuseMalformedResourceEntries}, whose text is false here. That text
|
|
25292
|
+
* says "Nothing was locked", but the deploy holds its lock at both sites. Same
|
|
25293
|
+
* predicate, so the verdict cannot diverge.
|
|
25294
|
+
*
|
|
25295
|
+
* The engine passes its own resolved stack and region. `calculateDiff` holds no
|
|
25296
|
+
* trusted pair and passes neither (see {@link stackClause}).
|
|
25297
|
+
*/
|
|
25298
|
+
function refuseMalformedResourceEntriesForDeploy(state, stackName, region) {
|
|
25299
|
+
const unreadable = unreadableResourceEntries(state);
|
|
25300
|
+
if (unreadable.length === 0) return;
|
|
25301
|
+
throw markNonRetryable(new CdkdError(malformedDeployResourceEntriesRefusalMessage(stackName, region, unreadable), STATE_RESOURCES_MALFORMED));
|
|
25302
|
+
}
|
|
25303
|
+
/**
|
|
25304
|
+
* The text {@link refuseMalformedResourceEntriesForDeploy} raises. Like
|
|
25305
|
+
* {@link malformedResourcePropertiesRefusalMessage}, it must be true under
|
|
25306
|
+
* `--dry-run` too, since the dry-run return comes after the diff.
|
|
25307
|
+
*/
|
|
25308
|
+
function malformedDeployResourceEntriesRefusalMessage(rawStackName, rawRegion, logicalIds) {
|
|
25309
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
25310
|
+
const region = absentIfEmpty(rawRegion);
|
|
25311
|
+
return `${namedEntriesClause(stackName, region, logicalIds)} 'cdkd deploy' can WRITE state and AWS resources, so it refuses rather than continuing — under '--dry-run' too, because the plan a dry run would print is the wrong one: a row that is not an object reads as a resource cdkd does not manage, so the template's resource of that id is planned as a CREATE (a second copy of a live resource, or a name collision), and a row with no resource type is planned as a TYPE CHANGE, which replaces the live resource. Nothing was provisioned and no state was written FOR THIS STACK. Repair or remove the record first; 'cdkd diff' previews the rest of the stack without those rows and warns that it did. Inspect the record with: ` + inspectCommand(stackName, region);
|
|
25312
|
+
}
|
|
25313
|
+
/**
|
|
25215
25314
|
* For `cdkd orphan`: refuse a record whose SURVIVING `resources` entries are
|
|
25216
25315
|
* not readable resource records (go-to-k/cdkd#3350).
|
|
25217
25316
|
*
|
|
@@ -25305,12 +25404,177 @@ function malformedOrphanResourceAttributesRefusalMessage(rawStackName, rawRegion
|
|
|
25305
25404
|
return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} holds ${logicalIds.length} resource record(s) whose 'attributes' map cannot be read — ${named}${more} — because it is null or not an object. The record is malformed or truncated. 'cdkd orphan' REWRITES and SAVES every record it keeps, so it refuses rather than continuing — under '--dry-run' too, so a dry run never prints a plan the real run refuses. The map is carried into the save VERBATIM, and a list is walked, so its rewrites are recorded into a container that is still not a map. It is the cache a later 'cdkd deploy' reads another resource's 'Fn::GetAtt' of this one from, so continuing would report success over the one map that read depends on.`, SURVIVOR_THIRD_WAY_OUT);
|
|
25306
25405
|
}
|
|
25307
25406
|
/**
|
|
25407
|
+
* Is ONE `orphans[]` record PREVIEWABLE — the narrow half of
|
|
25408
|
+
* {@link isReadableOrphanRecord}, for `cdkd diff` alone (go-to-k/cdkd#3500).
|
|
25409
|
+
*
|
|
25410
|
+
* An object, a string `logicalId`, and a `state` that is a readable resource
|
|
25411
|
+
* entry with a non-empty string `physicalId`: everything the adoption preview
|
|
25412
|
+
* dereferences, and nothing more. The `physicalId` half is NOT inherited from
|
|
25413
|
+
* {@link isReadableResourceEntry} — see {@link hasStringPhysicalId} for why that
|
|
25414
|
+
* one stops at `resourceType` and why a ROW cannot. It
|
|
25415
|
+
* deliberately does not ask about that entry's `properties`, because `cdkd diff`
|
|
25416
|
+
* has a LATER answer for that one — `computeStackDiff` runs the `properties`
|
|
25417
|
+
* repair a second time over the adopted records and names what it emptied, which
|
|
25418
|
+
* `docs/cli-diff.md` and `.claude/rules/state-malformed-properties.md` both
|
|
25419
|
+
* describe. Dropping such a row here instead would make that repair unreachable
|
|
25420
|
+
* and silently retire a documented report. A torn `attributes` map rides through
|
|
25421
|
+
* for the same reason and gets NO later answer: stated rather than solved, and
|
|
25422
|
+
* the same residual `cdkd diff` had before this predicate existed.
|
|
25423
|
+
*
|
|
25424
|
+
* It CANNOT see rows sharing a `logicalId` (go-to-k/cdkd#3643), a LIST-level
|
|
25425
|
+
* defect — never filter a list with it alone; take
|
|
25426
|
+
* {@link previewableOrphanRecords} / {@link unpreviewableOrphanRecords}.
|
|
25427
|
+
*
|
|
25428
|
+
* Every WRITER takes the full predicate: none of them has a second answer, and
|
|
25429
|
+
* a torn `properties` map reaching a save is go-to-k/cdkd#3344's defect.
|
|
25430
|
+
*/
|
|
25431
|
+
function isPreviewableOrphanRecord(record) {
|
|
25432
|
+
if (!isReadableBag(record)) return false;
|
|
25433
|
+
if (typeof record.logicalId !== "string") return false;
|
|
25434
|
+
const entry = record.state;
|
|
25435
|
+
return isReadableResourceEntry(entry) && hasStringPhysicalId(entry);
|
|
25436
|
+
}
|
|
25437
|
+
/**
|
|
25438
|
+
* Does this resource entry carry a NON-EMPTY string `physicalId`?
|
|
25439
|
+
*
|
|
25440
|
+
* Its own helper rather than a clause spelled in each row predicate, so the two
|
|
25441
|
+
* cannot drift on it, and deliberately NOT folded into
|
|
25442
|
+
* {@link isReadableResourceEntry}: that one answers for a `resources` ENTRY,
|
|
25443
|
+
* where stopping at `resourceType` is a recorded decision — a row with a type and
|
|
25444
|
+
* no physical id fails per-resource where it is used and is reported by that
|
|
25445
|
+
* command in its own terms.
|
|
25446
|
+
*
|
|
25447
|
+
* An `orphans` ROW has no such second report, which is why it asks for more
|
|
25448
|
+
* (go-to-k/cdkd#3641 review). The record names a resource cdkd deliberately LEFT
|
|
25449
|
+
* LIVE in AWS, so the physical id is the only handle on it: `cdkd destroy`'s
|
|
25450
|
+
* pre-confirmation listing is the operator's only notice before the record is
|
|
25451
|
+
* deleted, and it rendered an absent id as an EMPTY field in the row they
|
|
25452
|
+
* approve. `planOrphanAdoption` dereferences it eight times over — including
|
|
25453
|
+
* `knownPhysicalId` on the provider call and `claims().has(...)` for a
|
|
25454
|
+
* cross-stack collision — so a row without one decides an adoption from
|
|
25455
|
+
* `undefined`.
|
|
25456
|
+
*/
|
|
25457
|
+
function hasStringPhysicalId(entry) {
|
|
25458
|
+
const physicalId = entry.physicalId;
|
|
25459
|
+
return typeof physicalId === "string" && physicalId !== "";
|
|
25460
|
+
}
|
|
25461
|
+
/**
|
|
25462
|
+
* The `orphans[]` records {@link isPreviewableOrphanRecord} rejects, PLUS every
|
|
25463
|
+
* row sharing its string `logicalId` with another row (go-to-k/cdkd#3643),
|
|
25464
|
+
* named the way {@link unreadableOrphanRecords} names its own.
|
|
25465
|
+
*/
|
|
25466
|
+
function unpreviewableOrphanRecords(state) {
|
|
25467
|
+
if (!Array.isArray(state.orphans)) return [];
|
|
25468
|
+
const rows = state.orphans;
|
|
25469
|
+
const shared = sharedOrphanLogicalIds(rows);
|
|
25470
|
+
return rows.filter((record) => !isPreviewableOrphanRecord(record) || sharesLogicalId(record, shared)).map(orphanRowName);
|
|
25471
|
+
}
|
|
25472
|
+
/**
|
|
25473
|
+
* The rows `cdkd diff` KEEPS for the adoption preview: the complement of
|
|
25474
|
+
* {@link unpreviewableOrphanRecords}, homed beside it so the two cannot
|
|
25475
|
+
* disagree about a row (go-to-k/cdkd#3643). `[]` for a container that is not a
|
|
25476
|
+
* list, which {@link hasReadableOrphans} reports.
|
|
25477
|
+
*
|
|
25478
|
+
* Why not `orphans.filter(isPreviewableOrphanRecord)` at the call site, which is
|
|
25479
|
+
* what `cdkd diff` did: that predicate decides ONE record, and a shared
|
|
25480
|
+
* `logicalId` is a property of the LIST. Two rows carrying one id both pass it,
|
|
25481
|
+
* and `planOrphanAdoption` then keys its adoption map on that id, so the preview
|
|
25482
|
+
* shows ONE adoption for two rows — the collapse the writers now refuse.
|
|
25483
|
+
*/
|
|
25484
|
+
function previewableOrphanRecords(state) {
|
|
25485
|
+
if (!Array.isArray(state.orphans)) return [];
|
|
25486
|
+
const rows = state.orphans;
|
|
25487
|
+
const shared = sharedOrphanLogicalIds(rows);
|
|
25488
|
+
return rows.filter((record) => isPreviewableOrphanRecord(record) && !sharesLogicalId(record, shared));
|
|
25489
|
+
}
|
|
25490
|
+
/**
|
|
25491
|
+
* The string `logicalId`s that TWO OR MORE rows of `orphans` carry
|
|
25492
|
+
* (go-to-k/cdkd#3643) — `''` included, since an empty string is still a key.
|
|
25493
|
+
*
|
|
25494
|
+
* Such a record is MALFORMED, not merely unusual: no supported writer produces
|
|
25495
|
+
* one, because `orphansAfterRollback` merges by `logicalId` and keeps one row per
|
|
25496
|
+
* id. What a reader does with it is the loss the row predicate exists to refuse
|
|
25497
|
+
* for a MISSING id — `orphansAfterRollback` keeps only the LAST of the rows, and
|
|
25498
|
+
* the deploy's adoption pass writes `adopted[logicalId]` for each, so the first
|
|
25499
|
+
* row's resource stays live in AWS with nothing tracking it.
|
|
25500
|
+
*
|
|
25501
|
+
* Counted over EVERY row that is an object carrying a string id, not only the
|
|
25502
|
+
* rows the per-record predicate accepts: a torn row and a healthy one sharing an
|
|
25503
|
+
* id still say the record was edited or damaged, and keeping the healthy one
|
|
25504
|
+
* would have a read-only command preview, as the stack's only row of that id, a
|
|
25505
|
+
* row whose twin the writers refuse over. A `Map` rather than a plain object, so
|
|
25506
|
+
* an id spelled `__proto__` or `constructor` is counted rather than resolved
|
|
25507
|
+
* through the prototype.
|
|
25508
|
+
*/
|
|
25509
|
+
function sharedOrphanLogicalIds(rows) {
|
|
25510
|
+
const seen = /* @__PURE__ */ new Map();
|
|
25511
|
+
for (const record of rows) {
|
|
25512
|
+
if (!isReadableBag(record)) continue;
|
|
25513
|
+
const id = record.logicalId;
|
|
25514
|
+
if (typeof id !== "string") continue;
|
|
25515
|
+
seen.set(id, (seen.get(id) ?? 0) + 1);
|
|
25516
|
+
}
|
|
25517
|
+
const shared = /* @__PURE__ */ new Set();
|
|
25518
|
+
for (const [id, count] of seen) if (count > 1) shared.add(id);
|
|
25519
|
+
return shared;
|
|
25520
|
+
}
|
|
25521
|
+
/** Does this row carry one of the {@link sharedOrphanLogicalIds}? */
|
|
25522
|
+
function sharesLogicalId(record, shared) {
|
|
25523
|
+
if (shared.size === 0 || !isReadableBag(record)) return false;
|
|
25524
|
+
const id = record.logicalId;
|
|
25525
|
+
return typeof id === "string" && shared.has(id);
|
|
25526
|
+
}
|
|
25527
|
+
/**
|
|
25528
|
+
* How every `orphans` ROW helper names a row: its `logicalId`, or `''`
|
|
25529
|
+
* (rendered as the `UNRENDERABLE` stand-in) when it has no string one.
|
|
25530
|
+
*/
|
|
25531
|
+
function orphanRowName(record) {
|
|
25532
|
+
const id = isReadableBag(record) ? record.logicalId : void 0;
|
|
25533
|
+
return typeof id === "string" ? id : "";
|
|
25534
|
+
}
|
|
25535
|
+
/**
|
|
25536
|
+
* Is ONE `orphans[]` record usable by a reader (go-to-k/cdkd#3500)?
|
|
25537
|
+
*
|
|
25538
|
+
* Split out of {@link unreadableOrphanRecords} rather than written a second
|
|
25539
|
+
* time, so the five WRITE-capable readers that take a row's fields off the cast
|
|
25540
|
+
* and the `cdkd orphan` refusal that predates them cannot disagree about which
|
|
25541
|
+
* rows are usable. `cdkd diff` deliberately disagrees for one class — see
|
|
25542
|
+
* {@link isPreviewableOrphanRecord}, which is the narrower half it takes. The two shapes answer different questions and share this verdict:
|
|
25543
|
+
* this one decides ONE record, that one names every record a state fails on.
|
|
25544
|
+
*
|
|
25545
|
+
* A reader needs all of it to hold, because it reaches the record as a WHOLE:
|
|
25546
|
+
* the record is an object, its `logicalId` is a string (a row with none keys
|
|
25547
|
+
* `orphansAfterRollback`'s merge map on `undefined`, so several of them collapse
|
|
25548
|
+
* into one), its `state` is a readable resource entry carrying a NON-EMPTY string
|
|
25549
|
+
* `physicalId` ({@link hasStringPhysicalId} carries why that is asked here and
|
|
25550
|
+
* not for a `resources` entry), and that entry's `properties` and `attributes`
|
|
25551
|
+
* maps are readable.
|
|
25552
|
+
*
|
|
25553
|
+
* It CANNOT see the one LIST-level defect: two rows sharing a string `logicalId`
|
|
25554
|
+
* collapse in the same merge map, and each of them passes this test
|
|
25555
|
+
* (go-to-k/cdkd#3643). So never filter a list with it alone — take
|
|
25556
|
+
* {@link unreadableOrphanRecords} (or, for `cdkd diff`,
|
|
25557
|
+
* {@link previewableOrphanRecords}), which add that check.
|
|
25558
|
+
*/
|
|
25559
|
+
function isReadableOrphanRecord(record) {
|
|
25560
|
+
if (!isPreviewableOrphanRecord(record)) return false;
|
|
25561
|
+
const entry = record.state;
|
|
25562
|
+
return isReadableBag(entry.properties) && hasReadableAttributes(entry);
|
|
25563
|
+
}
|
|
25564
|
+
/**
|
|
25308
25565
|
* The `orphans[]` records a reader cannot use: a record that is not an object
|
|
25309
|
-
* or has no string `logicalId`, whose `state` is not a readable resource entry,
|
|
25310
|
-
*
|
|
25566
|
+
* or has no string `logicalId`, or whose `state` is not a readable resource entry,
|
|
25567
|
+
* carries no non-empty string `physicalId`, or carries an unreadable `properties`
|
|
25568
|
+
* or `attributes` map
|
|
25311
25569
|
* (go-to-k/cdkd#3344). The `logicalId` half is go-to-k/cdkd#3500's row
|
|
25312
|
-
* predicate: rows
|
|
25313
|
-
* collapses
|
|
25570
|
+
* predicate: rows MISSING one all key the same map entry, and
|
|
25571
|
+
* `orphansAfterRollback` collapses those into one. EVERY row whose string
|
|
25572
|
+
* `logicalId` another row also carries is named too — each of them, since
|
|
25573
|
+
* nothing says which is the live resource (go-to-k/cdkd#3643,
|
|
25574
|
+
* {@link sharedOrphanLogicalIds}): those collapse in the same map by the same
|
|
25575
|
+
* mechanism, and it is the check {@link isReadableOrphanRecord} cannot make.
|
|
25576
|
+
* Folded in HERE so every refusal, the read-only repair and `cdkd orphan`
|
|
25577
|
+
* inherit it and no caller re-spells it.
|
|
25314
25578
|
*
|
|
25315
25579
|
* Every `ResourceState` question the `resources` side answers in separate
|
|
25316
25580
|
* predicates, asked in ONE here: a rollback-orphan record is reached only as a
|
|
@@ -25323,15 +25587,100 @@ function malformedOrphanResourceAttributesRefusalMessage(rawStackName, rawRegion
|
|
|
25323
25587
|
*/
|
|
25324
25588
|
function unreadableOrphanRecords(state) {
|
|
25325
25589
|
if (!Array.isArray(state.orphans)) return [];
|
|
25326
|
-
|
|
25327
|
-
|
|
25328
|
-
|
|
25329
|
-
|
|
25330
|
-
|
|
25331
|
-
|
|
25332
|
-
|
|
25333
|
-
|
|
25334
|
-
|
|
25590
|
+
const rows = state.orphans;
|
|
25591
|
+
const shared = sharedOrphanLogicalIds(rows);
|
|
25592
|
+
return rows.filter((record) => isUnusableOrphanRow(record, shared)).map(orphanRowName);
|
|
25593
|
+
}
|
|
25594
|
+
/**
|
|
25595
|
+
* The writers' per-row verdict with the list-level half applied: the ONE test
|
|
25596
|
+
* {@link unreadableOrphanRecords} names by and
|
|
25597
|
+
* {@link repairMalformedOrphanRecordsForReadOnly} drops by, so the rows a
|
|
25598
|
+
* dry run drops are exactly the rows the real run refuses over.
|
|
25599
|
+
*/
|
|
25600
|
+
function isUnusableOrphanRow(record, shared) {
|
|
25601
|
+
return !isReadableOrphanRecord(record) || sharesLogicalId(record, shared);
|
|
25602
|
+
}
|
|
25603
|
+
/**
|
|
25604
|
+
* Refuse a readable `orphans` list holding a record no reader can use, on a
|
|
25605
|
+
* path that can WRITE state (go-to-k/cdkd#3500).
|
|
25606
|
+
*
|
|
25607
|
+
* The CONTAINER pair beside this one ({@link refuseMalformedOrphans} and its
|
|
25608
|
+
* destroy twin) answers "is the field a list"; this answers "is every row in it
|
|
25609
|
+
* usable", and a list can fail the second while passing the first. One
|
|
25610
|
+
* predicate for both questions would be wrong in the direction that loses
|
|
25611
|
+
* evidence: `cdkd diff` repairs the container and must DROP a row, which is not
|
|
25612
|
+
* the same verdict.
|
|
25613
|
+
*
|
|
25614
|
+
* Marked non-retryable for {@link refuseMalformedOrphans}'s reason: a retry
|
|
25615
|
+
* cannot change a persisted record, and a nested child's deploy runs inside a
|
|
25616
|
+
* `withRetry`.
|
|
25617
|
+
*
|
|
25618
|
+
* It takes NO `LockRecoveryContext`, matching its container twin
|
|
25619
|
+
* {@link refuseMalformedOrphans}: no caller on these paths holds one, and a
|
|
25620
|
+
* parameter every call site omits renders nothing. The message builder keeps its
|
|
25621
|
+
* own `recovery` parameter, and its arms are pinned by calling it directly —
|
|
25622
|
+
* `refuseMalformedOrphansForOrphan` is NOT that route, since it raises a
|
|
25623
|
+
* different text ({@link malformedOrphansForOrphanRefusalMessage}).
|
|
25624
|
+
*/
|
|
25625
|
+
function refuseMalformedOrphanRecords(state, stackName, region) {
|
|
25626
|
+
const unreadable = unreadableOrphanRecords(state);
|
|
25627
|
+
if (unreadable.length === 0) return;
|
|
25628
|
+
throw markNonRetryable(new CdkdError(malformedOrphanRecordsRefusalMessage(stackName, region, unreadable), STATE_RESOURCES_MALFORMED));
|
|
25629
|
+
}
|
|
25630
|
+
/**
|
|
25631
|
+
* The DESTROY twin of {@link refuseMalformedOrphanRecords}, carrying its own
|
|
25632
|
+
* text for the reason the container pair splits: a destroy neither walks the
|
|
25633
|
+
* record back into `resources` nor writes a reshaped one, so the writer text's
|
|
25634
|
+
* mechanism would be false here. What it does instead is REPORT the rows — the
|
|
25635
|
+
* operator's only notice that those resources stop being tracked — from fields
|
|
25636
|
+
* it never validates, and then remove the record.
|
|
25637
|
+
*/
|
|
25638
|
+
function refuseMalformedOrphanRecordsForDestroy(state, stackName, region) {
|
|
25639
|
+
const unreadable = unreadableOrphanRecords(state);
|
|
25640
|
+
if (unreadable.length === 0) return;
|
|
25641
|
+
throw markNonRetryable(new CdkdError(malformedOrphanRecordsForDestroyRefusalMessage(stackName, region, unreadable), STATE_RESOURCES_MALFORMED));
|
|
25642
|
+
}
|
|
25643
|
+
/**
|
|
25644
|
+
* The WRITER text {@link refuseMalformedOrphanRecords} raises.
|
|
25645
|
+
*
|
|
25646
|
+
* Its mechanism clause names THREE outcomes rather than one, because a reader
|
|
25647
|
+
* meets a different one per shape: a row MISSING its `logicalId` keys
|
|
25648
|
+
* `orphansAfterRollback`'s merge map on `undefined`, so rows missing it collapse
|
|
25649
|
+
* to one saved survivor (distinct NUMERIC ids do not — they stay distinct keys),
|
|
25650
|
+
* and rows SHARING a string one collapse the same way (go-to-k/cdkd#3643);
|
|
25651
|
+
* a row whose `state` is absent or null aborts wherever it is first
|
|
25652
|
+
* dereferenced; and a `state` that is a primitive or names no resource type
|
|
25653
|
+
* reads as `undefined` and is carried or reported as though it were a record.
|
|
25654
|
+
*/
|
|
25655
|
+
function malformedOrphanRecordsRefusalMessage(rawStackName, rawRegion, logicalIds, recovery) {
|
|
25656
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
25657
|
+
const region = absentIfEmpty(rawRegion);
|
|
25658
|
+
return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read — ${namedOrphanRows(logicalIds)} — because the record has no string 'logicalId' or shares it with another row, or its 'state' is not an object, names no resource type, has no non-empty string 'physicalId', or holds a 'properties' or 'attributes' map that is not an object. This command can WRITE state, and what it would do with such a row is not one thing: 'cdkd rollback' merges by 'logicalId', so rows MISSING one, or SHARING one, key the same entry and only one of them survives into the record it saves, the others' resources left live in AWS with nothing tracking them; a row whose 'state' is absent or null aborts wherever it is first dereferenced, with an error naming neither the field nor the stack; and the quietest shape is neither — a 'state' that is a primitive, or an object naming no resource type, reads as 'undefined' and is carried or reported as if it were a record. It refuses rather than pick one of those outcomes.`, "Repair the record by hand rather than deleting it — it is the only record that an earlier failed deploy left its resource live in AWS.", ORPHANS_DROP_CAVEAT);
|
|
25659
|
+
}
|
|
25660
|
+
/** The DESTROY text {@link refuseMalformedOrphanRecordsForDestroy} raises. */
|
|
25661
|
+
function malformedOrphanRecordsForDestroyRefusalMessage(rawStackName, rawRegion, logicalIds, recovery) {
|
|
25662
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
25663
|
+
const region = absentIfEmpty(rawRegion);
|
|
25664
|
+
return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read — ${namedOrphanRows(logicalIds)} — because the record has no string 'logicalId' or shares it with another row, or its 'state' is not an object, names no resource type, has no non-empty string 'physicalId', or holds a 'properties' or 'attributes' map that is not an object. This command DELETES state, and the record is the only evidence that those resources are live in AWS — so it refuses over any part of a row it cannot read rather than removing evidence it could not fully report. What the DAMAGE costs the report depends on which part is torn: the listing that tells you which resources stop being tracked prints the row's own 'logicalId', resource type and physical id, from fields nothing else validates, so it can abort before the confirmation naming nothing, or print a row with a field missing and let you approve the delete. A torn 'properties' or 'attributes' map the listing never reads is refused too, because what is discarded is the whole record. So are rows sharing one 'logicalId', though the listing would print each: no cdkd command writes such a record — the rollback save merges by id and every other save carries the list unchanged — so it was damaged or edited by hand, and deleting it would discard it before anyone decides which of those resources the stack still owns.`, "Repair the record by hand rather than deleting it — it is the only record that an earlier failed deploy left its resource live in AWS.", ORPHANS_DROP_CAVEAT);
|
|
25665
|
+
}
|
|
25666
|
+
/**
|
|
25667
|
+
* The READ-ONLY disposition for the same rows: DROP them and return their
|
|
25668
|
+
* names, for a command that never writes the record back — `cdkd scrub
|
|
25669
|
+
* --dry-run` today.
|
|
25670
|
+
*
|
|
25671
|
+
* Returns the dropped names rather than a boolean because its caller reports
|
|
25672
|
+
* them: `cdkd scrub --dry-run` warns with them by name, and the stack joins the
|
|
25673
|
+
* audited-record refusal's list. `cdkd diff` does NOT call this — it needs the
|
|
25674
|
+
* narrower {@link isPreviewableOrphanRecord} and keeps the survivors itself. An
|
|
25675
|
+
* empty return means nothing was dropped and the list is untouched.
|
|
25676
|
+
*/
|
|
25677
|
+
function repairMalformedOrphanRecordsForReadOnly(state) {
|
|
25678
|
+
const unreadable = unreadableOrphanRecords(state);
|
|
25679
|
+
if (unreadable.length === 0) return [];
|
|
25680
|
+
const rows = state.orphans ?? [];
|
|
25681
|
+
const shared = sharedOrphanLogicalIds(rows);
|
|
25682
|
+
state.orphans = rows.filter((record) => !isUnusableOrphanRow(record, shared));
|
|
25683
|
+
return unreadable;
|
|
25335
25684
|
}
|
|
25336
25685
|
/**
|
|
25337
25686
|
* For `cdkd orphan`: refuse a record whose `orphans` list, or any record in
|
|
@@ -25355,6 +25704,87 @@ function refuseMalformedOrphansForOrphan(state, stackName, region, recovery) {
|
|
|
25355
25704
|
if (unreadable.length === 0) return;
|
|
25356
25705
|
throw new CdkdError(malformedOrphansForOrphanRefusalMessage(stackName, region, unreadable, recovery), STATE_RESOURCES_MALFORMED);
|
|
25357
25706
|
}
|
|
25707
|
+
/**
|
|
25708
|
+
* The `--fail` / exit-3 reason `cdkd diff` reports for an `orphans` row it KEEPS
|
|
25709
|
+
* in the preview and `cdkd deploy` REFUSES (go-to-k/cdkd#3641 maintainer review,
|
|
25710
|
+
* M1).
|
|
25711
|
+
*
|
|
25712
|
+
* The two predicates disagree on exactly one class — a row whose `properties` or
|
|
25713
|
+
* `attributes` map is torn — and that disagreement is deliberate: `cdkd diff`
|
|
25714
|
+
* keeps such a row so the second `properties` repair can name it. What was
|
|
25715
|
+
* missing is the OTHER half of keeping it: the deploy refuses the whole record
|
|
25716
|
+
* over that same row, so a preview that says nothing lets `cdkd diff --fail`
|
|
25717
|
+
* exit 0 and the deploy the operator runs next refuse. That is the contract
|
|
25718
|
+
* `cdkd diff` states for the adoption preview, and this PR is what made it
|
|
25719
|
+
* false. Precisely which shapes: a torn `attributes` map, and a torn `properties`
|
|
25720
|
+
* map on a row the adoption did NOT take — an ADOPTED torn-`properties` row was
|
|
25721
|
+
* already refused at deploy through `calculateDiff` before this lane
|
|
25722
|
+
* (go-to-k/cdkd#3641 item o5), and it is the one the sibling arm reports.
|
|
25723
|
+
*
|
|
25724
|
+
* Homed HERE rather than in `diff-recursive.ts` for the reason every text in
|
|
25725
|
+
* this module is: it renders untrusted logical ids, so it needs
|
|
25726
|
+
* {@link namedOrphanRows} — the same cap, the same `displayLogicalId`, the same
|
|
25727
|
+
* `UNRENDERABLE` stand-in. It NAMES the rows as well as counting them, unlike
|
|
25728
|
+
* {@link deployRefusesPropertiesReason}'s count-only line in that file. It keeps
|
|
25729
|
+
* the names even though {@link malformedOrphanRowsKeptWarning} now names them
|
|
25730
|
+
* too: this reason ships in the `--json` payload, where "see the warning above"
|
|
25731
|
+
* has no referent — the same argument that sibling's doc makes for its own
|
|
25732
|
+
* shape.
|
|
25733
|
+
*/
|
|
25734
|
+
function deployRefusesOrphanRowsReason(logicalIds) {
|
|
25735
|
+
return `${logicalIds.length} rollback-orphan record(s) in 'orphans' — ${namedOrphanRows(logicalIds)} — carry a 'properties' or 'attributes' map that cannot be read. This preview KEEPS them, so any adoption shown for them is one 'cdkd deploy' will not perform: it refuses the record over the same rows, and the deploy this previews will not start.`;
|
|
25736
|
+
}
|
|
25737
|
+
/**
|
|
25738
|
+
* The WARNING `cdkd diff` prints for an `orphans` row it KEEPS and a writer
|
|
25739
|
+
* refuses (go-to-k/cdkd#3641 maintainer round 2, M1 continued).
|
|
25740
|
+
*
|
|
25741
|
+
* At every node the RUN REACHES with an adoption preview, which is narrower than
|
|
25742
|
+
* "every node" and the difference is not pedantry (round 4): a non-recursive run —
|
|
25743
|
+
* the default — returns before visiting any child, a state-only child being
|
|
25744
|
+
* DELETED is built with no `previewOrphanAdoption` so the whole row pass is
|
|
25745
|
+
* skipped, and any other caller omitting that option skips it too.
|
|
25746
|
+
*
|
|
25747
|
+
* The exit-3 reason beside this one is TOP-LEVEL only, which is
|
|
25748
|
+
* go-to-k/cdkd#3335's scope decision and right: the deploy skips an unchanged
|
|
25749
|
+
* nested-stack row, so a reason there would report a refusal over a deploy that
|
|
25750
|
+
* succeeds. What made that split SAFE for every other class is that each one
|
|
25751
|
+
* still warns at every node — and this class had no warning at all, because the
|
|
25752
|
+
* row is KEPT and {@link malformedOrphanRecordsWarning} speaks only for rows that
|
|
25753
|
+
* were DROPPED. So a changed nested child holding such a row printed nothing and
|
|
25754
|
+
* its deploy refused.
|
|
25755
|
+
*
|
|
25756
|
+
* It says what the row IS and what the deploy will do, and makes no claim about
|
|
25757
|
+
* what else happens to the row — which is where the first two spellings went
|
|
25758
|
+
* wrong (go-to-k/cdkd#3641 rounds 3 and 4). One said the map "is repaired and
|
|
25759
|
+
* named again over the records an adoption takes", false for every row that
|
|
25760
|
+
* survives the caller's subtraction; the next said nothing else repairs or
|
|
25761
|
+
* previews these rows, false for an ADOPTED row whose `properties` are healthy and
|
|
25762
|
+
* whose `attributes` are torn — the subtraction removes adopted torn-`properties`
|
|
25763
|
+
* names, not every adopted row, and `planOrphanAdoption` rebuilds that row's
|
|
25764
|
+
* attributes and previews the adopted resource. The row's disposition beyond
|
|
25765
|
+
* "kept" is the caller's business, not this sentence's.
|
|
25766
|
+
*
|
|
25767
|
+
* It says the deploy of THIS stack refuses, not that "the deploy this previews"
|
|
25768
|
+
* will not start (round 4 again): under `--recursive` this warning can name a row
|
|
25769
|
+
* in an UNCHANGED nested child, whose parent deploy skips that child and
|
|
25770
|
+
* succeeds. The stack the message already names is the one whose deploy refuses.
|
|
25771
|
+
*/
|
|
25772
|
+
function malformedOrphanRowsKeptWarning(rawStackName, rawRegion, logicalIds) {
|
|
25773
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
25774
|
+
const region = absentIfEmpty(rawRegion);
|
|
25775
|
+
return `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' — ${namedOrphanRows(logicalIds)} — whose 'properties' or 'attributes' map is not an object. This preview KEEPS them. 'cdkd deploy' of THIS stack does NOT: it refuses the whole record over these rows and will not start until they are repaired. See the stored values with: ` + inspectCommand(stackName, region);
|
|
25776
|
+
}
|
|
25777
|
+
/**
|
|
25778
|
+
* The `<ids> and N more` fragment every `orphans` ROW text shares — the three
|
|
25779
|
+
* refusals and the warning — so a fifth cannot spell the cap differently
|
|
25780
|
+
* (go-to-k/cdkd#3500). Derive the list with
|
|
25781
|
+
* `grep -n "namedOrphanRows(" src/state/malformed-resources-bag.ts`.
|
|
25782
|
+
*/
|
|
25783
|
+
function namedOrphanRows(logicalIds) {
|
|
25784
|
+
const named = logicalIds.slice(0, NAMED_UNREADABLE_ENTRIES).map((id) => displayLogicalId(id)).join(", ");
|
|
25785
|
+
const rest = logicalIds.length - NAMED_UNREADABLE_ENTRIES;
|
|
25786
|
+
return `${named}${rest > 0 ? ` and ${rest} more` : ""}`;
|
|
25787
|
+
}
|
|
25358
25788
|
/** See {@link orphanRefusal}'s `dropCaveat`. */
|
|
25359
25789
|
const ORPHANS_DROP_CAVEAT = "; it also discards the 'orphans' list, the only record of resources an earlier failed deploy left live in AWS";
|
|
25360
25790
|
/**
|
|
@@ -25371,10 +25801,7 @@ function malformedOrphansForOrphanRefusalMessage(rawStackName, rawRegion, logica
|
|
|
25371
25801
|
const region = absentIfEmpty(rawRegion);
|
|
25372
25802
|
const verbatim = "'cdkd orphan' carries it into the record it saves VERBATIM, without reading it, so it refuses rather than continuing — under '--dry-run' too, so a dry run never prints a plan the real run refuses.";
|
|
25373
25803
|
if (logicalIds === void 0) return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} has no readable 'orphans' list — the record is malformed or truncated. ${verbatim} The next 'cdkd deploy' refuses the same record, so continuing would only report success over it and leave that refusal one command later.`, "'cdkd orphan' cannot address this list at all, and rewriting it to [] by hand discards the only record of resources an earlier failed deploy left live in AWS.", ORPHANS_DROP_CAVEAT);
|
|
25374
|
-
|
|
25375
|
-
const rest = logicalIds.length - NAMED_UNREADABLE_ENTRIES;
|
|
25376
|
-
const more = rest > 0 ? ` and ${rest} more` : "";
|
|
25377
|
-
return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read — ${named}${more} — because the record has no string 'logicalId', its 'state' is not an object or names no resource type, or that state's 'properties' or 'attributes' map is not one. The record is malformed or truncated. ${verbatim} Those records are not inert: they are what the next 'cdkd deploy' may re-adopt into 'resources' and what 'cdkd diff' previews for adoption, so continuing would report success over damage the next command meets.`, "'cdkd orphan' cannot remove such a record itself: it is not in 'resources', so it has no construct path. Repair the record by hand rather than deleting it — it is the only record that an earlier failed deploy left its resource live in AWS.", ORPHANS_DROP_CAVEAT);
|
|
25804
|
+
return orphanRefusal(stackName, region, recovery, `${stackClause(stackName, region)} holds ${logicalIds.length} rollback-orphan record(s) in 'orphans' that cannot be read — ${namedOrphanRows(logicalIds)} — because the record has no string 'logicalId' or shares it with another row, or its 'state' is not an object, names no resource type, has no non-empty string 'physicalId', or holds a 'properties' or 'attributes' map that is not an object. The record is malformed or truncated. ${verbatim} Those records are not inert: they are what the next 'cdkd deploy' may re-adopt into 'resources' and what 'cdkd diff' previews for adoption, so continuing would report success over damage the next command meets.`, "'cdkd orphan' cannot remove such a record itself: it is not in 'resources', so it has no construct path. Repair the record by hand rather than deleting it — it is the only record that an earlier failed deploy left its resource live in AWS.", ORPHANS_DROP_CAVEAT);
|
|
25378
25805
|
}
|
|
25379
25806
|
|
|
25380
25807
|
//#endregion
|
|
@@ -25429,6 +25856,21 @@ const INTRINSIC_KEYS = /* @__PURE__ */ new Set([
|
|
|
25429
25856
|
*/
|
|
25430
25857
|
const IN_PLACE_UPDATE_DERIVED_ATTRS = Object.freeze({ "AWS::EC2::LaunchTemplate": /* @__PURE__ */ new Set(["LatestVersionNumber", "DefaultVersionNumber"]) });
|
|
25431
25858
|
/**
|
|
25859
|
+
* The PREFIX twin of {@link IN_PLACE_UPDATE_DERIVED_ATTRS}, for a type whose
|
|
25860
|
+
* derived attributes are an open family rather than a fixed list (issue
|
|
25861
|
+
* [#3631](https://github.com/go-to-k/cdkd/issues/3631)).
|
|
25862
|
+
*
|
|
25863
|
+
* A nested stack's `Outputs.<Key>` attributes are the child's outputs, and a
|
|
25864
|
+
* child-only change moves them while the parent's `AWS::CloudFormation::Stack`
|
|
25865
|
+
* row changes only `TemplateURL` / `Parameters`. The parent's diff runs BEFORE
|
|
25866
|
+
* the child deploys, so a reader of `Fn::GetAtt [Child, 'Outputs.<Key>']`
|
|
25867
|
+
* resolves against the PREVIOUS value and diffs NO_CHANGE. Which outputs move
|
|
25868
|
+
* is decided by the child's own deploy, so it is not knowable here: every
|
|
25869
|
+
* reader is promoted, and the deploy engine's re-resolve-and-skip drops the
|
|
25870
|
+
* ones whose output did not move.
|
|
25871
|
+
*/
|
|
25872
|
+
const IN_PLACE_UPDATE_DERIVED_ATTR_PREFIXES = Object.freeze({ "AWS::CloudFormation::Stack": Object.freeze(["Outputs."]) });
|
|
25873
|
+
/**
|
|
25432
25874
|
* Diff calculator for comparing desired state (template) with current state
|
|
25433
25875
|
*/
|
|
25434
25876
|
var DiffCalculator = class DiffCalculator {
|
|
@@ -25464,6 +25906,7 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25464
25906
|
*/
|
|
25465
25907
|
async calculateDiff(currentState, desiredTemplate, resolveFn, canonicalizeProperties, allowedUnsupportedProperties) {
|
|
25466
25908
|
const changes = /* @__PURE__ */ new Map();
|
|
25909
|
+
refuseMalformedResourceEntriesForDeploy(currentState, void 0, void 0);
|
|
25467
25910
|
refuseMalformedResourceProperties(currentState, void 0, void 0);
|
|
25468
25911
|
const currentResources = currentState.resources;
|
|
25469
25912
|
const desiredResources = desiredTemplate.Resources;
|
|
@@ -25558,8 +26001,11 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25558
26001
|
});
|
|
25559
26002
|
this.logger.debug(`DELETE: ${logicalId} (${currentResource.resourceType})`);
|
|
25560
26003
|
}
|
|
25561
|
-
|
|
25562
|
-
|
|
26004
|
+
let round = 0;
|
|
26005
|
+
do {
|
|
26006
|
+
round++;
|
|
26007
|
+
this.promoteReplacementDependents(changes, desiredTemplate);
|
|
26008
|
+
} while (this.promoteInPlaceAttributeDependents(changes, desiredTemplate, rawGetAttRefs, currentResources, round));
|
|
25563
26009
|
const summary = this.getSummary(changes);
|
|
25564
26010
|
this.logger.debug(`Diff calculated: ${summary.create} CREATE, ${summary.update} UPDATE, ${summary.delete} DELETE, ${summary.noChange} NO_CHANGE`);
|
|
25565
26011
|
return changes;
|
|
@@ -25671,7 +26117,11 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25671
26117
|
* update side-effects even though it is not a template property — the
|
|
25672
26118
|
* per-type {@link IN_PLACE_UPDATE_DERIVED_ATTRS} allow list (issue #985;
|
|
25673
26119
|
* e.g. `AWS::EC2::LaunchTemplate.LatestVersionNumber`, which an
|
|
25674
|
-
* `autoscaling.AutoScalingGroup` reads for its `LaunchTemplate.Version`)
|
|
26120
|
+
* `autoscaling.AutoScalingGroup` reads for its `LaunchTemplate.Version`);
|
|
26121
|
+
* or
|
|
26122
|
+
* 3. `Attr` starts with a derived-attribute PREFIX of `Up`'s type — the
|
|
26123
|
+
* {@link IN_PLACE_UPDATE_DERIVED_ATTR_PREFIXES} table (issue #3631; a
|
|
26124
|
+
* nested stack's `Outputs.<Key>`).
|
|
25675
26125
|
* (`Ref` resolves to the physical id, which an in-place update never moves, so
|
|
25676
26126
|
* Ref-only dependents are left NO_CHANGE; likewise a GetAtt of a computed
|
|
25677
26127
|
* attribute NOT in the allow list, e.g. a Lambda `Arn` on a Description edit.)
|
|
@@ -25680,14 +26130,25 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25680
26130
|
* promoted resource against the in-flight state and skips the provider call
|
|
25681
26131
|
* when nothing actually changed.
|
|
25682
26132
|
*
|
|
25683
|
-
*
|
|
25684
|
-
*
|
|
25685
|
-
*
|
|
25686
|
-
*
|
|
25687
|
-
*
|
|
25688
|
-
*
|
|
25689
|
-
|
|
25690
|
-
|
|
26133
|
+
* One pass is single-hop: `changedPropsByUpstream` is frozen at entry, so a
|
|
26134
|
+
* chain `A(in-place) -> B(reads A's changed attr) -> C(reads B's now-changed
|
|
26135
|
+
* attr)` promotes B but not C. `calculateDiff` re-runs it to a fixpoint, and
|
|
26136
|
+
* the pass after B's promotion sees B as an in-place UPDATE.
|
|
26137
|
+
*
|
|
26138
|
+
* A SPECULATIVE promotion — arm 3 in any round, and every arm after the first
|
|
26139
|
+
* round, whose upstreams exist only because an earlier promotion guessed —
|
|
26140
|
+
* skips a dependent that reads a MASKED attribute anywhere
|
|
26141
|
+
* ({@link readsMaskedAttribute}). The engine resolves the dependent's whole
|
|
26142
|
+
* bag and refuses a read of `***` BEFORE its no-change skip, so such a guess
|
|
26143
|
+
* would fail a deploy that left the dependent alone before this pass could
|
|
26144
|
+
* reach it (go-to-k/cdkd#3662). The first round's arms 1 and 2 keep their
|
|
26145
|
+
* behaviour: a property they match really changed.
|
|
26146
|
+
*
|
|
26147
|
+
* @param round 1-based fixpoint round; see the speculative-promotion note.
|
|
26148
|
+
* @returns whether any synthetic PropertyChange was added (the caller's
|
|
26149
|
+
* fixpoint signal).
|
|
26150
|
+
*/
|
|
26151
|
+
promoteInPlaceAttributeDependents(changes, desiredTemplate, rawGetAttRefs, currentResources, round) {
|
|
25691
26152
|
const changedPropsByUpstream = /* @__PURE__ */ new Map();
|
|
25692
26153
|
const inPlaceUpdateTypeByUpstream = /* @__PURE__ */ new Map();
|
|
25693
26154
|
for (const [logicalId, change] of changes) {
|
|
@@ -25697,7 +26158,8 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25697
26158
|
const props = propertyChanges.map((pc) => pc.path).filter((p) => typeof p === "string");
|
|
25698
26159
|
if (props.length > 0) changedPropsByUpstream.set(logicalId, new Set(props));
|
|
25699
26160
|
}
|
|
25700
|
-
if (changedPropsByUpstream.size === 0 && inPlaceUpdateTypeByUpstream.size === 0) return;
|
|
26161
|
+
if (changedPropsByUpstream.size === 0 && inPlaceUpdateTypeByUpstream.size === 0) return false;
|
|
26162
|
+
let added = false;
|
|
25701
26163
|
for (const [dependentId, perProp] of rawGetAttRefs) {
|
|
25702
26164
|
const resource = desiredTemplate.Resources[dependentId];
|
|
25703
26165
|
if (!resource || resource.Type === "AWS::CDK::Metadata") continue;
|
|
@@ -25706,22 +26168,29 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25706
26168
|
if (change.changeType !== "NO_CHANGE" && change.changeType !== "UPDATE") continue;
|
|
25707
26169
|
const existingPaths = new Set((change.propertyChanges ?? []).map((pc) => pc.path));
|
|
25708
26170
|
const syntheticChanges = [];
|
|
26171
|
+
const speculationAllowed = !DiffCalculator.readsMaskedAttribute(perProp, currentResources);
|
|
25709
26172
|
for (const [propKey, getAttRefs] of perProp) {
|
|
25710
26173
|
if (existingPaths.has(propKey)) continue;
|
|
25711
26174
|
let matched = false;
|
|
25712
26175
|
for (const [upstreamId, attrs] of getAttRefs) {
|
|
25713
26176
|
if (upstreamId === dependentId) continue;
|
|
26177
|
+
if (round > 1 && !speculationAllowed) break;
|
|
25714
26178
|
const changedProps = changedPropsByUpstream.get(upstreamId);
|
|
25715
26179
|
if (changedProps && [...attrs].some((attr) => changedProps.has(attr))) {
|
|
25716
26180
|
matched = true;
|
|
25717
26181
|
break;
|
|
25718
26182
|
}
|
|
25719
26183
|
const upstreamType = inPlaceUpdateTypeByUpstream.get(upstreamId);
|
|
25720
|
-
const derivedAttrs = upstreamType ? IN_PLACE_UPDATE_DERIVED_ATTRS[upstreamType] : void 0;
|
|
26184
|
+
const derivedAttrs = upstreamType !== void 0 && Object.hasOwn(IN_PLACE_UPDATE_DERIVED_ATTRS, upstreamType) ? IN_PLACE_UPDATE_DERIVED_ATTRS[upstreamType] : void 0;
|
|
25721
26185
|
if (derivedAttrs && [...attrs].some((attr) => derivedAttrs.has(attr))) {
|
|
25722
26186
|
matched = true;
|
|
25723
26187
|
break;
|
|
25724
26188
|
}
|
|
26189
|
+
const derivedPrefixes = upstreamType !== void 0 && Object.hasOwn(IN_PLACE_UPDATE_DERIVED_ATTR_PREFIXES, upstreamType) ? IN_PLACE_UPDATE_DERIVED_ATTR_PREFIXES[upstreamType] : void 0;
|
|
26190
|
+
if (speculationAllowed && derivedPrefixes && [...attrs].some((attr) => derivedPrefixes.some((prefix) => attr.startsWith(prefix)))) {
|
|
26191
|
+
matched = true;
|
|
26192
|
+
break;
|
|
26193
|
+
}
|
|
25725
26194
|
}
|
|
25726
26195
|
if (!matched) continue;
|
|
25727
26196
|
syntheticChanges.push({
|
|
@@ -25732,12 +26201,51 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25732
26201
|
});
|
|
25733
26202
|
}
|
|
25734
26203
|
if (syntheticChanges.length === 0) continue;
|
|
26204
|
+
added = true;
|
|
25735
26205
|
if (change.changeType === "NO_CHANGE") {
|
|
25736
26206
|
change.changeType = "UPDATE";
|
|
25737
26207
|
change.propertyChanges = syntheticChanges;
|
|
25738
26208
|
this.logger.debug(`UPDATE (in-place attr propagated): ${dependentId} reads a changed attribute of an updated resource`);
|
|
25739
26209
|
} else change.propertyChanges = [...change.propertyChanges ?? [], ...syntheticChanges];
|
|
25740
26210
|
}
|
|
26211
|
+
return added;
|
|
26212
|
+
}
|
|
26213
|
+
/**
|
|
26214
|
+
* Whether any `Fn::GetAtt` / `Fn::Sub` read of a dependent (its
|
|
26215
|
+
* {@link extractGetAttRefs} map, every property and every upstream) lands on
|
|
26216
|
+
* a PERSISTED attribute carrying the redaction mask. The attribute is found
|
|
26217
|
+
* the way the resolver finds it: the flat key, else the dot-separated path
|
|
26218
|
+
* walked through nested objects (a Cloud Control record's
|
|
26219
|
+
* `Endpoint.Address`).
|
|
26220
|
+
*
|
|
26221
|
+
* What it cannot see, and the engine still refuses on a speculative
|
|
26222
|
+
* promotion: a masked cross-stack read (`Fn::ImportValue` /
|
|
26223
|
+
* `Fn::GetStackOutput`), whose producer record is another stack's, and a
|
|
26224
|
+
* `Ref` whose state-key lookup lands on a masked property, since `Ref`
|
|
26225
|
+
* reads are not extracted.
|
|
26226
|
+
*/
|
|
26227
|
+
static readsMaskedAttribute(perProp, currentResources) {
|
|
26228
|
+
for (const getAttRefs of perProp.values()) for (const [upstreamId, attrs] of getAttRefs) {
|
|
26229
|
+
const attributes = Object.hasOwn(currentResources, upstreamId) ? currentResources[upstreamId]?.attributes : void 0;
|
|
26230
|
+
if (!attributes) continue;
|
|
26231
|
+
for (const attr of attrs) if (carriesSecretMask(DiffCalculator.persistedAttribute(attributes, attr))) return true;
|
|
26232
|
+
}
|
|
26233
|
+
return false;
|
|
26234
|
+
}
|
|
26235
|
+
/**
|
|
26236
|
+
* A persisted attribute by the resolver's lookup rule: the own flat key, else
|
|
26237
|
+
* the dot-separated path through own keys of nested objects; `undefined`
|
|
26238
|
+
* when neither exists.
|
|
26239
|
+
*/
|
|
26240
|
+
static persistedAttribute(attributes, attr) {
|
|
26241
|
+
if (Object.hasOwn(attributes, attr)) return attributes[attr];
|
|
26242
|
+
if (!attr.includes(".")) return void 0;
|
|
26243
|
+
let cursor = attributes;
|
|
26244
|
+
for (const part of attr.split(".")) {
|
|
26245
|
+
if (cursor === null || typeof cursor !== "object" || !Object.hasOwn(cursor, part)) return;
|
|
26246
|
+
cursor = cursor[part];
|
|
26247
|
+
}
|
|
26248
|
+
return cursor;
|
|
25741
26249
|
}
|
|
25742
26250
|
/**
|
|
25743
26251
|
* Extract `Fn::GetAtt` / `Fn::Sub`-`${X.Attr}` references from a property value
|
|
@@ -25767,6 +26275,10 @@ var DiffCalculator = class DiffCalculator {
|
|
|
25767
26275
|
if ("Fn::GetAtt" in obj) {
|
|
25768
26276
|
const ga = obj["Fn::GetAtt"];
|
|
25769
26277
|
if (Array.isArray(ga) && typeof ga[0] === "string" && typeof ga[1] === "string") add(ga[0], ga[1]);
|
|
26278
|
+
else if (typeof ga === "string") {
|
|
26279
|
+
const split = splitGetAttStringForm(ga);
|
|
26280
|
+
if (split) add(split.logicalId, split.attributeName);
|
|
26281
|
+
}
|
|
25770
26282
|
return;
|
|
25771
26283
|
}
|
|
25772
26284
|
if ("Fn::Sub" in obj) {
|
|
@@ -26148,7 +26660,8 @@ function applyCallerIdentityCredentials(env) {
|
|
|
26148
26660
|
//#endregion
|
|
26149
26661
|
//#region src/utils/role-arn.ts
|
|
26150
26662
|
/**
|
|
26151
|
-
* Process-lifetime cache of assumed credentials keyed by RoleArn
|
|
26663
|
+
* Process-lifetime cache of assumed credentials keyed by RoleArn AND the
|
|
26664
|
+
* SOURCE identity the `sts:AssumeRole` hop runs as.
|
|
26152
26665
|
*
|
|
26153
26666
|
* Storing the in-flight `Promise` (rather than the resolved value) collapses
|
|
26154
26667
|
* concurrent first-time callers into a single `sts:AssumeRole` request. After
|
|
@@ -26156,10 +26669,19 @@ function applyCallerIdentityCredentials(env) {
|
|
|
26156
26669
|
* stack that references the same producer N times via `Fn::GetStackOutput`
|
|
26157
26670
|
* only pays the STS hop once.
|
|
26158
26671
|
*
|
|
26159
|
-
*
|
|
26160
|
-
* credentials
|
|
26161
|
-
*
|
|
26162
|
-
*
|
|
26672
|
+
* Not keyed by region, because STS credentials are global — assumed
|
|
26673
|
+
* credentials work against any region's service endpoint. The downstream S3
|
|
26674
|
+
* client built from these credentials picks its own region via
|
|
26675
|
+
* `GetBucketLocation`.
|
|
26676
|
+
*
|
|
26677
|
+
* KEYED BY THE SOURCE IDENTITY TOO (issue
|
|
26678
|
+
* [#3588](https://github.com/go-to-k/cdkd/issues/3588)): the hop runs as the
|
|
26679
|
+
* ACTIVE `AwsClients`' credential configuration, and a library caller can
|
|
26680
|
+
* install (`setAwsClients`) two different explicit credentials in one process,
|
|
26681
|
+
* as can cdkd's own per-stack scopes. Keyed by RoleArn alone, the second would be handed
|
|
26682
|
+
* credentials the FIRST identity obtained — a role the second one may not even
|
|
26683
|
+
* be trusted to assume. The source half is `credentialFingerprint`'s (profile +
|
|
26684
|
+
* access key id, never secret material).
|
|
26163
26685
|
*
|
|
26164
26686
|
* **Expiration handling**: on every cache hit, the cached credentials'
|
|
26165
26687
|
* `expiration` is compared against `Date.now()` with a 60-second safety
|
|
@@ -26219,7 +26741,7 @@ function parseIamRoleArn(roleArn) {
|
|
|
26219
26741
|
* the consumer account's normal credentials). Threading the credentials
|
|
26220
26742
|
* through a fresh `S3Client` via this helper keeps the scope narrow.
|
|
26221
26743
|
*
|
|
26222
|
-
* **Why cache per
|
|
26744
|
+
* **Why cache per RoleArn (and source identity) for the process lifetime.** A multi-resource
|
|
26223
26745
|
* stack typically references `Fn::GetStackOutput` from many template sites
|
|
26224
26746
|
* (every IAM policy / Lambda env / ALB listener that pulls a shared VPC ID
|
|
26225
26747
|
* from a platform stack). Assuming the role once per deploy is sufficient;
|
|
@@ -26242,17 +26764,19 @@ function parseIamRoleArn(roleArn) {
|
|
|
26242
26764
|
* uniformly), but the next caller after rejection gets a clean slate.
|
|
26243
26765
|
*/
|
|
26244
26766
|
async function assumeRoleForCrossAccountStateRead(roleArn) {
|
|
26245
|
-
const
|
|
26767
|
+
const sourceConfig = ambientCredentialConfig();
|
|
26768
|
+
const cacheKey = JSON.stringify([credentialFingerprint(sourceConfig), roleArn]);
|
|
26769
|
+
const cached = crossAccountCredentialsCache.get(cacheKey);
|
|
26246
26770
|
if (cached) {
|
|
26247
26771
|
const cachedCreds = await cached;
|
|
26248
26772
|
if (!cachedCreds.expiration || Date.now() < cachedCreds.expiration.getTime() - CRED_EXPIRY_SAFETY_MS) return cachedCreds;
|
|
26249
|
-
crossAccountCredentialsCache.delete(
|
|
26773
|
+
crossAccountCredentialsCache.delete(cacheKey);
|
|
26250
26774
|
}
|
|
26251
26775
|
const promise = (async () => {
|
|
26252
26776
|
const logger = getLogger().child("role-arn");
|
|
26253
26777
|
const displayRoleArn = displayIdent(roleArn, { maxCodePoints: 613 });
|
|
26254
26778
|
logger.debug(`Assuming role for cross-account state read: ${displayRoleArn}`);
|
|
26255
|
-
const sts = new STSClient({ ...
|
|
26779
|
+
const sts = new STSClient({ ...clientDefaultsFor(sourceConfig) });
|
|
26256
26780
|
try {
|
|
26257
26781
|
let response;
|
|
26258
26782
|
try {
|
|
@@ -26279,10 +26803,10 @@ async function assumeRoleForCrossAccountStateRead(roleArn) {
|
|
|
26279
26803
|
sts.destroy();
|
|
26280
26804
|
}
|
|
26281
26805
|
})().catch((err) => {
|
|
26282
|
-
if (crossAccountCredentialsCache.get(
|
|
26806
|
+
if (crossAccountCredentialsCache.get(cacheKey) === promise) crossAccountCredentialsCache.delete(cacheKey);
|
|
26283
26807
|
throw err;
|
|
26284
26808
|
});
|
|
26285
|
-
crossAccountCredentialsCache.set(
|
|
26809
|
+
crossAccountCredentialsCache.set(cacheKey, promise);
|
|
26286
26810
|
return promise;
|
|
26287
26811
|
}
|
|
26288
26812
|
/**
|
|
@@ -28179,7 +28703,7 @@ var WAFv2WebACLProvider = class {
|
|
|
28179
28703
|
])]]);
|
|
28180
28704
|
getClient() {
|
|
28181
28705
|
if (!this.wafv2Client) this.wafv2Client = new WAFV2Client({
|
|
28182
|
-
...
|
|
28706
|
+
...ambientClientDefaults(),
|
|
28183
28707
|
...this.providerRegion ? { region: this.providerRegion } : {}
|
|
28184
28708
|
});
|
|
28185
28709
|
return this.wafv2Client;
|
|
@@ -29603,6 +30127,18 @@ async function allSettledKeepingFirstRejection(promises, onAbandoned) {
|
|
|
29603
30127
|
}
|
|
29604
30128
|
}
|
|
29605
30129
|
/**
|
|
30130
|
+
* The key for the resolver's per-region SDK client caches ({@link
|
|
30131
|
+
* IntrinsicFunctionResolver}'s `cfnClients`, `regionScopedClients` and
|
|
30132
|
+
* `serviceDiscoveryClients`): the region PLUS the credential fingerprint of the
|
|
30133
|
+
* configuration the cached client was built from (issue
|
|
30134
|
+
* [#3588](https://github.com/go-to-k/cdkd/issues/3588)). Encoded through
|
|
30135
|
+
* {@link injectiveKey}, so no region or profile spelling can forge another
|
|
30136
|
+
* pair's key.
|
|
30137
|
+
*/
|
|
30138
|
+
function clientCacheKey(region, credentialConfig) {
|
|
30139
|
+
return injectiveKey(region, credentialFingerprint(credentialConfig));
|
|
30140
|
+
}
|
|
30141
|
+
/**
|
|
29606
30142
|
* Is `region` safe to build an AWS SDK client from?
|
|
29607
30143
|
*
|
|
29608
30144
|
* This is a SECURITY gate, not an AWS region registry, and the distinction
|
|
@@ -30084,15 +30620,22 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
30084
30620
|
* foreign region per resolver, versus the ambient clients which are already
|
|
30085
30621
|
* created and destroyed per stack by `deploy.ts`.
|
|
30086
30622
|
*
|
|
30087
|
-
* KEYED BY REGION
|
|
30088
|
-
*
|
|
30089
|
-
*
|
|
30090
|
-
* is process-wide
|
|
30091
|
-
*
|
|
30092
|
-
*
|
|
30093
|
-
*
|
|
30094
|
-
*
|
|
30095
|
-
*
|
|
30623
|
+
* KEYED BY REGION AND CREDENTIAL FINGERPRINT ({@link clientCacheKey}, issue
|
|
30624
|
+
* [#3588](https://github.com/go-to-k/cdkd/issues/3588)). An entry pins the
|
|
30625
|
+
* credential configuration of the ambient instance it was derived from, and
|
|
30626
|
+
* that half is process-wide only for the CLI (one `--profile`, one
|
|
30627
|
+
* `--role-arn`): a LIBRARY caller can drive one resolver across two
|
|
30628
|
+
* `setAwsClients` installs (or cdkd's per-stack scopes) with different
|
|
30629
|
+
* explicit credentials, and keyed by region alone the second's lookups ran under the first's
|
|
30630
|
+
* identity. {@link cfnClients} and {@link serviceDiscoveryClients} share the
|
|
30631
|
+
* key for the same reason, and the two CloudFormation fallback memos
|
|
30632
|
+
* ({@link cfnExportsPromises}, {@link cfnStackOutputsCache}) carry the
|
|
30633
|
+
* fingerprint too.
|
|
30634
|
+
*
|
|
30635
|
+
* THE CLIENT HALF IS CLOSED, NOT THE WHOLE CLASS: {@link cachedDynamicReferences}
|
|
30636
|
+
* (keyed by the expression alone) and the PROCESS-GLOBAL account identity
|
|
30637
|
+
* behind `getAccountInfo` still assume one identity per resolver and per
|
|
30638
|
+
* process respectively — a value one identity read is served to the next.
|
|
30096
30639
|
*/
|
|
30097
30640
|
regionScopedClients = /* @__PURE__ */ new Map();
|
|
30098
30641
|
/**
|
|
@@ -30159,9 +30702,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
30159
30702
|
/**
|
|
30160
30703
|
* Per-region CloudFormation clients for the cross-stack fallback
|
|
30161
30704
|
* lookups (issue #1697). Keyed by region because `Fn::GetStackOutput`
|
|
30162
|
-
* may target a region different from the consumer's deploy region
|
|
30705
|
+
* may target a region different from the consumer's deploy region, and by
|
|
30706
|
+
* the credential fingerprint for {@link regionScopedClients}' reason.
|
|
30163
30707
|
*/
|
|
30164
|
-
cfnClients =
|
|
30708
|
+
cfnClients = /* @__PURE__ */ new Map();
|
|
30165
30709
|
/**
|
|
30166
30710
|
* Memoized full `ListExports` listing for the `Fn::ImportValue`
|
|
30167
30711
|
* fallback (issue #1697 review). Without it, EVERY cdkd-miss import
|
|
@@ -30173,14 +30717,18 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
30173
30717
|
* deploys. FAILED fetches are not cached (the rejection handler
|
|
30174
30718
|
* clears the slot) so a transient throttle does not poison the rest
|
|
30175
30719
|
* of the deploy's lookups.
|
|
30720
|
+
*
|
|
30721
|
+
* Keyed by the credential fingerprint (issue #3588): a listing is an answer
|
|
30722
|
+
* one identity was allowed to read, so it is never handed to another.
|
|
30176
30723
|
*/
|
|
30177
|
-
|
|
30724
|
+
cfnExportsPromises = /* @__PURE__ */ new Map();
|
|
30178
30725
|
/**
|
|
30179
30726
|
* Memoized per-(region, stack) `DescribeStacks` outputs for the
|
|
30180
30727
|
* `Fn::GetStackOutput` fallback (issue #1697 review) — a stack
|
|
30181
30728
|
* referencing the same CFn producer N times pays one call. Successful
|
|
30182
30729
|
* lookups (including the definitive "stack does not exist" miss) are
|
|
30183
|
-
* cached; lookup FAILURES are evicted so they are retried.
|
|
30730
|
+
* cached; lookup FAILURES are evicted so they are retried. Keyed by the
|
|
30731
|
+
* credential fingerprint as well, for {@link cfnExportsPromises}' reason.
|
|
30184
30732
|
*/
|
|
30185
30733
|
cfnStackOutputsCache = /* @__PURE__ */ new Map();
|
|
30186
30734
|
/**
|
|
@@ -30412,11 +30960,12 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
30412
30960
|
const loggedTarget = targetLogText ?? (targetRegion === this.explicitRegion ? this.explicitRegionLogText : void 0) ?? target;
|
|
30413
30961
|
if (!isClientSafeRegion(target)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to build AWS clients for the region '${displaySafe(stripControlChars(loggedTarget)).slice(0, 64)}': it is not a valid AWS region name, and a region is substituted into the AWS service hostname.`));
|
|
30414
30962
|
if (typeof ambient.withRegion !== "function") return ambient;
|
|
30415
|
-
const
|
|
30963
|
+
const cacheKey = clientCacheKey(target, ambient.credentialConfig ?? {});
|
|
30964
|
+
const cached = this.regionScopedClients.get(cacheKey);
|
|
30416
30965
|
if (cached) return cached;
|
|
30417
30966
|
if (canonicalizeRegion(ambient.configuredRegion) === target) return ambient;
|
|
30418
30967
|
const scoped = ambient.withRegion(target);
|
|
30419
|
-
this.regionScopedClients.set(
|
|
30968
|
+
this.regionScopedClients.set(cacheKey, scoped);
|
|
30420
30969
|
this.logger.debug(`Using region-scoped AWS clients for ${displaySafe(loggedTarget)}`);
|
|
30421
30970
|
return scoped;
|
|
30422
30971
|
}
|
|
@@ -30447,21 +30996,21 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
30447
30996
|
* `getAccountInfo`'s in-flight promise and reach here one at a time, which
|
|
30448
30997
|
* the case says out loud. A REJECTED import is evicted
|
|
30449
30998
|
* so a transient failure does not poison the rest of the deploy, mirroring
|
|
30450
|
-
* `
|
|
30999
|
+
* `cfnExportsPromises`. Lifetime is the resolver's own, like
|
|
30451
31000
|
* {@link regionScopedClients} and {@link cfnClients}: at most one per region
|
|
30452
31001
|
* per resolver, versus the one-per-CALL this replaces.
|
|
30453
31002
|
*/
|
|
30454
31003
|
async serviceDiscoveryClient() {
|
|
30455
31004
|
const scoped = this.clientsForRegion(this.explicitRegion);
|
|
30456
31005
|
const region = scoped.configuredRegion;
|
|
30457
|
-
const
|
|
31006
|
+
const credentialConfig = scoped.credentialConfig ?? {};
|
|
31007
|
+
const key = clientCacheKey(region ?? "", credentialConfig);
|
|
30458
31008
|
const cached = this.serviceDiscoveryClients.get(key);
|
|
30459
31009
|
if (cached) return cached;
|
|
30460
31010
|
const building = (async () => {
|
|
30461
31011
|
const { ServiceDiscoveryClient } = await import("@aws-sdk/client-servicediscovery");
|
|
30462
31012
|
return new ServiceDiscoveryClient({
|
|
30463
|
-
...
|
|
30464
|
-
...scoped.credentialConfig ?? {},
|
|
31013
|
+
...clientDefaultsFor(credentialConfig),
|
|
30465
31014
|
...region ? { region } : {}
|
|
30466
31015
|
});
|
|
30467
31016
|
})();
|
|
@@ -31106,12 +31655,15 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
31106
31655
|
}
|
|
31107
31656
|
if (resource.resourceType === "AWS::Route53::HostedZone" && attributeName === "NameServers" && typeof flatValue === "string") {
|
|
31108
31657
|
const nameServers = flatValue === "" ? [] : flatValue.split(",");
|
|
31658
|
+
const notedNameServers = this.noteAttributeSecrecy(logicalId, attributeName, nameServers, context);
|
|
31109
31659
|
this.logger.debug(`Normalized legacy Fn::GetAtt attribute: ${this.displayMasked(logicalId, context)}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(nameServers, context)), context)}`);
|
|
31110
|
-
return
|
|
31660
|
+
return notedNameServers;
|
|
31111
31661
|
}
|
|
31662
|
+
const reresolvesNestedReference = resource.resourceType === NESTED_STACK_RESOURCE_TYPE$2 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX) && carriesDynamicReference(flatValue);
|
|
31663
|
+
const notedFlatValue = reresolvesNestedReference ? flatValue : this.noteAttributeSecrecy(logicalId, attributeName, flatValue, context);
|
|
31112
31664
|
this.logger.debug(`Resolved Fn::GetAtt from attributes: ${this.displayMasked(logicalId, context)}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(flatValue, context)), context)}`);
|
|
31113
|
-
if (
|
|
31114
|
-
return
|
|
31665
|
+
if (reresolvesNestedReference) return await this.reresolveCrossStackValue(flatValue, nestedStackChildRegionFromLocalArn(resource.physicalId), context, `nested stack ${logicalId} ${this.displayLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
|
|
31666
|
+
return notedFlatValue;
|
|
31115
31667
|
}
|
|
31116
31668
|
if (attributeName.includes(".")) {
|
|
31117
31669
|
const parts = attributeName.split(".");
|
|
@@ -31122,8 +31674,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
31122
31674
|
break;
|
|
31123
31675
|
}
|
|
31124
31676
|
if (cursor !== void 0) {
|
|
31677
|
+
const notedCursor = this.noteAttributeSecrecy(logicalId, attributeName, cursor, context);
|
|
31125
31678
|
this.logger.debug(`Resolved Fn::GetAtt from nested attributes: ${this.displayMasked(logicalId, context)}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(cursor, context)), context)}`);
|
|
31126
|
-
return
|
|
31679
|
+
return notedCursor;
|
|
31127
31680
|
}
|
|
31128
31681
|
}
|
|
31129
31682
|
}
|
|
@@ -31182,6 +31735,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
31182
31735
|
*
|
|
31183
31736
|
* A context supplying NEITHER field — the diff / no-op resolver, `cdkd
|
|
31184
31737
|
* scrub`, `cdkd import` — pays two undefined checks and gets its value back.
|
|
31738
|
+
*
|
|
31739
|
+
* ORDERING: call it BEFORE any log line that prints the value
|
|
31740
|
+
* (go-to-k/cdkd#3659). Note 1 is what puts a `NoEcho` value into the bag
|
|
31741
|
+
* `displayMasked` masks against, so a line logged first prints the plaintext
|
|
31742
|
+
* at `--verbose`.
|
|
31185
31743
|
*/
|
|
31186
31744
|
noteAttributeSecrecy(logicalId, attributeName, value, context) {
|
|
31187
31745
|
const declared = context.noEchoAttributeResources?.get(logicalId);
|
|
@@ -31316,8 +31874,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
31316
31874
|
}
|
|
31317
31875
|
/** Serve a value the #1852 heal just read from AWS, logging it like a cached read. */
|
|
31318
31876
|
serveHealedAttribute(logicalId, attributeName, value, context) {
|
|
31877
|
+
const noted = this.noteAttributeSecrecy(logicalId, attributeName, value, context);
|
|
31319
31878
|
this.logger.debug(`Resolved Fn::GetAtt from a re-read of AWS (the state record lacked it): ${this.displayMasked(logicalId, context)}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(value, context)), context)}`);
|
|
31320
|
-
return
|
|
31879
|
+
return noted;
|
|
31321
31880
|
}
|
|
31322
31881
|
/**
|
|
31323
31882
|
* {@link constructGuardedAttribute}, healing a STALE state record first when
|
|
@@ -32857,12 +33416,14 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
32857
33416
|
* the same not-found error anyway.
|
|
32858
33417
|
*/
|
|
32859
33418
|
async lookupCfnExport(exportName, context) {
|
|
32860
|
-
|
|
33419
|
+
const listingKey = credentialFingerprint(ambientCredentialConfig());
|
|
33420
|
+
let listing = this.cfnExportsPromises.get(listingKey);
|
|
32861
33421
|
if (!listing) {
|
|
32862
|
-
|
|
32863
|
-
|
|
32864
|
-
|
|
32865
|
-
|
|
33422
|
+
const fetched = this.fetchAllCfnExports();
|
|
33423
|
+
listing = fetched;
|
|
33424
|
+
this.cfnExportsPromises.set(listingKey, fetched);
|
|
33425
|
+
fetched.catch(() => {
|
|
33426
|
+
if (this.cfnExportsPromises.get(listingKey) === fetched) this.cfnExportsPromises.delete(listingKey);
|
|
32866
33427
|
});
|
|
32867
33428
|
}
|
|
32868
33429
|
try {
|
|
@@ -32932,7 +33493,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
32932
33493
|
* contract as {@link lookupCfnExport}.
|
|
32933
33494
|
*/
|
|
32934
33495
|
async lookupCfnStackOutputs(stackName, region, context, loggedRegionText) {
|
|
32935
|
-
const cacheKey = injectiveKey(region, stackName);
|
|
33496
|
+
const cacheKey = injectiveKey(region, stackName, credentialFingerprint(ambientCredentialConfig()));
|
|
32936
33497
|
let fetch = this.cfnStackOutputsCache.get(cacheKey);
|
|
32937
33498
|
if (!fetch) {
|
|
32938
33499
|
fetch = this.fetchCfnStackOutputs(stackName, region);
|
|
@@ -32983,19 +33544,19 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
|
|
|
32983
33544
|
* Not routed through {@link clientsForRegion}: the region here is always
|
|
32984
33545
|
* the one the caller named, never the ambient's, and a test double without
|
|
32985
33546
|
* `credentialConfig` degrades to the default chain rather than throwing.
|
|
32986
|
-
* Keyed by region
|
|
32987
|
-
*
|
|
33547
|
+
* Keyed by region AND credential fingerprint for the reason
|
|
33548
|
+
* {@link regionScopedClients} gives (issue #3588).
|
|
32988
33549
|
*/
|
|
32989
33550
|
getCfnClient(region) {
|
|
32990
|
-
|
|
33551
|
+
const credentialConfig = ambientCredentialConfig();
|
|
33552
|
+
const key = clientCacheKey(region, credentialConfig);
|
|
33553
|
+
let client = this.cfnClients.get(key);
|
|
32991
33554
|
if (!client) {
|
|
32992
|
-
const credentialConfig = getAwsClients().credentialConfig ?? {};
|
|
32993
33555
|
client = new CloudFormationClient({
|
|
32994
|
-
...
|
|
32995
|
-
...credentialConfig,
|
|
33556
|
+
...clientDefaultsFor(credentialConfig),
|
|
32996
33557
|
region
|
|
32997
33558
|
});
|
|
32998
|
-
this.cfnClients
|
|
33559
|
+
this.cfnClients.set(key, client);
|
|
32999
33560
|
}
|
|
33000
33561
|
return client;
|
|
33001
33562
|
}
|
|
@@ -35272,6 +35833,15 @@ const CC_PROTECTION_PROPERTIES = {
|
|
|
35272
35833
|
function ccProtectionProperty(resourceType) {
|
|
35273
35834
|
return CC_PROTECTION_PROPERTIES[resourceType];
|
|
35274
35835
|
}
|
|
35836
|
+
/**
|
|
35837
|
+
* Every resource type registered in the CC protection registry. Consumed by
|
|
35838
|
+
* the cross-site consistency test that keeps this registry, the destroy
|
|
35839
|
+
* confirm-prompt count map, the `--remove-protection` help strings, and the
|
|
35840
|
+
* docs tables from drifting apart.
|
|
35841
|
+
*/
|
|
35842
|
+
function ccProtectionRegistryTypes() {
|
|
35843
|
+
return Object.keys(CC_PROTECTION_PROPERTIES);
|
|
35844
|
+
}
|
|
35275
35845
|
|
|
35276
35846
|
//#endregion
|
|
35277
35847
|
//#region src/provisioning/unsupported-types.generated.ts
|
|
@@ -36328,7 +36898,7 @@ var CloudControlProvider = class {
|
|
|
36328
36898
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
36329
36899
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
36330
36900
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
36331
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
36901
|
+
const { ASGProvider } = await import("./asg-provider-Dpki2-Xd.js").then((n) => n.n);
|
|
36332
36902
|
const asgProvider = new ASGProvider();
|
|
36333
36903
|
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
36334
36904
|
}
|
|
@@ -36878,7 +37448,7 @@ var CloudControlProvider = class {
|
|
|
36878
37448
|
break;
|
|
36879
37449
|
case "AWS::RDS::DBCluster":
|
|
36880
37450
|
try {
|
|
36881
|
-
const cluster = (await new RDSClient({ ...
|
|
37451
|
+
const cluster = (await new RDSClient({ ...ambientClientDefaults() }).send(new DescribeDBClustersCommand({ DBClusterIdentifier: physicalId }))).DBClusters?.[0];
|
|
36882
37452
|
if (cluster) {
|
|
36883
37453
|
if (cluster.Endpoint) enriched["Endpoint.Address"] = cluster.Endpoint;
|
|
36884
37454
|
if (cluster.Port !== void 0) enriched["Endpoint.Port"] = String(cluster.Port);
|
|
@@ -36893,7 +37463,7 @@ var CloudControlProvider = class {
|
|
|
36893
37463
|
break;
|
|
36894
37464
|
case "AWS::RDS::DBInstance":
|
|
36895
37465
|
try {
|
|
36896
|
-
const inst = (await new RDSClient({ ...
|
|
37466
|
+
const inst = (await new RDSClient({ ...ambientClientDefaults() }).send(new DescribeDBInstancesCommand({ DBInstanceIdentifier: physicalId }))).DBInstances?.[0];
|
|
36897
37467
|
if (inst) {
|
|
36898
37468
|
if (inst.Endpoint?.Address) enriched["Endpoint.Address"] = inst.Endpoint.Address;
|
|
36899
37469
|
if (inst.Endpoint?.Port !== void 0) enriched["Endpoint.Port"] = String(inst.Endpoint.Port);
|
|
@@ -37047,7 +37617,7 @@ var CloudControlProvider = class {
|
|
|
37047
37617
|
break;
|
|
37048
37618
|
case "AWS::ElastiCache::ReplicationGroup":
|
|
37049
37619
|
try {
|
|
37050
|
-
const rg = (await new ElastiCacheClient({ ...
|
|
37620
|
+
const rg = (await new ElastiCacheClient({ ...ambientClientDefaults() }).send(new DescribeReplicationGroupsCommand({ ReplicationGroupId: physicalId }))).ReplicationGroups?.[0];
|
|
37051
37621
|
if (rg) {
|
|
37052
37622
|
const primaryNode = rg.NodeGroups?.[0];
|
|
37053
37623
|
if (primaryNode?.PrimaryEndpoint?.Address) enriched["PrimaryEndPoint.Address"] = primaryNode.PrimaryEndpoint.Address;
|
|
@@ -37069,7 +37639,7 @@ var CloudControlProvider = class {
|
|
|
37069
37639
|
break;
|
|
37070
37640
|
case "AWS::Redshift::Cluster":
|
|
37071
37641
|
try {
|
|
37072
|
-
const cluster = (await new RedshiftClient({ ...
|
|
37642
|
+
const cluster = (await new RedshiftClient({ ...ambientClientDefaults() }).send(new DescribeClustersCommand({ ClusterIdentifier: physicalId }))).Clusters?.[0];
|
|
37073
37643
|
if (cluster?.Endpoint) {
|
|
37074
37644
|
if (cluster.Endpoint.Address) enriched["Endpoint.Address"] = cluster.Endpoint.Address;
|
|
37075
37645
|
if (cluster.Endpoint.Port !== void 0) enriched["Endpoint.Port"] = String(cluster.Endpoint.Port);
|
|
@@ -37081,7 +37651,7 @@ var CloudControlProvider = class {
|
|
|
37081
37651
|
break;
|
|
37082
37652
|
case "AWS::OpenSearchService::Domain":
|
|
37083
37653
|
try {
|
|
37084
|
-
const domain = (await new OpenSearchClient({ ...
|
|
37654
|
+
const domain = (await new OpenSearchClient({ ...ambientClientDefaults() }).send(new DescribeDomainCommand({ DomainName: physicalId }))).DomainStatus;
|
|
37085
37655
|
if (domain) {
|
|
37086
37656
|
const endpoint = domain.Endpoint ?? domain.Endpoints?.["vpc"];
|
|
37087
37657
|
if (endpoint) enriched["DomainEndpoint"] = endpoint;
|
|
@@ -41576,7 +42146,8 @@ var ProviderRegistry = class {
|
|
|
41576
42146
|
provisionedBy: "sdk"
|
|
41577
42147
|
};
|
|
41578
42148
|
}
|
|
41579
|
-
|
|
42149
|
+
const unroutable = this.ccRouteUnavailableReason(resourceType);
|
|
42150
|
+
if (unroutable !== void 0) throw new Error(this.buildUnroutableSilentDropMessage(resourceType, actionableDrops, unroutable));
|
|
41580
42151
|
this.logger.debug(`Auto-routing ${resourceType} via Cloud Control (silent-drop properties: ${actionableDrops.map((d) => d.property).join(", ")})`);
|
|
41581
42152
|
return {
|
|
41582
42153
|
provider: this.cloudControlProvider,
|
|
@@ -41601,19 +42172,29 @@ var ProviderRegistry = class {
|
|
|
41601
42172
|
throw new Error(`No provider available for resource type: ${resourceType}. This resource type is not supported by Cloud Control API and no SDK provider is registered.`);
|
|
41602
42173
|
}
|
|
41603
42174
|
/**
|
|
42175
|
+
* Why the Cloud Control auto-route cannot serve `resourceType`, or
|
|
42176
|
+
* `undefined` when it can. The ONE predicate both refusal sites
|
|
42177
|
+
* (`getProviderFor` and `reportSilentDropDecisions`) and the accepted-drop
|
|
42178
|
+
* warn read, so the warn that predicts what a flag-less deploy does cannot
|
|
42179
|
+
* disagree with the refusal that deploy then hits (issue #2792).
|
|
42180
|
+
*/
|
|
42181
|
+
ccRouteUnavailableReason(resourceType) {
|
|
42182
|
+
if (isNonProvisionable(resourceType)) return "ProvisioningType: NON_PROVISIONABLE — Cloud Control has no handlers for it";
|
|
42183
|
+
if (this.providers.get(resourceType)?.disableCcApiFallback === true) return "the type's SDK provider opts out of the Cloud Control fallback (disableCcApiFallback)";
|
|
42184
|
+
}
|
|
42185
|
+
/**
|
|
41604
42186
|
* Error message for a resource whose template uses SDK-provider-unhandled
|
|
41605
42187
|
* properties on a type where the Cloud Control auto-route (issue #614) is
|
|
41606
42188
|
* NOT viable — `ProvisioningType: NON_PROVISIONABLE` (no CC handlers) or a
|
|
41607
|
-
* provider-level `disableCcApiFallback` opt-out
|
|
42189
|
+
* provider-level `disableCcApiFallback` opt-out; `reason` is
|
|
42190
|
+
* {@link ccRouteUnavailableReason}'s answer. Includes each property's
|
|
41608
42191
|
* `unhandledByDesign` rationale so the user sees WHY it is unhandled, plus
|
|
41609
42192
|
* the `--allow-unsupported-properties` escape hatch (which forces the SDK
|
|
41610
42193
|
* path and accepts the drop — the provider may still reject the resource
|
|
41611
42194
|
* if the property is load-bearing, e.g. a non-Lustre FSx variant config).
|
|
41612
42195
|
*/
|
|
41613
|
-
buildUnroutableSilentDropMessage(resourceType, drops) {
|
|
41614
|
-
|
|
41615
|
-
const overrideHint = drops.map((d) => `${resourceType}:${d.property}`).join(",");
|
|
41616
|
-
return `${resourceType} uses properties cdkd's SDK Provider does not handle, and this type cannot fall back to Cloud Control API (${isNonProvisionable(resourceType) ? "ProvisioningType: NON_PROVISIONABLE — Cloud Control has no handlers for it" : "the type's SDK provider opts out of the Cloud Control fallback (disableCcApiFallback)"}):\n${details}\nRemove the properties, or force the SDK provider path and accept the drop via --prefer-sdk-route ${overrideHint} (the provider may still reject the resource if the property is required).`;
|
|
42196
|
+
buildUnroutableSilentDropMessage(resourceType, drops, reason) {
|
|
42197
|
+
return `${resourceType} uses properties cdkd's SDK Provider does not handle, and this type cannot fall back to Cloud Control API (${reason}):\n${drops.map((d) => ` - ${d.property}: ${d.rationale}`).join("\n")}\nRemove the properties, or force the SDK provider path and accept the drop via --prefer-sdk-route ${drops.map((d) => `${resourceType}:${d.property}`).join(",")} (the provider may still reject the resource if the property is required).`;
|
|
41617
42198
|
}
|
|
41618
42199
|
/**
|
|
41619
42200
|
* Legacy entry point that returns just the provider. Delegates to
|
|
@@ -41795,8 +42376,8 @@ var ProviderRegistry = class {
|
|
|
41795
42376
|
const overridden = stickyCc ? [] : findAcceptedSilentDrops(resourceType, properties, this.allowedUnsupportedProperties);
|
|
41796
42377
|
const autoRouted = drops.map(({ property }) => property).filter((property) => !this.allowedUnsupportedProperties.has(`${resourceType}:${property}`));
|
|
41797
42378
|
if (autoRouted.length > 0) {
|
|
41798
|
-
const
|
|
41799
|
-
if (
|
|
42379
|
+
const unroutable = this.ccRouteUnavailableReason(resourceType);
|
|
42380
|
+
if (unroutable !== void 0) throw new Error(`${logicalId}: ${this.buildUnroutableSilentDropMessage(resourceType, drops.filter((d) => autoRouted.includes(d.property)), unroutable)}`);
|
|
41800
42381
|
const message = `${logicalId} (${resourceType}): routing via Cloud Control API (cdkd's SDK Provider does not yet wire ${autoRouted.join(", ")} — CC API will forward the full property map. Override via --prefer-sdk-route ${autoRouted.map((p) => `${resourceType}:${p}`).join(",")}.)`;
|
|
41801
42382
|
if (provisionedBy === "cc-api") this.logger.debug(message);
|
|
41802
42383
|
else this.logger.info(message);
|
|
@@ -41810,9 +42391,11 @@ var ProviderRegistry = class {
|
|
|
41810
42391
|
}
|
|
41811
42392
|
if (overridden.length > 0) {
|
|
41812
42393
|
const createOnly = getPropertyCoverage(resourceType)?.createOnlyDrops;
|
|
41813
|
-
const
|
|
41814
|
-
const
|
|
42394
|
+
const unroutable = this.ccRouteUnavailableReason(resourceType);
|
|
42395
|
+
const reroutable = unroutable === void 0 ? overridden.filter((p) => createOnly?.has(p) !== true) : [];
|
|
42396
|
+
const needsRecreate = unroutable === void 0 ? overridden.filter((p) => createOnly?.has(p) === true) : [];
|
|
41815
42397
|
const remedies = [];
|
|
42398
|
+
if (unroutable !== void 0) remedies.push(`This type cannot be routed via Cloud Control API (${unroutable}), so removing the override makes the deploy refuse at pre-flight instead of rerouting; cdkd has no route that applies ${overridden.length === 1 ? "it" : "them"} to this type.`);
|
|
41816
42399
|
if (reroutable.length > 0) remedies.push(`Remove the override for ${reroutable.join(", ")} to route this resource via Cloud Control API instead.`);
|
|
41817
42400
|
if (needsRecreate.length > 0) {
|
|
41818
42401
|
const one = needsRecreate.length === 1;
|
|
@@ -44305,8 +44888,11 @@ async function planOrphanAdoption(params) {
|
|
|
44305
44888
|
const claims = async () => siblingClaims ??= await params.readSiblingClaims();
|
|
44306
44889
|
for (const record of params.records) {
|
|
44307
44890
|
const { logicalId, state } = record;
|
|
44891
|
+
const shownId = displayIdent(logicalId);
|
|
44892
|
+
const shownType = displayIdent(state.resourceType);
|
|
44893
|
+
const shownPhysicalId = displaySafe(state.physicalId);
|
|
44308
44894
|
if (params.managedLogicalIds.has(logicalId)) {
|
|
44309
|
-
params.logger.debug(`orphan ${
|
|
44895
|
+
params.logger.debug(`orphan ${shownId}: already present in state.resources — dropping the stale record`);
|
|
44310
44896
|
continue;
|
|
44311
44897
|
}
|
|
44312
44898
|
let provider;
|
|
@@ -44314,12 +44900,12 @@ async function planOrphanAdoption(params) {
|
|
|
44314
44900
|
provider = params.getProvider(state.resourceType, state.provisionedBy);
|
|
44315
44901
|
} catch (error) {
|
|
44316
44902
|
outcome.remaining.push(record);
|
|
44317
|
-
outcome.notices.push(`${
|
|
44903
|
+
outcome.notices.push(`${shownId} (${shownType}) is still in AWS as ${shownPhysicalId} from an earlier rollback, but this build cannot route that type (${displayAwsMessage(error instanceof Error ? error.message : String(error))}) — cdkd is not adopting it.`);
|
|
44318
44904
|
continue;
|
|
44319
44905
|
}
|
|
44320
44906
|
if (!provider.import) {
|
|
44321
44907
|
outcome.remaining.push(record);
|
|
44322
|
-
outcome.notices.push(`${
|
|
44908
|
+
outcome.notices.push(`${shownId} (${shownType}) was left in AWS by an earlier rollback as ${shownPhysicalId}, but its provider cannot verify it — cdkd is not adopting it.`);
|
|
44323
44909
|
continue;
|
|
44324
44910
|
}
|
|
44325
44911
|
let found;
|
|
@@ -44333,32 +44919,32 @@ async function planOrphanAdoption(params) {
|
|
|
44333
44919
|
knownPhysicalId: state.physicalId
|
|
44334
44920
|
});
|
|
44335
44921
|
} catch (error) {
|
|
44336
|
-
outcome.notices.push(`${
|
|
44922
|
+
outcome.notices.push(`${shownId} (${shownType}) is recorded as left in AWS as ${shownPhysicalId}, but cdkd could not confirm it exists (${displayAwsMessage(error instanceof Error ? error.message : String(error))}) — keeping the record and not adopting it this run.`);
|
|
44337
44923
|
outcome.remaining.push(record);
|
|
44338
44924
|
continue;
|
|
44339
44925
|
}
|
|
44340
44926
|
if (found !== null && found.physicalId !== state.physicalId) {
|
|
44341
44927
|
outcome.remaining.push(record);
|
|
44342
|
-
outcome.notices.push(`${
|
|
44928
|
+
outcome.notices.push(`${shownId} (${shownType}): cdkd asked about ${shownPhysicalId} and its provider answered for ${displaySafe(found.physicalId)} — not adopting.`);
|
|
44343
44929
|
continue;
|
|
44344
44930
|
}
|
|
44345
44931
|
if (found === null) {
|
|
44346
|
-
params.logger.debug(`orphan ${
|
|
44932
|
+
params.logger.debug(`orphan ${shownId}: ${shownPhysicalId} no longer exists in AWS — dropping the record`);
|
|
44347
44933
|
continue;
|
|
44348
44934
|
}
|
|
44349
44935
|
if (params.nameProperties(state.resourceType).length === 0 || ADOPTION_REFUSED_TYPES.has(state.resourceType)) {
|
|
44350
44936
|
outcome.remaining.push(record);
|
|
44351
44937
|
const why = ADOPTION_REFUSED_TYPES.has(state.resourceType) ? "a new deploy of it mints a new resource rather than colliding, and cdkd cannot update one in place — so adopting it would end in a replacement that destroys what DeletionPolicy: Retain preserved" : "cdkd does not derive that resource's physical name, so a new deploy mints a new resource instead of colliding";
|
|
44352
|
-
outcome.notices.push(`${
|
|
44938
|
+
outcome.notices.push(`${shownId} (${shownType}) is still in AWS as ${shownPhysicalId} from an earlier rollback. cdkd does not re-adopt this type: ${why}. Delete it yourself when you no longer need it.`);
|
|
44353
44939
|
continue;
|
|
44354
44940
|
}
|
|
44355
44941
|
if (!templateStillDeclares(params.template, record, params.nameProperties(state.resourceType))) {
|
|
44356
44942
|
outcome.remaining.push(record);
|
|
44357
|
-
outcome.notices.push(`${
|
|
44943
|
+
outcome.notices.push(`${shownId} (${shownType}) is still in AWS as ${shownPhysicalId} from an earlier rollback. This deploy does not create it under that name, so cdkd is leaving it alone.`);
|
|
44358
44944
|
continue;
|
|
44359
44945
|
}
|
|
44360
44946
|
if ((await claims()).has(state.physicalId)) {
|
|
44361
|
-
outcome.refusals.push(`${
|
|
44947
|
+
outcome.refusals.push(`${shownId}: ${shownPhysicalId} is already recorded by another cdkd stack. cdkd will not adopt a resource another stack manages.`);
|
|
44362
44948
|
outcome.remaining.push(record);
|
|
44363
44949
|
continue;
|
|
44364
44950
|
}
|
|
@@ -44411,7 +44997,7 @@ function makeSiblingClaimReader(params) {
|
|
|
44411
44997
|
try {
|
|
44412
44998
|
refs = await stateBackend.listStacks();
|
|
44413
44999
|
} catch (error) {
|
|
44414
|
-
logger.debug(`orphan adoption: could not list sibling stacks — ${error instanceof Error ? error.message : String(error)}`);
|
|
45000
|
+
logger.debug(`orphan adoption: could not list sibling stacks — ${displayAwsMessage(error instanceof Error ? error.message : String(error))}`);
|
|
44415
45001
|
return claimed;
|
|
44416
45002
|
}
|
|
44417
45003
|
for (const ref of refs) {
|
|
@@ -44421,7 +45007,7 @@ function makeSiblingClaimReader(params) {
|
|
|
44421
45007
|
const sibling = await stateBackend.getState(ref.stackName, ref.region);
|
|
44422
45008
|
for (const record of Object.values(sibling?.state.resources ?? {})) claimed.add(record.physicalId);
|
|
44423
45009
|
} catch (error) {
|
|
44424
|
-
logger.debug(`orphan adoption: skipping unreadable state for ${ref.stackName} — ${error instanceof Error ? error.message : String(error)}`);
|
|
45010
|
+
logger.debug(`orphan adoption: skipping unreadable state for ${displayStackName(ref.stackName)} — ${displayAwsMessage(error instanceof Error ? error.message : String(error))}`);
|
|
44425
45011
|
}
|
|
44426
45012
|
}
|
|
44427
45013
|
return claimed;
|
|
@@ -49762,7 +50348,9 @@ var DeployEngine = class DeployEngine {
|
|
|
49762
50348
|
this.healBaseline = currentState.resources ?? {};
|
|
49763
50349
|
refuseMalformedOutputs(currentState, stackName, this.stackRegion);
|
|
49764
50350
|
refuseMalformedResourcesForDeploy(currentState, stackName, this.stackRegion);
|
|
50351
|
+
refuseMalformedResourceEntriesForDeploy(currentState, stackName, this.stackRegion);
|
|
49765
50352
|
refuseMalformedOrphans(currentState, stackName, this.stackRegion);
|
|
50353
|
+
refuseMalformedOrphanRecords(currentState, stackName, this.stackRegion);
|
|
49766
50354
|
const migrationPending = currentStateData?.migrationPending ?? false;
|
|
49767
50355
|
this.logger.debug(`Loaded current state: ${Object.keys(currentState.resources).length} resources`);
|
|
49768
50356
|
if (this.options.onCurrentStateLoaded) await this.options.onCurrentStateLoaded(stackName, currentStateData?.state);
|
|
@@ -50342,7 +50930,7 @@ var DeployEngine = class DeployEngine {
|
|
|
50342
50930
|
if (plan.refusals.length > 0) throw new Error(`Deploy refused — cdkd left ${plan.refusals.length} resource(s) in AWS that it cannot safely re-adopt:\n ${plan.refusals.join("\n ")}`);
|
|
50343
50931
|
for (const [logicalId, record] of Object.entries(plan.adopted)) {
|
|
50344
50932
|
currentState.resources[logicalId] = record;
|
|
50345
|
-
this.logger.info(`Adopting ${logicalId} (${record.resourceType}) left in AWS by an earlier rollback as ${record.physicalId}`);
|
|
50933
|
+
this.logger.info(`Adopting ${displayIdent(logicalId)} (${displayIdent(record.resourceType)}) left in AWS by an earlier rollback as ${displaySafe(record.physicalId)}`);
|
|
50346
50934
|
}
|
|
50347
50935
|
if (records.length > 0) currentState.orphans = plan.remaining;
|
|
50348
50936
|
return plan;
|
|
@@ -51809,5 +52397,5 @@ var DeployEngine = class DeployEngine {
|
|
|
51809
52397
|
};
|
|
51810
52398
|
|
|
51811
52399
|
//#endregion
|
|
51812
|
-
export { yellow as $, isCdkdError as $a, findLargeInlineResources as $i, repairMalformedOutputsForReadOnly as $n, WorkGraph as $r, replayWarn as $t, createPreDeleteFinalSnapshot as A, setAwsClients as Aa, runDockerStreaming as Ai, malformedOrphansRefusalMessage as An, scrubResourceRecord as Ar, isTerminationProtectionPropagationError as At, isStatefulRecreateTargetSync as B, LocalStartServiceError as Ba, resolveApp as Bi, refuseMalformedNestedChildOutputs as Bn, DEFAULT_STATE_PREFIX as Br, parameterTypeMayLoseSecretIdentity as Bt, namesAnyDeclaredParameter as C, resolveAssemblyPath as Ca, formatDockerLoginError as Ci, hasReadableOutputs as Cn, maskSecretsInError as Cr, CloudControlProvider as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, getAwsClients as Da, partitionSensitiveEnv as Di, malformedExportSourceWarning as Dn, recordMaskOnlyValuesIn as Dr, deleteSkipReason as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, AwsClients as Ea, isMalformedEnvKey as Ei, malformedExportNamesWarning as En, recordMaskOnlyValue as Er, deleteIndeterminateGuards as Et, extractDeploymentEventError as F, DependencyError as Fa, getDockerImageBySourceHash as Fi, malformedResourceEntriesWarning as Fn, buildForceUnlockCommand as Fr, coerceParameterTypedValue as Ft, toCfnInteger as G, ProvisioningError as Ga, resolveStateBucketWithDefaultAndSource as Gi, refuseMalformedOutputsForDestroy as Gn, importableOutputKeys as Gr, resolveExplicitPhysicalId as Gt, WARM_THROUGHPUT_MEMBERS as H, MalformedProducerRecordRefusalError as Ha, resolveCaptureObservedState as Hi, refuseMalformedOrphansForDestroy as Hn, hasReadableExportSet as Hr, isSettledInstanceState as Ht, makeSiblingClaimReader as I, DeployCancelledError as Ia, Synthesizer as Ii, malformedResourcePropertiesWarning as In, buildLockContentionMessage as Ir, getAccountInfo as It, bold as J, StackHasActiveImportsError as Ja, warnDeprecatedNoPrefixCliFlag as Ji, refuseMalformedResourceEntriesForOrphan as Jn, orphansAfterRollback as Jr, coerceCfnInteger as Jt, toFiniteNumber as K, ResourceTimeoutError as Ka, resolveUseCdkBootstrapAssets as Ki, refuseMalformedResourceAttributesForOrphan as Kn, importableOutputs as Kr, assertRegionMatch as Kt, planOrphanAdoption as L, DynamicReferenceRegionAmbiguousError as La, synthesisStatusMessage as Li, malformedResourcesWarning as Ln, forceQuitRecoveryClause as Lr, isImpossibleEmptyStoredAttribute as Lt, refusesFinalSnapshot as M, CdkdError as Ma, escapeRegExp$1 as Mi, malformedOutputsRefusalMessage as Mn, S3StateBackend as Mr, carriesDynamicReference as Mt, unsupportedFinalSnapshotError as N, ConfigError as Na, stripControlChars as Ni, malformedOutputsWarning as Nn, rebuildClientForBucketRegion as Nr, carriesFetchableDynamicReference as Nt, buildFinalSnapshotIdentifier as O, resetAwsClients as Oa, redactDockerArgvValues as Oi, malformedLocalOutputsWarning as On, recoverMaskedOutput as Or, isWaitAbandonedError as Ot, makeCanonicalizePropertiesFn as P, CrossAccountSecretRefusalError as Pa, AssetManifestLoader as Pi, malformedRenderedContainersWarning as Pn, UNREPRODUCIBLE_LOCK_CLAUSE as Pr, cfnRefValueFromPhysicalId as Pt, red as Q, formatError as Qa, MIGRATE_TMP_PREFIX as Qi, repairMalformedOrphansForReadOnly as Qn, stringifyValue as Qr, readConfigString as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, IntrinsicResolutionRefusalError as Ra, getDefaultStateBucketName as Ri, malformedStateRefusalMessage as Rn, formatLockExpiry as Rr, isNamelessDynamicReferenceError as Rt, computeParameterTaint as S, renderAssemblyPathEscape as Sa, finchSecretArgvRefusal as Si, hasReadableOrphans as Sn, markSameGenerationBag as Sr, startInterruptWatch as St, resourcesNamingDeclaredParameter as T, resolveBucketRegion as Ta, isDockerClientEnvKey as Ti, isReadableResourceEntry as Tn, pathCrossesDottedKey as Tr, UNSPECIFIED_SKIP_REASON as Tt, coerceWarmThroughput as U, NestedStackChildDirectDestroyError as Ua, resolveSkipPrefix as Ui, refuseMalformedOrphansForOrphan as Un, hasReasonlessBaselineRefusal as Ur, WAFv2WebACLProvider as Ut, renderStatefulReason as V, LockError as Va, resolveAutoAssetStorage as Vi, refuseMalformedOrphans as Vn, exportNamesCarriedFrom as Vr, refStateLookupFromResource as Vt, isWarmThroughputDecrease as W, PartialFailureError as Wa, resolveStateBucketWithDefault as Wi, refuseMalformedOutputs as Wn, hasUnverifiableParameterRefusal as Wr, normalizeAwsTagsToCfn as Wt, gray as X, StateError as Xa, CFN_TEMPLATE_BODY_LIMIT as Xi, refuseMalformedResourcesForDestroy as Xn, shouldRetainResource as Xr, configIntegerRefusal as Xt, cyan as Y, StackTerminationProtectionError as Ya, ssmResolvedValueType as Yi, refuseMalformedResourcePropertiesForOrphan as Yn, orphansCarriedFrom as Yr, configBooleanRefusal as Yt, green as Z, SynthesisError as Za, CFN_TEMPLATE_URL_LIMIT as Zi, refuseMalformedState as Zn, AssetPublisher as Zr, configStringRefusal as Zt, bagHoldsSecretExpression as _, hasPlainPrototype$1 as _a, resolveDockerContextDirectory as _i, INTRINSIC_KEYS as _n, dynamicReferenceTokens as _r, maskerOrIdentity as _t, DeploymentEventsStore as a, producerRecordKey as aa, BOOTSTRAP_MARKER_PREFIX as ai, withSharedDrainBudget as an, isRetryableTransientError as ao, findActionableSilentDrops as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, absoluteAssemblyPathEscape as ba, describeDockerFailure as bi, UNREADABLE_RESOURCES_MAP_ROW as bn, isSingleDynamicReferenceToken as br, interruptWatchListenerCount as bt, replayFailedOperations as c, PARTITION_TABLE as ca, getBootstrapMarkerKey as ci, s3BucketDualStackDomainName as cn, markNonRetryable as co, withRetry as cr, IAMRoleProvider as ct, updatePartialMessage as d, AssemblyReader as da, readBootstrapMarkerBody as di, applyRoleArnIfSet as dn, describeAwsFailure as do, STATE_SOURCED_BASELINE_RULES as dr, definedAttributes as dt, uploadCfnTemplate as ea, buildAssetRedirectMap as ei, requireConfigArray as en, normalizeAwsError as eo, repairMalformedResourceEntriesForReadOnly as er, collectDeclaredOutputNames as et, updatePartialReason as f, failedStageNote as fa, validateAssetBucketName as fi, AWS_CREDENTIAL_ENV_KEYS as fn, safeStringify$1 as fo, STATE_SOURCED_CROSS_GENERATION_RULES as fr, stringifyIfAssigned as ft, computeImplicitDeleteEdges as g, hasOwnKey as ga, buildDockerImage as gi, DiffCalculator as gn, createSecretMasker as gr, maskDeep as gt, IMPLICIT_DELETE_DEPENDENCIES as h, defineOwnKey as ha, assertCdkLocalDockerContextContained as hi, envCredentialsAreAssumedRole as hn, carriesSecretMask as hr, createMaskedRetryLogger as ht, DeploymentEventsReader as i, producerCoordinateKey as ia, AssetModeResolver as ii, producerRegionsFromState as in, isMarkedNonRetryable as io, safeStackName as ir, secretBearing as it, isFinalSnapshotError as j, AssetError as ja, warnFinchArgvExposure as ji, malformedOrphansWarning as jn, LockManager as jr, IntrinsicFunctionResolver as jt, ccRoutedFinalSnapshotError as k, runWithStackAwsClients as ka, runDockerForeground as ki, malformedOrphanRecordsWarning as kn, redactSecretsForState as kr, disableInstanceApiTermination as kt, replayRollback as l, canonicalizeRegion as la, isCrossRegionRedirect as li, s3BucketRegionalDomainName as ln, markRedactedCause as lo, DagBuilder as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, processStackMessages as ma, buildDenyExternalAccessPolicy as mi, callerEnvCredentials as mn, TEMPLATE_SOURCED_RULES as mr, wouldReturnToSdkProvider as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, injectiveKey as na, loadPublishableAssetManifest as ni, requireConfigString as nn, pasteableCommand as no, repairMalformedResourcesForReadOnly as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, decodeListingKey as oa, assertAssetBucketRegion as oi, s3BucketArn as on, isThrottlingError as oo, findSilentDropProperties as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, globMatches as pa, validateContainerRepoName as pi, applyCallerIdentityCredentials as pn, __exportAll as po, STATE_SOURCED_READBACK_RULES as pr, ProviderRegistry as pt, formatResourceLine as q, ResourceUpdateNotSupportedError as qa, stateBucketExistenceConfirmed as qi, refuseMalformedResourceEntries as qn, isReadableBag as qr, coerceCfnBoolean as qt, DeployEngine as r, injectiveKeyPrefix as ra, rewriteTemplateAssetReferences as ri, classifyReplaySecretRegion as rn, shellQuote as ro, safeRegion as rr, isExportAliasCollision as rt, planRollback as s, expectedOwnerParam as sa, ensureAssetStorage as si, s3BucketDomainName as sn, isTransientServerError as so, describeTypeWithThrottleRetry as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as ta, createAssetRedirectResolver as ti, requireConfigObject as tn, withErrorHandling as to, repairMalformedResourcePropertiesForReadOnly as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, derivePartitionAndUrlSuffix as ua, parseBootstrapMarker as ui, s3BucketWebsiteUrl as un, retryClassificationText as uo, TemplateParser as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, nullPrototypeRecord as va, describeDockerCapturedOutput as vi, STATE_RESOURCES_MALFORMED as vn, errorCauseChain as vr, beginCommandInterruptScope as vt, reachableDivergentParameters as w, clearBucketRegionCache as wa, getDockerCmd as wi, hasReadableResources as wn, maskSecretsInText as wr, slowCcOperationTimeoutMs as wt, bindingSkippedOutputs as x, displayAssemblyPath as xa, dockerSpawnEnvWithSensitive as xi, displayLogicalId as xn, isUncertifiedBaselineMaskPosition as xr, isInterruptedWaitError as xt, keptWholeReasonText as y, ownValue as ya, describeDockerExecFailure as yi, UNREADABLE_ORPHANS_CONTAINER_ROW as yn, identityKeyFor as yr, endCommandInterruptScope as yt, isStatefulRecreateTargetForReplace as z, LocalInvokeBuildError as za, getLegacyStateBucketName as zi, refuseDivergentRecordRegionForDestroy as zn, CUSTOM_RESOURCE_RESPONSE_PREFIX as zr, isUnboundTemplateParameter as zt };
|
|
51813
|
-
//# sourceMappingURL=deploy-engine-
|
|
52400
|
+
export { yellow as $, MalformedProducerRecordRefusalError as $a, resolveSkipPrefix as $i, refuseMalformedOutputsForDestroy as $n, hasReadableExportSet as $r, readConfigString as $t, createPreDeleteFinalSnapshot as A, ownValue as Aa, describeDockerFailure as Ai, malformedExportSourceWarning as An, identityKeyFor as Ar, disableInstanceApiTermination as At, isStatefulRecreateTargetSync as B, runWithStackAwsClients as Ba, runDockerStreaming as Bi, malformedResourceEntriesWarning as Bn, redactSecretsForState as Br, isUnboundTemplateParameter as Bt, namesAnyDeclaredParameter as C, failedStageNote as Ca, validateAssetBucketName as Ci, displayLogicalId as Cn, safeStringify$1 as Co, STATE_SOURCED_CROSS_GENERATION_RULES as Cr, CloudControlProvider as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, hasOwnKey as Da, resolveDockerContextDirectory as Di, isReadableOrphanRecord as Dn, createSecretMasker as Dr, deleteIndeterminateGuards as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, defineOwnKey as Ea, buildDockerImage as Ei, hasReadableResources as En, carriesSecretMask as Er, UNSPECIFIED_SKIP_REASON as Et, extractDeploymentEventError as F, clearBucketRegionCache as Fa, isDockerClientEnvKey as Fi, malformedOrphansRefusalMessage as Fn, maskSecretsInText as Fr, cfnRefValueFromPhysicalId as Ft, toCfnInteger as G, CrossAccountSecretRefusalError as Ga, getDockerImageBySourceHash as Gi, refuseDivergentRecordRegionForDestroy as Gn, UNREPRODUCIBLE_LOCK_CLAUSE as Gr, normalizeAwsTagsToCfn as Gt, WARM_THROUGHPUT_MEMBERS as H, AssetError as Ha, escapeRegExp$1 as Hi, malformedResourcesWarning as Hn, LockManager as Hr, refStateLookupFromResource as Ht, makeSiblingClaimReader as I, resolveBucketRegion as Ia, isMalformedEnvKey as Ii, malformedOrphansWarning as In, pathCrossesDottedKey as Ir, coerceParameterTypedValue as It, bold as J, DynamicReferenceRegionAmbiguousError as Ja, getDefaultStateBucketName as Ji, refuseMalformedOrphanRecordsForDestroy as Jn, forceQuitRecoveryClause as Jr, coerceCfnBoolean as Jt, toFiniteNumber as K, DependencyError as Ka, Synthesizer as Ki, refuseMalformedNestedChildOutputs as Kn, buildForceUnlockCommand as Kr, resolveExplicitPhysicalId as Kt, planOrphanAdoption as L, AwsClients as La, partitionSensitiveEnv as Li, malformedOutputsRefusalMessage as Ln, recordMaskOnlyValue as Lr, getAccountInfo as Lt, refusesFinalSnapshot as M, displayAssemblyPath as Ma, finchSecretArgvRefusal as Mi, malformedOrphanRecordsRefusalMessage as Mn, isUncertifiedBaselineMaskPosition as Mr, IntrinsicFunctionResolver as Mt, unsupportedFinalSnapshotError as N, renderAssemblyPathEscape as Na, formatDockerLoginError as Ni, malformedOrphanRecordsWarning as Nn, markSameGenerationBag as Nr, carriesDynamicReference as Nt, buildFinalSnapshotIdentifier as O, hasPlainPrototype$1 as Oa, describeDockerCapturedOutput as Oi, isReadableResourceEntry as On, dynamicReferenceTokens as Or, deleteSkipReason as Ot, makeCanonicalizePropertiesFn as P, resolveAssemblyPath as Pa, getDockerCmd as Pi, malformedOrphanRowsKeptWarning as Pn, maskSecretsInError as Pr, carriesFetchableDynamicReference as Pt, red as Q, LockError as Qa, resolveCaptureObservedState as Qi, refuseMalformedOutputs as Qn, exportNamesCarriedFrom as Qr, configStringRefusal as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, getAwsClients as Ra, redactDockerArgvValues as Ri, malformedOutputsWarning as Rn, recordMaskOnlyValuesIn as Rr, isImpossibleEmptyStoredAttribute as Rt, computeParameterTaint as S, AssemblyReader as Sa, readBootstrapMarkerBody as Si, deployRefusesOrphanRowsReason as Sn, describeAwsFailure as So, STATE_SOURCED_BASELINE_RULES as Sr, startInterruptWatch as St, resourcesNamingDeclaredParameter as T, processStackMessages as Ta, buildDenyExternalAccessPolicy as Ti, hasReadableOutputs as Tn, TEMPLATE_SOURCED_RULES as Tr, ccProtectionRegistryTypes as Tt, coerceWarmThroughput as U, CdkdError as Ua, stripControlChars as Ui, malformedStateRefusalMessage as Un, S3StateBackend as Ur, isSettledInstanceState as Ut, renderStatefulReason as V, setAwsClients as Va, warnFinchArgvExposure as Vi, malformedResourcePropertiesWarning as Vn, scrubResourceRecord as Vr, parameterTypeMayLoseSecretIdentity as Vt, isWarmThroughputDecrease as W, ConfigError as Wa, AssetManifestLoader as Wi, previewableOrphanRecords as Wn, rebuildClientForBucketRegion as Wr, WAFv2WebACLProvider as Wt, gray as X, LocalInvokeBuildError as Xa, resolveApp as Xi, refuseMalformedOrphansForDestroy as Xn, CUSTOM_RESOURCE_RESPONSE_PREFIX as Xr, configBooleanRefusal as Xt, cyan as Y, IntrinsicResolutionRefusalError as Ya, getLegacyStateBucketName as Yi, refuseMalformedOrphans as Yn, formatLockExpiry as Yr, coerceCfnInteger as Yt, green as Z, LocalStartServiceError as Za, resolveAutoAssetStorage as Zi, refuseMalformedOrphansForOrphan as Zn, DEFAULT_STATE_PREFIX as Zr, configIntegerRefusal as Zt, bagHoldsSecretExpression as _, expectedOwnerParam as _a, assertAssetBucketRegion as _i, DiffCalculator as _n, isThrottlingError as _o, findSilentDropProperties as _r, maskerOrIdentity as _t, DeploymentEventsStore as a, ssmResolvedValueType as aa, orphansAfterRollback as ai, producerRegionsFromState as an, StackHasActiveImportsError as ao, refuseMalformedState as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, derivePartitionAndUrlSuffix as ba, isCrossRegionRedirect as bi, UNREADABLE_ORPHANS_CONTAINER_ROW as bn, markRedactedCause as bo, DagBuilder as br, interruptWatchListenerCount as bt, replayFailedOperations as c, MIGRATE_TMP_PREFIX as ca, AssetPublisher as ci, s3BucketDomainName as cn, SynthesisError as co, repairMalformedOutputsForReadOnly as cr, IAMRoleProvider as ct, updatePartialMessage as d, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as da, buildAssetRedirectMap as di, s3BucketWebsiteUrl as dn, normalizeAwsError as do, repairMalformedResourcesForReadOnly as dr, definedAttributes as dt, resolveStateBucketWithDefault as ea, hasReasonlessBaselineRefusal as ei, replayWarn as en, NestedStackChildDirectDestroyError as eo, refuseMalformedResourceAttributesForOrphan as er, collectDeclaredOutputNames as et, updatePartialReason as f, injectiveKey as fa, createAssetRedirectResolver as fi, applyRoleArnIfSet as fn, withErrorHandling as fo, safeRegion as fr, stringifyIfAssigned as ft, computeImplicitDeleteEdges as g, decodeListingKey as ga, BOOTSTRAP_MARKER_PREFIX as gi, envCredentialsAreAssumedRole as gn, isRetryableTransientError as go, findActionableSilentDrops as gr, maskDeep as gt, IMPLICIT_DELETE_DEPENDENCIES as h, producerRecordKey as ha, AssetModeResolver as hi, callerEnvCredentials as hn, isMarkedNonRetryable as ho, unreadableOrphanRecords as hr, createMaskedRetryLogger as ht, DeploymentEventsReader as i, warnDeprecatedNoPrefixCliFlag as ia, isReadableBag as ii, classifyReplaySecretRegion as in, ResourceUpdateNotSupportedError as io, refuseMalformedResourcesForDestroy as ir, secretBearing as it, isFinalSnapshotError as j, absoluteAssemblyPathEscape as ja, dockerSpawnEnvWithSensitive as ji, malformedLocalOutputsWarning as jn, isSingleDynamicReferenceToken as jr, isTerminationProtectionPropagationError as jt, ccRoutedFinalSnapshotError as k, nullPrototypeRecord as ka, describeDockerExecFailure as ki, malformedExportNamesWarning as kn, errorCauseChain as kr, isWaitAbandonedError as kt, replayRollback as l, findLargeInlineResources as la, stringifyValue as li, s3BucketDualStackDomainName as ln, formatError as lo, repairMalformedResourceEntriesForReadOnly as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, producerCoordinateKey as ma, rewriteTemplateAssetReferences as mi, applyCallerIdentityCredentials as mn, shellQuote as mo, unpreviewableOrphanRecords as mr, wouldReturnToSdkProvider as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, resolveUseCdkBootstrapAssets as na, importableOutputKeys as ni, requireConfigObject as nn, ProvisioningError as no, refuseMalformedResourceEntriesForOrphan as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, CFN_TEMPLATE_BODY_LIMIT as oa, orphansCarriedFrom as oi, withSharedDrainBudget as on, StackTerminationProtectionError as oo, repairMalformedOrphanRecordsForReadOnly as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, injectiveKeyPrefix as pa, loadPublishableAssetManifest as pi, AWS_CREDENTIAL_ENV_KEYS as pn, pasteableCommand as po, safeStackName as pr, ProviderRegistry as pt, formatResourceLine as q, DeployCancelledError as qa, synthesisStatusMessage as qi, refuseMalformedOrphanRecords as qn, buildLockContentionMessage as qr, assertRegionMatch as qt, DeployEngine as r, stateBucketExistenceConfirmed as ra, importableOutputs as ri, requireConfigString as rn, ResourceTimeoutError as ro, refuseMalformedResourcePropertiesForOrphan as rr, isExportAliasCollision as rt, planRollback as s, CFN_TEMPLATE_URL_LIMIT as sa, shouldRetainResource as si, s3BucketArn as sn, StateError as so, repairMalformedOrphansForReadOnly as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, resolveStateBucketWithDefaultAndSource as ta, hasUnverifiableParameterRefusal as ti, requireConfigArray as tn, PartialFailureError as to, refuseMalformedResourceEntries as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, uploadCfnTemplate as ua, WorkGraph as ui, s3BucketRegionalDomainName as un, isCdkdError as uo, repairMalformedResourcePropertiesForReadOnly as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, PARTITION_TABLE as va, ensureAssetStorage as vi, INTRINSIC_KEYS as vn, isTransientServerError as vo, describeTypeWithThrottleRetry as vr, beginCommandInterruptScope as vt, reachableDivergentParameters as w, globMatches as wa, validateContainerRepoName as wi, hasReadableOrphans as wn, __exportAll as wo, STATE_SOURCED_READBACK_RULES as wr, slowCcOperationTimeoutMs as wt, bindingSkippedOutputs as x, ambientClientDefaults as xa, parseBootstrapMarker as xi, UNREADABLE_RESOURCES_MAP_ROW as xn, retryClassificationText as xo, TemplateParser as xr, isInterruptedWaitError as xt, keptWholeReasonText as y, canonicalizeRegion as ya, getBootstrapMarkerKey as yi, STATE_RESOURCES_MALFORMED as yn, markNonRetryable as yo, withRetry as yr, endCommandInterruptScope as yt, isStatefulRecreateTargetForReplace as z, resetAwsClients as za, runDockerForeground as zi, malformedRenderedContainersWarning as zn, recoverMaskedOutput as zr, isNamelessDynamicReferenceError as zt };
|
|
52401
|
+
//# sourceMappingURL=deploy-engine-OgrMdBRR.js.map
|