@go-to-k/cdkd 0.284.36 → 0.284.38
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-kqBWElNc.js} +2 -2
- package/dist/{asg-provider-2wQUtu7f.js.map → asg-provider-kqBWElNc.js.map} +1 -1
- package/dist/cli.js +186 -132
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-Csb2eS97.js → deploy-engine-DyxASW-O.js} +3 -3
- package/dist/{deploy-engine-Csb2eS97.js.map → deploy-engine-DyxASW-O.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-DyxASW-O.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-kqBWElNc.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";
|
|
@@ -58335,19 +58335,40 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58335
58335
|
const stackRegion = state.region;
|
|
58336
58336
|
let destroyProviderRegistry = ctx.providerRegistry;
|
|
58337
58337
|
let destroyAwsClients;
|
|
58338
|
+
let regionSwitched = false;
|
|
58339
|
+
const restoreBaseRegionAndClients = () => {
|
|
58340
|
+
if (!regionSwitched) return;
|
|
58341
|
+
regionSwitched = false;
|
|
58342
|
+
const switchedClients = destroyAwsClients;
|
|
58343
|
+
destroyAwsClients = void 0;
|
|
58344
|
+
process.env["AWS_REGION"] = ctx.baseRegion;
|
|
58345
|
+
process.env["AWS_DEFAULT_REGION"] = ctx.baseRegion;
|
|
58346
|
+
setAwsClients(ctx.baseAwsClients);
|
|
58347
|
+
try {
|
|
58348
|
+
switchedClients?.destroy();
|
|
58349
|
+
} catch (destroyError) {
|
|
58350
|
+
logger.debug(`Failed to destroy region-scoped AWS clients: ${destroyError instanceof Error ? destroyError.message : String(destroyError)}`);
|
|
58351
|
+
}
|
|
58352
|
+
};
|
|
58338
58353
|
if (stackRegion && stackRegion !== ctx.baseRegion) {
|
|
58339
58354
|
logger.info(`Stack region: ${stackRegion}`);
|
|
58340
58355
|
process.env["AWS_REGION"] = stackRegion;
|
|
58341
58356
|
process.env["AWS_DEFAULT_REGION"] = stackRegion;
|
|
58342
|
-
|
|
58343
|
-
|
|
58344
|
-
|
|
58345
|
-
|
|
58346
|
-
|
|
58347
|
-
|
|
58348
|
-
|
|
58349
|
-
|
|
58350
|
-
|
|
58357
|
+
regionSwitched = true;
|
|
58358
|
+
try {
|
|
58359
|
+
destroyAwsClients = new AwsClients({
|
|
58360
|
+
region: stackRegion,
|
|
58361
|
+
...ctx.profile && { profile: ctx.profile }
|
|
58362
|
+
});
|
|
58363
|
+
setAwsClients(destroyAwsClients);
|
|
58364
|
+
destroyProviderRegistry = new ProviderRegistry();
|
|
58365
|
+
registerAllProviders(destroyProviderRegistry);
|
|
58366
|
+
destroyProviderRegistry.setCustomResourceResponseBucket(ctx.stateBucket);
|
|
58367
|
+
if (ctx.allowUnsupportedTypes?.length) destroyProviderRegistry.allowUnsupportedTypes(ctx.allowUnsupportedTypes);
|
|
58368
|
+
} catch (setupError) {
|
|
58369
|
+
restoreBaseRegionAndClients();
|
|
58370
|
+
throw setupError;
|
|
58371
|
+
}
|
|
58351
58372
|
}
|
|
58352
58373
|
const renderer = getLiveRenderer();
|
|
58353
58374
|
let draining = false;
|
|
@@ -58367,10 +58388,11 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58367
58388
|
};
|
|
58368
58389
|
process.setMaxListeners(Math.max(process.getMaxListeners(), 100));
|
|
58369
58390
|
process.on("SIGINT", sigintHandler);
|
|
58370
|
-
logger.info(`\nAcquiring lock for stack ${stackName}...`);
|
|
58371
58391
|
try {
|
|
58372
|
-
|
|
58392
|
+
logger.info(`\nAcquiring lock for stack ${stackName}...`);
|
|
58393
|
+
if (!await ctx.lockManager.acquireLock(stackName, regionForState, void 0, "destroy")) throw new Error(`Could not acquire lock for stack '${stackName}' (${regionForState}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${stackName} --stack-region ${regionForState}' if you are certain no other process is active.`);
|
|
58373
58394
|
} catch (error) {
|
|
58395
|
+
restoreBaseRegionAndClients();
|
|
58374
58396
|
process.removeListener("SIGINT", sigintHandler);
|
|
58375
58397
|
throw error;
|
|
58376
58398
|
}
|
|
@@ -58382,6 +58404,7 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58382
58404
|
} catch (releaseErr) {
|
|
58383
58405
|
logger.warn(`Failed to release lock after strong-ref refusal/failure: ${releaseErr instanceof Error ? releaseErr.message : String(releaseErr)}`);
|
|
58384
58406
|
}
|
|
58407
|
+
restoreBaseRegionAndClients();
|
|
58385
58408
|
process.removeListener("SIGINT", sigintHandler);
|
|
58386
58409
|
};
|
|
58387
58410
|
let consumers;
|
|
@@ -58422,8 +58445,8 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58422
58445
|
}
|
|
58423
58446
|
});
|
|
58424
58447
|
};
|
|
58425
|
-
renderer.start();
|
|
58426
58448
|
try {
|
|
58449
|
+
renderer.start();
|
|
58427
58450
|
logger.info("Building dependency graph...");
|
|
58428
58451
|
const template = {
|
|
58429
58452
|
AWSTemplateFormatVersion: "2010-09-09",
|
|
@@ -58693,14 +58716,9 @@ async function runDestroyForStack(stackName, state, ctx) {
|
|
|
58693
58716
|
await ctx.lockManager.releaseLock(stackName, regionForState);
|
|
58694
58717
|
} finally {
|
|
58695
58718
|
process.removeListener("SIGINT", sigintHandler);
|
|
58719
|
+
restoreBaseRegionAndClients();
|
|
58696
58720
|
}
|
|
58697
58721
|
result.interrupted ||= draining;
|
|
58698
|
-
if (destroyAwsClients) {
|
|
58699
|
-
destroyAwsClients.destroy();
|
|
58700
|
-
process.env["AWS_REGION"] = ctx.baseRegion;
|
|
58701
|
-
process.env["AWS_DEFAULT_REGION"] = ctx.baseRegion;
|
|
58702
|
-
setAwsClients(ctx.baseAwsClients);
|
|
58703
|
-
}
|
|
58704
58722
|
}
|
|
58705
58723
|
return result;
|
|
58706
58724
|
}
|
|
@@ -62709,28 +62727,6 @@ function redactUnaccountedOutputs(positioned, stored, accountedKeys, secrets) {
|
|
|
62709
62727
|
return repaired ?? positioned;
|
|
62710
62728
|
}
|
|
62711
62729
|
/**
|
|
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
62730
|
* The `cdkd scrub` resolvers: the stack's own, plus one pinned sibling per
|
|
62735
62731
|
* FOREIGN region an ARN-named secret reference asks for (issue
|
|
62736
62732
|
* [#2109](https://github.com/go-to-k/cdkd/issues/2109)).
|
|
@@ -62822,7 +62818,7 @@ const DYNAMIC_REFERENCE_OPENING = "{{resolve:";
|
|
|
62822
62818
|
* followed by a service whose VALUE CloudFormation defines as a secret. Counted
|
|
62823
62819
|
* against the number of WHOLE tokens of the same class the scan matched, which
|
|
62824
62820
|
* is how an ASSEMBLED reference is detected without parsing intrinsics — see
|
|
62825
|
-
* {@link
|
|
62821
|
+
* {@link isAssembledSecretReference}.
|
|
62826
62822
|
*
|
|
62827
62823
|
* WHY THE SERVICE IS PART OF THE OPENING (issue #2109 review). Counting the bare
|
|
62828
62824
|
* `{{resolve:` made the guard fire on any leaf that merely MENTIONS the syntax
|
|
@@ -62859,7 +62855,7 @@ const SECRET_REFERENCE_OPENINGS = [
|
|
|
62859
62855
|
];
|
|
62860
62856
|
/**
|
|
62861
62857
|
* What an `Fn::Sub` placeholder opens with. A whole token that CONTAINS one is
|
|
62862
|
-
* the third assembled shape — see {@link
|
|
62858
|
+
* the third assembled shape — see {@link isAssembledSecretReference}.
|
|
62863
62859
|
*/
|
|
62864
62860
|
const SUB_PLACEHOLDER_OPENING = "${";
|
|
62865
62861
|
/** How many SECRET references {@link SECRET_REFERENCE_OPENINGS} `leaf` opens. */
|
|
@@ -62873,16 +62869,17 @@ function isSecretReferenceToken(token) {
|
|
|
62873
62869
|
return SECRET_REFERENCE_OPENINGS.some((opening) => token.startsWith(opening));
|
|
62874
62870
|
}
|
|
62875
62871
|
/**
|
|
62876
|
-
*
|
|
62877
|
-
*
|
|
62878
|
-
* class in it, or a whole token that still
|
|
62872
|
+
* Does this leaf ASSEMBLE a secret reference out of parts (issue #2109 review)
|
|
62873
|
+
* — i.e. does it OPEN more SECRET references than the scan found COMPLETE
|
|
62874
|
+
* tokens of that class in it, or carry a whole token that still holds an
|
|
62875
|
+
* `Fn::Sub` placeholder?
|
|
62879
62876
|
*
|
|
62880
62877
|
* WHY THIS EXISTS, and it is the load-bearing half of this pre-pass rather than
|
|
62881
62878
|
* an edge case. The region split runs on the RAW template leaf, BEFORE intrinsic
|
|
62882
62879
|
* resolution, and the shared token scan is `\{\{resolve:[^}]+\}\}` — a class
|
|
62883
62880
|
* that cannot cross a `}`. So none of the three shapes that assemble a
|
|
62884
62881
|
* reference out of parts yields the ONE WHOLE token a literal reference does,
|
|
62885
|
-
* and the third one is why this
|
|
62882
|
+
* and the third one is why this predicate needs two tests rather than one
|
|
62886
62883
|
* (all four rows MEASURED):
|
|
62887
62884
|
*
|
|
62888
62885
|
* ```text
|
|
@@ -62900,40 +62897,42 @@ function isSecretReferenceToken(token) {
|
|
|
62900
62897
|
* test: a WHOLE token that still contains `${` has not been assembled yet.
|
|
62901
62898
|
* Neither a Secrets Manager secret name nor an SSM parameter name may contain
|
|
62902
62899
|
* `$` 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
|
-
|
|
62900
|
+
* literally spelled `${...}` in a leaf that is NOT under an `Fn::Sub` — and a
|
|
62901
|
+
* false positive here now costs a DEFERRAL rather than a refusal, so it is
|
|
62902
|
+
* cheaper than it was when this predicate raised
|
|
62903
|
+
* `SCRUB_SECRET_REFERENCE_UNCLASSIFIABLE`.
|
|
62904
|
+
*
|
|
62905
|
+
* WHAT A `true` MEANS FOR THE CALLER, and it changed with issue
|
|
62906
|
+
* [#2157](https://github.com/go-to-k/cdkd/issues/2157): the leaf is handed on
|
|
62907
|
+
* BY IDENTITY, so the PRIMARY resolver classifies the reference once
|
|
62908
|
+
* `resolveSub` / `resolveJoin` have assembled it. Before issue
|
|
62909
|
+
* [#2134](https://github.com/go-to-k/cdkd/issues/2134) that was issue #2109
|
|
62910
|
+
* verbatim — the resolver had no region question at all, so an identity return
|
|
62911
|
+
* meant a foreign secret fetched against the stack's own endpoint, and this
|
|
62912
|
+
* predicate therefore had to REFUSE (gated on a foreign producer region being
|
|
62913
|
+
* on record, to keep it from refusing the world). #2134 put the classification
|
|
62914
|
+
* in `resolveDynamicReferences`, which sees the COMPLETE expression, so the
|
|
62915
|
+
* safety property the refusal bought — a reference whose region cannot be
|
|
62916
|
+
* established is never resolved in the stack's own region — is now bought
|
|
62917
|
+
* downstream over strictly more information.
|
|
62918
|
+
*
|
|
62919
|
+
* The trailing-placeholder row reached the resolver a different way before that
|
|
62920
|
+
* second test existed: the truncated token WAS classified here, and only
|
|
62921
|
+
* downstream luck kept it safe (the name form classifies `ambiguous`, the ARN
|
|
62922
|
+
* form fails into `SCRUB_CROSS_REGION_SECRET_UNRESOLVED` because the id it
|
|
62923
|
+
* looks up still has a literal `${Field}` in it). Post-#2157 it is deferred
|
|
62924
|
+
* like the other three, and the resolver answers it on the assembled
|
|
62925
|
+
* expression instead of on a token one brace short. Every row is pinned by the
|
|
62926
|
+
* suite rather than assumed.
|
|
62927
|
+
*
|
|
62928
|
+
* Residual, unchanged and stated rather than hidden: an `Fn::Join` that splits
|
|
62929
|
+
* BEFORE the service name opens no counted reference at all (see
|
|
62930
|
+
* {@link SECRET_REFERENCE_OPENINGS}), so this predicate returns `false` for it
|
|
62931
|
+
* and the leaf is returned by identity anyway — the same destination, reached
|
|
62932
|
+
* without being noticed.
|
|
62933
|
+
*/
|
|
62934
|
+
function isAssembledSecretReference(leaf, secretTokens) {
|
|
62935
|
+
return countSecretReferenceOpenings(leaf) !== secretTokens.length || secretTokens.some((token) => token.includes(SUB_PLACEHOLDER_OPENING));
|
|
62937
62936
|
}
|
|
62938
62937
|
/**
|
|
62939
62938
|
* Resolve every FOREIGN-region `{{resolve:...}}` reference in one leaf through
|
|
@@ -62955,10 +62954,9 @@ function unclassifiableScrubSecretError(origin, leafPath, stackName, foreignProd
|
|
|
62955
62954
|
* closed: a stopped scrub is recoverable, a lookup for a secret id spliced
|
|
62956
62955
|
* together out of a plaintext is not.
|
|
62957
62956
|
*/
|
|
62958
|
-
async function resolveForeignRegionTokens(leaf, stackName, ctx
|
|
62957
|
+
async function resolveForeignRegionTokens(leaf, stackName, ctx) {
|
|
62959
62958
|
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);
|
|
62959
|
+
if (isAssembledSecretReference(leaf, tokens.filter(isSecretReferenceToken))) return leaf;
|
|
62962
62960
|
const verdicts = tokens.map((token) => [token, classifyReplaySecretRegion(token, ctx.stackRegion, ctx.producerRegions)]);
|
|
62963
62961
|
for (const [, verdict] of verdicts) if (verdict.kind === "ambiguous") throw regionAmbiguousScrubSecretError(ctx.origin, stackName, verdict.secretName, verdict.foreignProducerRegions, ctx.stackRegion);
|
|
62964
62962
|
if (!verdicts.some(([, verdict]) => verdict.kind === "named-region")) return leaf;
|
|
@@ -63026,16 +63024,16 @@ async function resolveForeignRegionTokens(leaf, stackName, ctx, leafPath) {
|
|
|
63026
63024
|
* off it.
|
|
63027
63025
|
*/
|
|
63028
63026
|
async function pinCrossRegionSecrets(bag, stackName, ctx) {
|
|
63029
|
-
const walk = async (v
|
|
63027
|
+
const walk = async (v) => {
|
|
63030
63028
|
if (typeof v === "string") {
|
|
63031
63029
|
if (!v.includes(DYNAMIC_REFERENCE_OPENING)) return v;
|
|
63032
|
-
return await resolveForeignRegionTokens(v, stackName, ctx
|
|
63030
|
+
return await resolveForeignRegionTokens(v, stackName, ctx);
|
|
63033
63031
|
}
|
|
63034
63032
|
if (Array.isArray(v)) {
|
|
63035
63033
|
const out = new Array(v.length);
|
|
63036
63034
|
let changed = false;
|
|
63037
63035
|
for (let i = 0; i < v.length; i++) {
|
|
63038
|
-
out[i] = await walk(v[i]
|
|
63036
|
+
out[i] = await walk(v[i]);
|
|
63039
63037
|
if (out[i] !== v[i]) changed = true;
|
|
63040
63038
|
}
|
|
63041
63039
|
return changed ? out : v;
|
|
@@ -63044,14 +63042,14 @@ async function pinCrossRegionSecrets(bag, stackName, ctx) {
|
|
|
63044
63042
|
const out = Object.create(null);
|
|
63045
63043
|
let changed = false;
|
|
63046
63044
|
for (const [k, val] of Object.entries(v)) {
|
|
63047
|
-
out[k] = await walk(val
|
|
63045
|
+
out[k] = await walk(val);
|
|
63048
63046
|
if (out[k] !== val) changed = true;
|
|
63049
63047
|
}
|
|
63050
63048
|
return changed ? out : v;
|
|
63051
63049
|
}
|
|
63052
63050
|
return v;
|
|
63053
63051
|
};
|
|
63054
|
-
return await walk(bag
|
|
63052
|
+
return await walk(bag);
|
|
63055
63053
|
}
|
|
63056
63054
|
/**
|
|
63057
63055
|
* Order scrub targets PRODUCER-BEFORE-CONSUMER (issue
|
|
@@ -63460,8 +63458,11 @@ function storedValueCarriesNoPlaintext(stored) {
|
|
|
63460
63458
|
* {@link buildExportOwnerIndex} and `producerTemplates` are keyed by stack
|
|
63461
63459
|
* NAME alone, so the walk reads that name's template regardless of `Region`;
|
|
63462
63460
|
* - 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
|
|
63461
|
+
* producer's output: see {@link selectTakenConditionalBranches}, which takes
|
|
63462
|
+
* the FALSE branch for a condition it cannot evaluate -- and which, since
|
|
63463
|
+
* issue [#2150](https://github.com/go-to-k/cdkd/issues/2150), feeds BOTH the
|
|
63464
|
+
* literal scan below and {@link collectReExportHops} from that one
|
|
63465
|
+
* selection.
|
|
63465
63466
|
*/
|
|
63466
63467
|
function producerPublishesSecretExpression(templates, exportOwners, producerStack, key) {
|
|
63467
63468
|
const seen = /* @__PURE__ */ new Set([`${producerStack}\u0000${key}`]);
|
|
@@ -63489,7 +63490,8 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63489
63490
|
widened = true;
|
|
63490
63491
|
subjects = Object.values(outputs).map((o) => o?.Value);
|
|
63491
63492
|
} else continue;
|
|
63492
|
-
for (const
|
|
63493
|
+
for (const rawSubject of subjects) {
|
|
63494
|
+
const subject = selectTakenConditionalBranches(rawSubject);
|
|
63493
63495
|
if (JSON.stringify(subject ?? null).includes("{{resolve:")) {
|
|
63494
63496
|
if (widened) return {
|
|
63495
63497
|
kind: "widened",
|
|
@@ -63518,6 +63520,64 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63518
63520
|
return NO_SECRET_EXPRESSION;
|
|
63519
63521
|
}
|
|
63520
63522
|
/**
|
|
63523
|
+
* One node with every `Fn::If` collapsed to the branch scrub would TAKE
|
|
63524
|
+
* (issues #2146 and [#2150](https://github.com/go-to-k/cdkd/issues/2150)).
|
|
63525
|
+
*
|
|
63526
|
+
* ONE SPELLING, consumed verbatim by both halves of "does this producer publish
|
|
63527
|
+
* a secret expression?" — {@link collectReExportHops}, which follows the value
|
|
63528
|
+
* onward, and {@link producerPublishesSecretExpression}'s literal
|
|
63529
|
+
* `{{resolve:` scan, which tests the value itself. Those two are one question
|
|
63530
|
+
* asked twice, and they DISAGREED between #2146 and #2150: the hop walk took
|
|
63531
|
+
* the false branch while the scan `JSON.stringify`d the whole node and saw
|
|
63532
|
+
* both. A producer whose output is
|
|
63533
|
+
* `{"Fn::If": ["IsProd", "{{resolve:...}}", "plain"]}` deployed with `IsProd`
|
|
63534
|
+
* false therefore verdicted `declared`, the discriminator read the deployed
|
|
63535
|
+
* value `plain`, and scrub refused with `SCRUB_CROSS_STACK_PRODUCER_PLAINTEXT`
|
|
63536
|
+
* — an UNCLEARABLE refusal, because no `cdkd scrub` of the producer can turn
|
|
63537
|
+
* `plain` into an expression and there is no bypass flag, so every other secret
|
|
63538
|
+
* in the consumer stack was stranded. A second spelling of the selection would
|
|
63539
|
+
* only move where the two can drift apart again, so there is exactly one.
|
|
63540
|
+
*
|
|
63541
|
+
* WHICH BRANCH: the FALSE one, unconditionally, mirroring `resolveIf`'s
|
|
63542
|
+
* unknown-condition arm. Every condition met on this path belongs to ANOTHER
|
|
63543
|
+
* stack, and scrub evaluates conditions only for the stack it is scrubbing,
|
|
63544
|
+
* from that template's parameter DEFAULTS (it takes no `--parameters`), so a
|
|
63545
|
+
* producer's condition is not evaluable here.
|
|
63546
|
+
*
|
|
63547
|
+
* TWO SHAPES COLLAPSE MORE THAN THE SELECTED BRANCH, both fail-OPEN, both
|
|
63548
|
+
* stated rather than implied because the old whole-node `JSON.stringify` saw
|
|
63549
|
+
* them and this does not. Neither is CloudFormation-emittable, which is why
|
|
63550
|
+
* they are accepted rather than fixed:
|
|
63551
|
+
*
|
|
63552
|
+
* - a MALFORMED `Fn::If` (args not a 3-tuple) collapses to `null` -- NO branch.
|
|
63553
|
+
* Which branch is live is unknowable, so neither a hop nor a `{{resolve:`
|
|
63554
|
+
* sighting may be claimed from it. CloudFormation refuses such a template, so
|
|
63555
|
+
* a producer that reads this way cannot have been deployed carrying one.
|
|
63556
|
+
* - an object carrying `Fn::If` ALONGSIDE sibling keys keeps only the selected
|
|
63557
|
+
* branch, so a `{{resolve:` under a sibling is not seen. An intrinsic node has
|
|
63558
|
+
* exactly one key in any template CloudFormation accepts, and the hop walk
|
|
63559
|
+
* dropped those siblings before this function existed (its `Fn::If` arm
|
|
63560
|
+
* `return`ed rather than falling through), so this preserves that behaviour
|
|
63561
|
+
* rather than introducing it.
|
|
63562
|
+
*
|
|
63563
|
+
* Residual, and it is the direction this file accepts elsewhere: a secret
|
|
63564
|
+
* reachable only through the TRUE branch is not detected, so that reference
|
|
63565
|
+
* keeps its pre-#2133 outcome. The hop walk already took this trade for the
|
|
63566
|
+
* chain it follows; #2150 extends it to the scan so that the two agree.
|
|
63567
|
+
*/
|
|
63568
|
+
function selectTakenConditionalBranches(node) {
|
|
63569
|
+
if (Array.isArray(node)) return node.map(selectTakenConditionalBranches);
|
|
63570
|
+
if (node === null || typeof node !== "object") return node;
|
|
63571
|
+
const obj = node;
|
|
63572
|
+
if ("Fn::If" in obj) {
|
|
63573
|
+
const args = obj["Fn::If"];
|
|
63574
|
+
return Array.isArray(args) && args.length === 3 ? selectTakenConditionalBranches(args[2]) : null;
|
|
63575
|
+
}
|
|
63576
|
+
const out = Object.create(null);
|
|
63577
|
+
for (const [key, child] of Object.entries(obj)) out[key] = selectTakenConditionalBranches(child);
|
|
63578
|
+
return out;
|
|
63579
|
+
}
|
|
63580
|
+
/**
|
|
63521
63581
|
* The re-export hops one output VALUE carries (issue #2146).
|
|
63522
63582
|
*
|
|
63523
63583
|
* Only STATICALLY resolvable references produce a hop, mirroring
|
|
@@ -63536,8 +63596,9 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63536
63596
|
* routinely wrapped — `Fn::Join`ing an imported password into a URL is the
|
|
63537
63597
|
* shape the live fixture uses.
|
|
63538
63598
|
*
|
|
63539
|
-
* `Fn::If`
|
|
63540
|
-
* tidy (issue #2146 review). `makeCrossStackPrePass`
|
|
63599
|
+
* `Fn::If` NEVER REACHES THIS WALK, and the selection that used to live here
|
|
63600
|
+
* is load-bearing rather than tidy (issue #2146 review). `makeCrossStackPrePass`
|
|
63601
|
+
* deliberately mirrors
|
|
63541
63602
|
* `resolveIf` — selected branch only — so that a conditional import of a
|
|
63542
63603
|
* not-yet-deployed producer cannot refuse a whole stack, unbypassably, over a
|
|
63543
63604
|
* reference the deploy never read. A hop walk that descended into both arms
|
|
@@ -63549,24 +63610,24 @@ function producerPublishesSecretExpression(templates, exportOwners, producerStac
|
|
|
63549
63610
|
* flag. On main the same input answered `no`, so it would have been a
|
|
63550
63611
|
* regression this change introduced.
|
|
63551
63612
|
*
|
|
63552
|
-
*
|
|
63553
|
-
*
|
|
63554
|
-
*
|
|
63555
|
-
*
|
|
63556
|
-
*
|
|
63557
|
-
*
|
|
63558
|
-
*
|
|
63559
|
-
*
|
|
63560
|
-
*
|
|
63561
|
-
*
|
|
63562
|
-
*
|
|
63563
|
-
*
|
|
63564
|
-
*
|
|
63565
|
-
*
|
|
63566
|
-
*
|
|
63567
|
-
*
|
|
63568
|
-
*/
|
|
63569
|
-
function collectReExportHops(
|
|
63613
|
+
* `selectedValue` IS THE CONTRACT, and it is why this function carries no
|
|
63614
|
+
* `Fn::If` handling of its own: the only caller,
|
|
63615
|
+
* {@link producerPublishesSecretExpression}, applies
|
|
63616
|
+
* {@link selectTakenConditionalBranches} ONCE and hands the result to BOTH the
|
|
63617
|
+
* literal `{{resolve:` scan and this walk, so a node reaching here holds no
|
|
63618
|
+
* `Fn::If` at all. Issue [#2150](https://github.com/go-to-k/cdkd/issues/2150)
|
|
63619
|
+
* collapsed the two to one site deliberately: the scan used to `JSON.stringify`
|
|
63620
|
+
* the whole subject and therefore see BOTH arms while this walk took only the
|
|
63621
|
+
* false one, and two spellings of one question are exactly how they came to
|
|
63622
|
+
* disagree. A second selection HERE would restore that, and be worse than
|
|
63623
|
+
* useless — measured on the #2150 lane, a per-site copy was invisible to every
|
|
63624
|
+
* test in the suite, because the caller had already pruned, so deleting it
|
|
63625
|
+
* changed nothing and no probe could fence it.
|
|
63626
|
+
* {@link selectTakenConditionalBranches}'s own doc carries which branch is
|
|
63627
|
+
* selected, what a malformed `Fn::If` yields, and the TRUE-branch residual both
|
|
63628
|
+
* halves accept.
|
|
63629
|
+
*/
|
|
63630
|
+
function collectReExportHops(selectedValue, templates, exportOwners) {
|
|
63570
63631
|
const hops = [];
|
|
63571
63632
|
const walk = (node) => {
|
|
63572
63633
|
if (Array.isArray(node)) {
|
|
@@ -63575,11 +63636,6 @@ function collectReExportHops(value, templates, exportOwners) {
|
|
|
63575
63636
|
}
|
|
63576
63637
|
if (node === null || typeof node !== "object") return;
|
|
63577
63638
|
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
63639
|
const imported = obj["Fn::ImportValue"];
|
|
63584
63640
|
if (typeof imported === "string") for (const owner of exportOwners.get(imported) ?? []) hops.push({
|
|
63585
63641
|
stack: owner,
|
|
@@ -63597,7 +63653,7 @@ function collectReExportHops(value, templates, exportOwners) {
|
|
|
63597
63653
|
}
|
|
63598
63654
|
for (const child of Object.values(obj)) walk(child);
|
|
63599
63655
|
};
|
|
63600
|
-
walk(
|
|
63656
|
+
walk(selectedValue);
|
|
63601
63657
|
return hops;
|
|
63602
63658
|
}
|
|
63603
63659
|
/**
|
|
@@ -63990,7 +64046,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
63990
64046
|
const resolvers = new ScrubResolvers(region);
|
|
63991
64047
|
const resolver = resolvers.primary;
|
|
63992
64048
|
const producerRegions = producerRegionsFromState(state);
|
|
63993
|
-
const foreignProducerRegions = foreignRegionsOf(producerRegions, region);
|
|
63994
64049
|
let parameters = {};
|
|
63995
64050
|
let conditions = {};
|
|
63996
64051
|
try {
|
|
@@ -64031,7 +64086,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
64031
64086
|
const resolveInput = await pinCrossRegionSecrets(templateResource.Properties, stack.stackName, {
|
|
64032
64087
|
stackRegion: region,
|
|
64033
64088
|
producerRegions,
|
|
64034
|
-
foreignProducerRegions,
|
|
64035
64089
|
resolvers,
|
|
64036
64090
|
recordedSecretValues,
|
|
64037
64091
|
origin: `resource '${logicalId}'`
|
|
@@ -64059,7 +64113,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
64059
64113
|
const nameSource = await pinCrossRegionSecrets(declaredExportName, stack.stackName, {
|
|
64060
64114
|
stackRegion: region,
|
|
64061
64115
|
producerRegions,
|
|
64062
|
-
foreignProducerRegions,
|
|
64063
64116
|
resolvers,
|
|
64064
64117
|
recordedSecretValues: outputSecrets,
|
|
64065
64118
|
origin: `Export.Name of output '${name}'`
|
|
@@ -64094,7 +64147,6 @@ async function scrubStack(stack, region, stateBackend, lockManager, opts) {
|
|
|
64094
64147
|
const valueSource = await pinCrossRegionSecrets(value, stack.stackName, {
|
|
64095
64148
|
stackRegion: region,
|
|
64096
64149
|
producerRegions,
|
|
64097
|
-
foreignProducerRegions,
|
|
64098
64150
|
resolvers,
|
|
64099
64151
|
recordedSecretValues: outputSecrets,
|
|
64100
64152
|
origin: `output '${name}'`
|
|
@@ -66112,7 +66164,7 @@ async function runAccept(reports, stateBackend, stateConfig, awsClients, options
|
|
|
66112
66164
|
skipped: () => []
|
|
66113
66165
|
}));
|
|
66114
66166
|
if (driftedOutcomes.length === 0) continue;
|
|
66115
|
-
await lockManager.acquireLock(report.stackName, report.region, owner, "drift-accept");
|
|
66167
|
+
if (!await lockManager.acquireLock(report.stackName, report.region, owner, "drift-accept")) throw new Error(`Could not acquire lock for stack '${report.stackName}' (${report.region}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${report.stackName} --stack-region ${report.region}' if you are certain no other process is active.`);
|
|
66116
66168
|
try {
|
|
66117
66169
|
const resources = { ...report.state.resources };
|
|
66118
66170
|
for (const outcome of driftedOutcomes) {
|
|
@@ -66736,7 +66788,7 @@ async function runRevert(reports, providerRegistry, stateBackend, stateConfig, a
|
|
|
66736
66788
|
skipped: () => []
|
|
66737
66789
|
}));
|
|
66738
66790
|
if (driftedOutcomes.length === 0) continue;
|
|
66739
|
-
await lockManager.acquireLock(report.stackName, report.region, owner, "drift-revert");
|
|
66791
|
+
if (!await lockManager.acquireLock(report.stackName, report.region, owner, "drift-revert")) throw new Error(`Could not acquire lock for stack '${report.stackName}' (${report.region}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${report.stackName} --stack-region ${report.region}' if you are certain no other process is active.`);
|
|
66740
66792
|
const narrowedByLogicalId = /* @__PURE__ */ new Map();
|
|
66741
66793
|
const revertSecretResolvers = new DriftSecretResolvers(report.region);
|
|
66742
66794
|
const revertProducerRegions = producerRegionsFromState(report.state);
|
|
@@ -69026,7 +69078,7 @@ async function exportCommand(stackArg, options) {
|
|
|
69026
69078
|
}
|
|
69027
69079
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
69028
69080
|
if (!options.dryRun) {
|
|
69029
|
-
if (!await lockManager.acquireLock(resolvedStackName, targetRegion, owner, "export")) throw new Error(`Could not acquire lock for stack '${resolvedStackName}' (${targetRegion}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${resolvedStackName}' if you are certain no other process is active.`);
|
|
69081
|
+
if (!await lockManager.acquireLock(resolvedStackName, targetRegion, owner, "export")) throw new Error(`Could not acquire lock for stack '${resolvedStackName}' (${targetRegion}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${resolvedStackName} --stack-region ${targetRegion}' if you are certain no other process is active.`);
|
|
69030
69082
|
}
|
|
69031
69083
|
try {
|
|
69032
69084
|
if (nestedStackRows.length > 0) {
|
|
@@ -70942,7 +70994,7 @@ async function runPerStackImportLoop(args) {
|
|
|
70942
70994
|
try {
|
|
70943
70995
|
await deps.lockManager.acquireLockWithRetry(node.stackName, node.region, deps.lockOwner, "export", CHILD_LOCK_RETRY_MAX_ATTEMPTS, CHILD_LOCK_RETRY_DELAY_MS);
|
|
70944
70996
|
} catch (err) {
|
|
70945
|
-
throw new Error(`Could not acquire lock for nested-stack child '${node.stackName}' (${node.region}) — another cdkd process held it through the retry window. Wait for it to finish, or run 'cdkd force-unlock ${node.stackName}' if you are certain no other process is active. No CloudFormation changeset has been submitted; cdkd state is unchanged.`, { cause: err instanceof Error ? err : void 0 });
|
|
70997
|
+
throw new Error(`Could not acquire lock for nested-stack child '${node.stackName}' (${node.region}) — another cdkd process held it through the retry window. Wait for it to finish, or run 'cdkd force-unlock ${node.stackName} --stack-region ${node.region}' if you are certain no other process is active. No CloudFormation changeset has been submitted; cdkd state is unchanged.`, { cause: err instanceof Error ? err : void 0 });
|
|
70946
70998
|
}
|
|
70947
70999
|
acquiredChildLocks.push({
|
|
70948
71000
|
stackName: node.stackName,
|
|
@@ -72483,7 +72535,7 @@ async function refreshObservedForStack(stackName, region, stateBackend, lockMana
|
|
|
72483
72535
|
};
|
|
72484
72536
|
}
|
|
72485
72537
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
72486
|
-
await lockManager.acquireLock(stackName, region, owner, "state-refresh-observed");
|
|
72538
|
+
if (!await lockManager.acquireLock(stackName, region, owner, "state-refresh-observed")) throw new Error(`Could not acquire lock for stack '${stackName}' (${region}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${stackName} --stack-region ${region}' if you are certain no other process is active.`);
|
|
72487
72539
|
try {
|
|
72488
72540
|
let refreshed = 0;
|
|
72489
72541
|
let unsupported = 0;
|
|
@@ -74862,7 +74914,9 @@ async function orphanCommand(pathArgs, options) {
|
|
|
74862
74914
|
const targetRegion = await pickStackRegion(stateBackend, stackInfo.stackName, stackInfo.region, options.stackRegion);
|
|
74863
74915
|
logger.info(`Target: ${stackInfo.stackName} (${targetRegion}); orphaning ${orphanLogicalIds.length} resource(s): ${orphanLogicalIds.join(", ")}`);
|
|
74864
74916
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
74865
|
-
if (!options.dryRun)
|
|
74917
|
+
if (!options.dryRun) {
|
|
74918
|
+
if (!await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "orphan")) throw new Error(`Could not acquire lock for stack '${stackInfo.stackName}' (${targetRegion}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${stackInfo.stackName} --stack-region ${targetRegion}' if you are certain no other process is active.`);
|
|
74919
|
+
}
|
|
74866
74920
|
try {
|
|
74867
74921
|
const stateData = await stateBackend.getState(stackInfo.stackName, targetRegion);
|
|
74868
74922
|
if (!stateData) throw new Error(`No state found for stack '${stackInfo.stackName}' (${targetRegion}). Nothing to orphan. (Did the stack get deployed?)`);
|
|
@@ -75447,7 +75501,7 @@ async function importCommand(stackArg, options) {
|
|
|
75447
75501
|
}
|
|
75448
75502
|
for (const overrideId of overrides.keys()) if (!templateLogicalIds.has(overrideId)) throw new Error(`--resource / --resource-mapping references logical ID '${overrideId}' which is not in the synthesized template for stack '${stackInfo.stackName}'. Available IDs: ${[...templateLogicalIds].join(", ")}`);
|
|
75449
75503
|
const owner = `${process.env["USER"] || "unknown"}@${process.env["HOSTNAME"] || "host"}:${process.pid}`;
|
|
75450
|
-
await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "import");
|
|
75504
|
+
if (!await lockManager.acquireLock(stackInfo.stackName, targetRegion, owner, "import")) throw new Error(`Could not acquire lock for stack '${stackInfo.stackName}' (${targetRegion}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${stackInfo.stackName} --stack-region ${targetRegion}' if you are certain no other process is active.`);
|
|
75451
75505
|
try {
|
|
75452
75506
|
const rows = [];
|
|
75453
75507
|
for (const { logicalId, resource } of resources) {
|
|
@@ -76176,7 +76230,7 @@ async function importNestedStackChildrenRecursive(args) {
|
|
|
76176
76230
|
const childRewritten = rewriteTemplateAssetReferences(childTemplate, assetRedirect);
|
|
76177
76231
|
if (childRewritten > 0) logger.info(`Note: ${childRewritten} asset reference(s) in nested stack ${childStackName} are recorded in state at their pre-rewrite (CDK bootstrap) values, so the next 'cdkd deploy' repoints any resource that still holds them to cdkd asset storage.`);
|
|
76178
76232
|
}
|
|
76179
|
-
await lockManager.acquireLock(childStackName, childRegion, lockOwner, "import");
|
|
76233
|
+
if (!await lockManager.acquireLock(childStackName, childRegion, lockOwner, "import")) throw new Error(`Could not acquire lock for nested stack '${childStackName}' (${childRegion}) — another cdkd process holds it. Wait for it to finish, or run 'cdkd force-unlock ${childStackName} --stack-region ${childRegion}' if you are certain no other process is active.`);
|
|
76180
76234
|
try {
|
|
76181
76235
|
const childResources = collectImportableResources(childTemplate);
|
|
76182
76236
|
const childTemplateLogicalIds = new Set(childResources.map((r) => r.logicalId));
|
|
@@ -86091,7 +86145,7 @@ function createMigrateCommand() {
|
|
|
86091
86145
|
*/
|
|
86092
86146
|
function buildProgram() {
|
|
86093
86147
|
const program = new Command();
|
|
86094
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.
|
|
86148
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.284.38");
|
|
86095
86149
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
86096
86150
|
const { profile } = actionCommand.optsWithGlobals();
|
|
86097
86151
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|