@go-to-k/cdkd 0.290.29 → 0.290.31

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.
@@ -1,6 +1,6 @@
1
- import { C as displayIdent, S as UNRENDERABLE, T as truncateCodePoints, 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 displaySafe, x as STACK_REF_MAX_CODE_POINTS, y as withoutGeneratedFallbackName } from "./logger-6LP1UiFA.js";
1
+ import { C as displayAwsMessage, E 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-BjWM-UVj.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-snXN__f1.js";
3
+ import { t as getCdkdVersion } from "./version-IwTfNQ-K.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";
@@ -17109,7 +17109,8 @@ var DagBuilder = class {
17109
17109
  resourceIds.forEach((logicalId) => {
17110
17110
  const resource = this.parser.getResource(template, logicalId);
17111
17111
  graph.setNode(logicalId, resource);
17112
- this.logger.debug(`Added node: ${logicalId} (${resource?.Type})`);
17112
+ const typeText = resource?.Type == null ? "<no Type>" : displayIdent(resource.Type);
17113
+ this.logger.debug(`Added node: ${displayIdent(logicalId)} (${typeText})`);
17113
17114
  });
17114
17115
  this.logger.debug(`Total nodes: ${resourceIds.length}`);
17115
17116
  const parameterNames = new Set(Object.keys(template.Parameters ?? {}));
@@ -17123,15 +17124,15 @@ var DagBuilder = class {
17123
17124
  for (const depId of dependencies) {
17124
17125
  if (skip?.has(depId)) {
17125
17126
  relaxedEdgeCount++;
17126
- this.logger.debug(`Skipped CDK-defensive DependsOn edge: ${depId} -> ${logicalId} (default; opt out with --no-aggressive-vpc-parallel)`);
17127
+ this.logger.debug(`Skipped CDK-defensive DependsOn edge: ${displayIdent(depId)} -> ${displayIdent(logicalId)} (default; opt out with --no-aggressive-vpc-parallel)`);
17127
17128
  continue;
17128
17129
  }
17129
17130
  if (graph.hasNode(depId)) {
17130
17131
  graph.setEdge(depId, logicalId);
17131
17132
  edgeCount++;
17132
- this.logger.debug(`Added edge: ${depId} -> ${logicalId}`);
17133
- } else if (parameterNames.has(depId)) this.logger.debug(`Skipped Parameter reference: ${logicalId} -> ${depId}`);
17134
- else this.logger.warn(`Resource ${logicalId} depends on ${depId}, but ${depId} not found in template`);
17133
+ this.logger.debug(`Added edge: ${displayIdent(depId)} -> ${displayIdent(logicalId)}`);
17134
+ } else if (parameterNames.has(depId)) this.logger.debug(`Skipped Parameter reference: ${displayIdent(logicalId)} -> ${displayIdent(depId)}`);
17135
+ else this.logger.warn(`Resource ${displayIdent(logicalId)} depends on ${displayIdent(depId)}, but ${displayIdent(depId)} not found in template`);
17135
17136
  }
17136
17137
  }
17137
17138
  if (relaxedEdgeCount > 0) this.logger.info(`[DagBuilder] Relaxed ${relaxedEdgeCount} CDK-defensive DependsOn edge(s) (default; opt out with --no-aggressive-vpc-parallel)`);
@@ -17140,7 +17141,7 @@ var DagBuilder = class {
17140
17141
  edgeCount += this.addLambdaVpcEdges(graph, template);
17141
17142
  if (!alg.isAcyclic(graph)) {
17142
17143
  const cycles = this.findCycles(graph);
17143
- throw new DependencyError(`Circular dependency detected in template. Cycles: ${cycles.map((c) => c.join(" -> ")).join("; ")}`);
17144
+ throw new DependencyError(`Circular dependency detected in template. Cycles: ${cycles.map((c) => c.map((n) => displayIdent(n)).join(" -> ")).join("; ")}`);
17144
17145
  }
17145
17146
  return graph;
17146
17147
  }
@@ -17172,9 +17173,9 @@ var DagBuilder = class {
17172
17173
  });
17173
17174
  if (readyNodes.length === 0) {
17174
17175
  const remaining = graphCopy.nodes();
17175
- throw new DependencyError(`Circular dependency detected. Remaining nodes: ${remaining.join(", ")}`);
17176
+ throw new DependencyError(`Circular dependency detected. Remaining nodes: ${remaining.map((n) => displayIdent(n)).join(", ")}`);
17176
17177
  }
17177
- this.logger.debug(`Level ${levelNum}: ${readyNodes.length} resources - ${readyNodes.join(", ")}`);
17178
+ this.logger.debug(`Level ${levelNum}: ${readyNodes.length} resources - ${readyNodes.map((n) => displayIdent(n)).join(", ")}`);
17178
17179
  levels.push(readyNodes);
17179
17180
  readyNodes.forEach((node) => {
17180
17181
  graphCopy.removeNode(node);
@@ -17291,7 +17292,7 @@ var DagBuilder = class {
17291
17292
  if (graph.hasEdge(policyId, logicalId)) continue;
17292
17293
  graph.setEdge(policyId, logicalId);
17293
17294
  added++;
17294
- this.logger.debug(`Added implicit edge (custom resource policy): ${policyId} -> ${logicalId}`);
17295
+ this.logger.debug(`Added implicit edge (custom resource policy): ${displayIdent(policyId)} -> ${displayIdent(logicalId)}`);
17295
17296
  }
17296
17297
  }
17297
17298
  if (added > 0) this.logger.debug(`Added ${added} implicit edges for custom resource policies`);
@@ -17322,7 +17323,7 @@ var DagBuilder = class {
17322
17323
  if (graph.hasEdge(depId, dependentId)) continue;
17323
17324
  graph.setEdge(depId, dependentId);
17324
17325
  added++;
17325
- this.logger.debug(`Added implicit edge (lambda vpc): ${depId} -> ${dependentId}`);
17326
+ this.logger.debug(`Added implicit edge (lambda vpc): ${displayIdent(depId)} -> ${displayIdent(dependentId)}`);
17326
17327
  }
17327
17328
  if (added > 0) this.logger.debug(`Added ${added} implicit edges for Lambda VpcConfig`);
17328
17329
  return added;
@@ -20580,13 +20581,14 @@ const PROPERTY_COVERAGE_BY_TYPE = /* @__PURE__ */ new Map([
20580
20581
  "FifoThroughputScope",
20581
20582
  "FifoTopic",
20582
20583
  "KmsMasterKeyId",
20584
+ "MaximumMessageSize",
20583
20585
  "SignatureVersion",
20584
20586
  "Subscription",
20585
20587
  "Tags",
20586
20588
  "TopicName",
20587
20589
  "TracingConfig"
20588
20590
  ]),
20589
- silentDrop: /* @__PURE__ */ new Map([["MaximumMessageSize", "not yet implemented by cdkd"]]),
20591
+ silentDrop: /* @__PURE__ */ new Map(),
20590
20592
  createOnlyDrops: /* @__PURE__ */ new Set()
20591
20593
  }],
20592
20594
  ["AWS::SNS::TopicPolicy", {
@@ -23136,7 +23138,8 @@ async function assumeRoleForCrossAccountStateRead(roleArn) {
23136
23138
  }
23137
23139
  const promise = (async () => {
23138
23140
  const logger = getLogger().child("role-arn");
23139
- logger.debug(`Assuming role for cross-account state read: ${roleArn}`);
23141
+ const displayRoleArn = displayIdent(roleArn, { maxCodePoints: 613 });
23142
+ logger.debug(`Assuming role for cross-account state read: ${displayRoleArn}`);
23140
23143
  const sts = new STSClient({ ...awsClientDefaults() });
23141
23144
  try {
23142
23145
  let response;
@@ -23147,13 +23150,13 @@ async function assumeRoleForCrossAccountStateRead(roleArn) {
23147
23150
  DurationSeconds: 3600
23148
23151
  }));
23149
23152
  } catch (err) {
23150
- const message = err instanceof Error ? err.message : String(err);
23151
- throw new Error(`AssumeRole into ${roleArn} failed: ${message}. If this is a trust-policy issue, the producer's role must allow sts:AssumeRole from the consumer's principal. See https://github.com/go-to-k/cdkd/blob/main/docs/cross-stack-references.md for the trust-policy template.`, { cause: err instanceof Error ? err : void 0 });
23153
+ const message = displayAwsMessage(err instanceof Error ? err.message : String(err));
23154
+ throw new Error(`AssumeRole into ${displayRoleArn} failed: ${message}. If this is a trust-policy issue, the producer's role must allow sts:AssumeRole from the consumer's principal. See https://github.com/go-to-k/cdkd/blob/main/docs/cross-stack-references.md for the trust-policy template.`, { cause: err instanceof Error ? err : void 0 });
23152
23155
  }
23153
- if (!response.Credentials) throw new Error(`AssumeRole for cross-account Fn::GetStackOutput returned no credentials (RoleArn=${roleArn})`);
23156
+ if (!response.Credentials) throw new Error(`AssumeRole for cross-account Fn::GetStackOutput returned no credentials (RoleArn=${displayRoleArn})`);
23154
23157
  const { AccessKeyId, SecretAccessKey, SessionToken, Expiration } = response.Credentials;
23155
- if (!AccessKeyId || !SecretAccessKey || !SessionToken) throw new Error(`AssumeRole response missing required credentials fields for cross-account state read (RoleArn=${roleArn})`);
23156
- logger.info(`Assumed role for cross-account state read: ${roleArn} (session expires ${Expiration?.toISOString() ?? "unknown"})`);
23158
+ if (!AccessKeyId || !SecretAccessKey || !SessionToken) throw new Error(`AssumeRole response missing required credentials fields for cross-account state read (RoleArn=${displayRoleArn})`);
23159
+ logger.info(`Assumed role for cross-account state read: ${displayRoleArn} (session expires ${Expiration?.toISOString() ?? "unknown"})`);
23157
23160
  return {
23158
23161
  accessKeyId: AccessKeyId,
23159
23162
  secretAccessKey: SecretAccessKey,
@@ -23261,18 +23264,23 @@ async function applyRoleArnIfSet(opts) {
23261
23264
  if (!roleArn) return;
23262
23265
  if (getAssumedRoleCredentials() !== void 0) throw new Error(SECOND_ROLE_PUBLISH_REFUSAL);
23263
23266
  const logger = getLogger().child("role-arn");
23264
- const displayRoleArn = displaySafe(roleArn, { asciiOnly: true });
23267
+ const displayRoleArn = displayIdent(roleArn, { maxCodePoints: 613 });
23265
23268
  logger.debug(`Assuming role ${displayRoleArn}...`);
23266
23269
  const sts = new STSClient({
23267
23270
  ...awsClientDefaults({ ignoreAssumedRole: true }),
23268
23271
  ...opts.region && { region: opts.region }
23269
23272
  });
23270
23273
  try {
23271
- const response = await sts.send(new AssumeRoleCommand({
23272
- RoleArn: roleArn,
23273
- RoleSessionName: `cdkd-${Date.now()}`,
23274
- DurationSeconds: 3600
23275
- }));
23274
+ let response;
23275
+ try {
23276
+ response = await sts.send(new AssumeRoleCommand({
23277
+ RoleArn: roleArn,
23278
+ RoleSessionName: `cdkd-${Date.now()}`,
23279
+ DurationSeconds: 3600
23280
+ }));
23281
+ } catch (err) {
23282
+ throw new Error(`AssumeRole for ${displayRoleArn} failed: ${displayAwsMessage(err instanceof Error ? err.message : String(err))}`, { cause: err instanceof Error ? err : void 0 });
23283
+ }
23276
23284
  if (!response.Credentials) throw new Error(`AssumeRole returned no credentials for role ${displayRoleArn}`);
23277
23285
  const { AccessKeyId, SecretAccessKey, SessionToken, Expiration } = response.Credentials;
23278
23286
  if (!AccessKeyId || !SecretAccessKey || !SessionToken) throw new Error(`AssumeRole response missing credentials fields for role ${displayRoleArn}`);
@@ -27181,14 +27189,14 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27181
27189
  if (!targetRegion) return ambient;
27182
27190
  const target = canonicalizeRegion(targetRegion);
27183
27191
  const loggedTarget = targetLogText ?? (targetRegion === this.explicitRegion ? this.explicitRegionLogText : void 0) ?? target;
27184
- if (!isClientSafeRegion(target)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to build AWS clients for the region '${stripControlChars(loggedTarget).slice(0, 64)}': it is not a valid AWS region name, and a region is substituted into the AWS service hostname.`));
27192
+ 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.`));
27185
27193
  if (typeof ambient.withRegion !== "function") return ambient;
27186
27194
  const cached = this.regionScopedClients.get(target);
27187
27195
  if (cached) return cached;
27188
27196
  if (canonicalizeRegion(ambient.configuredRegion) === target) return ambient;
27189
27197
  const scoped = ambient.withRegion(target);
27190
27198
  this.regionScopedClients.set(target, scoped);
27191
- this.logger.debug(`Using region-scoped AWS clients for ${loggedTarget}`);
27199
+ this.logger.debug(`Using region-scoped AWS clients for ${displaySafe(loggedTarget)}`);
27192
27200
  return scoped;
27193
27201
  }
27194
27202
  /**
@@ -27254,7 +27262,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27254
27262
  */
27255
27263
  async resolveParameters(template, userParameters, options) {
27256
27264
  const inheritedSecrets = options?.inheritedSecrets;
27257
- const maskInherited = (text) => inheritedSecrets && inheritedSecrets.size > 0 ? maskSecretsInText(text, inheritedSecrets) : text;
27265
+ const maskInherited = (text) => {
27266
+ const mask = (value) => inheritedSecrets && inheritedSecrets.size > 0 ? maskSecretsInText(value, inheritedSecrets) : value;
27267
+ return displaySafe(mask(stripControlChars(mask(text))));
27268
+ };
27258
27269
  const inheritedLogContext = {
27259
27270
  template,
27260
27271
  resources: {},
@@ -27359,7 +27370,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27359
27370
  for (const name of Object.keys(templateConditions)) try {
27360
27371
  await withSharedDrainBudget(() => evaluateByName(name));
27361
27372
  } catch (error) {
27362
- this.logger.warn(this.maskSecretsForLog(`Failed to evaluate condition ${name}: ${error instanceof Error ? error.message : String(error)}, assuming false`, maskingContext));
27373
+ this.logger.warn(this.displayMasked(`Failed to evaluate condition ${name}: ${error instanceof Error ? error.message : String(error)}, assuming false`, maskingContext));
27363
27374
  conditions[name] = false;
27364
27375
  inProgress.delete(name);
27365
27376
  }
@@ -27647,7 +27658,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27647
27658
  const value = context.parameters[logicalId];
27648
27659
  const declared = context.template.Parameters;
27649
27660
  const paramDef = declared != null && Object.hasOwn(declared, logicalId) ? declared[logicalId] : void 0;
27650
- this.logger.debug(`Resolved Ref to parameter: ${logicalId} -> ${this.maskSecretsForLog(stringifyParameterForLog(paramDef, this.maskValueLeaves(value, context)), context)}`);
27661
+ this.logger.debug(`Resolved Ref to parameter: ${logicalId} -> ${this.displayMasked(stringifyParameterForLog(paramDef, this.maskValueLeaves(value, context)), context)}`);
27651
27662
  this.recordInheritedParameterSecrets(logicalId, value, context);
27652
27663
  return value;
27653
27664
  }
@@ -27657,10 +27668,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27657
27668
  this.logger.debug(`Resolved Ref to pseudo parameter: ${logicalId} -> ${valueStr}`);
27658
27669
  return pseudoValue;
27659
27670
  }
27660
- const notFoundMsg = `Ref ${logicalId} not found (not a resource, parameter, or pseudo parameter)`;
27671
+ const loggedLogicalId = this.displayMasked(logicalId, context);
27672
+ const notFoundMsg = `Ref ${loggedLogicalId} not found (not a resource, parameter, or pseudo parameter)`;
27661
27673
  if (context.bestEffort) this.logger.debug(notFoundMsg);
27662
27674
  else this.logger.warn(notFoundMsg);
27663
- throw markNonRetryable(/* @__PURE__ */ new Error(`Ref ${logicalId} not found`));
27675
+ throw markNonRetryable(/* @__PURE__ */ new Error(`Ref ${loggedLogicalId} not found`));
27664
27676
  }
27665
27677
  /**
27666
27678
  * Resolve the value a CloudFormation `Ref` returns for a resource.
@@ -27820,11 +27832,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27820
27832
  this.rejectPlaceholderArnAttribute(resource, attributeName, flatValue, logicalId, context);
27821
27833
  if (resource.resourceType === "AWS::Route53::HostedZone" && attributeName === "NameServers" && typeof flatValue === "string") {
27822
27834
  const nameServers = flatValue === "" ? [] : flatValue.split(",");
27823
- this.logger.debug(`Normalized legacy Fn::GetAtt attribute: ${logicalId}.${this.maskSecretsForLog(attributeName, context)} -> ${this.maskSecretsForLog(stringifyAttributeForLog(attributeName, this.maskValueLeaves(nameServers, context)), context)}`);
27835
+ this.logger.debug(`Normalized legacy Fn::GetAtt attribute: ${logicalId}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(nameServers, context)), context)}`);
27824
27836
  return this.noteAttributeSecrecy(logicalId, attributeName, nameServers, context);
27825
27837
  }
27826
- this.logger.debug(`Resolved Fn::GetAtt from attributes: ${logicalId}.${this.maskSecretsForLog(attributeName, context)} -> ${this.maskSecretsForLog(stringifyAttributeForLog(attributeName, this.maskValueLeaves(flatValue, context)), context)}`);
27827
- if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE$1 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX) && carriesDynamicReference(flatValue)) return await this.reresolveCrossStackValue(flatValue, nestedStackChildRegionFromLocalArn(resource.physicalId), context, `nested stack ${logicalId} ${this.logTextOfLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
27838
+ this.logger.debug(`Resolved Fn::GetAtt from attributes: ${logicalId}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(flatValue, context)), context)}`);
27839
+ if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE$1 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX) && carriesDynamicReference(flatValue)) return await this.reresolveCrossStackValue(flatValue, nestedStackChildRegionFromLocalArn(resource.physicalId), context, `nested stack ${logicalId} ${this.displayLeaf(attributeName, context)}`, crossStackSourceKey({ "Fn::GetAtt": getAtt }));
27828
27840
  return this.noteAttributeSecrecy(logicalId, attributeName, flatValue, context);
27829
27841
  }
27830
27842
  if (attributeName.includes(".")) {
@@ -27836,18 +27848,18 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27836
27848
  break;
27837
27849
  }
27838
27850
  if (cursor !== void 0) {
27839
- this.logger.debug(`Resolved Fn::GetAtt from nested attributes: ${logicalId}.${this.maskSecretsForLog(attributeName, context)} -> ${this.maskSecretsForLog(stringifyAttributeForLog(attributeName, this.maskValueLeaves(cursor, context)), context)}`);
27851
+ this.logger.debug(`Resolved Fn::GetAtt from nested attributes: ${logicalId}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(cursor, context)), context)}`);
27840
27852
  return this.noteAttributeSecrecy(logicalId, attributeName, cursor, context);
27841
27853
  }
27842
27854
  }
27843
27855
  }
27844
27856
  if (resource.resourceType === NESTED_STACK_RESOURCE_TYPE$1 && attributeName.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX)) {
27845
- const declared = Object.keys(resource.attributes ?? {}).filter((k) => k.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX)).sort().map((k) => this.maskSecretsForLog(this.outputNameLogText(k, context), context));
27857
+ const declared = Object.keys(resource.attributes ?? {}).filter((k) => k.startsWith(NESTED_STACK_OUTPUT_ATTRIBUTE_PREFIX)).sort().map((k) => this.displayMasked(this.outputNameLogText(k, context), context));
27846
27858
  const declaredText = declared.length > 0 ? declared.join(", ") : "(none)";
27847
- throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}]: the nested stack '${logicalId}' declares no output named '${this.maskSecretsForLog(this.outputNameLogText(attributeName, context), context)}'. Its outputs are ${this.maskSecretsForLog(declaredText, context)}. Check the output name in the nested stack's template, and deploy the child stack again if you have just added it.`));
27859
+ throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}]: the nested stack '${logicalId}' declares no output named '${this.displayMasked(this.outputNameLogText(attributeName, context), context)}'. Its outputs are ${this.displayMasked(declaredText, context)}. Check the output name in the nested stack's template, and deploy the child stack again if you have just added it.`));
27848
27860
  }
27849
27861
  const value = await this.constructGuardedAttribute(resource, attributeName, context, logicalId);
27850
- this.logger.debug(`Resolved Fn::GetAtt: ${logicalId}.${this.maskSecretsForLog(attributeName, context)} -> ${this.maskSecretsForLog(stringifyAttributeForLog(attributeName, this.maskValueLeaves(value, context)), context)}`);
27862
+ this.logger.debug(`Resolved Fn::GetAtt: ${logicalId}.${this.displayMasked(attributeName, context)} -> ${this.displayMasked(stringifyAttributeForLog(attributeName, this.maskValueLeaves(value, context)), context)}`);
27851
27863
  return value;
27852
27864
  }
27853
27865
  /**
@@ -27898,7 +27910,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27898
27910
  const declared = context.noEchoAttributeResources?.get(logicalId);
27899
27911
  if ((declared === true || declared !== void 0 && declared.has(attributeName)) && context.recordedSecretValues) recordMaskOnlyValuesIn(value, context.recordedSecretValues);
27900
27912
  if (context.redactedAttributeReads !== void 0 && carriesSecretMask(value)) {
27901
- const maskedAttributeName = this.maskSecretsForLog(attributeName, context);
27913
+ const maskedAttributeName = this.displayMasked(attributeName, context);
27902
27914
  this.pushRedactedAttributeRead(context, {
27903
27915
  kind: "attribute",
27904
27916
  logicalId,
@@ -27940,7 +27952,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27940
27952
  rejectPlaceholderArnAttribute(resource, attributeName, value, logicalId, context) {
27941
27953
  if (!REF_RETURNS_ARN_FROM_STATE.get(resource.resourceType)?.includes(attributeName)) return;
27942
27954
  if (typeof value !== "string" || !isPlaceholderArn(value)) return;
27943
- throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resource.resourceType}: the recorded value "${stringifyValue(this.maskValueLeaves(value, context))}" is a placeholder written by a cdkd version older than issue #1681 — its region and account fields are literal wildcards, so it is not a usable ARN. Deploy the stack again so the resource's next update heals the record (cdkd now records the real ARN), or re-import the resource.`));
27955
+ throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}] for ${resource.resourceType}: the recorded value "${stringifyValue(this.maskValueLeaves(value, context))}" is a placeholder written by a cdkd version older than issue #1681 — its region and account fields are literal wildcards, so it is not a usable ARN. Deploy the stack again so the resource's next update heals the record (cdkd now records the real ARN), or re-import the resource.`));
27944
27956
  }
27945
27957
  /**
27946
27958
  * Construct resource attribute value based on resource type, refusing to
@@ -27985,7 +27997,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
27985
27997
  async constructGuardedAttribute(resource, attributeName, context, logicalId) {
27986
27998
  const accountInfo = await getAccountInfo(this.resolverRegion);
27987
27999
  const value = await this.constructAttribute(resource, attributeName, context, logicalId, accountInfo);
27988
- if (accountInfo.fabricated && embedsAccountId(value, accountInfo.accountId)) throw new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resource.resourceType}: STS did not report this deploy's account id, so cdkd would build the value from the placeholder account ${accountInfo.accountId} — structurally valid, naming a different account, and indistinguishable downstream from a real one. Fix the AWS credentials (or set AWS_ACCOUNT_ID to this deploy's account) and deploy again.`);
28000
+ if (accountInfo.fabricated && embedsAccountId(value, accountInfo.accountId)) throw new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}] for ${resource.resourceType}: STS did not report this deploy's account id, so cdkd would build the value from the placeholder account ${accountInfo.accountId} — structurally valid, naming a different account, and indistinguishable downstream from a real one. Fix the AWS credentials (or set AWS_ACCOUNT_ID to this deploy's account) and deploy again.`);
27989
28001
  return value;
27990
28002
  }
27991
28003
  /**
@@ -28030,7 +28042,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28030
28042
  const associations = (await ec2.send(new DescribeVpcsCommand({ VpcIds: [physicalId] }))).Vpcs?.[0]?.Ipv6CidrBlockAssociationSet || [];
28031
28043
  const blocks = associations.filter((a) => a.Ipv6CidrBlockState?.State === "associated").map((a) => a.Ipv6CidrBlock);
28032
28044
  if (blocks.length > 0) {
28033
- this.logger.debug(`Resolved VPC Ipv6CidrBlocks for ${physicalId}: ${this.maskSecretsForLog(JSON.stringify(this.maskValueLeaves(blocks, context)), context)}`);
28045
+ this.logger.debug(`Resolved VPC Ipv6CidrBlocks for ${physicalId}: ${this.displayMasked(JSON.stringify(this.maskValueLeaves(blocks, context)), context)}`);
28034
28046
  return blocks;
28035
28047
  }
28036
28048
  if (associations.filter((a) => a.Ipv6CidrBlockState?.State === "associating").length === 0) {
@@ -28047,7 +28059,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28047
28059
  return [];
28048
28060
  }
28049
28061
  case "DefaultSecurityGroup": {
28050
- if (!/^vpc-[0-9a-f]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, DefaultSecurityGroup] for AWS::EC2::VPC: the state record's physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context)).slice(0, 64)}" is not a VPC id (vpc-<hex>), so cdkd will not use it as an EC2 filter value. Repair the record (cdkd import, or re-create the VPC) and deploy again.`));
28062
+ if (!/^vpc-[0-9a-f]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, DefaultSecurityGroup] for AWS::EC2::VPC: the state record's physical id "${this.displayMasked(physicalId, context).slice(0, 64)}" is not a VPC id (vpc-<hex>), so cdkd will not use it as an EC2 filter value. Repair the record (cdkd import, or re-create the VPC) and deploy again.`));
28051
28063
  const cachedGroupId = cachedVpcDefaultSecurityGroups[physicalId];
28052
28064
  if (cachedGroupId !== void 0) return cachedGroupId;
28053
28065
  let groupId;
@@ -28262,7 +28274,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28262
28274
  if (resourceType === "AWS::EC2::SecurityGroup") switch (attributeName) {
28263
28275
  case "GroupId": return physicalId;
28264
28276
  case "VpcId": {
28265
- if (!/^sg-[0-9a-f]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, VpcId] for AWS::EC2::SecurityGroup: the state record's physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context)).slice(0, 64)}" is not a security group id (sg-<hex>), so cdkd will not look it up. Repair the record (cdkd import, or re-create the security group) and deploy again.`));
28277
+ if (!/^sg-[0-9a-f]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, VpcId] for AWS::EC2::SecurityGroup: the state record's physical id "${this.displayMasked(physicalId, context).slice(0, 64)}" is not a security group id (sg-<hex>), so cdkd will not look it up. Repair the record (cdkd import, or re-create the security group) and deploy again.`));
28266
28278
  const cachedVpcId = cachedSecurityGroupVpcIds[physicalId];
28267
28279
  if (cachedVpcId !== void 0) return cachedVpcId;
28268
28280
  let vpcId;
@@ -28356,7 +28368,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28356
28368
  resourceType,
28357
28369
  physicalId,
28358
28370
  context,
28359
- observed: `DescribeInstances reports no ${this.maskSecretsForLog(attributeName, context)} yet (${observedState})`,
28371
+ observed: `DescribeInstances reports no ${this.displayMasked(attributeName, context)} yet (${observedState})`,
28360
28372
  remedy: settled ? "Check the instance in the console; a terminated or stopped instance has no such attribute to serve." : "Deploy without --no-wait so the instance is running before its attributes are read, or reference the attribute from a later deploy once it is."
28361
28373
  });
28362
28374
  }
@@ -28369,7 +28381,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28369
28381
  const value = attributeName === "LatestVersionNumber" ? lt?.LatestVersionNumber : lt?.DefaultVersionNumber;
28370
28382
  if (value !== void 0 && value !== null) return String(value);
28371
28383
  } catch (err) {
28372
- this.logger.warn(`DescribeLaunchTemplates(${physicalId}) failed for ${this.maskSecretsForLog(attributeName, context)}: ${this.maskSecretsForLog(err instanceof Error ? err.message : String(err), context)}`);
28384
+ this.logger.warn(`DescribeLaunchTemplates(${physicalId}) failed for ${this.displayMasked(attributeName, context)}: ${this.displayMasked(err instanceof Error ? err.message : String(err), context)}`);
28373
28385
  }
28374
28386
  return attributeName === "LatestVersionNumber" ? "$Latest" : "$Default";
28375
28387
  }
@@ -28379,7 +28391,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28379
28391
  if (resourceType === "AWS::CloudFront::Distribution") switch (attributeName) {
28380
28392
  case "Id": return physicalId;
28381
28393
  case "DomainName": {
28382
- if (!/^[A-Z0-9]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, DomainName] for AWS::CloudFront::Distribution: the state record's physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context)).slice(0, 64)}" is not a distribution id (upper-case alphanumerics), so cdkd will not look it up. Repair the record (cdkd import, or re-create the distribution) and deploy again.`));
28394
+ if (!/^[A-Z0-9]+$/.test(physicalId)) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, DomainName] for AWS::CloudFront::Distribution: the state record's physical id "${this.displayMasked(physicalId, context).slice(0, 64)}" is not a distribution id (upper-case alphanumerics), so cdkd will not look it up. Repair the record (cdkd import, or re-create the distribution) and deploy again.`));
28383
28395
  const cachedDomainName = cachedCloudFrontDomainNames[physicalId];
28384
28396
  if (cachedDomainName !== void 0) return cachedDomainName;
28385
28397
  let domainName;
@@ -28413,7 +28425,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28413
28425
  default: return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
28414
28426
  }
28415
28427
  if (resourceType === "AWS::RDS::DBProxy" || resourceType === "AWS::RDS::DBProxyEndpoint") {
28416
- if (attributeName === "VpcId") throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: the state record holds no VpcId for it (the read-back that would have recorded it reported none), and the physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" is a name, not a VPC id, so cdkd refuses to substitute it. Update the resource so its next deploy records the value, or reference the VPC directly.`));
28428
+ if (attributeName === "VpcId") throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}] for ${resourceType}: the state record holds no VpcId for it (the read-back that would have recorded it reported none), and the physical id "${this.displayMasked(physicalId, context)}" is a name, not a VPC id, so cdkd refuses to substitute it. Update the resource so its next deploy records the value, or reference the VPC directly.`));
28417
28429
  return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
28418
28430
  }
28419
28431
  return this.guardedPhysicalIdFallback(logicalId, attributeName, resourceType, physicalId, context);
@@ -28472,7 +28484,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28472
28484
  */
28473
28485
  refuseUnservedAttribute(site) {
28474
28486
  const { logicalId, attributeName, resourceType, physicalId, context, observed, remedy } = site;
28475
- throw new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: ${observed}. The physical id "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" is not a usable ${this.maskSecretsForLog(attributeName, context)}, so cdkd refuses to substitute it. ${remedy}`);
28487
+ throw new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}] for ${resourceType}: ${observed}. The physical id "${this.displayMasked(physicalId, context)}" is not a usable ${this.displayMasked(attributeName, context)}, so cdkd refuses to substitute it. ${remedy}`);
28476
28488
  }
28477
28489
  /**
28478
28490
  * The `observed` clause of {@link refuseUnservedAttribute} for a live read
@@ -28484,7 +28496,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28484
28496
  const name = displaySafe(err instanceof Error && err.name ? err.name : "Error", { asciiOnly: true }).slice(0, 64).trim() || "Error";
28485
28497
  const status = err?.$metadata?.httpStatusCode;
28486
28498
  const errorClass = typeof status === "number" && Number.isInteger(status) ? `${name}, HTTP ${status}` : name;
28487
- this.logger.debug(`${read} failed (${errorClass}): ${this.maskSecretsForLog(err instanceof Error ? err.message : String(err), context)}`);
28499
+ this.logger.debug(`${read} failed (${errorClass}): ${this.displayMasked(err instanceof Error ? err.message : String(err), context)}`);
28488
28500
  return `${read} failed (${errorClass}); re-run with --verbose for the AWS error text`;
28489
28501
  }
28490
28502
  /**
@@ -28519,11 +28531,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28519
28531
  const expectsUrlShape = attributeName.endsWith("Url") && !/^https?:\/\//.test(physicalId);
28520
28532
  if (expectsArnShape || expectsUrlShape) {
28521
28533
  const expectedShape = expectsArnShape ? "an ARN (arn:...)" : "a URL (http(s)://...)";
28522
- throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and the physical ID fallback "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" is not ${expectedShape}. CloudFormation would return a different value here, so falling back to the physical ID would silently produce a wrong value (e.g. in stack Outputs). Avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${this.maskSecretsForLog(attributeName, context)}.`));
28534
+ throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and the physical ID fallback "${this.displayMasked(physicalId, context)}" is not ${expectedShape}. CloudFormation would return a different value here, so falling back to the physical ID would silently produce a wrong value (e.g. in stack Outputs). Avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${this.displayMasked(attributeName, context)}.`));
28523
28535
  }
28524
- if (this.strictGetAtt) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.maskSecretsForLog(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and --strict-getatt rejects the physical ID fallback "${displaySafe(this.maskThenStripThenMask(physicalId, context))}" (which may not be the value CloudFormation would return). Drop --strict-getatt to fall back with a warning, avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${this.maskSecretsForLog(attributeName, context)}.`));
28536
+ if (this.strictGetAtt) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Cannot resolve Fn::GetAtt [${logicalId}, ${this.displayMasked(attributeName, context)}] for ${resourceType}: attributes are not enriched for this resource type, and --strict-getatt rejects the physical ID fallback "${this.displayMasked(physicalId, context)}" (which may not be the value CloudFormation would return). Drop --strict-getatt to fall back with a warning, avoid this Fn::GetAtt, or file an issue at https://github.com/go-to-k/cdkd/issues so cdkd can enrich ${resourceType}.${this.displayMasked(attributeName, context)}.`));
28525
28537
  this.physicalIdFallbackCount++;
28526
- this.logger.warn(`Unknown attribute ${this.maskSecretsForLog(attributeName, context)} for resource type ${resourceType}, returning physical ID`);
28538
+ this.logger.warn(`Unknown attribute ${this.displayMasked(attributeName, context)} for resource type ${resourceType}, returning physical ID`);
28527
28539
  return physicalId;
28528
28540
  }
28529
28541
  /**
@@ -28594,7 +28606,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28594
28606
  complete
28595
28607
  });
28596
28608
  this.rememberLogTwin(context, result, twin);
28597
- this.logger.debug(`Resolved Fn::Join: ${this.maskSecretsForLog(this.logTwinText(result, twin, context), context)}`);
28609
+ this.logger.debug(`Resolved Fn::Join: ${this.displayMasked(this.logTwinText(result, twin, context), context)}`);
28598
28610
  return result;
28599
28611
  }
28600
28612
  /**
@@ -28799,13 +28811,13 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28799
28811
  } catch (getAttError) {
28800
28812
  if (getAttError instanceof IntrinsicResolutionRefusalError) throw getAttError;
28801
28813
  this.rethrowStructuralSubFailure(varNameStr, getAttError, context);
28802
- this.logger.warn(this.maskSecretsForLog(this.subPlaceholderWarning(varNameStr, getAttError), context));
28814
+ this.logger.warn(this.displayMasked(this.subPlaceholderWarning(varNameStr, getAttError), context));
28803
28815
  replacement = match[0];
28804
28816
  }
28805
28817
  else {
28806
28818
  if (refError instanceof IntrinsicResolutionRefusalError) throw refError;
28807
28819
  this.rethrowStructuralSubFailure(varNameStr, refError, context);
28808
- this.logger.warn(this.maskSecretsForLog(this.subPlaceholderWarning(varNameStr, refError), context));
28820
+ this.logger.warn(this.displayMasked(this.subPlaceholderWarning(varNameStr, refError), context));
28809
28821
  replacement = match[0];
28810
28822
  }
28811
28823
  }
@@ -28843,7 +28855,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
28843
28855
  complete
28844
28856
  });
28845
28857
  this.rememberLogTwin(context, result, twin);
28846
- this.logger.debug(`Resolved Fn::Sub: ${this.maskSecretsForLog(this.logTwinText(result, twin, context), context)}`);
28858
+ this.logger.debug(`Resolved Fn::Sub: ${this.displayMasked(this.logTwinText(result, twin, context), context)}`);
28847
28859
  return result;
28848
28860
  }
28849
28861
  /**
@@ -29186,7 +29198,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29186
29198
  return recovered;
29187
29199
  }
29188
29200
  if (context.redactedAttributeReads !== void 0) {
29189
- const loggedOrigin = this.maskSecretsForLog(origin, context);
29201
+ const loggedOrigin = this.displayMasked(origin, context);
29190
29202
  this.pushRedactedAttributeRead(context, {
29191
29203
  kind: "cross-stack",
29192
29204
  display: loggedOrigin
@@ -29210,7 +29222,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29210
29222
  }
29211
29223
  return v;
29212
29224
  };
29213
- this.logger.debug(`Re-resolving dynamic reference(s) in ${this.maskSecretsForLog(origin, context)}`);
29225
+ this.logger.debug(`Re-resolving dynamic reference(s) in ${this.displayMasked(origin, context)}`);
29214
29226
  const reresolved = await walk(value);
29215
29227
  if (sourceKey !== void 0 && typeof value === "string" && isSingleDynamicReferenceToken(value) && typeof reresolved === "string" && context.recordedSecretValues?.has(reresolved) === true && isSecretExpressionByVerdictOrSpelling(value)) recordCrossStackExpression(context.recordedSecretValues, sourceKey, value, reresolved);
29216
29228
  return reresolved;
@@ -29280,7 +29292,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29280
29292
  const target = canonicalizeRegion(producerRegion);
29281
29293
  if (target === canonicalizeRegion(this.explicitRegion)) return this;
29282
29294
  const regionText = producerRegionLogText !== void 0 ? canonicalizeRegion(producerRegionLogText) : this.regionLogText(producerRegion, context);
29283
- const guestRegionText = this.maskThenStripThenMask(regionText, context);
29295
+ const guestRegionText = this.displayMasked(regionText, context);
29284
29296
  const cached = this.producerRegionResolvers.get(target);
29285
29297
  if (cached) {
29286
29298
  if (cached.explicitRegionLogText !== guestRegionText) cached.explicitRegionLogText = "***";
@@ -29306,20 +29318,20 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29306
29318
  const exportName = await this.resolveValue(importValueArg, context);
29307
29319
  if (typeof exportName !== "string") throw new Error(`Fn::ImportValue: export name must resolve to a string, got ${typeof exportName}`);
29308
29320
  if (!context.stateBackend) throw new Error("Fn::ImportValue: state backend is required for cross-stack references");
29309
- const loggedExportName = this.maskSecretsForLog(exportName, context);
29321
+ const loggedExportName = this.displayMasked(exportName, context);
29310
29322
  this.logger.debug(`Resolving Fn::ImportValue: ${loggedExportName}`);
29311
29323
  if (context.exportIndex) {
29312
29324
  let entry;
29313
29325
  try {
29314
29326
  entry = await context.exportIndex.lookup(exportName);
29315
29327
  } catch (err) {
29316
- this.logger.warn(`Exports index lookup failed for '${loggedExportName}': ${this.maskSecretsForLog(err instanceof Error ? err.message : String(err), context)}; falling back to state.json scan`);
29328
+ this.logger.warn(`Exports index lookup failed for '${loggedExportName}': ${this.displayMasked(err instanceof Error ? err.message : String(err), context)}; falling back to state.json scan`);
29317
29329
  entry = void 0;
29318
29330
  }
29319
29331
  if (entry && (!context.stackName || entry.producerStack !== context.stackName)) {
29320
29332
  this.recordImport(context, exportName, entry.producerStack, entry.producerRegion);
29321
- this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from index: ${this.maskSecretsForLog(entry.producerStack, context)} / ${this.maskSecretsForLog(entry.producerRegion, context)}; ${carriesDynamicReference(entry.value) ? "redacted dynamic reference" : "literal value"})`);
29322
- return await this.reresolveCrossStackValue(entry.value, entry.producerRegion, context, `Fn::ImportValue '${this.logTextOfLeaf(exportName, context)}' (producer ${this.logTextOfLeaf(entry.producerStack, context)} / ${this.logTextOfLeaf(entry.producerRegion, context)})`, sourceKey, {
29333
+ this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from index: ${this.displayMasked(entry.producerStack, context)} / ${this.displayMasked(entry.producerRegion, context)}; ${carriesDynamicReference(entry.value) ? "redacted dynamic reference" : "literal value"})`);
29334
+ return await this.reresolveCrossStackValue(entry.value, entry.producerRegion, context, `Fn::ImportValue '${this.displayLeaf(exportName, context)}' (producer ${this.displayLeaf(entry.producerStack, context)} / ${this.displayLeaf(entry.producerRegion, context)})`, sourceKey, {
29323
29335
  stackName: entry.producerStack,
29324
29336
  region: entry.producerRegion,
29325
29337
  outputKey: exportName
@@ -29332,30 +29344,30 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29332
29344
  for (const ref of allStacks) {
29333
29345
  const { stackName: refStack, region: refRegion } = ref;
29334
29346
  if (context.stackName && refStack === context.stackName) {
29335
- this.logger.debug(`Skipping current stack: ${this.maskSecretsForLog(refStack, context)}`);
29347
+ this.logger.debug(`Skipping current stack: ${this.displayMasked(refStack, context)}`);
29336
29348
  continue;
29337
29349
  }
29338
29350
  try {
29339
29351
  const lookupRegion = refRegion ?? this.resolverRegion ?? "";
29340
29352
  if (!lookupRegion) {
29341
- this.logger.debug(`No region available for stack '${this.maskSecretsForLog(refStack, context)}' — skipping (cdkd cannot read state without a region)`);
29353
+ this.logger.debug(`No region available for stack '${this.displayMasked(refStack, context)}' — skipping (cdkd cannot read state without a region)`);
29342
29354
  continue;
29343
29355
  }
29344
29356
  const stateData = await context.stateBackend.getState(refStack, lookupRegion);
29345
29357
  if (!stateData) {
29346
- this.logger.debug(`No state found for stack: ${this.maskSecretsForLog(refStack, context)} (${this.maskSecretsForLog(lookupRegion, context)})`);
29358
+ this.logger.debug(`No state found for stack: ${this.displayMasked(refStack, context)} (${this.displayMasked(lookupRegion, context)})`);
29347
29359
  continue;
29348
29360
  }
29349
29361
  const { state } = stateData;
29350
29362
  if (importableOutputKeys(state).includes(exportName)) {
29351
29363
  const value = state.outputs[exportName];
29352
- this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from stack: ${this.maskSecretsForLog(refStack, context)} / ${this.maskSecretsForLog(lookupRegion, context)}; ${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
29364
+ this.logger.info(`Resolved Fn::ImportValue: ${loggedExportName} (from stack: ${this.displayMasked(refStack, context)} / ${this.displayMasked(lookupRegion, context)}; ${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
29353
29365
  if (context.exportIndex) context.exportIndex.patchEntry(exportName, {
29354
29366
  value,
29355
29367
  producerStack: refStack,
29356
29368
  producerRegion: lookupRegion
29357
29369
  }).catch((err) => {
29358
- this.logger.debug(`Failed to patch exports index for '${this.maskSecretsForLog(exportName, context)}': ${this.maskSecretsForLog(err instanceof Error ? err.message : String(err), context)}`);
29370
+ this.logger.debug(`Failed to patch exports index for '${this.displayMasked(exportName, context)}': ${this.displayMasked(err instanceof Error ? err.message : String(err), context)}`);
29359
29371
  });
29360
29372
  this.recordImport(context, exportName, refStack, lookupRegion);
29361
29373
  found = {
@@ -29366,11 +29378,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29366
29378
  break;
29367
29379
  }
29368
29380
  } catch (error) {
29369
- this.logger.warn(`Failed to read state for stack ${this.maskSecretsForLog(refStack, context)}: ${this.maskSecretsForLog(error instanceof Error ? error.message : String(error), context)}`);
29381
+ this.logger.warn(`Failed to read state for stack ${this.displayMasked(refStack, context)}: ${this.displayMasked(error instanceof Error ? error.message : String(error), context)}`);
29370
29382
  continue;
29371
29383
  }
29372
29384
  }
29373
- if (found) return await this.reresolveCrossStackValue(found.value, found.lookupRegion, context, `Fn::ImportValue '${this.logTextOfLeaf(exportName, context)}' (producer ${this.logTextOfLeaf(found.refStack, context)} / ${this.logTextOfLeaf(found.lookupRegion, context)})`, sourceKey, {
29385
+ if (found) return await this.reresolveCrossStackValue(found.value, found.lookupRegion, context, `Fn::ImportValue '${this.displayLeaf(exportName, context)}' (producer ${this.displayLeaf(found.refStack, context)} / ${this.displayLeaf(found.lookupRegion, context)})`, sourceKey, {
29374
29386
  stackName: found.refStack,
29375
29387
  region: found.lookupRegion,
29376
29388
  outputKey: exportName
@@ -29413,7 +29425,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29413
29425
  };
29414
29426
  return;
29415
29427
  } catch (error) {
29416
- this.logger.warn(`Fn::ImportValue: CloudFormation ListExports fallback failed for export '${this.maskSecretsForLog(exportName, context)}' (region ${this.resolverRegion}): ${this.maskSecretsForLog(error instanceof Error ? error.message : String(error), context)}. Grant cloudformation:ListExports to resolve exports from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
29428
+ this.logger.warn(`Fn::ImportValue: CloudFormation ListExports fallback failed for export '${this.displayMasked(exportName, context)}' (region ${this.resolverRegion}): ${this.displayMasked(error instanceof Error ? error.message : String(error), context)}. Grant cloudformation:ListExports to resolve exports from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
29417
29429
  return;
29418
29430
  }
29419
29431
  }
@@ -29435,7 +29447,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29435
29447
  * `OutputName` is the overwhelmingly common cause, and the list is what makes
29436
29448
  * the error actionable.
29437
29449
  *
29438
- * `maskSecretsForLog` reads the consumer pass's log twin first (issue #3150),
29450
+ * `maskSecretsRaw` reads the consumer pass's log twin first (issue #3150),
29439
29451
  * so a key equal to a name this pass assembled around a short secret is
29440
29452
  * masked. Residual, stated rather than hidden: the needles and twins belong to the
29441
29453
  * CONSUMER's resolution, so a plaintext sitting in a PRODUCER key that this
@@ -29445,7 +29457,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29445
29457
  describeAvailableOutputs(keys, context) {
29446
29458
  if (keys.length === 0) return "(none)";
29447
29459
  const shown = keys.slice(0, MAX_LISTED_AVAILABLE_OUTPUTS);
29448
- const rendered = shown.map((k) => this.maskSecretsForLog(k, context)).join(", ");
29460
+ const rendered = shown.map((k) => this.displayMasked(k, context)).join(", ");
29449
29461
  const hidden = keys.length - shown.length;
29450
29462
  return hidden > 0 ? `${rendered} (+${hidden} more)` : rendered;
29451
29463
  }
@@ -29485,8 +29497,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29485
29497
  return await fetch;
29486
29498
  } catch (error) {
29487
29499
  const message = error instanceof Error ? error.message : String(error);
29488
- const cfnNameMask = this.positionalNameMask([[stackName, this.maskSecretsForLog(stackName, context)], [region, this.maskSecretsForLog(loggedRegionText, context)]]);
29489
- this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${this.maskSecretsForLog(stackName, context)}' (${this.maskSecretsForLog(loggedRegionText, context)}): ${this.maskSecretsForLog(cfnNameMask ? cfnNameMask(message) : message, context)}. Grant cloudformation:DescribeStacks to resolve outputs from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
29500
+ const cfnNameMask = this.positionalNameMask([[stackName, this.displayMasked(stackName, context)], [region, this.displayMasked(loggedRegionText, context)]]);
29501
+ this.logger.warn(`Fn::GetStackOutput: CloudFormation DescribeStacks fallback failed for stack '${this.displayMasked(stackName, context)}' (${this.displayMasked(loggedRegionText, context)}): ${displayAwsMessage(this.displayMasked(cfnNameMask ? cfnNameMask(message) : message, context))}. Grant cloudformation:DescribeStacks to resolve outputs from CloudFormation-managed stacks, or pass --no-cfn-fallback to disable the fallback.`);
29490
29502
  return;
29491
29503
  }
29492
29504
  }
@@ -29596,7 +29608,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29596
29608
  const resolvedRegion = await this.resolveValue(args["Region"], context);
29597
29609
  if (typeof resolvedRegion !== "string" || resolvedRegion === "") throw new Error(`Fn::GetStackOutput: Region must resolve to a non-empty string, got ${typeof resolvedRegion}`);
29598
29610
  const requestedRegion = canonicalizeRegion(resolvedRegion);
29599
- if (!isClientSafeRegion(requestedRegion)) throw new Error(`Fn::GetStackOutput: '${this.maskThenStripThenMask(this.logTextOfLeaf(resolvedRegion, context) !== resolvedRegion ? "***" : resolvedRegion, context).slice(0, 64)}' is not a valid AWS region name. The region selects both the AWS endpoint and the state-file key, so cdkd will not use it.`);
29611
+ if (!isClientSafeRegion(requestedRegion)) throw new Error(`Fn::GetStackOutput: '${this.displayMasked(this.logTextOfLeaf(resolvedRegion, context) !== resolvedRegion ? "***" : resolvedRegion, context).slice(0, 64)}' is not a valid AWS region name. The region selects both the AWS endpoint and the state-file key, so cdkd will not use it.`);
29600
29612
  region = requestedRegion;
29601
29613
  loggedRegionText = this.regionLogText(resolvedRegion, context);
29602
29614
  }
@@ -29606,11 +29618,12 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29606
29618
  if (typeof raw !== "string" || raw === "") throw new Error(`Fn::GetStackOutput: RoleArn must be a literal string in the template (no Ref / Fn::GetAtt / Fn::Sub allowed for cross-account references). Got ${raw === null ? "null" : Array.isArray(raw) ? "array" : typeof raw}${typeof raw === "object" ? ` (intrinsic shape: ${JSON.stringify(raw).slice(0, 80)})` : ""}.`);
29607
29619
  roleArn = raw;
29608
29620
  }
29609
- if (!roleArn && context.stackName && context.stackName === stackName && canonicalizeRegion(region) === canonicalizeRegion(this.resolverRegion)) throw new Error(`Fn::GetStackOutput: cannot reference own stack '${this.maskSecretsForLog(stackName, context)}' in the same region '${this.maskSecretsForLog(loggedRegionText, context)}'`);
29610
- const loggedStackName = this.maskSecretsForLog(stackName, context);
29611
- const loggedOutputName = this.maskSecretsForLog(outputName, context);
29612
- const loggedRegion = this.maskSecretsForLog(loggedRegionText, context);
29613
- this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${roleArn}` : ""}`);
29621
+ if (!roleArn && context.stackName && context.stackName === stackName && canonicalizeRegion(region) === canonicalizeRegion(this.resolverRegion)) throw new Error(`Fn::GetStackOutput: cannot reference own stack '${this.displayMasked(stackName, context)}' in the same region '${this.displayMasked(loggedRegionText, context)}'`);
29622
+ const loggedStackName = this.displayMasked(stackName, context);
29623
+ const loggedOutputName = this.displayMasked(outputName, context);
29624
+ const loggedRegion = this.displayMasked(loggedRegionText, context);
29625
+ const shownRoleArn = roleArn ? displayIdent(roleArn, { maxCodePoints: 613 }) : "";
29626
+ this.logger.debug(`Resolving Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${shownRoleArn}` : ""}`);
29614
29627
  let stateData;
29615
29628
  try {
29616
29629
  stateData = roleArn ? await this.getCrossAccountStackState(roleArn, stackName, region, context) : await this.getSameAccountStackState(stackName, region, context);
@@ -29630,7 +29643,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29630
29643
  return value;
29631
29644
  }
29632
29645
  }
29633
- throw new Error(`Fn::GetStackOutput: stack '${loggedStackName}' not found in region '${loggedRegion}'${roleArn ? ` (cross-account via ${roleArn})` : ""}. ${!roleArn && this.cfnFallback ? "Searched cdkd state and CloudFormation stacks. Make sure the producer stack has been deployed (via cdkd or CloudFormation)." : `Make sure the producer stack has been deployed via cdkd.`}`);
29646
+ throw new Error(`Fn::GetStackOutput: stack '${loggedStackName}' not found in region '${loggedRegion}'${roleArn ? ` (cross-account via ${shownRoleArn})` : ""}. ${!roleArn && this.cfnFallback ? "Searched cdkd state and CloudFormation stacks. Make sure the producer stack has been deployed (via cdkd or CloudFormation)." : `Make sure the producer stack has been deployed via cdkd.`}`);
29634
29647
  }
29635
29648
  if (!hasReadableOutputs(stateData.state)) throw markNonRetryable(new MalformedProducerRecordRefusalError(`Fn::GetStackOutput: the state record of producer stack '${loggedStackName}' (${loggedRegion}) has no readable 'outputs' map — the record is malformed or truncated. cdkd refuses to resolve from it rather than reading it as a map: 'Object.hasOwn' answers TRUE for '0' on a string and for an index on a list, so continuing would resolve ONE CHARACTER or element of the record as this reference's value and this deploy would send it to AWS. Inspect the producer's record with 'cdkd state show' --json, repair or remove it, then re-run.`));
29636
29649
  const outputs = stateData.state.outputs ?? {};
@@ -29639,10 +29652,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29639
29652
  throw new Error(`Fn::GetStackOutput: output '${loggedOutputName}' not found in stack '${loggedStackName}' (${loggedRegion}). Available outputs: ${available}`);
29640
29653
  }
29641
29654
  const value = outputs[outputName];
29642
- this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${roleArn}` : ""} (${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
29655
+ this.logger.info(`Resolved Fn::GetStackOutput: StackName=${loggedStackName}, Region=${loggedRegion}, OutputName=${loggedOutputName}${roleArn ? `, RoleArn=${shownRoleArn}` : ""} (${carriesDynamicReference(value) ? "redacted dynamic reference" : "literal value"})`);
29643
29656
  if (!roleArn) this.recordOutputRead(context, stackName, region, outputName);
29644
- if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new CrossAccountSecretRefusalError(`Fn::GetStackOutput: output '${loggedOutputName}' of stack '${loggedStackName}' (${loggedRegion}) is a redacted dynamic reference, and this is a CROSS-ACCOUNT reference (RoleArn ${roleArn}). cdkd will not resolve a producer account's secret with the consumer's credentials — a same-named secret in the consumer account would answer instead. Export a non-secret value (e.g. the secret's ARN) and resolve it in the consumer stack, or reference the producer stack from within its own account.`));
29645
- return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput '${this.logTextOfLeaf(outputName, context)}' (producer ${this.logTextOfLeaf(stackName, context)} / ${loggedRegionText})`, sourceKey, {
29657
+ if (roleArn && !context.skipDynamicReferences && carriesDynamicReference(value)) throw markNonRetryable(new CrossAccountSecretRefusalError(`Fn::GetStackOutput: output '${loggedOutputName}' of stack '${loggedStackName}' (${loggedRegion}) is a redacted dynamic reference, and this is a CROSS-ACCOUNT reference (RoleArn ${shownRoleArn}). cdkd will not resolve a producer account's secret with the consumer's credentials — a same-named secret in the consumer account would answer instead. Export a non-secret value (e.g. the secret's ARN) and resolve it in the consumer stack, or reference the producer stack from within its own account.`));
29658
+ return await this.reresolveCrossStackValue(value, region, context, `Fn::GetStackOutput '${this.displayLeaf(outputName, context)}' (producer ${this.displayLeaf(stackName, context)} / ${this.displayLeaf(loggedRegionText, context)})`, sourceKey, {
29646
29659
  stackName,
29647
29660
  region,
29648
29661
  outputKey: outputName,
@@ -29698,7 +29711,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29698
29711
  * own comment says why. What this clause is not is redundant against
29699
29712
  * `raw !== masked`: `rememberLogTwin` has no empty-key guard and
29700
29713
  * `splitLogTwins` registers every piece it produces, so `registeredLogTwin`
29701
- * can answer `***` for the empty string and make `maskSecretsForLog('')`
29714
+ * can answer `***` for the empty string and make `maskSecretsRaw('')`
29702
29715
  * differ from `''`. Neither call site can reach it — both refuse an empty
29703
29716
  * name upstream — so it fences nothing measured today.
29704
29717
  *
@@ -29794,7 +29807,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29794
29807
  */
29795
29808
  async getCrossAccountStackState(roleArn, stackName, region, context) {
29796
29809
  const parsed = parseIamRoleArn(roleArn);
29797
- if (!parsed) throw new Error(`Fn::GetStackOutput: RoleArn '${roleArn}' is not a valid IAM role ARN. Expected shape: arn:<partition>:iam::<12-digit-account-id>:role/<role-name> (e.g. arn:aws:iam::123456789012:role/MyRole, arn:aws-us-gov:iam::...).`);
29810
+ if (!parsed) throw new Error(`Fn::GetStackOutput: RoleArn '${displayIdent(roleArn, { maxCodePoints: 613 })}' is not a valid IAM role ARN. Expected shape: arn:<partition>:iam::<12-digit-account-id>:role/<role-name> (e.g. arn:aws:iam::123456789012:role/MyRole, arn:aws-us-gov:iam::...).`);
29798
29811
  const credentials = await assumeRoleForCrossAccountStateRead(roleArn);
29799
29812
  const { bucket, region: bucketRegion } = await resolveCrossAccountStateBucket(parsed.accountId, credentials);
29800
29813
  const prefix = context.stateBackend?.prefix ?? "cdkd";
@@ -29851,19 +29864,19 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29851
29864
  }
29852
29865
  if (!map) {
29853
29866
  if (hasDefaultValue) return await resolveDefault();
29854
- throw new Error(`Fn::FindInMap: mapping '${this.maskSecretsForLog(mapName, context)}' not found in Mappings section`);
29867
+ throw new Error(`Fn::FindInMap: mapping '${this.displayMasked(mapName, context)}' not found in Mappings section`);
29855
29868
  }
29856
29869
  const topLevel = Object.hasOwn(map, topLevelKey) ? map[topLevelKey] : void 0;
29857
29870
  if (!topLevel || typeof topLevel !== "object") {
29858
29871
  if (hasDefaultValue) return await resolveDefault();
29859
- throw new Error(`Fn::FindInMap: top-level key '${this.maskSecretsForLog(topLevelKey, context)}' not found in mapping '${this.maskSecretsForLog(mapName, context)}'`);
29872
+ throw new Error(`Fn::FindInMap: top-level key '${this.displayMasked(topLevelKey, context)}' not found in mapping '${this.displayMasked(mapName, context)}'`);
29860
29873
  }
29861
29874
  if (!Object.hasOwn(topLevel, secondLevelKey)) {
29862
29875
  if (hasDefaultValue) return await resolveDefault();
29863
- throw new Error(`Fn::FindInMap: second-level key '${this.maskSecretsForLog(secondLevelKey, context)}' not found in mapping '${this.maskSecretsForLog(mapName, context)}' -> '${this.maskSecretsForLog(topLevelKey, context)}'`);
29876
+ throw new Error(`Fn::FindInMap: second-level key '${this.displayMasked(secondLevelKey, context)}' not found in mapping '${this.displayMasked(mapName, context)}' -> '${this.displayMasked(topLevelKey, context)}'`);
29864
29877
  }
29865
29878
  const result = topLevel[secondLevelKey];
29866
- this.logger.debug(`Resolved Fn::FindInMap: ${this.maskSecretsForLog(mapName, context)}.${this.maskSecretsForLog(topLevelKey, context)}.${this.maskSecretsForLog(secondLevelKey, context)} -> ${this.maskSecretsForLog(JSON.stringify(this.maskValueLeaves(result, context)), context)}`);
29879
+ this.logger.debug(`Resolved Fn::FindInMap: ${this.displayMasked(mapName, context)}.${this.displayMasked(topLevelKey, context)}.${this.displayMasked(secondLevelKey, context)} -> ${this.displayMasked(JSON.stringify(this.maskValueLeaves(result, context)), context)}`);
29867
29880
  return result;
29868
29881
  }
29869
29882
  /**
@@ -29878,7 +29891,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29878
29891
  const result = Buffer.from(resolvedValue).toString("base64");
29879
29892
  const inputLogText = this.logTextOfLeaf(resolvedValue, context);
29880
29893
  if (context.recordedSecretValues && (inputLogText !== resolvedValue || this.maskNeedlesForLog(resolvedValue, context) !== resolvedValue)) recordMaskOnlyValue(context.recordedSecretValues, result);
29881
- this.logger.debug(`Resolved Fn::Base64: ${this.maskSecretsForLog(inputLogText, context)} -> ${this.maskSecretsForLog(inputLogText !== resolvedValue ? "***" : result, context)}`);
29894
+ this.logger.debug(`Resolved Fn::Base64: ${this.displayMasked(inputLogText, context)} -> ${this.displayMasked(inputLogText !== resolvedValue ? "***" : result, context)}`);
29882
29895
  return result;
29883
29896
  }
29884
29897
  /**
@@ -29910,7 +29923,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29910
29923
  let loggedRegionText;
29911
29924
  if (typeof resolvedValue === "string" && resolvedValue !== "") {
29912
29925
  const requested = canonicalizeRegion(resolvedValue);
29913
- if (!isClientSafeRegion(requested)) throw new Error(`Fn::GetAZs: '${this.maskThenStripThenMask(this.logTextOfLeaf(resolvedValue, context) !== resolvedValue ? "***" : resolvedValue, context).slice(0, 64)}' is not a valid AWS region name. A region is substituted into the AWS service hostname, so cdkd will not build a client from it.`);
29926
+ if (!isClientSafeRegion(requested)) throw new Error(`Fn::GetAZs: '${this.displayMasked(this.logTextOfLeaf(resolvedValue, context) !== resolvedValue ? "***" : resolvedValue, context).slice(0, 64)}' is not a valid AWS region name. A region is substituted into the AWS service hostname, so cdkd will not build a client from it.`);
29914
29927
  region = requested;
29915
29928
  clientRegion = requested;
29916
29929
  loggedRegionText = this.regionLogText(resolvedValue, context);
@@ -29920,10 +29933,10 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29920
29933
  }
29921
29934
  const cached = cachedAvailabilityZones[region];
29922
29935
  if (cached) {
29923
- this.logger.debug(`Resolved Fn::GetAZs from cache: ${this.maskSecretsForLog(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(cached, context))}`);
29936
+ this.logger.debug(`Resolved Fn::GetAZs from cache: ${this.displayMasked(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(cached, context))}`);
29924
29937
  return cached;
29925
29938
  }
29926
- const ec2Client = this.clientsForRegion(clientRegion, loggedRegionText === void 0 ? void 0 : this.maskSecretsForLog(loggedRegionText, context)).ec2;
29939
+ const ec2Client = this.clientsForRegion(clientRegion, loggedRegionText === void 0 ? void 0 : this.displayMasked(loggedRegionText, context)).ec2;
29927
29940
  let azNames;
29928
29941
  try {
29929
29942
  azNames = ((await ec2Client.send(new DescribeAvailabilityZonesCommand({ Filters: [{
@@ -29934,11 +29947,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29934
29947
  Values: ["available"]
29935
29948
  }] }))).AvailabilityZones || []).map((az) => az.ZoneName).filter((name) => name !== void 0).sort();
29936
29949
  } catch (error) {
29937
- throw new Error(`Fn::GetAZs: failed to describe availability zones for region '${this.maskSecretsForLog(loggedRegionText ?? region, context)}': ${this.maskSecretsForLog(error instanceof Error ? error.message : String(error), context)}`);
29950
+ throw new Error(`Fn::GetAZs: failed to describe availability zones for region '${this.displayMasked(loggedRegionText ?? region, context)}': ${this.displayMasked(error instanceof Error ? error.message : String(error), context)}`);
29938
29951
  }
29939
- if (azNames.length === 0) throw new Error(`Fn::GetAZs: no availability zones returned for region '${this.maskSecretsForLog(loggedRegionText ?? region, context)}'. Either the region is not enabled on this account (opt-in regions must be enabled before use), or the request was answered by a different region's endpoint.`);
29952
+ if (azNames.length === 0) throw new Error(`Fn::GetAZs: no availability zones returned for region '${this.displayMasked(loggedRegionText ?? region, context)}'. Either the region is not enabled on this account (opt-in regions must be enabled before use), or the request was answered by a different region's endpoint.`);
29940
29953
  cachedAvailabilityZones[region] = azNames;
29941
- this.logger.debug(`Resolved Fn::GetAZs: ${this.maskSecretsForLog(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(azNames, context))}`);
29954
+ this.logger.debug(`Resolved Fn::GetAZs: ${this.displayMasked(loggedRegionText ?? region, context)} -> ${JSON.stringify(this.maskValueLeaves(azNames, context))}`);
29942
29955
  return azNames;
29943
29956
  }
29944
29957
  /**
@@ -29972,9 +29985,31 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29972
29985
  * Results are cached to avoid repeated API calls.
29973
29986
  */
29974
29987
  /**
29975
- * Mask any resolved secret value out of a string bound for a log line, using
29976
- * the secrets recorded on the resolution pass (GHSA fix). No-op when the pass
29977
- * recorded no secrets.
29988
+ * The SECRET answer alone: mask any resolved secret value out of `text`,
29989
+ * using the secrets recorded on the resolution pass (GHSA fix). No-op when
29990
+ * the pass recorded no secrets.
29991
+ *
29992
+ * ## NOT a display form, and the name says so
29993
+ *
29994
+ * This was `maskSecretsForLog` until go-to-k/cdkd#3426, and the name was the
29995
+ * defect. It answers "does this text contain a recorded secret" and makes no
29996
+ * claim about CONTROL CHARACTERS — but it read as "the spelling a log line
29997
+ * takes", so TEN local bindings took its result and interpolated it later,
29998
+ * one of them reaching an `Fn::ImportValue` warn and throw with a live
29999
+ * `ESC[2K` + CR from a template-supplied export name (measured on this tree,
30000
+ * at DEFAULT verbosity, on the DEFAULT path). Renaming it is what makes the
30001
+ * hazard visible at the BINDING rather than at the render: `const x =
30002
+ * this.maskSecretsRaw(...)` states that more work is owed.
30003
+ *
30004
+ * Reachable from ONE place, {@link maskThenStripThenMask}, which is itself
30005
+ * reachable only from {@link displayMasked}. That containment is the whole
30006
+ * mechanism and it is enforced, not conventional:
30007
+ * `scripts/check-resolver-mask-coverage.ts` does not list this method in
30008
+ * `MASKERS`, so its AST walk — which RESOLVES an interpolated identifier to
30009
+ * its declaration — reports any render that reaches it, through a binding or
30010
+ * directly. Do not add it to that list, and do not call it from a new site.
30011
+ *
30012
+ * ## What the masking itself does
29978
30013
  *
29979
30014
  * A value with a registered LOG TWIN prints as its twin first (issue
29980
30015
  * [#3150](https://github.com/go-to-k/cdkd/issues/3150)). The needle mask
@@ -29984,7 +30019,8 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29984
30019
  * reference) printed in the clear at every site that handed its RAW value
29985
30020
  * here, although the pass had registered where the secret sits. Looking the
29986
30021
  * twin up HERE, rather than at each such site, is what makes the class
29987
- * closed for raw values: every one of those sites already calls this method.
30022
+ * closed for raw values: every one of those sites already reaches this
30023
+ * method through the builder.
29988
30024
  * The twin prints as it is: it is the raw text with masked spans, so it
29989
30025
  * holds no recorded needle the raw text lacks. When the needle mask ALSO
29990
30026
  * changes the raw text the whole text is masked instead, the rule
@@ -29992,8 +30028,21 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
29992
30028
  * cannot be merged. What this cannot see is a value TRANSFORMED before it
29993
30029
  * arrives (a lowercased region, a sliced output name, an assembled
29994
30030
  * sentence); those sites derive their text from the twin themselves.
30031
+ *
30032
+ * ## The SELF-COMPARISON, and why it did not block the strip
30033
+ *
30034
+ * The line below compares `maskNeedlesForLog(text) !== text` — the NEEDLE
30035
+ * mask, not this method's own result — so making the RENDER path strip
30036
+ * changes no comparison anywhere. An earlier revision of `displayMasked`'s
30037
+ * comment said stripping could not move inside "the masker" because its
30038
+ * result is also a comparison; that was a claim about this expression, and
30039
+ * the expression's operand is a different function. The measurement that
30040
+ * settled it: every one of this method's 20 escaping call sites rendered
30041
+ * into a log line, a throw, or a `display:` field that becomes one — none
30042
+ * compared, persisted or re-parsed the result — so the render path could
30043
+ * take the strip whole.
29995
30044
  */
29996
- maskSecretsForLog(text, context) {
30045
+ maskSecretsRaw(text, context) {
29997
30046
  const registered = this.registeredLogTwin(text, context);
29998
30047
  if (registered === void 0) return this.maskNeedlesForLog(text, context);
29999
30048
  return this.maskNeedlesForLog(text, context) !== text ? "***" : registered;
@@ -30012,19 +30061,19 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30012
30061
  const raw = error instanceof Error ? error.message : String(error);
30013
30062
  return {
30014
30063
  unit,
30015
- subject: this.maskSecretsForLog(subject, context),
30016
- message: this.maskSecretsForLog(preRedact === void 0 ? raw : preRedact(raw), context),
30064
+ subject: this.displayMasked(subject, context),
30065
+ message: this.displayMasked(preRedact === void 0 ? raw : preRedact(raw), context),
30017
30066
  error,
30018
30067
  carriedDynamicReference: carriesDynamicReference(rawInput),
30019
30068
  carriedFetchableReference: carriesFetchableDynamicReference(rawInput)
30020
30069
  };
30021
30070
  }
30022
30071
  /**
30023
- * The needle mask alone: {@link maskSecretsForLog} without the log-twin
30072
+ * The needle mask alone: {@link maskSecretsRaw} without the log-twin
30024
30073
  * lookup. For the two DETECTORS that must ask the needle mask apart from the
30025
30074
  * position mask: `logTwinText`, which asks it of a value that already has a
30026
30075
  * twin, and `resolveBase64`, whose other operand is the position mask. A
30027
- * message masks through `maskSecretsForLog`.
30076
+ * message masks through `displayMasked`.
30028
30077
  */
30029
30078
  maskNeedlesForLog(text, context) {
30030
30079
  let masked = text;
@@ -30052,7 +30101,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30052
30101
  * part of it outside the span. The value's own needle mask cannot be merged
30053
30102
  * with the twin's positions, so the line gives both up for `***`: never
30054
30103
  * more text than either mask alone would print. Returns the text BEFORE the
30055
- * needle mask; each log line wraps it in `maskSecretsForLog` itself, so the
30104
+ * needle mask; each log line wraps it in `displayMasked` itself, so the
30056
30105
  * resolver's mask-coverage checker sees a masker at the site.
30057
30106
  */
30058
30107
  logTwinText(result, twin, context) {
@@ -30104,12 +30153,12 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30104
30153
  * the leaf treated as a resolution product — masked whole when it is a
30105
30154
  * recorded secret, otherwise the masked twin this pass registered for it —
30106
30155
  * and then `logTwinText`'s whole-line guard. The caller still wraps the
30107
- * result in `maskSecretsForLog`. Used where the text is needed BEFORE that
30156
+ * result in `displayMasked`. Used where the text is needed BEFORE that
30108
30157
  * masker, or apart from it: the `Fn::Base64` line and its detector, and the
30109
30158
  * names issue [#3150](https://github.com/go-to-k/cdkd/issues/3150)
30110
30159
  * transforms or composes before printing (`regionLogText`,
30111
30160
  * `outputNameLogText`, the invalid-region refusals, the cross-stack `origin`
30112
- * strings). A leaf printed as it is needs none of it: `maskSecretsForLog`
30161
+ * strings). A leaf printed as it is needs none of it: `displayMasked`
30113
30162
  * looks the twin up itself, which is how `maskValueLeaves` gives its lines
30114
30163
  * and the THROWN messages it masks (the `Fn::Cidr` argument refusals, for
30115
30164
  * one) the same position mask.
@@ -30349,7 +30398,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30349
30398
  maskValueLeaves(value, context) {
30350
30399
  const done = /* @__PURE__ */ new Map();
30351
30400
  const walk = (node) => {
30352
- if (typeof node === "string") return this.maskSecretsForLog(node, context);
30401
+ if (typeof node === "string") return this.displayMasked(node, context);
30353
30402
  if (node === null || typeof node !== "object") return node;
30354
30403
  const memo = done.get(node);
30355
30404
  if (memo !== void 0) return memo;
@@ -30361,7 +30410,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30361
30410
  }
30362
30411
  const out = Object.create(null);
30363
30412
  done.set(node, out);
30364
- for (const [key, child] of Object.entries(node)) out[this.maskSecretsForLog(key, context)] = walk(child);
30413
+ for (const [key, child] of Object.entries(node)) out[this.displayMasked(key, context)] = walk(child);
30365
30414
  return out;
30366
30415
  };
30367
30416
  return walk(value);
@@ -30392,10 +30441,18 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30392
30441
  * of the text in hand. A value this resolver resolved cannot be that text
30393
30442
  * (the split copy is itself recorded, so the first mask catches it), but a
30394
30443
  * template LITERAL can: issue #3150's region-scoped clients refusal prints
30395
- * a producer-region guest's region through this helper, and a literal ARN
30396
- * region spelling a recorded `st-1` as `s` + U+0001 + `t-1` is masked only
30397
- * by the second pass (`intrinsic-resolver-name-argument-log-twin.test.ts`
30398
- * pins both halves on that route).
30444
+ * a producer-region guest's region through {@link displayMasked}, and a
30445
+ * literal ARN region spelling a recorded `st-1` as `s` + U+0001 + `t-1` is
30446
+ * masked only by the second pass
30447
+ * (`intrinsic-resolver-name-argument-log-twin.test.ts` pins both halves on
30448
+ * that route).
30449
+ *
30450
+ * ONE CALLER, {@link displayMasked}, since go-to-k/cdkd#3426. It is most of
30451
+ * the answer and reads like all of it — it omits `displaySafe`, and
30452
+ * therefore `U+2028` / `U+2029` and the bidi overrides — so a site reaching
30453
+ * for it directly is the near-miss back onto the treadmill. It is not in
30454
+ * `MASKERS` in `scripts/check-resolver-mask-coverage.ts`, so a render that
30455
+ * reaches it (through a binding or directly) is reported there.
30399
30456
  *
30400
30457
  * THE BOUND, since this file's job is to state them: this covers a needle
30401
30458
  * split by a character `stripControlChars` removes. A needle split by
@@ -30404,7 +30461,109 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30404
30461
  * solved here.
30405
30462
  */
30406
30463
  maskThenStripThenMask(value, context) {
30407
- return this.maskSecretsForLog(stripControlChars(this.maskSecretsForLog(value, context)), context);
30464
+ return this.maskSecretsRaw(stripControlChars(this.maskSecretsRaw(value, context)), context);
30465
+ }
30466
+ /**
30467
+ * The ONE way a masked value reaches a message in this file — and, since
30468
+ * go-to-k/cdkd#3426, the ONLY exit from the masking machinery at all.
30469
+ *
30470
+ * ## Why this exists rather than a rule about call sites
30471
+ *
30472
+ * {@link maskSecretsRaw} answers "does this text contain a recorded secret"
30473
+ * and makes NO claim about control characters. That split produced a
30474
+ * four-round treadmill on go-to-k/cdkd#3408. Round 1 found the four
30475
+ * `Fn::GetStackOutput` throws rendering a masked name raw and fixed them.
30476
+ * Round 2 found the CloudFormation-fallback warn — the DEFAULT path, at
30477
+ * DEFAULT verbosity — and the self-reference throw. Round 3 found the
30478
+ * `reresolveCrossStackValue` origin builder and `describeAvailableOutputs`.
30479
+ * Each round fixed what it found and the next round found more, because the
30480
+ * population was never enumerated. Measured 2026-09-19 with a
30481
+ * comment-stripped scan: SEVENTY-ONE interpolations rendered a bare masker
30482
+ * result directly, plus thirteen hand-spelled
30483
+ * `displaySafe(maskThenStripThenMask(...))` compositions and two bare
30484
+ * `maskThenStripThenMask` interpolations — and three reviewers between them
30485
+ * reached eight of the eighty-six.
30486
+ *
30487
+ * ROUND FIVE was the BINDING shape: `const loggedExportName =
30488
+ * this.<masker>(...)` interpolated later, which a line-shaped scanner
30489
+ * forbidding `${this.<masker>(` structurally cannot see. Ten of them existed,
30490
+ * and `loggedExportName` was a LIVE exposure — an `Fn::ImportValue` export
30491
+ * name carrying `ESC[2K` + CR reached a warn AND a throw unstripped, at
30492
+ * default verbosity on the default path.
30493
+ *
30494
+ * Patching those ten sites would have been the fifth round of one
30495
+ * enumeration. What closes the class instead is that there is no longer a
30496
+ * masking answer a site can reach WITHOUT the strip: every escaping call of
30497
+ * the old `maskSecretsForLog` now calls this builder, the raw masker is
30498
+ * reachable only through {@link maskThenStripThenMask}, and that helper is
30499
+ * reachable only from here.
30500
+ *
30501
+ * ## What keeps it closed
30502
+ *
30503
+ * `scripts/check-resolver-mask-coverage.ts` — an AST walk that already
30504
+ * RESOLVES an interpolated identifier to its declaration and judges the
30505
+ * initializer. Its `MASKERS` list names the functions a render may reach,
30506
+ * and since go-to-k/cdkd#3426 every entry on it SANITIZES as well as masks.
30507
+ * So a binding of a raw masker is a finding wherever it is later
30508
+ * interpolated, by the same mechanism that already answered the secret
30509
+ * question — no second scanner, and nothing line-shaped.
30510
+ * `tests/unit/deployment/resolver-display-masked-population.test.ts` pins the
30511
+ * population and the builder bodies beside it.
30512
+ *
30513
+ * KNOWN BOUND, stated rather than implied away: a site carrying an
30514
+ * exclusion marker is exempt from that walk, because the marker answers the
30515
+ * SECRET question ("this value cannot carry a plaintext"), which is not the
30516
+ * control-character question. Such a site sanitizes by hand or not at all —
30517
+ * `clientsForRegion`'s two region renders are both markered, and both
30518
+ * sanitize. Widening the walk to judge every interpolated value is
30519
+ * go-to-k/cdkd#3405's mixed-render scope, not this builder's.
30520
+ *
30521
+ * (The marker's literal spelling is deliberately not written in this comment:
30522
+ * the checker scans the raw text for it, and a prose mention parses as a
30523
+ * marker no site consumes — which it then reports STALE. Measured while
30524
+ * writing this paragraph.)
30525
+ *
30526
+ * ## What it does, in order
30527
+ *
30528
+ * `maskThenStripThenMask` first — mask, strip, mask — because
30529
+ * `stripControlChars` DELETES, so a plaintext split by an invisible would be
30530
+ * reconstituted contiguous by a strip applied after a single mask. Then
30531
+ * `displaySafe`, which covers the class `stripControlChars` does not:
30532
+ * `U+2028` / `U+2029` (line terminators to JSON and web log viewers) and the
30533
+ * Trojan-Source bidi overrides. That composition is what the `physicalId`
30534
+ * renders here already spelled by hand; this names it, and they now share it.
30535
+ *
30536
+ * It is listed in `MASKERS` in `scripts/check-resolver-mask-coverage.ts`,
30537
+ * which is a SECURITY decision and a sound one: every path through it passes
30538
+ * the needle-and-twin mask, twice, so it is strictly stronger than the bare
30539
+ * masker it replaced and cannot be weaker at any input.
30540
+ */
30541
+ displayMasked(value, context) {
30542
+ return displaySafe(this.maskThenStripThenMask(value, context));
30543
+ }
30544
+ /**
30545
+ * The display form of a LOG-TWIN leaf — the second render route, named for
30546
+ * the same reason as {@link displayMasked} and closed by the same scanner.
30547
+ *
30548
+ * `logTextOfLeaf` resolves a value to its registered twin (or `SECRET_MASK`),
30549
+ * which is a MASKING answer and, like `maskSecretsRaw`'s, says nothing
30550
+ * about control characters. Four `origin` builders interpolated it raw — the
30551
+ * `Fn::ImportValue` pair, the `Fn::GetStackOutput` one and the nested-stack
30552
+ * attribute one — and those strings flow into `redactedAttributeReads[].display`
30553
+ * and out through a `ProvisioningError` message.
30554
+ *
30555
+ * This route is why fixing the secret masker alone did not close the class:
30556
+ * `displayMasked` covers every site that renders a needle-masked value, and
30557
+ * these render something else. Two routes, two names, one checker refusing
30558
+ * the raw form of both.
30559
+ *
30560
+ * Composed rather than re-derived. `maskSecretsInText` is idempotent (see
30561
+ * {@link maskThenStripThenMask}), so masking twin text again costs nothing
30562
+ * and cannot change the twin — which keeps this a STRICT addition of the
30563
+ * strip and the `displaySafe` pass, with the twin resolution untouched.
30564
+ */
30565
+ displayLeaf(value, context) {
30566
+ return this.displayMasked(this.logTextOfLeaf(value, context), context);
30408
30567
  }
30409
30568
  async resolveDynamicReferences(value, context) {
30410
30569
  return (await this.resolveDynamicReferencesWithLogTwin(value, value, context)).result;
@@ -30455,7 +30614,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30455
30614
  continue;
30456
30615
  }
30457
30616
  const regionVerdict = classifyReplaySecretRegion(fullMatch, this.explicitRegion ?? this.resolverRegion, context?.producerRegions);
30458
- if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${this.maskSecretsForLog(tokenLogText, context)}: it names '${this.maskSecretsForLog(nameLogText(regionVerdict.secretName), context)}' without a region, and this stack reads from ${this.maskSecretsForLog(regionVerdict.foreignProducerRegions.map((r) => this.maskSecretsForLog(r, context)).join(", "), context)} as well as its own region. cdkd cannot tell which one must answer, and resolving against the wrong one yields a different secret. Spell the reference as a full ARN to say which region owns it.`));
30617
+ if (regionVerdict.kind === "ambiguous") throw markNonRetryable(new DynamicReferenceRegionAmbiguousError(`Refusing to resolve the secret reference ${this.displayMasked(tokenLogText, context)}: it names '${this.displayMasked(nameLogText(regionVerdict.secretName), context)}' without a region, and this stack reads from ${this.displayMasked(regionVerdict.foreignProducerRegions.map((r) => this.displayMasked(r, context)).join(", "), context)} as well as its own region. cdkd cannot tell which one must answer, and resolving against the wrong one yields a different secret. Spell the reference as a full ARN to say which region owns it.`));
30459
30618
  if (regionVerdict.kind === "named-region") {
30460
30619
  const foreign = await this.resolverForProducerRegion(regionVerdict.region, context, nameLogText(regionVerdict.region)).resolveDynamicReferencesWithLogTwin(fullMatch, fullMatch, withoutProducerRegions(context), {
30461
30620
  tokenLogText,
@@ -30520,11 +30679,11 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30520
30679
  resolved = param.value;
30521
30680
  } else if (service === "ssm-secure") {
30522
30681
  const param = await this.resolveSSMReference(parts, true, "ssm-secure", context, nameLogText);
30523
- if (!param.secure) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to resolve ${this.maskSecretsForLog(tokenLogText, context)}: the parameter is a ${param.type} parameter, and the ssm-secure spelling is defined for SecureString parameters only. Reference it as {{resolve:ssm:...}} if it is public configuration.`));
30682
+ if (!param.secure) throw markNonRetryable(new IntrinsicResolutionRefusalError(`Refusing to resolve ${this.displayMasked(tokenLogText, context)}: the parameter is a ${param.type} parameter, and the ssm-secure spelling is defined for SecureString parameters only. Reference it as {{resolve:ssm:...}} if it is public configuration.`));
30524
30683
  isSecret = true;
30525
30684
  resolved = param.value;
30526
30685
  } else {
30527
- this.logger.warn(this.maskSecretsForLog(`Unsupported dynamic reference service: ${this.maskSecretsForLog(nameLogText(String(service)), context)}`, context));
30686
+ this.logger.warn(this.displayMasked(`Unsupported dynamic reference service: ${this.displayMasked(nameLogText(String(service)), context)}`, context));
30528
30687
  complete = false;
30529
30688
  continue;
30530
30689
  }
@@ -30612,9 +30771,9 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30612
30771
  } else secretId = afterService;
30613
30772
  if (!versionStage) versionStage = "AWSCURRENT";
30614
30773
  if (!secretId) throw new Error("Dynamic reference: secretsmanager SECRET_ID is required");
30615
- const loggedSecretId = this.maskSecretsForLog(nameLogText(secretId), context);
30616
- const loggedJsonKey = this.maskSecretsForLog(nameLogText(jsonKey), context);
30617
- this.logger.debug(`Resolving dynamic reference: secretsmanager:${loggedSecretId}:SecretString:${loggedJsonKey}:${this.maskSecretsForLog(nameLogText(versionStage), context)}:${this.maskSecretsForLog(nameLogText(versionId), context)}`);
30774
+ const loggedSecretId = this.displayMasked(nameLogText(secretId), context);
30775
+ const loggedJsonKey = this.displayMasked(nameLogText(jsonKey), context);
30776
+ this.logger.debug(`Resolving dynamic reference: secretsmanager:${loggedSecretId}:SecretString:${loggedJsonKey}:${this.displayMasked(nameLogText(versionStage), context)}:${this.displayMasked(nameLogText(versionId), context)}`);
30618
30777
  const client = this.clientsForRegion(this.explicitRegion).secretsManager;
30619
30778
  const command = new GetSecretValueCommand({
30620
30779
  SecretId: secretId,
@@ -30656,7 +30815,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30656
30815
  const count = Number(await this.resolveValue(rawCount, context));
30657
30816
  const cidrBits = Number(await this.resolveValue(rawCidrBits, context));
30658
30817
  if (!ipBlock || typeof ipBlock !== "string") throw new Error(`Fn::Cidr: ipBlock must be a string, got ${typeof ipBlock}: ${JSON.stringify(this.maskValueLeaves(ipBlock, context))}`);
30659
- this.logger.debug(`Resolving Fn::Cidr: ipBlock=${this.maskSecretsForLog(JSON.stringify(this.maskValueLeaves(ipBlock, context)), context)}, count=${count}, cidrBits=${cidrBits}`);
30818
+ this.logger.debug(`Resolving Fn::Cidr: ipBlock=${this.displayMasked(JSON.stringify(this.maskValueLeaves(ipBlock, context)), context)}, count=${count}, cidrBits=${cidrBits}`);
30660
30819
  const isIpv6 = ipBlock.includes(":");
30661
30820
  const results = [];
30662
30821
  if (isIpv6) {
@@ -30688,7 +30847,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30688
30847
  results.push(`${a}.${b}.${c}.${d}/${subnetPrefix}`);
30689
30848
  }
30690
30849
  }
30691
- this.logger.debug(`Fn::Cidr result: ${this.maskSecretsForLog(JSON.stringify(this.maskValueLeaves(results, context)), context)}`);
30850
+ this.logger.debug(`Fn::Cidr result: ${this.displayMasked(JSON.stringify(this.maskValueLeaves(results, context)), context)}`);
30692
30851
  return results;
30693
30852
  }
30694
30853
  /** Expand IPv6 address to full 8-group form */
@@ -30778,7 +30937,7 @@ var IntrinsicFunctionResolver = class IntrinsicFunctionResolver {
30778
30937
  async resolveSSMReference(parts, decrypt, service, context, nameLogText) {
30779
30938
  const parameterName = parts.slice(1).join(":");
30780
30939
  if (!parameterName) throw new Error(`Dynamic reference: ${service} PARAMETER_NAME is required`);
30781
- const loggedParameterName = this.maskSecretsForLog(nameLogText(parameterName), context);
30940
+ const loggedParameterName = this.displayMasked(nameLogText(parameterName), context);
30782
30941
  this.logger.debug(`Resolving dynamic reference: ${service}:${loggedParameterName}`);
30783
30942
  const client = this.clientsForRegion(this.explicitRegion).ssm;
30784
30943
  const command = new GetParameterCommand({
@@ -32476,7 +32635,7 @@ var CloudControlProvider = class {
32476
32635
  const indeterminateGuard = await this.confirmDeleteTargetIdentity(logicalId, resourceType, physicalId, context);
32477
32636
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
32478
32637
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
32479
- const { ASGProvider } = await import("./asg-provider-Dwnb3CES.js").then((n) => n.n);
32638
+ const { ASGProvider } = await import("./asg-provider-DNzgk-BS.js").then((n) => n.n);
32480
32639
  const asgProvider = new ASGProvider();
32481
32640
  return withIndeterminateGuard(await asgProvider.delete(logicalId, physicalId, resourceType, _properties, context), indeterminateGuard);
32482
32641
  }
@@ -45543,4 +45702,4 @@ var DeployEngine = class DeployEngine {
45543
45702
 
45544
45703
  //#endregion
45545
45704
  export { secretBearing as $, SynthesisError as $i, recordMaskOnlyValue as $n, AssetManifestLoader as $r, s3BucketArn as $t, extractDeploymentEventError as A, getAwsClients as Ai, refuseMalformedState as An, BOOTSTRAP_MARKER_PREFIX as Ar, isImpossibleEmptyStoredAttribute as At, toCfnInteger as B, IntrinsicResolutionRefusalError as Bi, STATE_SOURCED_BASELINE_RULES as Bn, buildDockerImage as Br, coerceCfnBoolean as Bt, buildFinalSnapshotIdentifier as C, canonicalizeRegion as Ci, producerRecordKey as Cn, stringifyValue as Cr, isTerminationProtectionPropagationError as Ct, refusesFinalSnapshot as D, clearBucketRegionCache as Di, refuseMalformedOutputsForDestroy as Dn, loadPublishableAssetManifest as Dr, cfnRefValueFromPhysicalId as Dt, isFinalSnapshotError as E, processStackMessages as Ei, refuseMalformedOutputs as En, createAssetRedirectResolver as Er, carriesFetchableDynamicReference as Et, isStatefulRecreateTargetSync as F, ConfigError as Fi, findSilentDropProperties as Fn, parseBootstrapMarker as Fr, isSettledInstanceState as Ft, gray as G, NestedStackChildDirectDestroyError as Gi, createSecretMasker as Gn, formatDockerLoginError as Gr, readConfigString as Gt, formatResourceLine as H, LocalStartServiceError as Hi, STATE_SOURCED_READBACK_RULES as Hn, describeDockerExecFailure as Hr, configBooleanRefusal as Ht, renderStatefulReason as I, CrossAccountSecretRefusalError as Ii, describeTypeWithThrottleRetry as In, readBootstrapMarkerBody as Ir, WAFv2WebACLProvider as It, yellow as J, ResourceTimeoutError as Ji, identityKeyFor as Jn, redactDockerArgvValues as Jr, requireConfigObject as Jt, green as K, PartialFailureError as Ki, dynamicReferenceTokens as Kn, getDockerCmd as Kr, replayWarn as Kt, WARM_THROUGHPUT_MEMBERS as L, DependencyError as Li, withRetry as Ln, validateAssetBucketName as Lr, normalizeAwsTagsToCfn as Lt, planOrphanAdoption as M, setAwsClients as Mi, repairMalformedResourcePropertiesForReadOnly as Mn, ensureAssetStorage as Mr, isUnboundTemplateParameter as Mt, MULTI_REGION_RECREATE_BLOCKED_TYPES as N, AssetError as Ni, repairMalformedResourcesForReadOnly as Nn, getBootstrapMarkerKey as Nr, parameterTypeMayLoseSecretIdentity as Nt, unsupportedFinalSnapshotError as O, resolveBucketRegion as Oi, refuseMalformedResourcePropertiesForOrphan as On, rewriteTemplateAssetReferences as Or, coerceParameterTypedValue as Ot, isStatefulRecreateTargetForReplace as P, CdkdError as Pi, findActionableSilentDrops as Pn, isCrossRegionRedirect as Pr, refStateLookupFromResource as Pt, isExportAliasCollision as Q, StateError as Qi, maskSecretsInText as Qn, stripControlChars as Qr, withSharedDrainBudget as Qt, coerceWarmThroughput as R, DeployCancelledError as Ri, DagBuilder as Rn, validateContainerRepoName as Rr, resolveExplicitPhysicalId as Rt, PRE_DELETE_SNAPSHOT_TYPES as S, PARTITION_TABLE as Si, malformedStateRefusalMessage as Sn, AssetPublisher as Sr, disableInstanceApiTermination as St, createPreDeleteFinalSnapshot as T, AssemblyReader as Ti, refuseMalformedNestedChildOutputs as Tn, buildAssetRedirectMap as Tr, carriesDynamicReference as Tt, bold as U, LockError as Ui, TEMPLATE_SOURCED_RULES as Un, describeDockerFailure as Ur, configIntegerRefusal as Ut, toFiniteNumber as V, LocalInvokeBuildError as Vi, STATE_SOURCED_CROSS_GENERATION_RULES as Vn, describeDockerCapturedOutput as Vr, coerceCfnInteger as Vt, cyan as W, MalformedProducerRecordRefusalError as Wi, carriesSecretMask as Wn, dockerSpawnEnvWithSensitive as Wr, configStringRefusal as Wt, collectPublishedOutputNames as X, StackHasActiveImportsError as Xi, markSameGenerationBag as Xn, runDockerStreaming as Xr, classifyReplaySecretRegion as Xt, collectDeclaredOutputNames as Y, ResourceUpdateNotSupportedError as Yi, isSingleDynamicReferenceToken as Yn, runDockerForeground as Yr, requireConfigString as Yt, exportAliasCollisionScrubWarning as Z, StackTerminationProtectionError as Zi, maskSecretsInError as Zn, escapeRegExp$1 as Zr, producerRegionsFromState as Zt, isSecretBearingReferenceString as _, findLargeInlineResources as _i, malformedOutputsRefusalMessage as _n, importableOutputs as _r, isWaitAbandonedError as _t, DeploymentEventsStore as a, isRetryableTransientError as aa, resolveApp as ai, AWS_CREDENTIAL_ENV_KEYS as an, rebuildClientForBucketRegion as ar, clearOnUpdateRemoval as at, bindingSkippedOutputs as b, decodeListingKey as bi, malformedResourcePropertiesWarning as bn, orphansCarriedFrom as br, deleteIndeterminateGuards as bt, replayFailedOperations as c, markNonRetryable as ca, resolveSkipPrefix as ci, envCredentialsAreAssumedRole as cn, buildLockContentionMessage as cr, createMaskedRetryLogger as ct, updatePartialReason as d, describeAwsFailure as da, resolveUseCdkBootstrapAssets as di, STATE_RESOURCES_MALFORMED as dn, shellQuote as dr, beginCommandInterruptScope as dt, formatError as ea, getDockerImageBySourceHash as ei, s3BucketDomainName as en, recoverMaskedOutput as er, secretBearingStateKeyWarning as et, withResourceDeadline as f, safeStringify$1 as fa, stateBucketExistenceConfirmed as fi, hasReadableOutputs as fn, CUSTOM_RESOURCE_RESPONSE_PREFIX as fr, endCommandInterruptScope as ft, bagHoldsSecretExpression as g, MIGRATE_TMP_PREFIX as gi, malformedLocalOutputsWarning as gn, importableOutputKeys as gr, CloudControlProvider as gt, computeImplicitDeleteEdges as h, CFN_TEMPLATE_URL_LIMIT as hi, malformedExportSourceWarning as hn, hasReadableExportSet as hr, startInterruptWatch as ht, DeploymentEventsReader as i, isMarkedNonRetryable as ia, getLegacyStateBucketName as ii, applyRoleArnIfSet as in, S3StateBackend as ir, collectInlinePolicyNamesManagedBySiblings as it, makeSiblingClaimReader as j, resetAwsClients as ji, repairMalformedOutputsForReadOnly as jn, assertAssetBucketRegion as jr, isNamelessDynamicReferenceError as jt, makeCanonicalizePropertiesFn as k, AwsClients as ki, refuseMalformedResourcesForDestroy as kn, AssetModeResolver as kr, getAccountInfo as kt, replayRollback as l, markRedactedCause as la, resolveStateBucketWithDefault as li, DiffCalculator as ln, forceQuitRecoveryClause as lr, maskDeep as lt, IMPLICIT_DELETE_DEPENDENCIES as m, CFN_TEMPLATE_BODY_LIMIT as mi, malformedExportNamesWarning as mn, exportNamesCarriedFrom as mr, isInterruptedWaitError as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, normalizeAwsError as na, synthesisStatusMessage as ni, s3BucketRegionalDomainName as nn, scrubResourceRecord as nr, getCurrentResourceSecrets as nt, planFailedOps as o, isThrottlingError as oa, resolveAutoAssetStorage as oi, applyCallerIdentityCredentials as on, UNREPRODUCIBLE_LOCK_CLAUSE as or, ProviderRegistry as ot, maskingRetryLogger as p, __exportAll as pa, warnDeprecatedNoPrefixCliFlag as pi, hasReadableResources as pn, DEFAULT_STATE_PREFIX as pr, interruptWatchListenerCount as pt, red as q, ProvisioningError as qi, errorCauseChain as qn, partitionSensitiveEnv as qr, requireConfigArray as qt, DeployEngine as r, withErrorHandling as ra, getDefaultStateBucketName as ri, s3BucketWebsiteUrl as rn, LockManager as rr, IAMRoleProvider as rt, planRollback as s, isTransientServerError as sa, resolveCaptureObservedState as si, callerEnvCredentials as sn, buildForceUnlockCommand as sr, wouldReturnToSdkProvider as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, isCdkdError as ta, Synthesizer as ti, s3BucketDualStackDomainName as tn, redactSecretsForState as tr, secretSafeKeyDisplay as tt, updatePartialMessage as u, retryClassificationText as ua, resolveStateBucketWithDefaultAndSource as ui, INTRINSIC_KEYS as un, formatLockExpiry as ur, maskerOrIdentity as ut, keptWholeReasonText as v, uploadCfnTemplate as vi, malformedOutputsWarning as vn, isReadableBag as vr, slowCcOperationTimeoutMs as vt, ccRoutedFinalSnapshotError as w, derivePartitionAndUrlSuffix as wi, refuseDivergentRecordRegionForDestroy as wn, WorkGraph as wr, IntrinsicFunctionResolver as wt, ATOMIC_FINAL_SNAPSHOT_TYPES as x, expectedOwnerParam as xi, malformedResourcesWarning as xn, shouldRetainResource as xr, deleteSkipReason as xt, mergeNoChangeOutputs as y, CUSTOM_RESOURCE_RESPONSE_OBJECT_DESCRIPTION as yi, malformedRenderedContainersWarning as yn, orphansAfterRollback as yr, UNSPECIFIED_SKIP_REASON as yt, isWarmThroughputDecrease as z, DynamicReferenceRegionAmbiguousError as zi, TemplateParser as zn, buildDenyExternalAccessPolicy as zr, assertRegionMatch as zt };
45546
- //# sourceMappingURL=deploy-engine-Bcwb9_mO.js.map
45705
+ //# sourceMappingURL=deploy-engine-21iNqwR3.js.map