@go-to-k/cdkd 0.283.20 → 0.283.21

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.
@@ -11494,6 +11494,29 @@ const cachedAvailabilityZones = {};
11494
11494
  */
11495
11495
  const cachedDynamicReferences = {};
11496
11496
  /**
11497
+ * The `{{resolve:ssm:...}}` expressions this process has PROVEN point at a
11498
+ * `SecureString` parameter (issue #1901).
11499
+ *
11500
+ * A plain `ssm` reference is not a secret by SPELLING the way `secretsmanager`
11501
+ * is — whether it resolves to public config or to a decrypted secret depends on
11502
+ * the parameter's `Type`, which is only knowable from the `GetParameter`
11503
+ * response. So secret-ness is discovered on the first resolution and remembered
11504
+ * here, keyed by the full `{{resolve:...}}` expression, for the same lifetime as
11505
+ * {@link cachedDynamicReferences}.
11506
+ *
11507
+ * Two consumers need it AFTER the lookup that populated it: the cache-hit arm
11508
+ * (which must re-record the value as a secret for the current resolution pass)
11509
+ * and the diff / no-op path (which must leave a SecureString reference
11510
+ * unresolved without paying a lookup at all once the type is known). A
11511
+ * reference NOT in this set is only "not known to be secure" — never "proven
11512
+ * public" — so every arm that would leak still asks AWS for the type first.
11513
+ *
11514
+ * Only the TYPE is remembered, never the decrypted value: on the diff path the
11515
+ * lookup is made with `WithDecryption: false`, so the plaintext is never
11516
+ * fetched at all there.
11517
+ */
11518
+ const secureStringSsmReferences = /* @__PURE__ */ new Set();
11519
+ /**
11497
11520
  * Cache for EC2 instance attributes that require a live DescribeInstances
11498
11521
  * lookup (PrivateIp / PublicIp / PrivateDnsName / PublicDnsName /
11499
11522
  * AvailabilityZone). Keyed by `${physicalId}#${attributeName}`. The IP /
@@ -13304,25 +13327,35 @@ var IntrinsicFunctionResolver = class {
13304
13327
  });
13305
13328
  for (const { fullMatch, inner } of matches) {
13306
13329
  const service = inner.split(":")[0];
13307
- const isSecret = service === "secretsmanager";
13308
- if (isSecret && context?.skipDynamicReferences) continue;
13330
+ const isKnownSecret = service === "secretsmanager" || secureStringSsmReferences.has(fullMatch);
13331
+ if (isKnownSecret && context?.skipDynamicReferences) continue;
13309
13332
  if (fullMatch in cachedDynamicReferences) {
13310
13333
  const cached = cachedDynamicReferences[fullMatch];
13311
- if (isSecret && cached) context?.recordedSecretValues?.set(cached, fullMatch);
13312
- result = result.replace(fullMatch, cached);
13334
+ if (isKnownSecret && cached) context?.recordedSecretValues?.set(cached, fullMatch);
13335
+ result = result.replace(fullMatch, () => cached);
13313
13336
  continue;
13314
13337
  }
13315
13338
  const parts = inner.split(":");
13316
13339
  let resolved;
13340
+ let isSecret = isKnownSecret;
13317
13341
  if (service === "secretsmanager") resolved = await this.resolveSecretsManagerReference(inner);
13318
- else if (service === "ssm") resolved = await this.resolveSSMReference(parts);
13319
- else {
13342
+ else if (service === "ssm") {
13343
+ const decrypt = context?.skipDynamicReferences !== true;
13344
+ const param = await this.resolveSSMReference(parts, decrypt);
13345
+ if (param.type === "SecureString") secureStringSsmReferences.add(fullMatch);
13346
+ else if (!param.secure) secureStringSsmReferences.delete(fullMatch);
13347
+ isSecret = param.secure;
13348
+ if (param.secure) {
13349
+ if (!decrypt) continue;
13350
+ }
13351
+ resolved = param.value;
13352
+ } else {
13320
13353
  this.logger.warn(`Unsupported dynamic reference service: ${service}`);
13321
13354
  continue;
13322
13355
  }
13323
13356
  cachedDynamicReferences[fullMatch] = resolved;
13324
13357
  if (isSecret && resolved) context?.recordedSecretValues?.set(resolved, fullMatch);
13325
- result = result.replace(fullMatch, resolved);
13358
+ result = result.replace(fullMatch, () => resolved);
13326
13359
  }
13327
13360
  return result;
13328
13361
  }
@@ -13475,18 +13508,44 @@ var IntrinsicFunctionResolver = class {
13475
13508
  for (let i = 7; i >= 0; i--) parts.push((n >> BigInt(i * 16) & BigInt(65535)).toString(16));
13476
13509
  return parts.join(":");
13477
13510
  }
13478
- async resolveSSMReference(parts) {
13511
+ /**
13512
+ * Resolve an `{{resolve:ssm:...}}` dynamic reference, reporting whether the
13513
+ * parameter is a `SecureString` (issue #1901).
13514
+ *
13515
+ * `secure` is read off the SAME `GetParameter` response that carries the
13516
+ * value, so classifying a reference costs no extra API call — which is what
13517
+ * makes it affordable on the comparison path too.
13518
+ *
13519
+ * `decrypt` maps straight to `WithDecryption`. SSM ignores it for `String` /
13520
+ * `StringList` (their `Value` is identical either way), so the only thing it
13521
+ * changes is whether a `SecureString`'s `Value` comes back as plaintext or as
13522
+ * its encrypted blob. Callers that only need the TYPE pass `false` and MUST
13523
+ * discard the value when `secure` is set — it is ciphertext, not the resolved
13524
+ * reference.
13525
+ */
13526
+ async resolveSSMReference(parts, decrypt = true) {
13479
13527
  const parameterName = parts.slice(1).join(":");
13480
13528
  if (!parameterName) throw new Error("Dynamic reference: ssm PARAMETER_NAME is required");
13481
13529
  this.logger.debug(`Resolving dynamic reference: ssm:${parameterName}`);
13482
13530
  const client = getAwsClients().ssm;
13483
13531
  const command = new GetParameterCommand({
13484
13532
  Name: parameterName,
13485
- WithDecryption: true
13533
+ WithDecryption: decrypt
13486
13534
  });
13487
- const paramValue = (await client.send(command)).Parameter?.Value;
13535
+ const response = await client.send(command);
13536
+ const paramValue = response.Parameter?.Value;
13488
13537
  if (paramValue === void 0 || paramValue === null) throw new Error(`Dynamic reference: SSM parameter '${parameterName}' not found or has no value`);
13489
- return paramValue;
13538
+ const paramType = response.Parameter?.Type;
13539
+ const secure = paramType !== "String" && paramType !== "StringList";
13540
+ if (secure && paramType !== "SecureString") {
13541
+ const reported = paramType === void 0 ? "(absent)" : `'${String(paramType)}'`;
13542
+ this.logger.warn(`SSM parameter '${parameterName}' reported an unrecognized Type ${reported} — treating its value as a secret, so cdkd will persist the {{resolve:ssm:...}} expression rather than the resolved value. Declare the parameter as String / StringList if it is public config.`);
13543
+ }
13544
+ return {
13545
+ value: paramValue,
13546
+ secure,
13547
+ type: paramType
13548
+ };
13490
13549
  }
13491
13550
  };
13492
13551
 
@@ -14321,7 +14380,7 @@ var CloudControlProvider = class {
14321
14380
  if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
14322
14381
  if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
14323
14382
  this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
14324
- const { ASGProvider } = await import("./asg-provider-k-TEX_Ej.js").then((n) => n.n);
14383
+ const { ASGProvider } = await import("./asg-provider-DKjoomrX.js").then((n) => n.n);
14325
14384
  return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
14326
14385
  }
14327
14386
  const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
@@ -20892,9 +20951,13 @@ async function replayRollback(operations, stateResources, stackName, ctx, option
20892
20951
  * resolve-for-provider + redact-for-state split the deploy engine applies at its
20893
20952
  * save choke point. A bag with no `{{resolve:...}}` string resolves to a
20894
20953
  * structural copy of itself (secrets stays empty), so the non-secret rollback
20895
- * path is behaviourally unchanged. Only secretsmanager references are recorded
20896
- * (plain `ssm` is public config, stored resolved it never appears as an
20897
- * expression in the journal), matching the resolver's own `isSecret` gate.
20954
+ * path is behaviourally unchanged. Which references are RECORDED is the
20955
+ * resolver's own secret gate: every `secretsmanager` one, plus an `ssm` one
20956
+ * whose parameter is a `SecureString` (issue #1901 that form decrypts to a
20957
+ * real secret, so it is redacted into the journal and must be re-resolved here
20958
+ * exactly like a secretsmanager reference). An ssm reference to a `String` /
20959
+ * `StringList` parameter is public config, stored resolved, and never appears
20960
+ * as an expression in the journal.
20898
20961
  */
20899
20962
  async function resolveReplayProps(props, resolver, secrets) {
20900
20963
  if (props === void 0) return void 0;
@@ -21490,7 +21553,7 @@ const FLUSH_INTERVAL_MS = 2e3;
21490
21553
  const FLUSH_EVENT_THRESHOLD = 50;
21491
21554
  /** Build-time cdkd version, with a dev fallback for non-built contexts. */
21492
21555
  function getCdkdVersion() {
21493
- return "0.283.20";
21556
+ return "0.283.21";
21494
21557
  }
21495
21558
  /**
21496
21559
  * Generate a time-sortable unique run id, e.g.
@@ -23825,4 +23888,4 @@ var DeployEngine = class {
23825
23888
 
23826
23889
  //#endregion
23827
23890
  export { coerceCfnBoolean as $, resolveCaptureObservedState as $t, cyan as A, LocalStartServiceError as An, rewriteTemplateAssetReferences as At, findSilentDropProperties as B, StateError as Bn, buildDockerImage as Bt, makeCanonicalizePropertiesFn as C, AssetError as Cn, shouldRetainResource as Ct, renderStatefulReason as D, DeployCancelledError as Dn, buildAssetRedirectMap as Dt, isStatefulRecreateTargetSync as E, DependencyError as En, WorkGraph as Et, IAMRoleProvider as F, ProvisioningError as Fn, getBootstrapMarkerKey as Ft, IntrinsicFunctionResolver as G, withErrorHandling as Gn, AssetManifestLoader as Gt, slowCcOperationTimeoutMs as H, formatError as Hn, getDockerCmd as Ht, collectInlinePolicyNamesManagedBySiblings as I, ResourceTimeoutError as In, parseBootstrapMarker as It, refStateLookupFromResource as J, isThrottlingError as Jn, synthesisStatusMessage as Jt, cfnRefValueFromPhysicalId as K, isMarkedNonRetryable as Kn, getDockerImageBySourceHash as Kt, clearOnUpdateRemoval as L, ResourceUpdateNotSupportedError as Ln, validateAssetBucketName as Lt, green as M, MissingCdkCliError as Mn, AssetModeResolver as Mt, red as N, NestedStackChildDirectDestroyError as Nn, BOOTSTRAP_MARKER_PREFIX as Nt, formatResourceLine as O, LocalInvokeBuildError as On, createAssetRedirectResolver as Ot, yellow as P, PartialFailureError as Pn, ensureAssetStorage as Pt, assertRegionMatch as Q, resolveAutoAssetStorage as Qt, ProviderRegistry as R, StackHasActiveImportsError as Rn, validateContainerRepoName as Rt, unsupportedFinalSnapshotError as S, setAwsClients as Sn, rebuildClientForBucketRegion as St, MULTI_REGION_RECREATE_BLOCKED_TYPES as T, ConfigError as Tn, stringifyValue as Tt, disableInstanceApiTermination as U, isCdkdError as Un, runDockerForeground as Ut, CloudControlProvider as V, SynthesisError as Vn, formatDockerLoginError as Vt, isTerminationProtectionPropagationError as W, normalizeAwsError as Wn, runDockerStreaming as Wt, normalizeAwsTagsToCfn as X, __exportAll as Xn, getLegacyStateBucketName as Xt, WAFv2WebACLProvider as Y, markNonRetryable as Yn, getDefaultStateBucketName as Yt, resolveExplicitPhysicalId as Z, resolveApp as Zt, buildFinalSnapshotIdentifier as _, clearBucketRegionCache as _n, withRetry as _t, DeploymentEventsStore as a, warnDeprecatedNoPrefixCliFlag as an, requireConfigObject as at, isFinalSnapshotError as b, getAwsClients as bn, LockManager as bt, replayFailedOperations as c, MIGRATE_TMP_PREFIX as cn, scrubResourceRecord as ct, deleteSkipReason as d, expectedOwnerParam as dn, s3BucketDualStackDomainName as dt, resolveSkipPrefix as en, configBooleanRefusal as et, withResourceDeadline as f, PARTITION_TABLE as fn, s3BucketRegionalDomainName as ft, PRE_DELETE_SNAPSHOT_TYPES as g, processStackMessages as gn, describeTypeWithThrottleRetry as gt, ATOMIC_FINAL_SNAPSHOT_TYPES as h, AssemblyReader as hn, DiffCalculator as ht, DeploymentEventsReader as i, stateBucketExistenceConfirmed as in, requireConfigArray as it, gray as j, LockError as jn, escapeRegExp$1 as jt, bold as k, LocalMigrateError as kn, loadPublishableAssetManifest as kt, replayRollback as l, findLargeInlineResources as ln, s3BucketArn as lt, computeImplicitDeleteEdges as m, derivePartitionAndUrlSuffix as mn, applyRoleArnIfSet as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, resolveStateBucketWithDefaultAndSource as nn, readConfigString as nt, planFailedOps as o, CFN_TEMPLATE_BODY_LIMIT as on, requireConfigString as ot, IMPLICIT_DELETE_DEPENDENCIES as p, canonicalizeRegion as pn, s3BucketWebsiteUrl as pt, getAccountInfo as q, isRetryableTransientError as qn, Synthesizer as qt, DeployEngine as r, resolveUseCdkBootstrapAssets as rn, replayWarn as rt, planRollback as s, CFN_TEMPLATE_URL_LIMIT as sn, redactSecretsForState as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, resolveStateBucketWithDefault as tn, configStringRefusal as tt, UNSPECIFIED_SKIP_REASON as u, uploadCfnTemplate as un, s3BucketDomainName as ut, ccRoutedFinalSnapshotError as v, resolveBucketRegion as vn, DagBuilder as vt, extractDeploymentEventError as w, CdkdError as wn, AssetPublisher as wt, refusesFinalSnapshot as x, resetAwsClients as xn, S3StateBackend as xt, createPreDeleteFinalSnapshot as y, AwsClients as yn, TemplateParser as yt, findActionableSilentDrops as z, StackTerminationProtectionError as zn, buildDenyExternalAccessPolicy as zt };
23828
- //# sourceMappingURL=deploy-engine-ISOKkuun.js.map
23891
+ //# sourceMappingURL=deploy-engine-ISSt01TI.js.map