@go-to-k/cdkd 0.290.44 → 0.290.46
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-BwN09Zcn.js → asg-provider-BL_yHnHI.js} +3 -3
- package/dist/{asg-provider-BwN09Zcn.js.map → asg-provider-BL_yHnHI.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-CMD4BtQe.js → deploy-engine-BRy8S7QH.js} +275 -73
- package/dist/deploy-engine-BRy8S7QH.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{logger-DjBU2Ap3.js → logger-GASr9bAF.js} +25 -7
- package/dist/logger-GASr9bAF.js.map +1 -0
- package/dist/{program-CGhtrsw6.js → program-OigOAssB.js} +214 -33
- package/dist/{program-CGhtrsw6.js.map → program-OigOAssB.js.map} +1 -1
- package/dist/{version-4uhXCFhs.js → version-THOL_1Cg.js} +2 -2
- package/dist/{version-4uhXCFhs.js.map → version-THOL_1Cg.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-CMD4BtQe.js.map +0 -1
- package/dist/logger-DjBU2Ap3.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, 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-
|
|
1
|
+
import { C as displayAwsMessage, D as truncateCodePoints, E as isPasteableIdent, 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-GASr9bAF.js";
|
|
2
2
|
import { a as setAssumedRoleCredentials, i as getPreAssumeEnvCredentials, n as awsClientDefaults, o as setPreAssumeEnvCredentials, r as getAssumedRoleCredentials, t as SECOND_ROLE_PUBLISH_REFUSAL } from "./aws-client-defaults-BoIxyCir.js";
|
|
3
|
-
import { t as getCdkdVersion } from "./version-
|
|
3
|
+
import { t as getCdkdVersion } from "./version-THOL_1Cg.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";
|
|
@@ -1887,7 +1887,7 @@ function formatError(error) {
|
|
|
1887
1887
|
if (isCdkdError(error)) {
|
|
1888
1888
|
let message = `${error.name}: ${error.message}`;
|
|
1889
1889
|
if (error.cause) {
|
|
1890
|
-
const cause =
|
|
1890
|
+
const cause = displayAwsMessage(error.cause.message);
|
|
1891
1891
|
if (cause) message += `\nCaused by: ${cause}`;
|
|
1892
1892
|
}
|
|
1893
1893
|
return message;
|
|
@@ -4331,22 +4331,24 @@ var ContextProviderRegistry = class {
|
|
|
4331
4331
|
const results = {};
|
|
4332
4332
|
for (const entry of missing) {
|
|
4333
4333
|
const provider = this.providers.get(entry.provider);
|
|
4334
|
+
const shownProvider = displaySafe(entry.provider);
|
|
4334
4335
|
if (!provider) {
|
|
4335
|
-
this.logger.warn(`No context provider registered for: ${
|
|
4336
|
+
this.logger.warn(`No context provider registered for: ${shownProvider}`);
|
|
4336
4337
|
results[entry.key] = {
|
|
4337
|
-
[PROVIDER_ERROR_KEY]: `Unknown context provider: ${
|
|
4338
|
+
[PROVIDER_ERROR_KEY]: `Unknown context provider: ${shownProvider}`,
|
|
4338
4339
|
[TRANSIENT_CONTEXT_KEY]: true
|
|
4339
4340
|
};
|
|
4340
4341
|
continue;
|
|
4341
4342
|
}
|
|
4343
|
+
const shownKey = displaySafe(entry.key);
|
|
4342
4344
|
try {
|
|
4343
|
-
this.logger.debug(`Resolving context: ${
|
|
4345
|
+
this.logger.debug(`Resolving context: ${shownProvider} (key: ${shownKey})`);
|
|
4344
4346
|
const value = await provider.resolve(entry.props);
|
|
4345
4347
|
results[entry.key] = value;
|
|
4346
|
-
this.logger.debug(`Resolved context: ${
|
|
4348
|
+
this.logger.debug(`Resolved context: ${shownKey}`);
|
|
4347
4349
|
} catch (error) {
|
|
4348
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
4349
|
-
this.logger.error(`Context provider '${
|
|
4350
|
+
const message = displayAwsMessage(error instanceof Error ? error.message : String(error));
|
|
4351
|
+
this.logger.error(`Context provider '${shownProvider}' failed: ${message}`);
|
|
4350
4352
|
results[entry.key] = {
|
|
4351
4353
|
[PROVIDER_ERROR_KEY]: message,
|
|
4352
4354
|
[TRANSIENT_CONTEXT_KEY]: true
|
|
@@ -5961,6 +5963,21 @@ function ssmResolvedValueType(type) {
|
|
|
5961
5963
|
|
|
5962
5964
|
//#endregion
|
|
5963
5965
|
//#region src/synthesis/macro-expander.ts
|
|
5966
|
+
/**
|
|
5967
|
+
* A transform name comes from the TEMPLATE's own `Transform` / `Fn::Transform`
|
|
5968
|
+
* node, so every render of one goes through `displaySafe`, in thrown messages
|
|
5969
|
+
* and in the `debug` line alike
|
|
5970
|
+
* ([#3479](https://github.com/go-to-k/cdkd/issues/3479)). `displaySafe` neither
|
|
5971
|
+
* quotes nor truncates, so a legitimate `AWS::Serverless-2016-10-31` renders
|
|
5972
|
+
* byte-identically.
|
|
5973
|
+
*
|
|
5974
|
+
* A JOINED list sanitizes per ELEMENT so the separator stays
|
|
5975
|
+
* byte-exact; `displaySafe`'s own doc carries why that is a formatting rule
|
|
5976
|
+
* rather than a safety one.
|
|
5977
|
+
*/
|
|
5978
|
+
function displaySafeTransforms(names) {
|
|
5979
|
+
return names.map((name) => displaySafe(name)).join(", ");
|
|
5980
|
+
}
|
|
5964
5981
|
/** 600 seconds = 10 minutes. SDK waiter's `maxWaitTime` is in seconds. */
|
|
5965
5982
|
const WAITER_MAX_WAIT_SECONDS = 600;
|
|
5966
5983
|
const PARAMETER_PLACEHOLDER = "cdkd-macro-expand-placeholder";
|
|
@@ -5978,8 +5995,51 @@ const PARAMETER_PLACEHOLDER = "cdkd-macro-expand-placeholder";
|
|
|
5978
5995
|
const EARLY_VALIDATION_MAX_ATTEMPTS = 3;
|
|
5979
5996
|
const EARLY_VALIDATION_RETRY_BASE_DELAY_MS = 2e3;
|
|
5980
5997
|
/** Matches the changeset FAILED StatusReason emitted by the hook family. */
|
|
5998
|
+
const EARLY_VALIDATION_MARKER = /AWS::EarlyValidation::/;
|
|
5999
|
+
/**
|
|
6000
|
+
* Where the retry verdict is CARRIED, rather than re-derived from the rendered
|
|
6001
|
+
* message.
|
|
6002
|
+
*
|
|
6003
|
+
* The verdict used to be `EARLY_VALIDATION_MARKER.test(err.message)`, and that
|
|
6004
|
+
* became wrong the moment AWS's reply started rendering through
|
|
6005
|
+
* `displayAwsMessage` ([#3479](https://github.com/go-to-k/cdkd/issues/3479)):
|
|
6006
|
+
* the cap CUTS at `AWS_MESSAGE_MAX_CODE_POINTS`, so a `StatusReason` carrying
|
|
6007
|
+
* the hook marker past that point would no longer match, and `cdkd deploy` of a
|
|
6008
|
+
* macro stack would hard-fail on attempt 1 where issue
|
|
6009
|
+
* [#1151](https://github.com/go-to-k/cdkd/issues/1151) says it must retry. The
|
|
6010
|
+
* sanitizer's CHARSET half was never the risk — the marker is plain ASCII —
|
|
6011
|
+
* but a decision re-derived from display text inherits every display rule,
|
|
6012
|
+
* including ones added later for unrelated reasons.
|
|
6013
|
+
*
|
|
6014
|
+
* So each throw site tests the RAW text once and records the answer here. A
|
|
6015
|
+
* symbol rather than a field on `MacroExpansionError`: the verdict is this
|
|
6016
|
+
* module's business, not the shared error class's.
|
|
6017
|
+
*
|
|
6018
|
+
* IT ALSO CLOSES A PATH THAT PRE-DATES THE CAP, which is the stronger argument
|
|
6019
|
+
* for the shape. The old predicate matched the WHOLE message, and two of cdkd's
|
|
6020
|
+
* OWN refusals below interpolate template-supplied transform names — so an
|
|
6021
|
+
* assembly declaring `Transform: AWS::EarlyValidation::x` made the multi-stage
|
|
6022
|
+
* and no-TemplateBody refusals test positive, and a template value steered the
|
|
6023
|
+
* retry loop into three CFn changeset round-trips plus the backoff between
|
|
6024
|
+
* them. A verdict read from a symbol set out of AWS's own text cannot be
|
|
6025
|
+
* steered that way at all.
|
|
6026
|
+
*
|
|
6027
|
+
* IT RIDES THE INSTANCE, which is the one way a future edit can lose it: a site
|
|
6028
|
+
* that catches one of these and wraps it in a NEW `MacroExpansionError` drops
|
|
6029
|
+
* the verdict silently — the same shape as the bug above, one indirection over.
|
|
6030
|
+
* Re-tag at any such wrap.
|
|
6031
|
+
*/
|
|
6032
|
+
const EARLY_VALIDATION = Symbol("cdkd.macroExpansion.earlyValidationRejection");
|
|
6033
|
+
/**
|
|
6034
|
+
* Tag `error` when `rawReason` — AWS's text BEFORE any display helper touches
|
|
6035
|
+
* it — names a validation hook.
|
|
6036
|
+
*/
|
|
6037
|
+
function withEarlyValidationVerdict(error, rawReason) {
|
|
6038
|
+
if (EARLY_VALIDATION_MARKER.test(rawReason)) error[EARLY_VALIDATION] = true;
|
|
6039
|
+
return error;
|
|
6040
|
+
}
|
|
5981
6041
|
function isEarlyValidationRejection(err) {
|
|
5982
|
-
return err instanceof MacroExpansionError &&
|
|
6042
|
+
return err instanceof MacroExpansionError && err[EARLY_VALIDATION] === true;
|
|
5983
6043
|
}
|
|
5984
6044
|
/** Test seam: overridable sleep so retry tests don't wait wall-clock. */
|
|
5985
6045
|
const retryDelays = { sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)) };
|
|
@@ -6093,7 +6153,7 @@ async function expandMacros(template, opts) {
|
|
|
6093
6153
|
}
|
|
6094
6154
|
async function expandMacrosAttempt(template, opts, logger) {
|
|
6095
6155
|
const macros = enumerateMacros(template);
|
|
6096
|
-
logger.debug(`Macro expansion: detected transforms [${macros
|
|
6156
|
+
logger.debug(`Macro expansion: detected transforms [${displaySafeTransforms(macros)}], starting CFn round-trip...`);
|
|
6097
6157
|
const transientStackName = `cdkd-macro-expand-${randomUUID().slice(0, 16)}`;
|
|
6098
6158
|
const changeSetName = `${transientStackName}-changeset`;
|
|
6099
6159
|
const region = opts.region;
|
|
@@ -6136,7 +6196,8 @@ async function expandMacrosAttempt(template, opts, logger) {
|
|
|
6136
6196
|
...parameters.length > 0 && { Parameters: parameters }
|
|
6137
6197
|
}));
|
|
6138
6198
|
} catch (err) {
|
|
6139
|
-
|
|
6199
|
+
const rawMessage = err instanceof Error ? err.message : String(err);
|
|
6200
|
+
throw withEarlyValidationVerdict(new MacroExpansionError(`CloudFormation rejected the macro-expansion changeset: ${displayAwsMessage(rawMessage)}`, err instanceof Error ? err : void 0), rawMessage);
|
|
6140
6201
|
}
|
|
6141
6202
|
let waiterFailed = false;
|
|
6142
6203
|
let waiterError;
|
|
@@ -6159,20 +6220,21 @@ async function expandMacrosAttempt(template, opts, logger) {
|
|
|
6159
6220
|
StackName: transientStackName,
|
|
6160
6221
|
ChangeSetName: changeSetName
|
|
6161
6222
|
})).catch(() => void 0);
|
|
6162
|
-
const
|
|
6163
|
-
const
|
|
6164
|
-
|
|
6223
|
+
const rawReason = desc?.StatusReason ?? "unknown (DescribeChangeSet failed)";
|
|
6224
|
+
const reason = displayAwsMessage(rawReason);
|
|
6225
|
+
const status = displaySafe(desc?.Status ?? "UNKNOWN");
|
|
6226
|
+
throw withEarlyValidationVerdict(new MacroExpansionError(`CloudFormation macro expansion failed (status=${status}): ${reason}`, waiterError instanceof Error ? waiterError : void 0), rawReason);
|
|
6165
6227
|
}
|
|
6166
6228
|
const tpl = await cfn.send(new GetTemplateCommand({
|
|
6167
6229
|
StackName: transientStackName,
|
|
6168
6230
|
ChangeSetName: changeSetName,
|
|
6169
6231
|
TemplateStage: "Processed"
|
|
6170
6232
|
}));
|
|
6171
|
-
if (tpl.TemplateBody === void 0 || tpl.TemplateBody === null) throw new MacroExpansionError(`CloudFormation returned no Processed-stage template body for the macro-expansion changeset. This typically indicates a CFn-side regression — re-run, and if the failure persists open an issue with the transforms involved: [${macros
|
|
6233
|
+
if (tpl.TemplateBody === void 0 || tpl.TemplateBody === null) throw new MacroExpansionError(`CloudFormation returned no Processed-stage template body for the macro-expansion changeset. This typically indicates a CFn-side regression — re-run, and if the failure persists open an issue with the transforms involved: [${displaySafeTransforms(macros)}].`);
|
|
6172
6234
|
const expanded = parseTemplateBody(tpl.TemplateBody);
|
|
6173
6235
|
if (containsMacro(expanded)) {
|
|
6174
6236
|
const inner = enumerateMacros(expanded);
|
|
6175
|
-
throw new MacroExpansionError(`Macro expansion produced a template that still contains macros [${inner
|
|
6237
|
+
throw new MacroExpansionError(`Macro expansion produced a template that still contains macros [${displaySafeTransforms(inner)}]. Multi-stage macros (a macro whose expansion emits another macro reference) are intentionally out of scope in cdkd v1 — see https://github.com/go-to-k/cdkd/issues/463. If you need this pattern, manually pre-expand the template and deploy the result.`);
|
|
6176
6238
|
}
|
|
6177
6239
|
logger.debug(`Macro expansion: success — ${Object.keys(expanded.Resources ?? {}).length} resources after expansion.`);
|
|
6178
6240
|
return expanded;
|
|
@@ -6243,7 +6305,7 @@ function stringifyParamDefault(value, type, paramKey, logger) {
|
|
|
6243
6305
|
if (inner !== void 0 && isListParameterType(inner)) return "placeholder,placeholder";
|
|
6244
6306
|
return "placeholder";
|
|
6245
6307
|
}
|
|
6246
|
-
logger.warn(`Parameter '${paramKey}' has unrecognized CFn Type '${type}'; using a generic string placeholder for the transient macro-expansion changeset. If CFn rejects the changeset with a type error, file an issue with the offending Type.`);
|
|
6308
|
+
logger.warn(`Parameter '${displaySafe(paramKey)}' has unrecognized CFn Type '${displaySafe(type)}'; using a generic string placeholder for the transient macro-expansion changeset. If CFn rejects the changeset with a type error, file an issue with the offending Type.`);
|
|
6247
6309
|
return PARAMETER_PLACEHOLDER;
|
|
6248
6310
|
}
|
|
6249
6311
|
return PARAMETER_PLACEHOLDER;
|
|
@@ -6260,7 +6322,7 @@ function parseTemplateBody(body) {
|
|
|
6260
6322
|
if (typeof body === "string") try {
|
|
6261
6323
|
parsed = JSON.parse(body);
|
|
6262
6324
|
} catch (err) {
|
|
6263
|
-
throw new MacroExpansionError(`CloudFormation returned a non-JSON Processed-stage template body. cdkd's macro-expansion path only supports JSON-shaped synth templates (CDK apps emit JSON by default). Cause: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : void 0);
|
|
6325
|
+
throw new MacroExpansionError(`CloudFormation returned a non-JSON Processed-stage template body. cdkd's macro-expansion path only supports JSON-shaped synth templates (CDK apps emit JSON by default). Cause: ${displayAwsMessage(err instanceof Error ? err.message : String(err))}`, err instanceof Error ? err : void 0);
|
|
6264
6326
|
}
|
|
6265
6327
|
else if (body && typeof body === "object" && !Array.isArray(body)) parsed = body;
|
|
6266
6328
|
else throw new MacroExpansionError(`CloudFormation returned an unexpected TemplateBody shape (${typeof body}). Expected a JSON string or parsed object.`);
|
|
@@ -6270,7 +6332,7 @@ function parseTemplateBody(body) {
|
|
|
6270
6332
|
return parsed;
|
|
6271
6333
|
}
|
|
6272
6334
|
function formatErr(err) {
|
|
6273
|
-
return err instanceof Error ? err.message : String(err);
|
|
6335
|
+
return displayAwsMessage(err instanceof Error ? err.message : String(err));
|
|
6274
6336
|
}
|
|
6275
6337
|
|
|
6276
6338
|
//#endregion
|
|
@@ -6644,6 +6706,26 @@ async function probeBucket(client, bucketName, deps) {
|
|
|
6644
6706
|
//#endregion
|
|
6645
6707
|
//#region src/synthesis/synthesizer.ts
|
|
6646
6708
|
/**
|
|
6709
|
+
* Every manifest- or template-derived value this module RENDERS goes through
|
|
6710
|
+
* `displaySafe` — thrown messages and ordinary `logger.info` lines alike
|
|
6711
|
+
* ([#3479](https://github.com/go-to-k/cdkd/issues/3479)). Two reasons it is the
|
|
6712
|
+
* DEFAULT here rather than a judgement per message:
|
|
6713
|
+
*
|
|
6714
|
+
* - The "only where the input is untrusted" boundary keeps being drawn wrong. The
|
|
6715
|
+
* macro-expansion line below is a DEFAULT-verbosity `logger.info` on a normal
|
|
6716
|
+
* run, and a `stackName` carrying `ESC [ 2 K` plus a carriage return erases
|
|
6717
|
+
* cdkd's own line while a trailing line terminator forges another. Nothing
|
|
6718
|
+
* about the message being "operational" protects it, and `formatError`
|
|
6719
|
+
* sanitizes only an error's `cause`, never its own `message`.
|
|
6720
|
+
* - The cost is in the helper, not the scope: `displaySafe` neither quotes nor
|
|
6721
|
+
* truncates, so it is the identity on every legitimate stack name, context key
|
|
6722
|
+
* and transform name.
|
|
6723
|
+
*
|
|
6724
|
+
* A JOINED list sanitizes per ELEMENT so the separator stays
|
|
6725
|
+
* byte-exact; `displaySafe`'s own doc carries why that is a formatting rule
|
|
6726
|
+
* rather than a safety one.
|
|
6727
|
+
*/
|
|
6728
|
+
/**
|
|
6647
6729
|
* CDK CLI compatibility: a `--app` value pointing at an existing directory is
|
|
6648
6730
|
* treated as a pre-synthesized cloud assembly — synthesis (the subprocess
|
|
6649
6731
|
* execution) is skipped and the manifest is read directly. A `--app` value that
|
|
@@ -6771,7 +6853,7 @@ var Synthesizer = class {
|
|
|
6771
6853
|
}
|
|
6772
6854
|
const missingKeys = new Set(manifest.missing.map((m) => m.key));
|
|
6773
6855
|
this.logger.debug(`Missing context: ${manifest.missing.length} value(s)`);
|
|
6774
|
-
if (previousMissingKeys && setsEqual(missingKeys, previousMissingKeys)) throw new SynthesisError(`Context resolution made no progress. Missing context keys: ${[...missingKeys].join(", ")}. Ensure cdk.context.json is correctly configured or required AWS permissions are granted.`);
|
|
6856
|
+
if (previousMissingKeys && setsEqual(missingKeys, previousMissingKeys)) throw new SynthesisError(`Context resolution made no progress. Missing context keys: ${[...missingKeys].map((k) => displaySafe(k)).join(", ")}. Ensure cdk.context.json is correctly configured or required AWS permissions are granted.`);
|
|
6775
6857
|
previousMissingKeys = missingKeys;
|
|
6776
6858
|
this.logger.info("Resolving missing context...");
|
|
6777
6859
|
const resolved = await contextProviderRegistry.resolve(manifest.missing);
|
|
@@ -6816,7 +6898,7 @@ var Synthesizer = class {
|
|
|
6816
6898
|
const stacksWithMacros = stacks.filter((s) => containsMacro(s.template));
|
|
6817
6899
|
if (stacksWithMacros.length === 0) return;
|
|
6818
6900
|
const region = resolved?.region || options.region || process.env["AWS_REGION"] || process.env["AWS_DEFAULT_REGION"] || stacksWithMacros[0]?.region || await resolveSdkDefaultRegion(options.profile);
|
|
6819
|
-
if (!region) throw new SynthesisError(`Stack(s) [${stacksWithMacros.map((s) => s.stackName).join(", ")}] use CloudFormation macros (Transform / Fn::Transform) but cdkd could not resolve an AWS region for the expansion round-trip. Set AWS_REGION, pass --region <r>, or set env: { region: '<r>' } in your CDK Stack constructor.`);
|
|
6901
|
+
if (!region) throw new SynthesisError(`Stack(s) [${stacksWithMacros.map((s) => displaySafe(s.stackName)).join(", ")}] use CloudFormation macros (Transform / Fn::Transform) but cdkd could not resolve an AWS region for the expansion round-trip. Set AWS_REGION, pass --region <r>, or set env: { region: '<r>' } in your CDK Stack constructor.`);
|
|
6820
6902
|
let accountId = resolved?.accountId;
|
|
6821
6903
|
if (resolved === void 0 && !options.stateBucket) try {
|
|
6822
6904
|
const stsClient = new STSClient({
|
|
@@ -6833,12 +6915,12 @@ var Synthesizer = class {
|
|
|
6833
6915
|
else if (accountId) stateBucket = `cdkd-state-${accountId}`;
|
|
6834
6916
|
else {
|
|
6835
6917
|
const oversize = stacksWithMacros.find((s) => JSON.stringify(s.template).length > 51200);
|
|
6836
|
-
if (oversize) throw new SynthesisError(`Stack '${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>').`);
|
|
6918
|
+
if (oversize) throw new SynthesisError(`Stack '${displaySafe(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>').`);
|
|
6837
6919
|
stateBucket = void 0;
|
|
6838
6920
|
}
|
|
6839
6921
|
for (const stack of stacksWithMacros) {
|
|
6840
6922
|
const macros = enumerateMacros(stack.template);
|
|
6841
|
-
this.logger.info(`[macros] Expanding CloudFormation macros for stack '${stack.stackName}' via CFn round-trip (transforms: ${macros.join(", ")}; may take 30-60s)...`);
|
|
6923
|
+
this.logger.info(`[macros] Expanding CloudFormation macros for stack '${displaySafe(stack.stackName)}' via CFn round-trip (transforms: ${macros.map((m) => displaySafe(m)).join(", ")}; may take 30-60s)...`);
|
|
6842
6924
|
const before = Date.now();
|
|
6843
6925
|
const expanded = await expandMacros(stack.template, {
|
|
6844
6926
|
region,
|
|
@@ -21981,25 +22063,32 @@ function displayLogicalId(value) {
|
|
|
21981
22063
|
/**
|
|
21982
22064
|
* The DIAGNOSIS sentence itself, with no identity and no remedy in it.
|
|
21983
22065
|
*
|
|
21984
|
-
* ONE spelling, because two copies of a diagnosis are what drift.
|
|
21985
|
-
* {@link
|
|
21986
|
-
*
|
|
21987
|
-
*
|
|
21988
|
-
*
|
|
22066
|
+
* ONE spelling, because two copies of a diagnosis are what drift. Its two
|
|
22067
|
+
* consumers are the arms of {@link malformedStateDiagnosis}, which differ by
|
|
22068
|
+
* the IDENTITY they may name and not by this sentence — since
|
|
22069
|
+
* go-to-k/cdkd#3516 neither arm carries a command at all, so there is nothing
|
|
22070
|
+
* else for them to differ in.
|
|
21989
22071
|
*/
|
|
21990
22072
|
const MALFORMED_RESOURCES_DIAGNOSIS = "has no readable 'resources' map — the record is malformed or truncated. Both 'cdkd deploy' and 'cdkd destroy' REFUSE such a record rather than acting on it: they read the same map, an unreadable one is indistinguishable from an empty stack, and acting on that reading would make a deploy re-CREATE every resource and a destroy delete none of them.";
|
|
21991
22073
|
/**
|
|
21992
|
-
*
|
|
21993
|
-
*
|
|
21994
|
-
*
|
|
21995
|
-
*
|
|
21996
|
-
*
|
|
22074
|
+
* Identity plus the diagnosis, and NO command — every consumer appends prose
|
|
22075
|
+
* after this half, so a command baked in here can only land mid-sentence
|
|
22076
|
+
* (go-to-k/cdkd#3516). It used to end on a substituted `cdkd state show`, which
|
|
22077
|
+
* put the one runnable command in four messages one space from the next clause:
|
|
22078
|
+
* a line-select paste then handed `cdkd state show` the following sentence as
|
|
22079
|
+
* positional arguments. The command is {@link inspectCommand}'s, and the
|
|
22080
|
+
* caller ends ON it — the contract that function's own note states, and the
|
|
22081
|
+
* shape {@link malformedDestroyOutputsRefusalMessage} already had. Its
|
|
22082
|
+
* `orphans` twin had it too until this change gave both DESTROY refusals a
|
|
22083
|
+
* per-line shape instead, so that one is no longer the example to copy.
|
|
22084
|
+
*
|
|
22085
|
+
* `stackName` is optional so the withhold arm of
|
|
22086
|
+
* {@link malformedDestroyResourcesRefusalMessage} takes this same helper: that
|
|
22087
|
+
* arm must state the diagnosis under an identity it does not trust, which is
|
|
22088
|
+
* {@link stackClause}'s no-identity form rather than a second spelling.
|
|
21997
22089
|
*/
|
|
21998
|
-
function
|
|
21999
|
-
|
|
22000
|
-
const where = region === void 0 ? "" : ` (${shellQuote(safeRegion(region))})`;
|
|
22001
|
-
const regionFlag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeRegion(region))}`;
|
|
22002
|
-
return `State for ${shellQuote(stack)}${where} ${MALFORMED_RESOURCES_DIAGNOSIS} Inspect it with: cdkd state show ${shellQuote(stack)}${regionFlag} --json`;
|
|
22090
|
+
function malformedStateDiagnosis(stackName, region) {
|
|
22091
|
+
return `${stackClause(stackName, region)} ${MALFORMED_RESOURCES_DIAGNOSIS}`;
|
|
22003
22092
|
}
|
|
22004
22093
|
/**
|
|
22005
22094
|
* For a READ-ONLY command: give the record an empty resource bag so the
|
|
@@ -22053,8 +22142,55 @@ function repairMalformedResourcesForReadOnly(state) {
|
|
|
22053
22142
|
* documents `2` as "PARTIAL — journal kept, idempotent re-run", so a `2` here
|
|
22054
22143
|
* would tell an operator to re-run a command that attempted nothing.
|
|
22055
22144
|
*/
|
|
22056
|
-
function malformedStateRefusalMessage(
|
|
22057
|
-
|
|
22145
|
+
function malformedStateRefusalMessage(rawStackName, rawRegion) {
|
|
22146
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
22147
|
+
const region = absentIfEmpty(rawRegion);
|
|
22148
|
+
return `${malformedStateDiagnosis(stackName, region)} This command can WRITE state, so it refuses rather than continuing: saving over a record whose resource map could not be read would replace the evidence with a well-formed empty one and lose it permanently. Repair or remove the record first. Inspect it with: ${inspectCommand(stackName, region)}`;
|
|
22149
|
+
}
|
|
22150
|
+
/**
|
|
22151
|
+
* The destructive template, in the three messages that offer one.
|
|
22152
|
+
*
|
|
22153
|
+
* ONE spelling, because copies are what drift, and they carry it byte-identically
|
|
22154
|
+
* on purpose — a reader who has met one must recognise the others. Two wrap it
|
|
22155
|
+
* in {@link DROP_RECORD_LINE}'s label; `divergentRecordRegionRefusalMessage`
|
|
22156
|
+
* ends on it bare. `<stack>` / `<region>` are LITERAL: nothing may substitute them, for
|
|
22157
|
+
* the reason {@link malformedDestroyResourcesRefusalMessage}'s note gives.
|
|
22158
|
+
*/
|
|
22159
|
+
const DROP_RECORD_TEMPLATE = "cdkd state orphan <stack> --stack-region <region>";
|
|
22160
|
+
/**
|
|
22161
|
+
* The same template as a LABELLED line, for the two messages that carry their
|
|
22162
|
+
* commands one per line. The COMMAND is the atom rather than the line, because
|
|
22163
|
+
* the command is what drifts: `divergentRecordRegionRefusalMessage` ends on it
|
|
22164
|
+
* with no label, so THIS PAIR cannot half-land a `--stack-region` rename.
|
|
22165
|
+
* {@link dropRecordCommand} still spells it separately for the `cdkd orphan`
|
|
22166
|
+
* messages, which substitute into it — that one is not covered here.
|
|
22167
|
+
*/
|
|
22168
|
+
const DROP_RECORD_LINE = `Drop the record: ${DROP_RECORD_TEMPLATE}`;
|
|
22169
|
+
/**
|
|
22170
|
+
* May this message NAME its target and offer the destructive template beside
|
|
22171
|
+
* it (go-to-k/cdkd#3516 review)?
|
|
22172
|
+
*
|
|
22173
|
+
* Stricter than `safeIdentifier(x) === x`, which is what these two arms used
|
|
22174
|
+
* and which keeps a space, a `:`, a `'`, a `;` and a `|` — the `:` and the
|
|
22175
|
+
* space being the pair a label needs. That was enough while the
|
|
22176
|
+
* message was one paragraph, and stopped being enough the moment the commands
|
|
22177
|
+
* moved onto LABELLED lines: a stack name spelling
|
|
22178
|
+
* `Drop the record: cdkd state orphan prod --stack-region us-east-1` renders
|
|
22179
|
+
* exactly, takes this arm, and lands inside the quoted name on the inspect
|
|
22180
|
+
* line — where a terminal wrap puts cdkd's own label at the start of a visual
|
|
22181
|
+
* line, carrying a destructive command whose holes are already filled. A
|
|
22182
|
+
* line-select copies it. The label vocabulary is what made the forgery
|
|
22183
|
+
* credible, so the gate that admits a name into it is the one that had to
|
|
22184
|
+
* tighten.
|
|
22185
|
+
*
|
|
22186
|
+
* {@link isPasteableIdent} is that gate and the codebase already spends it on
|
|
22187
|
+
* this question (`gc.ts` gates its own destructive hint on the same pair). It
|
|
22188
|
+
* refuses a space and a quote outright while keeping every name CloudFormation
|
|
22189
|
+
* can produce, `Parent~Child` included, so no healthy record loses its
|
|
22190
|
+
* identity here.
|
|
22191
|
+
*/
|
|
22192
|
+
function mayNameTargetWithDestructiveRemedy(stackName, region) {
|
|
22193
|
+
return safeStackName(stackName) === stackName && safeRegion(region) === region && isPasteableIdent(stackName) && isPasteableIdent(region);
|
|
22058
22194
|
}
|
|
22059
22195
|
/**
|
|
22060
22196
|
* The DESTROY refusal text for the `resources` bag (issue
|
|
@@ -22117,7 +22253,7 @@ function malformedStateRefusalMessage(stackName, region) {
|
|
|
22117
22253
|
* destructive command at a DIFFERENT region's record for the same stack. That
|
|
22118
22254
|
* is the misdirection class {@link stackClause} records for stack names, one
|
|
22119
22255
|
* field over. Substituting into the read-only `state show` line is the
|
|
22120
|
-
* pre-existing behaviour of {@link
|
|
22256
|
+
* pre-existing behaviour of {@link inspectCommand} and is left alone;
|
|
22121
22257
|
* what this lane must not add is a destructive one.
|
|
22122
22258
|
*
|
|
22123
22259
|
* **go-to-k/cdkd#3328 closed the BODY half of that, and the template stays
|
|
@@ -22164,23 +22300,28 @@ function malformedStateRefusalMessage(stackName, region) {
|
|
|
22164
22300
|
* because a LEGACY record has no key region at all, in which case the value
|
|
22165
22301
|
* printed is the CLI's own and `--stack-region` must be omitted.
|
|
22166
22302
|
*
|
|
22167
|
-
* **The VERDICT
|
|
22168
|
-
*
|
|
22169
|
-
*
|
|
22170
|
-
*
|
|
22303
|
+
* **The VERDICT is {@link mayNameTargetWithDestructiveRemedy}** — the identifier
|
|
22304
|
+
* caps AND pasteability, since go-to-k/cdkd#3516 — so the stack name is
|
|
22305
|
+
* measured at `STACK_REF_MAX_CODE_POINTS` and the region at a region's 128,
|
|
22306
|
+
* which no real region approaches. Measuring the STACK at 128 instead is the
|
|
22307
|
+
* trap: an ordinary multi-level CDK nested child
|
|
22171
22308
|
* (`<root>~<...NestedStackResource><hash>~<...>`, measured past 150 code
|
|
22172
|
-
* points)
|
|
22173
|
-
*
|
|
22174
|
-
*
|
|
22175
|
-
*
|
|
22176
|
-
*
|
|
22309
|
+
* points) WOULD truncate there and take the withhold arm on a HEALTHY record,
|
|
22310
|
+
* making the fallback the common path for exactly the nested destroys this
|
|
22311
|
+
* lane added a guard to (review round 2 of go-to-k/cdkd#3332). The bound is
|
|
22312
|
+
* still a bound: a planted multi-kilobyte name is truncated at 1152 and lands
|
|
22313
|
+
* in the withhold arm.
|
|
22177
22314
|
*
|
|
22178
22315
|
* Identifiers are sanitized and THEN shell-quoted, for the reasons
|
|
22179
22316
|
* {@link safeIdentifier}'s note gives.
|
|
22180
22317
|
*/
|
|
22181
22318
|
function malformedDestroyResourcesRefusalMessage(stackName, region) {
|
|
22182
|
-
const exact =
|
|
22183
|
-
return
|
|
22319
|
+
const exact = mayNameTargetWithDestructiveRemedy(stackName, region);
|
|
22320
|
+
return [
|
|
22321
|
+
`${malformedStateDiagnosis(exact ? stackName : void 0, exact ? region : void 0)} This command DELETES state, so it refuses rather than continuing: the resource map IS the list of what to delete, so an unreadable one counts as ZERO resources and the run takes the empty-stack fast path, which removes state.json and reports success while every resource the record named is still live in AWS and no longer referenced by anything. Reading the bag as EMPTY is that same outcome rather than an alternative to it, so there is no repair available here. Repair or remove the record first. ${exact ? "To drop the record deliberately and leave the live resources standing, run 'cdkd state orphan' against the stack and the region THE RECORD'S S3 KEY holds. It is spelled as a template on its own line below rather than handed over ready to run, because that command DELETES a record and a key segment is chosen by anyone who can write this bucket: the key says WHICH record this is, which is not the same as vouching for it as a delete target. Confirm the key with 'cdkd state list --long' — a legacy record shows none, and for one of those the flag must be OMITTED or it selects nothing." : "This record's stack name or region does NOT render exactly — what is printed above is a sanitized form, and another record may render identically — so this message names no target and offers no command against one. List the records as stored with 'cdkd state list --long', which prints a name needing sanitizing in quoted form, and act on the one whose key matches."}`,
|
|
22322
|
+
`Inspect the record: ${inspectCommand(exact ? stackName : void 0, exact ? region : void 0)}`,
|
|
22323
|
+
...exact ? [DROP_RECORD_LINE] : []
|
|
22324
|
+
].join("\n");
|
|
22184
22325
|
}
|
|
22185
22326
|
/**
|
|
22186
22327
|
* For `cdkd destroy` / `cdkd state destroy`: refuse a record whose `resources`
|
|
@@ -22258,11 +22399,11 @@ const STATE_REGION_DIVERGED = "STATE_REGION_DIVERGED";
|
|
|
22258
22399
|
*/
|
|
22259
22400
|
function divergentRecordRegionRefusalMessage(stackName, keyRegion, divergentBodyRegion, resourceCount) {
|
|
22260
22401
|
const cap = STACK_REF_MAX_CODE_POINTS;
|
|
22261
|
-
const exact = safeIdentifier(stackName, cap) === stackName && safeIdentifier(keyRegion, cap) === keyRegion;
|
|
22402
|
+
const exact = safeIdentifier(stackName, cap) === stackName && safeIdentifier(keyRegion, cap) === keyRegion && isPasteableIdent(stackName) && isPasteableIdent(keyRegion);
|
|
22262
22403
|
const lists = resourceCount === void 0 ? "its resources map cannot be read" : `it still lists ${resourceCount} resource${resourceCount === 1 ? "" : "s"}`;
|
|
22263
22404
|
const kind = describeRegionValueKind(divergentBodyRegion);
|
|
22264
22405
|
const opening = exact ? `cdkd will not destroy stack ${shellQuote(safeIdentifier(stackName, cap))} (${shellQuote(safeIdentifier(keyRegion, cap))}): the state record read from that region's key carries a 'region' of its own (${kind}) that is not the key's, and ${lists}` : `cdkd will not destroy the state record this command loaded: it carries a 'region' of its own (${kind}) that is not the region of the key it was read from, and ${lists}`;
|
|
22265
|
-
const remedy = exact ? "Re-run with --verbose to see what the record's region field holds, then either destroy against the region the resources are really in, or repair that field to match the key it is stored under and re-run. To drop the record and leave the live resources standing, spelled out rather than pasteable because that command DELETES a record:
|
|
22406
|
+
const remedy = exact ? "Re-run with --verbose to see what the record's region field holds, then either destroy against the region the resources are really in, or repair that field to match the key it is stored under and re-run. To drop the record and leave the live resources standing, spelled out rather than pasteable because that command DELETES a record: " + DROP_RECORD_TEMPLATE : `This record's stack name or region does NOT render exactly — what any surrounding output shows is a sanitized form, and another record may render identically — so this message names no target and offers no command against one. List the records as stored with 'cdkd state list --long', which prints a name needing sanitizing in quoted form, and act on the one whose key matches. Inspect it with: ${inspectCommand(void 0, void 0)}`;
|
|
22266
22407
|
return `${opening} ${resourceCount === void 0 ? `— so cdkd can neither count what it would delete nor tell which region it is in` : `— so cdkd cannot tell which region those resources are in`}. cdkd stamps the key's region into every record it writes, so this record was not written by cdkd. Destroying against the key's region would issue every delete there; if the record's own region is the honest half, each delete comes back not-found, which this command reads as ALREADY DELETED — it would report success, remove the record, and leave every resource standing in the other region with nothing naming it. ${remedy}`;
|
|
22267
22408
|
}
|
|
22268
22409
|
/**
|
|
@@ -22313,8 +22454,10 @@ function refuseDivergentRecordRegionForDestroy(state, stackName, keyRegion, dive
|
|
|
22313
22454
|
* Identifiers are sanitized and THEN shell-quoted and the command is emitted
|
|
22314
22455
|
* LAST, for the reasons {@link safeIdentifier}'s note gives.
|
|
22315
22456
|
*/
|
|
22316
|
-
function malformedDeployResourcesRefusalMessage(
|
|
22317
|
-
|
|
22457
|
+
function malformedDeployResourcesRefusalMessage(rawStackName, rawRegion) {
|
|
22458
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
22459
|
+
const region = absentIfEmpty(rawRegion);
|
|
22460
|
+
return `${malformedStateDiagnosis(stackName, region)} '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: an unreadable map reads as ZERO recorded resources, so every resource the template declares is planned as a CREATE and the deploy re-provisions a stack that already exists, colliding on each deterministic name and duplicating the rest, then saves a well-formed record over the only evidence anything was wrong. Reading the bag as EMPTY produces that same plan rather than avoiding it. Nothing was provisioned and no state was written FOR THIS STACK. Repair or remove the record first; 'cdkd diff' previews the stack with this map read as EMPTY and warns that it did. Inspect it with: ${inspectCommand(stackName, region)}`;
|
|
22318
22461
|
}
|
|
22319
22462
|
/**
|
|
22320
22463
|
* For `cdkd deploy`: refuse a record whose `resources` bag cannot be read
|
|
@@ -22403,9 +22546,48 @@ function malformedRenderedContainersWarning(stackName, region, containers) {
|
|
|
22403
22546
|
const names = containers.map((name) => `'${safeIdentifier(name, SHORT_NAME_MAX_CODE_POINTS)}'`).join(", ");
|
|
22404
22547
|
return `State for ${shellQuote(stack)} (${shellQuote(reg)}) has a non-object ${names} — the record is malformed or truncated. 'Object.entries' walks a string or a list as readily as a map, so rendering one INVENTS a row per character or element. Continuing with it EMPTY: this view shows no rows there, which is not the same as the record holding none. A per-resource container is named once however many resources hold one. See the stored values with: cdkd state show ${shellQuote(stack)} --stack-region ${shellQuote(reg)} --json`;
|
|
22405
22548
|
}
|
|
22549
|
+
/**
|
|
22550
|
+
* `''` is NOT an identity, and every renderer below treats it as one
|
|
22551
|
+
* (go-to-k/cdkd#3520). `safeStackName('')` and `safeRegion('')` are both
|
|
22552
|
+
* `UNRENDERABLE`, so an empty region rendered `('<unrenderable>')` in the
|
|
22553
|
+
* clause AND `--stack-region '<unrenderable>'` in the command the reader
|
|
22554
|
+
* pastes — a flag that selects no record at all, on a message whose whole job
|
|
22555
|
+
* is to send them to the damaged one. `undefined` already means "absent" to
|
|
22556
|
+
* {@link stackClause} and {@link inspectCommand}, which drop the clause and
|
|
22557
|
+
* the flag, and that is the right answer for both identifiers.
|
|
22558
|
+
*
|
|
22559
|
+
* NORMALISE AT THE BOUNDARY. `dropRecordCommand`, `identityWithheld` and
|
|
22560
|
+
* `orphanInspectClause` each carry their own `=== ''` arm on purpose, so this
|
|
22561
|
+
* is not the module's only floor — but a floor in the SHARED helpers was tried
|
|
22562
|
+
* here and removed, and the reason is NOT that nothing reaches them: three
|
|
22563
|
+
* unboundaried builders do. It is that each passes `exact ? x : undefined`,
|
|
22564
|
+
* and `''` is never exact — `safeIdentifier('')` is the placeholder, so
|
|
22565
|
+
* `safeStackName('') !== ''` — so those helpers already receive `undefined`
|
|
22566
|
+
* and a floor there reddened no case. The boundary is what covers every
|
|
22567
|
+
* helper a builder reaches at once, which is the property
|
|
22568
|
+
* {@link malformedOrphanResourcePropertiesRefusalMessage} measured when
|
|
22569
|
+
* guarding inside ONE helper fixed only part of its message.
|
|
22570
|
+
*
|
|
22571
|
+
* Not reachable from today's callers: `cdkd state`'s sites sit below an
|
|
22572
|
+
* `if (!ref.region) throw`, which is falsy and so rejects `''` too, and
|
|
22573
|
+
* `cdkd export` normalises at its own call. What was missing is the CONTRACT —
|
|
22574
|
+
* a caller that hands `''` got the placeholder silently, and the guard that
|
|
22575
|
+
* would have caught it lived in another file.
|
|
22576
|
+
*
|
|
22577
|
+
* One cost, stated rather than discovered later: an empty STACK name with a
|
|
22578
|
+
* real region now drops that region from the clause and the command too, since
|
|
22579
|
+
* {@link inspectCommand} answers a missing stack with the two-hole template.
|
|
22580
|
+
* That is the existing `undefined` behaviour rather than a new rule — a record
|
|
22581
|
+
* cdkd cannot name is one it cannot build a selecting command for either.
|
|
22582
|
+
*/
|
|
22583
|
+
function absentIfEmpty(value) {
|
|
22584
|
+
return value === "" ? void 0 : value;
|
|
22585
|
+
}
|
|
22406
22586
|
/** The warning a caller of {@link repairMalformedResourcesForReadOnly} emits. */
|
|
22407
|
-
function malformedResourcesWarning(
|
|
22408
|
-
|
|
22587
|
+
function malformedResourcesWarning(rawStackName, rawRegion) {
|
|
22588
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
22589
|
+
const region = absentIfEmpty(rawRegion);
|
|
22590
|
+
return `${malformedStateDiagnosis(stackName, region)} Continuing with an EMPTY resource set: this command's output describes zero resources, which is not the same as the stack having none. Inspect it with: ${inspectCommand(stackName, region)}`;
|
|
22409
22591
|
}
|
|
22410
22592
|
/**
|
|
22411
22593
|
* The `outputs` half of {@link repairMalformedResourcesForReadOnly}, for a
|
|
@@ -22739,8 +22921,12 @@ function malformedOrphansRefusalMessage(stackName, region) {
|
|
|
22739
22921
|
* against a record that may not be the damaged one.
|
|
22740
22922
|
*/
|
|
22741
22923
|
function malformedDestroyOrphansRefusalMessage(stackName, region) {
|
|
22742
|
-
const exact =
|
|
22743
|
-
return
|
|
22924
|
+
const exact = mayNameTargetWithDestructiveRemedy(stackName, region);
|
|
22925
|
+
return [
|
|
22926
|
+
`${`${stackClause(exact ? stackName : void 0, exact ? region : void 0)} has no readable 'orphans' list — the record is malformed or truncated.`} This command DELETES state, so it refuses rather than continuing: an unreadable container counts as no orphans, so the run would proceed through resource deletion to removing state.json while the record's evidence that an earlier failed deploy left resources live in AWS was never read — and that evidence goes with the record. Reading it as EMPTY is that outcome rather than an alternative to it, so there is no repair available here. Repair or remove the record first. ${exact ? "To drop the record deliberately and leave every live resource standing, run 'cdkd state orphan' against the stack and the region THE RECORD'S S3 KEY holds. It is spelled as a template on its own line below rather than handed over ready to run, because that command DELETES a record and a key segment is chosen by anyone who can write this bucket: the key says WHICH record this is, which is not the same as vouching for it as a delete target. Confirm the key with 'cdkd state list --long' — a legacy record shows none, and for one of those the flag must be OMITTED or it selects nothing." : "This record's stack name or region does NOT render exactly, so this message names no target and offers no command against one. List the records as stored with 'cdkd state list --long' and act on the one whose key matches."}`,
|
|
22927
|
+
`Inspect the record: ${inspectCommand(exact ? stackName : void 0, exact ? region : void 0)}`,
|
|
22928
|
+
...exact ? [DROP_RECORD_LINE] : []
|
|
22929
|
+
].join("\n");
|
|
22744
22930
|
}
|
|
22745
22931
|
/**
|
|
22746
22932
|
* The destroy-path twin of {@link refuseMalformedOrphans}, carrying the text
|
|
@@ -22919,7 +23105,7 @@ const NAMED_UNREADABLE_PROPERTY_BAGS = 5;
|
|
|
22919
23105
|
* A region may also be absent on a v1 record, which predates the
|
|
22920
23106
|
* region-prefixed key layout. A placeholder would put a `--stack-region` into
|
|
22921
23107
|
* a pasted command that selects no record at all, so it is dropped for the
|
|
22922
|
-
* same reason — the call go-to-k/cdkd#3226 makes for `
|
|
23108
|
+
* same reason — the call go-to-k/cdkd#3226 makes for `inspectCommand`.
|
|
22923
23109
|
*/
|
|
22924
23110
|
function stackClause(stackName, region) {
|
|
22925
23111
|
if (stackName === void 0) return "The state record this command loaded";
|
|
@@ -23005,15 +23191,27 @@ function dropRecordCommand(stackName, region, recovery) {
|
|
|
23005
23191
|
* something PASTEABLE from — the drop command ({@link dropRecordCommand}), the
|
|
23006
23192
|
* `cdkd state show` line ({@link orphanInspectCommand}) and the object path
|
|
23007
23193
|
* ({@link orphanInspectClause}) — so no two of them can disagree about a name
|
|
23008
|
-
* (go-to-k/cdkd#3363 review, M0 and M2).
|
|
23009
|
-
*
|
|
23010
|
-
*
|
|
23011
|
-
*
|
|
23194
|
+
* (go-to-k/cdkd#3363 review, M0 and M2). The shared {@link inspectCommand}
|
|
23195
|
+
* stays ungated for its other callers, which offer a read only.
|
|
23196
|
+
*
|
|
23197
|
+
* It is NOT the module's gate for a DESTRUCTIVE remedy and must not be unified
|
|
23198
|
+
* with one: the three messages that offer a hole TEMPLATE are all stricter,
|
|
23199
|
+
* adding {@link isPasteableIdent} (go-to-k/cdkd#3516). This one is weaker on
|
|
23200
|
+
* purpose, and the gap is tracked rather than closed (go-to-k/cdkd#3523):
|
|
23201
|
+
* {@link dropRecordCommand} SUBSTITUTES, so tightening it here withholds the
|
|
23202
|
+
* drop command from a legacy record whose name merely needs quoting — the very
|
|
23203
|
+
* path go-to-k/cdkd#3359 built, where `cdkd state show` refuses outright and
|
|
23204
|
+
* this command is the way out. Measured: `It's Legacy` loses it.
|
|
23012
23205
|
*/
|
|
23013
23206
|
function rendersExactly(value) {
|
|
23014
23207
|
return safeIdentifier(value, STACK_REF_MAX_CODE_POINTS) === value;
|
|
23015
23208
|
}
|
|
23016
|
-
/**
|
|
23209
|
+
/**
|
|
23210
|
+
* The remedy command a message ends ON — unless the message also offers the
|
|
23211
|
+
* destructive template, in which case it ends the READ's own LINE and
|
|
23212
|
+
* {@link DROP_RECORD_LINE} is last (go-to-k/cdkd#3516). Two of the eight call
|
|
23213
|
+
* sites are that shape; the rest close their string with it.
|
|
23214
|
+
*/
|
|
23017
23215
|
function inspectCommand(stackName, region) {
|
|
23018
23216
|
if (stackName === void 0) return `cdkd state show ${commandHole("stack")} --stack-region ${commandHole("region")} --json`;
|
|
23019
23217
|
const flag = region === void 0 ? "" : ` --stack-region ${shellQuote(safeRegion(region))}`;
|
|
@@ -23237,7 +23435,9 @@ function namedPropertyBagsClause(stackName, region, logicalIds) {
|
|
|
23237
23435
|
* by a refusal the moment the flag comes off. So the message points at
|
|
23238
23436
|
* `cdkd diff` instead of weakening the guard.
|
|
23239
23437
|
*/
|
|
23240
|
-
function malformedResourcePropertiesRefusalMessage(
|
|
23438
|
+
function malformedResourcePropertiesRefusalMessage(rawStackName, rawRegion, logicalIds) {
|
|
23439
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
23440
|
+
const region = absentIfEmpty(rawRegion);
|
|
23241
23441
|
return `${namedPropertyBagsClause(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 DELETE and re-create of resources the template did not change, and reading the bag as empty produces that same verdict rather than avoiding it. 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 with those maps read as EMPTY and warns that it did. Inspect the record with: ${inspectCommand(stackName, region)}`;
|
|
23242
23442
|
}
|
|
23243
23443
|
/**
|
|
@@ -23328,8 +23528,8 @@ function malformedResourcePropertiesRefusalMessage(stackName, region, logicalIds
|
|
|
23328
23528
|
* validated either — go-to-k/cdkd#3360). See {@link stackClause}.
|
|
23329
23529
|
*/
|
|
23330
23530
|
function malformedOrphanResourcePropertiesRefusalMessage(rawStackName, rawRegion, logicalIds, recovery) {
|
|
23331
|
-
const stackName = rawStackName
|
|
23332
|
-
const region = rawRegion
|
|
23531
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
23532
|
+
const region = absentIfEmpty(rawRegion);
|
|
23333
23533
|
const inspect = orphanInspectClause(stackName, region, recovery);
|
|
23334
23534
|
const listCommand = withheldIdentityListCommand(stackName, region, recovery);
|
|
23335
23535
|
const commands = [
|
|
@@ -23528,7 +23728,9 @@ function refuseMalformedResourcePropertiesForOrphan(state, removedLogicalIds, st
|
|
|
23528
23728
|
* The warning a caller of {@link repairMalformedResourcePropertiesForReadOnly}
|
|
23529
23729
|
* emits.
|
|
23530
23730
|
*/
|
|
23531
|
-
function malformedResourcePropertiesWarning(
|
|
23731
|
+
function malformedResourcePropertiesWarning(rawStackName, rawRegion, logicalIds) {
|
|
23732
|
+
const stackName = absentIfEmpty(rawStackName);
|
|
23733
|
+
const region = absentIfEmpty(rawRegion);
|
|
23532
23734
|
return `${namedPropertyBagsClause(stackName, region, logicalIds)} Continuing with those maps EMPTY: what these records are stored as holding is NOT what this preview compares against. Where the template still declares the resource, every property it declares previews as an addition and a create-only one as a replacement; where it no longer declares it, the DELETE row shows an empty previous side instead of the stored one. Do NOT run 'cdkd deploy' against this record — it REFUSES on the same defect rather than acting on this preview. See the stored values with: ${inspectCommand(stackName, region)}`;
|
|
23533
23735
|
}
|
|
23534
23736
|
/**
|
|
@@ -34411,7 +34613,7 @@ var CloudControlProvider = class {
|
|
|
34411
34613
|
const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
|
|
34412
34614
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
34413
34615
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
34414
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
34616
|
+
const { ASGProvider } = await import("./asg-provider-BL_yHnHI.js").then((n) => n.n);
|
|
34415
34617
|
const asgProvider = new ASGProvider();
|
|
34416
34618
|
return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
|
|
34417
34619
|
}
|
|
@@ -48121,4 +48323,4 @@ var DeployEngine = class DeployEngine {
|
|
|
48121
48323
|
|
|
48122
48324
|
//#endregion
|
|
48123
48325
|
export { yellow as $, AssemblyReader as $i, safeStackName as $n, assertAssetBucketRegion as $r, requireConfigObject as $t, createPreDeleteFinalSnapshot as A, ResourceTimeoutError as Aa, resolveCaptureObservedState as Ai, malformedOutputsRefusalMessage as An, formatLockExpiry as Ar, carriesDynamicReference as At, isStatefulRecreateTargetSync as B, isMarkedNonRetryable as Ba, MIGRATE_TMP_PREFIX as Bi, refuseMalformedOrphansForDestroy as Bn, isReadableBag as Br, isSettledInstanceState as Bt, namesAnyDeclaredParameter as C, LocalInvokeBuildError as Ca, getDockerImageBySourceHash as Ci, isReadableResourceEntry as Cn, LockManager as Cr, slowCcOperationTimeoutMs as Ct, PRE_DELETE_SNAPSHOT_TYPES as D, NestedStackChildDirectDestroyError as Da, getLegacyStateBucketName as Di, malformedOrphanRecordsWarning as Dn, buildForceUnlockCommand as Dr, disableInstanceApiTermination as Dt, ATOMIC_FINAL_SNAPSHOT_TYPES as E, MalformedProducerRecordRefusalError as Ea, getDefaultStateBucketName as Ei, malformedLocalOutputsWarning as En, UNREPRODUCIBLE_LOCK_CLAUSE as Er, deleteSkipReason as Et, extractDeploymentEventError as F, SynthesisError as Fa, stateBucketExistenceConfirmed as Fi, malformedResourcesWarning as Fn, hasReadableExportSet as Fr, isImpossibleEmptyStoredAttribute as Ft, toCfnInteger as G, markRedactedCause as Ga, injectiveKeyPrefix as Gi, refuseMalformedResourcesForDestroy as Gn, stringifyValue as Gr, coerceCfnBoolean as Gt, WARM_THROUGHPUT_MEMBERS as H, isThrottlingError as Ha, uploadCfnTemplate as Hi, refuseMalformedOutputsForDestroy as Hn, orphansCarriedFrom as Hr, normalizeAwsTagsToCfn as Ht, makeSiblingClaimReader as I, formatError as Ia, warnDeprecatedNoPrefixCliFlag as Ii, malformedStateRefusalMessage as In, hasReasonlessBaselineRefusal as Ir, isNamelessDynamicReferenceError as It, bold as J, safeStringify$1 as Ja, decodeListingKey as Ji, repairMalformedOutputsForReadOnly as Jn, createAssetRedirectResolver as Jr, configIntegerRefusal as Jt, toFiniteNumber as K, retryClassificationText as Ka, producerCoordinateKey as Ki, refuseMalformedState as Kn, WorkGraph as Kr, coerceCfnInteger as Kt, planOrphanAdoption as L, isCdkdError as La, ssmResolvedValueType as Li, refuseDivergentRecordRegionForDestroy as Ln, hasUnverifiableParameterRefusal as Lr, isUnboundTemplateParameter as Lt, refusesFinalSnapshot as M, StackHasActiveImportsError as Ma, resolveStateBucketWithDefault as Mi, malformedRenderedContainersWarning as Mn, CUSTOM_RESOURCE_RESPONSE_PREFIX as Mr, cfnRefValueFromPhysicalId as Mt, unsupportedFinalSnapshotError as N, StackTerminationProtectionError as Na, resolveStateBucketWithDefaultAndSource as Ni, malformedResourceEntriesWarning as Nn, DEFAULT_STATE_PREFIX as Nr, coerceParameterTypedValue as Nt, buildFinalSnapshotIdentifier as O, PartialFailureError as Oa, resolveApp as Oi, malformedOrphansRefusalMessage as On, buildLockContentionMessage as Or, isTerminationProtectionPropagationError as Ot, makeCanonicalizePropertiesFn as P, StateError as Pa, resolveUseCdkBootstrapAssets as Pi, malformedResourcePropertiesWarning as Pn, exportNamesCarriedFrom as Pr, getAccountInfo as Pt, red as Q, derivePartitionAndUrlSuffix as Qi, safeRegion as Qn, BOOTSTRAP_MARKER_PREFIX as Qr, requireConfigArray as Qt, MULTI_REGION_RECREATE_BLOCKED_TYPES as R, normalizeAwsError as Ra, CFN_TEMPLATE_BODY_LIMIT as Ri, refuseMalformedNestedChildOutputs as Rn, importableOutputKeys as Rr, parameterTypeMayLoseSecretIdentity as Rt, computeParameterTaint as S, IntrinsicResolutionRefusalError as Sa, AssetManifestLoader as Si, hasReadableResources as Sn, scrubResourceRecord as Sr, isWaitAbandonedError as St, resourcesNamingDeclaredParameter as T, LockError as Ta, synthesisStatusMessage as Ti, malformedExportSourceWarning as Tn, rebuildClientForBucketRegion as Tr, deleteIndeterminateGuards as Tt, coerceWarmThroughput as U, isTransientServerError as Ua, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as Ui, refuseMalformedResourceEntries as Un, shouldRetainResource as Ur, resolveExplicitPhysicalId as Ut, renderStatefulReason as V, isRetryableTransientError as Va, findLargeInlineResources as Vi, refuseMalformedOutputs as Vn, orphansAfterRollback as Vr, WAFv2WebACLProvider as Vt, isWarmThroughputDecrease as W, markNonRetryable as Wa, injectiveKey as Wi, refuseMalformedResourcePropertiesForOrphan as Wn, AssetPublisher as Wr, assertRegionMatch as Wt, gray as X, PARTITION_TABLE as Xi, repairMalformedResourcePropertiesForReadOnly as Xn, rewriteTemplateAssetReferences as Xr, readConfigString as Xt, cyan as Y, __exportAll as Ya, expectedOwnerParam as Yi, repairMalformedResourceEntriesForReadOnly as Yn, loadPublishableAssetManifest as Yr, configStringRefusal as Yt, green as Z, canonicalizeRegion as Zi, repairMalformedResourcesForReadOnly as Zn, AssetModeResolver as Zr, replayWarn as Zt, bagHoldsSecretExpression as _, ConfigError as _a, redactDockerArgvValues as _i, UNREADABLE_ORPHANS_CONTAINER_ROW as _n, maskSecretsInError as _r, endCommandInterruptScope as _t, DeploymentEventsStore as a, nullPrototypeRecord as aa, validateAssetBucketName as ai, s3BucketDomainName as an, TemplateParser as ar, secretBearingStateKeyWarning as at, mergeNoChangeOutputs as b, DeployCancelledError as ba, escapeRegExp$1 as bi, hasReadableOrphans as bn, recoverMaskedOutput as br, startInterruptWatch as bt, replayFailedOperations as c, resolveAssemblyPath as ca, buildDockerImage as ci, s3BucketWebsiteUrl as cn, STATE_SOURCED_READBACK_RULES as cr, IAMRoleProvider as ct, updatePartialMessage as d, AwsClients as da, describeDockerExecFailure as di, applyCallerIdentityCredentials as dn, createSecretMasker as dr, ProviderRegistry as dt, failedStageNote as ea, ensureAssetStorage as ei, requireConfigString as en, findActionableSilentDrops as er, collectDeclaredOutputNames as et, updatePartialReason as f, getAwsClients as fa, describeDockerFailure as fi, callerEnvCredentials as fn, dynamicReferenceTokens as fr, wouldReturnToSdkProvider as ft, computeImplicitDeleteEdges as g, CdkdError as ga, partitionSensitiveEnv as gi, STATE_RESOURCES_MALFORMED as gn, markSameGenerationBag as gr, beginCommandInterruptScope as gt, IMPLICIT_DELETE_DEPENDENCIES as h, AssetError as ha, getDockerCmd as hi, INTRINSIC_KEYS as hn, isSingleDynamicReferenceToken as hr, maskerOrIdentity as ht, DeploymentEventsReader as i, hasPlainPrototype$1 as ia, readBootstrapMarkerBody as ii, s3BucketArn as in, DagBuilder as ir, secretBearing as it, isFinalSnapshotError as j, ResourceUpdateNotSupportedError as ja, resolveSkipPrefix as ji, malformedOutputsWarning as jn, shellQuote as jr, carriesFetchableDynamicReference as jt, ccRoutedFinalSnapshotError as k, ProvisioningError as ka, resolveAutoAssetStorage as ki, malformedOrphansWarning as kn, forceQuitRecoveryClause as kr, IntrinsicFunctionResolver as kt, replayRollback as l, clearBucketRegionCache as la, resolveDockerContextDirectory as li, applyRoleArnIfSet as ln, TEMPLATE_SOURCED_RULES as lr, collectInlinePolicyNamesManagedBySiblings as lt, maskingRetryLogger as m, setAwsClients as ma, formatDockerLoginError as mi, DiffCalculator as mn, identityKeyFor as mr, maskDeep as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, defineOwnKey as na, isCrossRegionRedirect as ni, producerRegionsFromState as nn, describeTypeWithThrottleRetry as nr, exportAliasCollisionScrubWarning as nt, planFailedOps as o, ownValue as oa, validateContainerRepoName as oi, s3BucketDualStackDomainName as on, STATE_SOURCED_BASELINE_RULES as or, secretSafeKeyDisplay as ot, withResourceDeadline as p, resetAwsClients as pa, dockerSpawnEnvWithSensitive as pi, envCredentialsAreAssumedRole as pn, errorCauseChain as pr, createMaskedRetryLogger as pt, formatResourceLine as q, describeAwsFailure as qa, producerRecordKey as qi, repairMalformedOrphansForReadOnly as qn, buildAssetRedirectMap as qr, configBooleanRefusal as qt, DeployEngine as r, hasOwnKey as ra, parseBootstrapMarker as ri, withSharedDrainBudget as rn, withRetry as rr, isExportAliasCollision as rt, planRollback as s, renderAssemblyPathEscape as sa, buildDenyExternalAccessPolicy as si, s3BucketRegionalDomainName as sn, STATE_SOURCED_CROSS_GENERATION_RULES as sr, getCurrentResourceSecrets as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, processStackMessages as ta, getBootstrapMarkerKey as ti, classifyReplaySecretRegion as tn, findSilentDropProperties as tr, collectPublishedOutputNames as tt, resolveReplacementOldType as u, resolveBucketRegion as ua, describeDockerCapturedOutput as ui, AWS_CREDENTIAL_ENV_KEYS as un, carriesSecretMask as ur, clearOnUpdateRemoval as ut, isSecretBearingReferenceString as v, CrossAccountSecretRefusalError as va, runDockerForeground as vi, UNREADABLE_RESOURCES_MAP_ROW as vn, maskSecretsInText as vr, interruptWatchListenerCount as vt, reachableDivergentParameters as w, LocalStartServiceError as wa, Synthesizer as wi, malformedExportNamesWarning as wn, S3StateBackend as wr, UNSPECIFIED_SKIP_REASON as wt, bindingSkippedOutputs as x, DynamicReferenceRegionAmbiguousError as xa, stripControlChars as xi, hasReadableOutputs as xn, redactSecretsForState as xr, CloudControlProvider as xt, keptWholeReasonText as y, DependencyError as ya, runDockerStreaming as yi, displayLogicalId as yn, recordMaskOnlyValue as yr, isInterruptedWaitError as yt, isStatefulRecreateTargetForReplace as z, withErrorHandling as za, CFN_TEMPLATE_URL_LIMIT as zi, refuseMalformedOrphans as zn, importableOutputs as zr, refStateLookupFromResource as zt };
|
|
48124
|
-
//# sourceMappingURL=deploy-engine-
|
|
48326
|
+
//# sourceMappingURL=deploy-engine-BRy8S7QH.js.map
|