@go-to-k/cdkd 0.284.36 → 0.284.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{asg-provider-2wQUtu7f.js → asg-provider-BbWubpjP.js} +2 -2
- package/dist/{asg-provider-2wQUtu7f.js.map → asg-provider-BbWubpjP.js.map} +1 -1
- package/dist/cli.js +140 -106
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-Csb2eS97.js → deploy-engine-C62UGXid.js} +3 -3
- package/dist/{deploy-engine-Csb2eS97.js.map → deploy-engine-C62UGXid.js.map} +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as startInterruptWatch, $t as buildAssetRedirectMap, A as renderStatefulReason, An as resolveStateBucketWithDefaultAndSource, At as redactSecretsForState, B as exportAliasCollisionScrubWarning, Bn as PARTITION_TABLE, Bt as DiffCalculator, C as isFinalSnapshotError, Cn as getDefaultStateBucketName, Cr as isRetryableTransientError, Ct as TEMPLATE_SOURCED_RULES, D as extractDeploymentEventError, Dn as resolveCaptureObservedState, Dt as isSingleDynamicReferenceToken, E as makeCanonicalizePropertiesFn, En as resolveAutoAssetStorage, Et as errorCauseChain, F as green, Fn as CFN_TEMPLATE_URL_LIMIT, Ft as s3BucketDomainName, G as collectInlinePolicyNamesManagedBySiblings, Gt as TemplateParser, H as secretBearingStateKeyWarning, Hn as derivePartitionAndUrlSuffix, Ht as describeTypeWithThrottleRetry, I as red, In as MIGRATE_TMP_PREFIX, It as s3BucketDualStackDomainName, J as findActionableSilentDrops, Jn as getAwsClients, Jt as rebuildClientForBucketRegion, K as clearOnUpdateRemoval, Kn as resolveBucketRegion, Kt as LockManager, L as yellow, Ln as findLargeInlineResources, Lt as s3BucketRegionalDomainName, M as bold, Mn as stateBucketExistenceConfirmed, Mt as classifyReplaySecretRegion, N as cyan, Nn as warnDeprecatedNoPrefixCliFlag, Nt as producerRegionsFromState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as resolveSkipPrefix, Ot as maskSecretsInError, P as gray, Pn as CFN_TEMPLATE_BODY_LIMIT, Pt as s3BucketArn, Q as isInterruptedWaitError, Qn as CdkdError, Qt as WorkGraph, R as collectDeclaredOutputNames, Rn as uploadCfnTemplate, Rt as s3BucketWebsiteUrl, S as createPreDeleteFinalSnapshot, Sn as synthesisStatusMessage, Sr as isMarkedNonRetryable, St as STATE_SOURCED_READBACK_RULES, T as unsupportedFinalSnapshotError, Tn as resolveApp, Tr as markNonRetryable, Tt as dynamicReferenceTokens, U as stateKeySecretExposure, Un as AssemblyReader, Ut as withRetry, V as isExportAliasCollision, Vn as canonicalizeRegion, Vt as INTRINSIC_KEYS, W as IAMRoleProvider, Wn as processStackMessages, Wt as DagBuilder, X as beginCommandInterruptScope, Xn as setAwsClients, Xt as AssetPublisher, Y as findSilentDropProperties, Yn as resetAwsClients, Yt as shouldRetainResource, Z as endCommandInterruptScope, Zt as stringifyValue, _ as computeImplicitDeleteEdges, _n as runDockerForeground, _t as replayWarn, a as DeploymentEventsStore, an as AssetModeResolver, ar as LocalMigrateError, at as carriesDynamicReference, b as buildFinalSnapshotIdentifier, bn as getDockerImageBySourceHash, br as normalizeAwsError, bt as requireConfigString, c as replayFailedOperations, cn as getBootstrapMarkerKey, cr as MissingCdkCliError, ct as refStateLookupFromResource, d as updatePartialReason, dn as validateAssetBucketName, dr as ProvisioningError, dt as resolveExplicitPhysicalId, en as createAssetRedirectResolver, er as CrossAccountSecretRefusalError, et as CloudControlProvider, f as UNSPECIFIED_SKIP_REASON, fn as validateContainerRepoName, fr as ResourceTimeoutError, ft as assertRegionMatch, g as IMPLICIT_DELETE_DEPENDENCIES, gn as getDockerCmd, gt as readConfigString, h as maskingRetryLogger, hn as formatDockerLoginError, hr as StackTerminationProtectionError, ht as configStringRefusal, i as DeploymentEventsReader, in as stripControlChars, ir as LocalInvokeBuildError$1, it as IntrinsicFunctionResolver, j as formatResourceLine, jn as resolveUseCdkBootstrapAssets, jt as scrubResourceRecord, k as isStatefulRecreateTargetSync, kn as resolveStateBucketWithDefault, kt as maskSecretsInText, l as replayRollback, ln as parseBootstrapMarker, lr as NestedStackChildDirectDestroyError, lt as WAFv2WebACLProvider, m as withResourceDeadline, mn as buildDockerImage, mr as StackHasActiveImportsError, mt as configBooleanRefusal, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as rewriteTemplateAssetReferences, nr as DeployCancelledError, nt as disableInstanceApiTermination, o as planFailedOps, on as BOOTSTRAP_MARKER_PREFIX, or as LocalStartServiceError, ot as cfnRefValueFromPhysicalId, p as deleteSkipReason, pn as buildDenyExternalAccessPolicy, pr as ResourceUpdateNotSupportedError, pt as coerceCfnBoolean, q as ProviderRegistry, qn as AwsClients, qt as S3StateBackend, r as DeployEngine, rn as escapeRegExp, rr as DynamicReferenceRegionAmbiguousError, rt as isTerminationProtectionPropagationError, s as planRollback, sn as ensureAssetStorage, st as getAccountInfo, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as loadPublishableAssetManifest, tt as slowCcOperationTimeoutMs, u as updatePartialMessage, un as readBootstrapMarkerBody, ur as PartialFailureError, ut as normalizeAwsTagsToCfn, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as runDockerStreaming, vt as requireConfigArray, w as refusesFinalSnapshot, wn as getLegacyStateBucketName, wr as isThrottlingError, wt as createSecretMasker, x as ccRoutedFinalSnapshotError, xn as Synthesizer, xr as withErrorHandling, xt as STATE_SOURCED_CROSS_GENERATION_RULES, y as PRE_DELETE_SNAPSHOT_TYPES, yn as AssetManifestLoader, yt as requireConfigObject, z as collectPublishedOutputNames, zn as expectedOwnerParam, zt as applyRoleArnIfSet } from "./deploy-engine-
|
|
2
|
+
import { $ as startInterruptWatch, $t as buildAssetRedirectMap, A as renderStatefulReason, An as resolveStateBucketWithDefaultAndSource, At as redactSecretsForState, B as exportAliasCollisionScrubWarning, Bn as PARTITION_TABLE, Bt as DiffCalculator, C as isFinalSnapshotError, Cn as getDefaultStateBucketName, Cr as isRetryableTransientError, Ct as TEMPLATE_SOURCED_RULES, D as extractDeploymentEventError, Dn as resolveCaptureObservedState, Dt as isSingleDynamicReferenceToken, E as makeCanonicalizePropertiesFn, En as resolveAutoAssetStorage, Et as errorCauseChain, F as green, Fn as CFN_TEMPLATE_URL_LIMIT, Ft as s3BucketDomainName, G as collectInlinePolicyNamesManagedBySiblings, Gt as TemplateParser, H as secretBearingStateKeyWarning, Hn as derivePartitionAndUrlSuffix, Ht as describeTypeWithThrottleRetry, I as red, In as MIGRATE_TMP_PREFIX, It as s3BucketDualStackDomainName, J as findActionableSilentDrops, Jn as getAwsClients, Jt as rebuildClientForBucketRegion, K as clearOnUpdateRemoval, Kn as resolveBucketRegion, Kt as LockManager, L as yellow, Ln as findLargeInlineResources, Lt as s3BucketRegionalDomainName, M as bold, Mn as stateBucketExistenceConfirmed, Mt as classifyReplaySecretRegion, N as cyan, Nn as warnDeprecatedNoPrefixCliFlag, Nt as producerRegionsFromState, O as MULTI_REGION_RECREATE_BLOCKED_TYPES, On as resolveSkipPrefix, Ot as maskSecretsInError, P as gray, Pn as CFN_TEMPLATE_BODY_LIMIT, Pt as s3BucketArn, Q as isInterruptedWaitError, Qn as CdkdError, Qt as WorkGraph, R as collectDeclaredOutputNames, Rn as uploadCfnTemplate, Rt as s3BucketWebsiteUrl, S as createPreDeleteFinalSnapshot, Sn as synthesisStatusMessage, Sr as isMarkedNonRetryable, St as STATE_SOURCED_READBACK_RULES, T as unsupportedFinalSnapshotError, Tn as resolveApp, Tr as markNonRetryable, Tt as dynamicReferenceTokens, U as stateKeySecretExposure, Un as AssemblyReader, Ut as withRetry, V as isExportAliasCollision, Vn as canonicalizeRegion, Vt as INTRINSIC_KEYS, W as IAMRoleProvider, Wn as processStackMessages, Wt as DagBuilder, X as beginCommandInterruptScope, Xn as setAwsClients, Xt as AssetPublisher, Y as findSilentDropProperties, Yn as resetAwsClients, Yt as shouldRetainResource, Z as endCommandInterruptScope, Zt as stringifyValue, _ as computeImplicitDeleteEdges, _n as runDockerForeground, _t as replayWarn, a as DeploymentEventsStore, an as AssetModeResolver, ar as LocalMigrateError, at as carriesDynamicReference, b as buildFinalSnapshotIdentifier, bn as getDockerImageBySourceHash, br as normalizeAwsError, bt as requireConfigString, c as replayFailedOperations, cn as getBootstrapMarkerKey, cr as MissingCdkCliError, ct as refStateLookupFromResource, d as updatePartialReason, dn as validateAssetBucketName, dr as ProvisioningError, dt as resolveExplicitPhysicalId, en as createAssetRedirectResolver, er as CrossAccountSecretRefusalError, et as CloudControlProvider, f as UNSPECIFIED_SKIP_REASON, fn as validateContainerRepoName, fr as ResourceTimeoutError, ft as assertRegionMatch, g as IMPLICIT_DELETE_DEPENDENCIES, gn as getDockerCmd, gt as readConfigString, h as maskingRetryLogger, hn as formatDockerLoginError, hr as StackTerminationProtectionError, ht as configStringRefusal, i as DeploymentEventsReader, in as stripControlChars, ir as LocalInvokeBuildError$1, it as IntrinsicFunctionResolver, j as formatResourceLine, jn as resolveUseCdkBootstrapAssets, jt as scrubResourceRecord, k as isStatefulRecreateTargetSync, kn as resolveStateBucketWithDefault, kt as maskSecretsInText, l as replayRollback, ln as parseBootstrapMarker, lr as NestedStackChildDirectDestroyError, lt as WAFv2WebACLProvider, m as withResourceDeadline, mn as buildDockerImage, mr as StackHasActiveImportsError, mt as configBooleanRefusal, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as rewriteTemplateAssetReferences, nr as DeployCancelledError, nt as disableInstanceApiTermination, o as planFailedOps, on as BOOTSTRAP_MARKER_PREFIX, or as LocalStartServiceError, ot as cfnRefValueFromPhysicalId, p as deleteSkipReason, pn as buildDenyExternalAccessPolicy, pr as ResourceUpdateNotSupportedError, pt as coerceCfnBoolean, q as ProviderRegistry, qn as AwsClients, qt as S3StateBackend, r as DeployEngine, rn as escapeRegExp, rr as DynamicReferenceRegionAmbiguousError, rt as isTerminationProtectionPropagationError, s as planRollback, sn as ensureAssetStorage, st as getAccountInfo, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as loadPublishableAssetManifest, tt as slowCcOperationTimeoutMs, u as updatePartialMessage, un as readBootstrapMarkerBody, ur as PartialFailureError, ut as normalizeAwsTagsToCfn, v as ATOMIC_FINAL_SNAPSHOT_TYPES, vn as runDockerStreaming, vt as requireConfigArray, w as refusesFinalSnapshot, wn as getLegacyStateBucketName, wr as isThrottlingError, wt as createSecretMasker, x as ccRoutedFinalSnapshotError, xn as Synthesizer, xr as withErrorHandling, xt as STATE_SOURCED_CROSS_GENERATION_RULES, y as PRE_DELETE_SNAPSHOT_TYPES, yn as AssetManifestLoader, yt as requireConfigObject, z as collectPublishedOutputNames, zn as expectedOwnerParam, zt as applyRoleArnIfSet } from "./deploy-engine-C62UGXid.js";
|
|
3
3
|
import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, i as runStackBuffered, m as withSkipPrefix, n as getLogger, o as PATTERN_B_NAME_OPTIONS, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
4
|
-
import { t as ASGProvider } from "./asg-provider-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-BbWubpjP.js";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
7
7
|
import { CopyObjectCommand, CreateBucketCommand, DeleteBucketAnalyticsConfigurationCommand, DeleteBucketCommand, DeleteBucketCorsCommand, DeleteBucketEncryptionCommand, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketOwnershipControlsCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, GetBucketOwnershipControlsCommand, GetBucketPolicyCommand, GetBucketReplicationCommand, GetBucketTaggingCommand, GetBucketVersioningCommand, GetBucketWebsiteCommand, GetObjectCommand, GetObjectLockConfigurationCommand, GetPublicAccessBlockCommand, HeadBucketCommand, ListBucketAnalyticsConfigurationsCommand, ListBucketIntelligentTieringConfigurationsCommand, ListBucketInventoryConfigurationsCommand, ListBucketMetricsConfigurationsCommand, ListObjectVersionsCommand, ListObjectsV2Command, NoSuchBucket, PutBucketAccelerateConfigurationCommand, PutBucketAnalyticsConfigurationCommand, PutBucketCorsCommand, PutBucketEncryptionCommand, PutBucketIntelligentTieringConfigurationCommand, PutBucketInventoryConfigurationCommand, PutBucketLifecycleConfigurationCommand, PutBucketLoggingCommand, PutBucketMetricsConfigurationCommand, PutBucketNotificationConfigurationCommand, PutBucketOwnershipControlsCommand, PutBucketPolicyCommand, PutBucketReplicationCommand, PutBucketTaggingCommand, PutBucketVersioningCommand, PutBucketWebsiteCommand, PutObjectCommand, PutObjectLockConfigurationCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
@@ -62709,28 +62709,6 @@ function redactUnaccountedOutputs(positioned, stored, accountedKeys, secrets) {
|
|
|
62709
62709
|
return repaired ?? positioned;
|
|
62710
62710
|
}
|
|
62711
62711
|
/**
|
|
62712
|
-
* The producer regions that are genuinely FOREIGN to this stack, canonicalized
|
|
62713
|
-
* and de-duplicated (issue #2109 review).
|
|
62714
|
-
*
|
|
62715
|
-
* The same filter {@link classifyReplaySecretRegion} applies to its own
|
|
62716
|
-
* `importedProducerRegions` argument, spelled here because the
|
|
62717
|
-
* unclassifiable-reference guard needs the answer WITHOUT an expression to hand
|
|
62718
|
-
* to the classifier. A same-region cross-stack read is the common case and
|
|
62719
|
-
* raises no cross-region question, so it must not arm a refusal.
|
|
62720
|
-
*/
|
|
62721
|
-
function foreignRegionsOf(producerRegions, stackRegion) {
|
|
62722
|
-
const seen = /* @__PURE__ */ new Set();
|
|
62723
|
-
const foreign = [];
|
|
62724
|
-
for (const candidate of producerRegions) {
|
|
62725
|
-
const canonical = canonicalizeRegion(candidate);
|
|
62726
|
-
if (!canonical || canonical === canonicalizeRegion(stackRegion)) continue;
|
|
62727
|
-
if (seen.has(canonical)) continue;
|
|
62728
|
-
seen.add(canonical);
|
|
62729
|
-
foreign.push(candidate);
|
|
62730
|
-
}
|
|
62731
|
-
return foreign;
|
|
62732
|
-
}
|
|
62733
|
-
/**
|
|
62734
62712
|
* The `cdkd scrub` resolvers: the stack's own, plus one pinned sibling per
|
|
62735
62713
|
* FOREIGN region an ARN-named secret reference asks for (issue
|
|
62736
62714
|
* [#2109](https://github.com/go-to-k/cdkd/issues/2109)).
|
|
@@ -62822,7 +62800,7 @@ const DYNAMIC_REFERENCE_OPENING = "{{resolve:";
|
|
|
62822
62800
|
* followed by a service whose VALUE CloudFormation defines as a secret. Counted
|
|
62823
62801
|
* against the number of WHOLE tokens of the same class the scan matched, which
|
|
62824
62802
|
* is how an ASSEMBLED reference is detected without parsing intrinsics — see
|
|
62825
|
-
* {@link
|
|
62803
|
+
* {@link isAssembledSecretReference}.
|
|
62826
62804
|
*
|
|
62827
62805
|
* WHY THE SERVICE IS PART OF THE OPENING (issue #2109 review). Counting the bare
|
|
62828
62806
|
* `{{resolve:` made the guard fire on any leaf that merely MENTIONS the syntax
|
|
@@ -62859,7 +62837,7 @@ const SECRET_REFERENCE_OPENINGS = [
|
|
|
62859
62837
|
];
|
|
62860
62838
|
/**
|
|
62861
62839
|
* What an `Fn::Sub` placeholder opens with. A whole token that CONTAINS one is
|
|
62862
|
-
* the third assembled shape — see {@link
|
|
62840
|
+
* the third assembled shape — see {@link isAssembledSecretReference}.
|
|
62863
62841
|
*/
|
|
62864
62842
|
const SUB_PLACEHOLDER_OPENING = "${";
|
|
62865
62843
|
/** How many SECRET references {@link SECRET_REFERENCE_OPENINGS} `leaf` opens. */
|
|
@@ -62873,16 +62851,17 @@ function isSecretReferenceToken(token) {
|
|
|
62873
62851
|
return SECRET_REFERENCE_OPENINGS.some((opening) => token.startsWith(opening));
|
|
62874
62852
|
}
|
|
62875
62853
|
/**
|
|
62876
|
-
*
|
|
62877
|
-
*
|
|
62878
|
-
* class in it, or a whole token that still
|
|
62854
|
+
* Does this leaf ASSEMBLE a secret reference out of parts (issue #2109 review)
|
|
62855
|
+
* — i.e. does it OPEN more SECRET references than the scan found COMPLETE
|
|
62856
|
+
* tokens of that class in it, or carry a whole token that still holds an
|
|
62857
|
+
* `Fn::Sub` placeholder?
|
|
62879
62858
|
*
|
|
62880
62859
|
* WHY THIS EXISTS, and it is the load-bearing half of this pre-pass rather than
|
|
62881
62860
|
* an edge case. The region split runs on the RAW template leaf, BEFORE intrinsic
|
|
62882
62861
|
* resolution, and the shared token scan is `\{\{resolve:[^}]+\}\}` — a class
|
|
62883
62862
|
* that cannot cross a `}`. So none of the three shapes that assemble a
|
|
62884
62863
|
* reference out of parts yields the ONE WHOLE token a literal reference does,
|
|
62885
|
-
* and the third one is why this
|
|
62864
|
+
* and the third one is why this predicate needs two tests rather than one
|
|
62886
62865
|
* (all four rows MEASURED):
|
|
62887
62866
|
*
|
|
62888
62867
|
* ```text
|
|
@@ -62900,40 +62879,42 @@ function isSecretReferenceToken(token) {
|
|
|
62900
62879
|
* test: a WHOLE token that still contains `${` has not been assembled yet.
|
|
62901
62880
|
* Neither a Secrets Manager secret name nor an SSM parameter name may contain
|
|
62902
62881
|
* `$` or `{`, so the only false positive that test can produce is a JSON key
|
|
62903
|
-
* literally spelled `${...}` in a leaf that is NOT under an `Fn::Sub` — and
|
|
62904
|
-
*
|
|
62905
|
-
*
|
|
62906
|
-
*
|
|
62907
|
-
*
|
|
62908
|
-
*
|
|
62909
|
-
*
|
|
62910
|
-
*
|
|
62911
|
-
*
|
|
62912
|
-
*
|
|
62913
|
-
*
|
|
62914
|
-
*
|
|
62915
|
-
*
|
|
62916
|
-
*
|
|
62917
|
-
*
|
|
62918
|
-
*
|
|
62919
|
-
*
|
|
62920
|
-
*
|
|
62921
|
-
*
|
|
62922
|
-
*
|
|
62923
|
-
*
|
|
62924
|
-
*
|
|
62925
|
-
*
|
|
62926
|
-
*
|
|
62927
|
-
*
|
|
62928
|
-
*
|
|
62929
|
-
*
|
|
62930
|
-
*
|
|
62931
|
-
*
|
|
62932
|
-
*
|
|
62933
|
-
*
|
|
62934
|
-
|
|
62935
|
-
|
|
62936
|
-
|
|
62882
|
+
* literally spelled `${...}` in a leaf that is NOT under an `Fn::Sub` — and a
|
|
62883
|
+
* false positive here now costs a DEFERRAL rather than a refusal, so it is
|
|
62884
|
+
* cheaper than it was when this predicate raised
|
|
62885
|
+
* `SCRUB_SECRET_REFERENCE_UNCLASSIFIABLE`.
|
|
62886
|
+
*
|
|
62887
|
+
* WHAT A `true` MEANS FOR THE CALLER, and it changed with issue
|
|
62888
|
+
* [#2157](https://github.com/go-to-k/cdkd/issues/2157): the leaf is handed on
|
|
62889
|
+
* BY IDENTITY, so the PRIMARY resolver classifies the reference once
|
|
62890
|
+
* `resolveSub` / `resolveJoin` have assembled it. Before issue
|
|
62891
|
+
* [#2134](https://github.com/go-to-k/cdkd/issues/2134) that was issue #2109
|
|
62892
|
+
* verbatim — the resolver had no region question at all, so an identity return
|
|
62893
|
+
* meant a foreign secret fetched against the stack's own endpoint, and this
|
|
62894
|
+
* predicate therefore had to REFUSE (gated on a foreign producer region being
|
|
62895
|
+
* on record, to keep it from refusing the world). #2134 put the classification
|
|
62896
|
+
* in `resolveDynamicReferences`, which sees the COMPLETE expression, so the
|
|
62897
|
+
* safety property the refusal bought — a reference whose region cannot be
|
|
62898
|
+
* established is never resolved in the stack's own region — is now bought
|
|
62899
|
+
* downstream over strictly more information.
|
|
62900
|
+
*
|
|
62901
|
+
* The trailing-placeholder row reached the resolver a different way before that
|
|
62902
|
+
* second test existed: the truncated token WAS classified here, and only
|
|
62903
|
+
* downstream luck kept it safe (the name form classifies `ambiguous`, the ARN
|
|
62904
|
+
* form fails into `SCRUB_CROSS_REGION_SECRET_UNRESOLVED` because the id it
|
|
62905
|
+
* looks up still has a literal `${Field}` in it). Post-#2157 it is deferred
|
|
62906
|
+
* like the other three, and the resolver answers it on the assembled
|
|
62907
|
+
* expression instead of on a token one brace short. Every row is pinned by the
|
|
62908
|
+
* suite rather than assumed.
|
|
62909
|
+
*
|
|
62910
|
+
* Residual, unchanged and stated rather than hidden: an `Fn::Join` that splits
|
|
62911
|
+
* BEFORE the service name opens no counted reference at all (see
|
|
62912
|
+
* {@link SECRET_REFERENCE_OPENINGS}), so this predicate returns `false` for it
|
|
62913
|
+
* and the leaf is returned by identity anyway — the same destination, reached
|
|
62914
|
+
* without being noticed.
|
|
62915
|
+
*/
|
|
62916
|
+
function isAssembledSecretReference(leaf, secretTokens) {
|
|
62917
|
+
return countSecretReferenceOpenings(leaf) !== secretTokens.length || secretTokens.some((token) => token.includes(SUB_PLACEHOLDER_OPENING));
|
|
62937
62918
|
}
|
|
62938
62919
|
/**
|
|
62939
62920
|
* Resolve every FOREIGN-region `{{resolve:...}}` reference in one leaf through
|
|
@@ -62955,10 +62936,9 @@ function unclassifiableScrubSecretError(origin, leafPath, stackName, foreignProd
|
|
|
62955
62936
|
* closed: a stopped scrub is recoverable, a lookup for a secret id spliced
|
|
62956
62937
|
* together out of a plaintext is not.
|
|
62957
62938
|
*/
|
|
62958
|
-
async function resolveForeignRegionTokens(leaf, stackName, ctx
|
|
62939
|
+
async function resolveForeignRegionTokens(leaf, stackName, ctx) {
|
|
62959
62940
|
const tokens = dynamicReferenceTokens(leaf);
|
|
62960
|
-
|
|
62961
|
-
if ((countSecretReferenceOpenings(leaf) !== secretTokens.length || secretTokens.some((token) => token.includes(SUB_PLACEHOLDER_OPENING))) && ctx.foreignProducerRegions.length > 0) throw unclassifiableScrubSecretError(ctx.origin, leafPath, stackName, ctx.foreignProducerRegions, ctx.stackRegion);
|
|
62941
|
+
if (isAssembledSecretReference(leaf, tokens.filter(isSecretReferenceToken))) return leaf;
|
|
62962
62942
|
const verdicts = tokens.map((token) => [token, classifyReplaySecretRegion(token, ctx.stackRegion, ctx.producerRegions)]);
|
|
62963
62943
|
for (const [, verdict] of verdicts) if (verdict.kind === "ambiguous") throw regionAmbiguousScrubSecretError(ctx.origin, stackName, verdict.secretName, verdict.foreignProducerRegions, ctx.stackRegion);
|
|
62964
62944
|
if (!verdicts.some(([, verdict]) => verdict.kind === "named-region")) return leaf;
|
|
@@ -63026,16 +63006,16 @@ async function resolveForeignRegionTokens(leaf, stackName, ctx, leafPath) {
|
|
|
63026
63006
|
* off it.
|
|
63027
63007
|
*/
|
|
63028
63008
|
async function pinCrossRegionSecrets(bag, stackName, ctx) {
|
|
63029
|
-
const walk = async (v
|
|
63009
|
+
const walk = async (v) => {
|
|
63030
63010
|
if (typeof v === "string") {
|
|
63031
63011
|
if (!v.includes(DYNAMIC_REFERENCE_OPENING)) return v;
|
|
63032
|
-
return await resolveForeignRegionTokens(v, stackName, ctx
|
|
63012
|
+
return await resolveForeignRegionTokens(v, stackName, ctx);
|
|
63033
63013
|
}
|
|
63034
63014
|
if (Array.isArray(v)) {
|
|
63035
63015
|
const out = new Array(v.length);
|
|
63036
63016
|
let changed = false;
|
|
63037
63017
|
for (let i = 0; i < v.length; i++) {
|
|
63038
|
-
out[i] = await walk(v[i]
|
|
63018
|
+
out[i] = await walk(v[i]);
|
|
63039
63019
|
if (out[i] !== v[i]) changed = true;
|
|
63040
63020
|
}
|
|
63041
63021
|
return changed ? out : v;
|
|
@@ -63044,14 +63024,14 @@ async function pinCrossRegionSecrets(bag, stackName, ctx) {
|
|
|
63044
63024
|
const out = Object.create(null);
|
|
63045
63025
|
let changed = false;
|
|
63046
63026
|
for (const [k, val] of Object.entries(v)) {
|
|
63047
|
-
out[k] = await walk(val
|
|
63027
|
+
out[k] = await walk(val);
|
|
63048
63028
|
if (out[k] !== val) changed = true;
|
|
63049
63029
|
}
|
|
63050
63030
|
return changed ? out : v;
|
|
63051
63031
|
}
|
|
63052
63032
|
return v;
|
|
63053
63033
|
};
|
|
63054
|
-
return await walk(bag
|
|
63034
|
+
return await walk(bag);
|
|
63055
63035
|
}
|
|
63056
63036
|
/**
|
|
63057
63037
|
* Order scrub targets PRODUCER-BEFORE-CONSUMER (issue
|
|
@@ -63460,8 +63440,11 @@ function storedValueCarriesNoPlaintext(stored) {
|
|
|
63460
63440
|
* {@link buildExportOwnerIndex} and `producerTemplates` are keyed by stack
|
|
63461
63441
|
* NAME alone, so the walk reads that name's template regardless of `Region`;
|
|
63462
63442
|
* - a secret reachable only through the TRUE branch of an `Fn::If` in a
|
|
63463
|
-
* producer's output: see {@link
|
|
63464
|
-
* branch for a condition it cannot evaluate
|
|
63443
|
+
* producer's output: see {@link selectTakenConditionalBranches}, which takes
|
|
63444
|
+
* the FALSE branch for a condition it cannot evaluate -- and which, since
|
|
63445
|
+
* issue [#2150](https://github.com/go-to-k/cdkd/issues/2150), feeds BOTH the
|
|
63446
|
+
* literal scan below and {@link collectReExportHops} from that one
|
|
63447
|
+
* selection.
|
|
63465
63448
|
*/
|
|
63466
63449
|
function producerPublishesSecretExpression(templates, exportOwners, producerStack, key) {
|
|
63467
63450
|
const seen = /* @__PURE__ */ new Set([`${producerStack}\u0000${key}`]);
|
|
@@ -63489,7 +63472,8 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63489
63472
|
widened = true;
|
|
63490
63473
|
subjects = Object.values(outputs).map((o) => o?.Value);
|
|
63491
63474
|
} else continue;
|
|
63492
|
-
for (const
|
|
63475
|
+
for (const rawSubject of subjects) {
|
|
63476
|
+
const subject = selectTakenConditionalBranches(rawSubject);
|
|
63493
63477
|
if (JSON.stringify(subject ?? null).includes("{{resolve:")) {
|
|
63494
63478
|
if (widened) return {
|
|
63495
63479
|
kind: "widened",
|
|
@@ -63518,6 +63502,64 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63518
63502
|
return NO_SECRET_EXPRESSION;
|
|
63519
63503
|
}
|
|
63520
63504
|
/**
|
|
63505
|
+
* One node with every `Fn::If` collapsed to the branch scrub would TAKE
|
|
63506
|
+
* (issues #2146 and [#2150](https://github.com/go-to-k/cdkd/issues/2150)).
|
|
63507
|
+
*
|
|
63508
|
+
* ONE SPELLING, consumed verbatim by both halves of "does this producer publish
|
|
63509
|
+
* a secret expression?" — {@link collectReExportHops}, which follows the value
|
|
63510
|
+
* onward, and {@link producerPublishesSecretExpression}'s literal
|
|
63511
|
+
* `{{resolve:` scan, which tests the value itself. Those two are one question
|
|
63512
|
+
* asked twice, and they DISAGREED between #2146 and #2150: the hop walk took
|
|
63513
|
+
* the false branch while the scan `JSON.stringify`d the whole node and saw
|
|
63514
|
+
* both. A producer whose output is
|
|
63515
|
+
* `{"Fn::If": ["IsProd", "{{resolve:...}}", "plain"]}` deployed with `IsProd`
|
|
63516
|
+
* false therefore verdicted `declared`, the discriminator read the deployed
|
|
63517
|
+
* value `plain`, and scrub refused with `SCRUB_CROSS_STACK_PRODUCER_PLAINTEXT`
|
|
63518
|
+
* — an UNCLEARABLE refusal, because no `cdkd scrub` of the producer can turn
|
|
63519
|
+
* `plain` into an expression and there is no bypass flag, so every other secret
|
|
63520
|
+
* in the consumer stack was stranded. A second spelling of the selection would
|
|
63521
|
+
* only move where the two can drift apart again, so there is exactly one.
|
|
63522
|
+
*
|
|
63523
|
+
* WHICH BRANCH: the FALSE one, unconditionally, mirroring `resolveIf`'s
|
|
63524
|
+
* unknown-condition arm. Every condition met on this path belongs to ANOTHER
|
|
63525
|
+
* stack, and scrub evaluates conditions only for the stack it is scrubbing,
|
|
63526
|
+
* from that template's parameter DEFAULTS (it takes no `--parameters`), so a
|
|
63527
|
+
* producer's condition is not evaluable here.
|
|
63528
|
+
*
|
|
63529
|
+
* TWO SHAPES COLLAPSE MORE THAN THE SELECTED BRANCH, both fail-OPEN, both
|
|
63530
|
+
* stated rather than implied because the old whole-node `JSON.stringify` saw
|
|
63531
|
+
* them and this does not. Neither is CloudFormation-emittable, which is why
|
|
63532
|
+
* they are accepted rather than fixed:
|
|
63533
|
+
*
|
|
63534
|
+
* - a MALFORMED `Fn::If` (args not a 3-tuple) collapses to `null` -- NO branch.
|
|
63535
|
+
* Which branch is live is unknowable, so neither a hop nor a `{{resolve:`
|
|
63536
|
+
* sighting may be claimed from it. CloudFormation refuses such a template, so
|
|
63537
|
+
* a producer that reads this way cannot have been deployed carrying one.
|
|
63538
|
+
* - an object carrying `Fn::If` ALONGSIDE sibling keys keeps only the selected
|
|
63539
|
+
* branch, so a `{{resolve:` under a sibling is not seen. An intrinsic node has
|
|
63540
|
+
* exactly one key in any template CloudFormation accepts, and the hop walk
|
|
63541
|
+
* dropped those siblings before this function existed (its `Fn::If` arm
|
|
63542
|
+
* `return`ed rather than falling through), so this preserves that behaviour
|
|
63543
|
+
* rather than introducing it.
|
|
63544
|
+
*
|
|
63545
|
+
* Residual, and it is the direction this file accepts elsewhere: a secret
|
|
63546
|
+
* reachable only through the TRUE branch is not detected, so that reference
|
|
63547
|
+
* keeps its pre-#2133 outcome. The hop walk already took this trade for the
|
|
63548
|
+
* chain it follows; #2150 extends it to the scan so that the two agree.
|
|
63549
|
+
*/
|
|
63550
|
+
function selectTakenConditionalBranches(node) {
|
|
63551
|
+
if (Array.isArray(node)) return node.map(selectTakenConditionalBranches);
|
|
63552
|
+
if (node === null || typeof node !== "object") return node;
|
|
63553
|
+
const obj = node;
|
|
63554
|
+
if ("Fn::If" in obj) {
|
|
63555
|
+
const args = obj["Fn::If"];
|
|
63556
|
+
return Array.isArray(args) && args.length === 3 ? selectTakenConditionalBranches(args[2]) : null;
|
|
63557
|
+
}
|
|
63558
|
+
const out = Object.create(null);
|
|
63559
|
+
for (const [key, child] of Object.entries(obj)) out[key] = selectTakenConditionalBranches(child);
|
|
63560
|
+
return out;
|
|
63561
|
+
}
|
|
63562
|
+
/**
|
|
63521
63563
|
* The re-export hops one output VALUE carries (issue #2146).
|
|
63522
63564
|
*
|
|
63523
63565
|
* Only STATICALLY resolvable references produce a hop, mirroring
|
|
@@ -63536,8 +63578,9 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63536
63578
|
* routinely wrapped — `Fn::Join`ing an imported password into a URL is the
|
|
63537
63579
|
* shape the live fixture uses.
|
|
63538
63580
|
*
|
|
63539
|
-
* `Fn::If`
|
|
63540
|
-
* tidy (issue #2146 review). `makeCrossStackPrePass`
|
|
63581
|
+
* `Fn::If` NEVER REACHES THIS WALK, and the selection that used to live here
|
|
63582
|
+
* is load-bearing rather than tidy (issue #2146 review). `makeCrossStackPrePass`
|
|
63583
|
+
* deliberately mirrors
|
|
63541
63584
|
* `resolveIf` — selected branch only — so that a conditional import of a
|
|
63542
63585
|
* not-yet-deployed producer cannot refuse a whole stack, unbypassably, over a
|
|
63543
63586
|
* reference the deploy never read. A hop walk that descended into both arms
|
|
@@ -63549,24 +63592,24 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63549
63592
|
* flag. On main the same input answered `no`, so it would have been a
|
|
63550
63593
|
* regression this change introduced.
|
|
63551
63594
|
*
|
|
63552
|
-
*
|
|
63553
|
-
*
|
|
63554
|
-
*
|
|
63555
|
-
*
|
|
63556
|
-
*
|
|
63557
|
-
*
|
|
63558
|
-
*
|
|
63559
|
-
*
|
|
63560
|
-
*
|
|
63561
|
-
*
|
|
63562
|
-
*
|
|
63563
|
-
*
|
|
63564
|
-
*
|
|
63565
|
-
*
|
|
63566
|
-
*
|
|
63567
|
-
*
|
|
63568
|
-
*/
|
|
63569
|
-
function collectReExportHops(
|
|
63595
|
+
* `selectedValue` IS THE CONTRACT, and it is why this function carries no
|
|
63596
|
+
* `Fn::If` handling of its own: the only caller,
|
|
63597
|
+
* {@link producerPublishesSecretExpression}, applies
|
|
63598
|
+
* {@link selectTakenConditionalBranches} ONCE and hands the result to BOTH the
|
|
63599
|
+
* literal `{{resolve:` scan and this walk, so a node reaching here holds no
|
|
63600
|
+
* `Fn::If` at all. Issue [#2150](https://github.com/go-to-k/cdkd/issues/2150)
|
|
63601
|
+
* collapsed the two to one site deliberately: the scan used to `JSON.stringify`
|
|
63602
|
+
* the whole subject and therefore see BOTH arms while this walk took only the
|
|
63603
|
+
* false one, and two spellings of one question are exactly how they came to
|
|
63604
|
+
* disagree. A second selection HERE would restore that, and be worse than
|
|
63605
|
+
* useless — measured on the #2150 lane, a per-site copy was invisible to every
|
|
63606
|
+
* test in the suite, because the caller had already pruned, so deleting it
|
|
63607
|
+
* changed nothing and no probe could fence it.
|
|
63608
|
+
* {@link selectTakenConditionalBranches}'s own doc carries which branch is
|
|
63609
|
+
* selected, what a malformed `Fn::If` yields, and the TRUE-branch residual both
|
|
63610
|
+
* halves accept.
|
|
63611
|
+
*/
|
|
63612
|
+
function collectReExportHops(selectedValue, templates, exportOwners) {
|
|
63570
63613
|
const hops = [];
|
|
63571
63614
|
const walk = (node) => {
|
|
63572
63615
|
if (Array.isArray(node)) {
|
|
@@ -63575,11 +63618,6 @@ function collectReExportHops(value, templates, exportOwners) {
|
|
|
63575
63618
|
}
|
|
63576
63619
|
if (node === null || typeof node !== "object") return;
|
|
63577
63620
|
const obj = node;
|
|
63578
|
-
if ("Fn::If" in obj) {
|
|
63579
|
-
const args = obj["Fn::If"];
|
|
63580
|
-
if (Array.isArray(args) && args.length === 3) walk(args[2]);
|
|
63581
|
-
return;
|
|
63582
|
-
}
|
|
63583
63621
|
const imported = obj["Fn::ImportValue"];
|
|
63584
63622
|
if (typeof imported === "string") for (const owner of exportOwners.get(imported) ?? []) hops.push({
|
|
63585
63623
|
stack: owner,
|
|
@@ -63597,7 +63635,7 @@ function collectReExportHops(value, templates, exportOwners) {
|
|
|
63597
63635
|
}
|
|
63598
63636
|
for (const child of Object.values(obj)) walk(child);
|
|
63599
63637
|
};
|
|
63600
|
-
walk(
|
|
63638
|
+
walk(selectedValue);
|
|
63601
63639
|
return hops;
|
|
63602
63640
|
}
|
|
63603
63641
|
/**
|
|
@@ -63990,7 +64028,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
63990
64028
|
const resolvers = new ScrubResolvers(region);
|
|
63991
64029
|
const resolver = resolvers.primary;
|
|
63992
64030
|
const producerRegions = producerRegionsFromState(state);
|
|
63993
|
-
const foreignProducerRegions = foreignRegionsOf(producerRegions, region);
|
|
63994
64031
|
let parameters = {};
|
|
63995
64032
|
let conditions = {};
|
|
63996
64033
|
try {
|
|
@@ -64031,7 +64068,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
64031
64068
|
const resolveInput = await pinCrossRegionSecrets(templateResource.Properties, stack.stackName, {
|
|
64032
64069
|
stackRegion: region,
|
|
64033
64070
|
producerRegions,
|
|
64034
|
-
foreignProducerRegions,
|
|
64035
64071
|
resolvers,
|
|
64036
64072
|
recordedSecretValues,
|
|
64037
64073
|
origin: `resource '${logicalId}'`
|
|
@@ -64059,7 +64095,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
64059
64095
|
const nameSource = await pinCrossRegionSecrets(declaredExportName, stack.stackName, {
|
|
64060
64096
|
stackRegion: region,
|
|
64061
64097
|
producerRegions,
|
|
64062
|
-
foreignProducerRegions,
|
|
64063
64098
|
resolvers,
|
|
64064
64099
|
recordedSecretValues: outputSecrets,
|
|
64065
64100
|
origin: `Export.Name of output '${name}'`
|
|
@@ -64094,7 +64129,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
64094
64129
|
const valueSource = await pinCrossRegionSecrets(value, stack.stackName, {
|
|
64095
64130
|
stackRegion: region,
|
|
64096
64131
|
producerRegions,
|
|
64097
|
-
foreignProducerRegions,
|
|
64098
64132
|
resolvers,
|
|
64099
64133
|
recordedSecretValues: outputSecrets,
|
|
64100
64134
|
origin: `output '${name}'`
|
|
@@ -86091,7 +86125,7 @@ function createMigrateCommand() {
|
|
|
86091
86125
|
*/
|
|
86092
86126
|
function buildProgram() {
|
|
86093
86127
|
const program = new Command();
|
|
86094
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.
|
|
86128
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.37");
|
|
86095
86129
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
86096
86130
|
const { profile } = actionCommand.optsWithGlobals();
|
|
86097
86131
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|