@go-to-k/cdkd 0.284.59 → 0.284.60
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-BkbyCmqe.js → asg-provider-D9nlNFCU.js} +2 -2
- package/dist/{asg-provider-BkbyCmqe.js.map → asg-provider-D9nlNFCU.js.map} +1 -1
- package/dist/cli.js +2 -2
- package/dist/{deploy-engine-B6cbj8-j.js → deploy-engine-Cc6OYj-d.js} +126 -7
- package/dist/deploy-engine-Cc6OYj-d.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{program-D2zqjYCT.js → program-BYmBfcxJ.js} +8 -7
- package/dist/{program-D2zqjYCT.js.map → program-BYmBfcxJ.js.map} +1 -1
- package/dist/{version-Biow6J38.js → version-Dqo5kOZi.js} +2 -2
- package/dist/{version-Biow6J38.js.map → version-Dqo5kOZi.js.map} +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-B6cbj8-j.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as getLiveRenderer, d as generateResourceNameWithFallback, f as getCurrentStackName, h as withStackName, l as applyDefaultNameForFallback, n as getLogger, p as looksLikeCdkdGeneratedName, u as generateResourceName } from "./logger-zRrlbaQt.js";
|
|
2
|
-
import { t as getCdkdVersion } from "./version-
|
|
2
|
+
import { t as getCdkdVersion } from "./version-Dqo5kOZi.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { CreateBucketCommand, DeleteObjectCommand, DeleteObjectsCommand, GetBucketLocationCommand, GetObjectCommand, HeadBucketCommand, HeadObjectCommand, ListObjectsV2Command, NoSuchKey, PutBucketEncryptionCommand, PutBucketPolicyCommand, PutObjectCommand, PutPublicAccessBlockCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
5
5
|
import { CloudControlClient, CreateResourceCommand, DeleteResourceCommand, GetResourceCommand, GetResourceRequestStatusCommand, ListResourcesCommand, UpdateResourceCommand } from "@aws-sdk/client-cloudcontrol";
|
|
@@ -5833,6 +5833,110 @@ function getCdkdAssetBucketName(accountId, region) {
|
|
|
5833
5833
|
return `cdkd-assets-${accountId}-${region}`;
|
|
5834
5834
|
}
|
|
5835
5835
|
/**
|
|
5836
|
+
* Read a bucket's home region off an S3 error's response headers.
|
|
5837
|
+
*
|
|
5838
|
+
* S3 answers a cross-region request with `x-amz-bucket-region` on BOTH shapes
|
|
5839
|
+
* this module can meet, measured against real S3 on 2026-08-26 (issue
|
|
5840
|
+
* [#2240](https://github.com/go-to-k/cdkd/issues/2240)):
|
|
5841
|
+
*
|
|
5842
|
+
* - the `301` a `HeadBucket` returns for a bucket in another region, whose
|
|
5843
|
+
* empty HEAD body the SDK turns into a synthetic `name: 'Unknown'` /
|
|
5844
|
+
* `message: 'UnknownError'` (see `normalizeAwsError`), and
|
|
5845
|
+
* - the `409 BucketAlreadyOwnedByYou` a `CreateBucket` returns for a bucket
|
|
5846
|
+
* this account owns elsewhere.
|
|
5847
|
+
*
|
|
5848
|
+
* The SDK lowercases header keys; the scan is case-insensitive anyway so a
|
|
5849
|
+
* test double spelling it canonically is still read.
|
|
5850
|
+
*/
|
|
5851
|
+
function readBucketRegionHeader(error) {
|
|
5852
|
+
const headers = error?.$response?.headers;
|
|
5853
|
+
if (!headers) return void 0;
|
|
5854
|
+
for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === "x-amz-bucket-region" && value) return value;
|
|
5855
|
+
}
|
|
5856
|
+
/**
|
|
5857
|
+
* Fold a `GetBucketLocation` `LocationConstraint` to a region name.
|
|
5858
|
+
*
|
|
5859
|
+
* The API answers with an EMPTY constraint for `us-east-1` and the legacy `EU`
|
|
5860
|
+
* alias for `eu-west-1`; every other region comes back verbatim.
|
|
5861
|
+
*/
|
|
5862
|
+
function bucketLocationToRegion(constraint) {
|
|
5863
|
+
if (!constraint) return "us-east-1";
|
|
5864
|
+
if (constraint === "EU") return "eu-west-1";
|
|
5865
|
+
return constraint;
|
|
5866
|
+
}
|
|
5867
|
+
/**
|
|
5868
|
+
* Does this error mean "the bucket lives in another region"?
|
|
5869
|
+
*
|
|
5870
|
+
* Derived from the AWS SDK's own predicate, and deliberately WIDER -- not a
|
|
5871
|
+
* mirror of it. `@aws-sdk/middleware-sdk-s3`'s `regionRedirectMiddleware` fires
|
|
5872
|
+
* when `x-amz-bucket-region` is present AND the status is `301`, OR `400` with
|
|
5873
|
+
* either `IllegalLocationConstraintException` or a `HeadBucket` command. This
|
|
5874
|
+
* drops that inner conjunct and accepts ANY header-carrying `400`, because the
|
|
5875
|
+
* conjunct exists to decide whether the SDK should silently RETRY against
|
|
5876
|
+
* another region, while the only thing done here is REFUSE -- and a `400` that
|
|
5877
|
+
* carries a bucket region is a cross-region answer whatever raised it. The
|
|
5878
|
+
* widening is safe in the other direction too: a same-region `400` folds to
|
|
5879
|
+
* `actual === want` and falls through to a throw either way --
|
|
5880
|
+
* `normalizeAwsError` at the two `ensureAssetStorage` / `bootstrap-destroy`
|
|
5881
|
+
* sites, and the raw error at `verifyAssetStorageExists`, whose non-redirect
|
|
5882
|
+
* arm rethrows verbatim. It is never an adoption and never a skipped
|
|
5883
|
+
* teardown.
|
|
5884
|
+
*
|
|
5885
|
+
* A status-`301`-only test would MISS the `400` spelling entirely, on which the
|
|
5886
|
+
* guard silently would not fire.
|
|
5887
|
+
*/
|
|
5888
|
+
function isCrossRegionRedirect(error) {
|
|
5889
|
+
const status = error?.$metadata?.httpStatusCode;
|
|
5890
|
+
if (status === 301) return true;
|
|
5891
|
+
return status === 400 && readBucketRegionHeader(error) !== void 0;
|
|
5892
|
+
}
|
|
5893
|
+
/**
|
|
5894
|
+
* Refuse an asset bucket this account owns that lives in a DIFFERENT region
|
|
5895
|
+
* (issue [#2240](https://github.com/go-to-k/cdkd/issues/2240)).
|
|
5896
|
+
*
|
|
5897
|
+
* `BucketAlreadyOwnedByYou` and a cross-region HeadBucket redirect are both
|
|
5898
|
+
* ACCOUNT-global ownership signals while a bucket is REGIONAL, so neither one
|
|
5899
|
+
* means "the bucket is in this region". The DEFAULT asset-bucket name embeds
|
|
5900
|
+
* the region (`getCdkdAssetBucketName`), which is why this looked structurally
|
|
5901
|
+
* unreachable — but that is only the default. `cdkd bootstrap --asset-bucket
|
|
5902
|
+
* <name>` takes a caller-chosen, region-free name, so bootstrapping two
|
|
5903
|
+
* regions under one custom name reaches every site below.
|
|
5904
|
+
*
|
|
5905
|
+
* Why REFUSE rather than follow the redirect: `bootstrap.ts` deliberately
|
|
5906
|
+
* re-points the STATE bucket at its own region via
|
|
5907
|
+
* `rebuildClientForBucketRegion`, because one state bucket serves the whole
|
|
5908
|
+
* account. Asset storage is the opposite — per-region by design, with the
|
|
5909
|
+
* marker, the publish path and the template rewrite all assuming the bucket
|
|
5910
|
+
* sits in the deploy region. Adopting a foreign-region bucket would publish
|
|
5911
|
+
* this region's assets into another region and apply this region's bucket
|
|
5912
|
+
* configuration (encryption, public-access block, deny-external-account
|
|
5913
|
+
* policy) there.
|
|
5914
|
+
*
|
|
5915
|
+
* Deliberately NOT `resolveBucketRegion` from `utils/aws-region-resolver.ts`:
|
|
5916
|
+
* that helper never throws and returns its `fallbackRegion` on a failed probe,
|
|
5917
|
+
* which would turn this fail-CLOSED guard into a fail-OPEN one. Both arms here
|
|
5918
|
+
* end in a refusal, including the one where the region cannot be determined.
|
|
5919
|
+
*/
|
|
5920
|
+
async function assertAssetBucketRegion(s3Client, bucketName, expectedRegion, accountId, cause) {
|
|
5921
|
+
const want = canonicalizeRegion(expectedRegion);
|
|
5922
|
+
const remedy = `Either bootstrap ${want} with an asset-bucket name unique to it ('cdkd bootstrap --region ${want} --asset-bucket <name>'), or run this against the bucket's own region.`;
|
|
5923
|
+
let actual;
|
|
5924
|
+
const fromHeader = readBucketRegionHeader(cause);
|
|
5925
|
+
if (fromHeader) actual = canonicalizeRegion(fromHeader);
|
|
5926
|
+
else try {
|
|
5927
|
+
actual = canonicalizeRegion(bucketLocationToRegion((await s3Client.send(new GetBucketLocationCommand({
|
|
5928
|
+
Bucket: bucketName,
|
|
5929
|
+
ExpectedBucketOwner: accountId
|
|
5930
|
+
}))).LocationConstraint));
|
|
5931
|
+
} catch (probeError) {
|
|
5932
|
+
const fromProbe = readBucketRegionHeader(probeError);
|
|
5933
|
+
if (fromProbe) actual = canonicalizeRegion(fromProbe);
|
|
5934
|
+
else throw new CdkdError(`Asset bucket '${bucketName}' is claimed by an existing bucket, but cdkd could not determine which region that bucket is in, so it cannot confirm it belongs to ${want}. Refusing to adopt it. (region probe failed: ${probeError instanceof Error ? probeError.message : String(probeError)}) ${remedy}`, "ASSET_STORAGE_FOREIGN_REGION_BUCKET", cause);
|
|
5935
|
+
}
|
|
5936
|
+
if (actual === want) return;
|
|
5937
|
+
throw new CdkdError(`Asset bucket name '${bucketName}' resolves to a bucket in ${actual}, while this operation targets ${want}. S3 bucket names are globally unique, and both 'BucketAlreadyOwnedByYou' and a cross-region redirect report ACCOUNT ownership rather than the bucket's region, so cdkd cannot treat it as ${want}'s asset bucket. cdkd asset storage is per-region by design: adopting it would publish ${want}'s assets into ${actual} and apply ${want}'s bucket configuration there. ${remedy}`, "ASSET_STORAGE_FOREIGN_REGION_BUCKET", cause);
|
|
5938
|
+
}
|
|
5939
|
+
/**
|
|
5836
5940
|
* Name of the cdkd-owned container-asset ECR repository for an
|
|
5837
5941
|
* (account, region) pair. ECR repos are account+region scoped by ARN, so the
|
|
5838
5942
|
* suffix is not strictly needed — the CDK-parallel shape keeps the future
|
|
@@ -5991,6 +6095,13 @@ async function verifyAssetStorageExists(marker, accountId, region, opts = {}) {
|
|
|
5991
6095
|
const err = error;
|
|
5992
6096
|
if (err.name === "NotFound" || err.name === "NoSuchBucket") throw new CdkdError(`cdkd asset storage is bootstrapped for region '${region}' but the asset bucket '${marker.assetBucket}' is missing. ${rebootstrapHint}`, "ASSET_STORAGE_MISSING");
|
|
5993
6097
|
if (err.$metadata?.httpStatusCode === 403) throw new CdkdError(`Asset bucket '${marker.assetBucket}' exists but is not owned by account ${accountId} (or access is denied). Refusing to use it. ${rebootstrapHint}`, "ASSET_STORAGE_FOREIGN_BUCKET", error);
|
|
6098
|
+
if (isCrossRegionRedirect(error)) {
|
|
6099
|
+
await assertAssetBucketRegion(s3Client, marker.assetBucket, region, accountId, error);
|
|
6100
|
+
throw normalizeAwsError(error, {
|
|
6101
|
+
bucket: marker.assetBucket,
|
|
6102
|
+
operation: "HeadBucket"
|
|
6103
|
+
});
|
|
6104
|
+
}
|
|
5994
6105
|
throw error;
|
|
5995
6106
|
}
|
|
5996
6107
|
try {
|
|
@@ -6060,7 +6171,13 @@ async function ensureAssetStorage(options) {
|
|
|
6060
6171
|
} catch (error) {
|
|
6061
6172
|
const err = error;
|
|
6062
6173
|
if (err.name === "NotFound" || err.name === "NoSuchBucket") {} else if (err.$metadata?.httpStatusCode === 403) throw new CdkdError(`Asset bucket name '${assetBucket}' is already taken by a bucket this account does not own (or access is denied). Refusing to adopt it — resolve the naming conflict before re-running 'cdkd bootstrap'.`, "ASSET_STORAGE_FOREIGN_BUCKET", error);
|
|
6063
|
-
else
|
|
6174
|
+
else if (isCrossRegionRedirect(error)) {
|
|
6175
|
+
await assertAssetBucketRegion(s3Client, assetBucket, region, accountId, error);
|
|
6176
|
+
throw normalizeAwsError(error, {
|
|
6177
|
+
bucket: assetBucket,
|
|
6178
|
+
operation: "HeadBucket"
|
|
6179
|
+
});
|
|
6180
|
+
} else throw normalizeAwsError(error, {
|
|
6064
6181
|
bucket: assetBucket,
|
|
6065
6182
|
operation: "HeadBucket"
|
|
6066
6183
|
});
|
|
@@ -6075,8 +6192,10 @@ async function ensureAssetStorage(options) {
|
|
|
6075
6192
|
logger.info(`✓ Created asset bucket: ${assetBucket}`);
|
|
6076
6193
|
} catch (error) {
|
|
6077
6194
|
const err = error;
|
|
6078
|
-
if (err.name === "BucketAlreadyOwnedByYou")
|
|
6079
|
-
|
|
6195
|
+
if (err.name === "BucketAlreadyOwnedByYou") {
|
|
6196
|
+
await assertAssetBucketRegion(s3Client, assetBucket, region, accountId, error);
|
|
6197
|
+
logger.info(`Asset bucket ${assetBucket} already exists`);
|
|
6198
|
+
} else if (err.name === "BucketAlreadyExists") throw new CdkdError(`Asset bucket name '${assetBucket}' is already taken by another AWS account. Refusing to adopt it — resolve the naming conflict before re-running 'cdkd bootstrap'.`, "ASSET_STORAGE_FOREIGN_BUCKET", error);
|
|
6080
6199
|
else throw normalizeAwsError(error, {
|
|
6081
6200
|
bucket: assetBucket,
|
|
6082
6201
|
operation: "CreateBucket"
|
|
@@ -18498,7 +18617,7 @@ var CloudControlProvider = class {
|
|
|
18498
18617
|
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);
|
|
18499
18618
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
18500
18619
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
18501
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
18620
|
+
const { ASGProvider } = await import("./asg-provider-D9nlNFCU.js").then((n) => n.n);
|
|
18502
18621
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
18503
18622
|
}
|
|
18504
18623
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -29906,5 +30025,5 @@ var DeployEngine = class {
|
|
|
29906
30025
|
};
|
|
29907
30026
|
|
|
29908
30027
|
//#endregion
|
|
29909
|
-
export { endCommandInterruptScope as $,
|
|
29910
|
-
//# sourceMappingURL=deploy-engine-
|
|
30028
|
+
export { endCommandInterruptScope as $, derivePartitionAndUrlSuffix as $n, exportNamesCarriedFrom as $t, renderStatefulReason as A, AssetManifestLoader as An, isCdkdError as Ar, isSingleDynamicReferenceToken as At, exportAliasCollisionScrubWarning as B, resolveStateBucketWithDefault as Bn, s3BucketRegionalDomainName as Bt, isFinalSnapshotError as C, buildDockerImage as Cn, ResourceTimeoutError as Cr, requireConfigString as Ct, extractDeploymentEventError as D, partitionSensitiveEnv as Dn, StateError as Dr, createSecretMasker as Dt, makeCanonicalizePropertiesFn as E, getDockerCmd as En, StackTerminationProtectionError as Er, TEMPLATE_SOURCED_RULES as Et, green as F, getLegacyStateBucketName as Fn, isThrottlingError as Fr, classifyReplaySecretRegion as Ft, collectInlinePolicyNamesManagedBySiblings as G, CFN_TEMPLATE_BODY_LIMIT as Gn, describeTypeWithThrottleRetry as Gt, secretBearingStateKeyWarning as H, resolveUseCdkBootstrapAssets as Hn, applyRoleArnIfSet as Ht, red as I, resolveApp as In, markNonRetryable as Ir, producerRegionsFromState as It, findActionableSilentDrops as J, findLargeInlineResources as Jn, TemplateParser as Jt, clearOnUpdateRemoval as K, CFN_TEMPLATE_URL_LIMIT as Kn, withRetry as Kt, yellow as L, resolveAutoAssetStorage as Ln, __exportAll as Lr, s3BucketArn as Lt, bold as M, Synthesizer as Mn, withErrorHandling as Mr, maskSecretsInText as Mt, cyan as N, synthesisStatusMessage as Nn, isMarkedNonRetryable as Nr, redactSecretsForState as Nt, MULTI_REGION_RECREATE_BLOCKED_TYPES as O, runDockerForeground as On, SynthesisError as Or, dynamicReferenceTokens as Ot, gray as P, getDefaultStateBucketName as Pn, isRetryableTransientError as Pr, scrubResourceRecord as Pt, beginCommandInterruptScope as Q, canonicalizeRegion as Qn, rebuildClientForBucketRegion as Qt, collectDeclaredOutputNames as R, resolveCaptureObservedState as Rn, s3BucketDomainName as Rt, createPreDeleteFinalSnapshot as S, buildDenyExternalAccessPolicy as Sn, ProvisioningError as Sr, requireConfigObject as St, unsupportedFinalSnapshotError as T, formatDockerLoginError as Tn, StackHasActiveImportsError as Tr, STATE_SOURCED_READBACK_RULES as Tt, stateKeySecretExposure as U, stateBucketExistenceConfirmed as Un, DiffCalculator as Ut, isExportAliasCollision as V, resolveStateBucketWithDefaultAndSource as Vn, s3BucketWebsiteUrl as Vt, IAMRoleProvider as W, warnDeprecatedNoPrefixCliFlag as Wn, INTRINSIC_KEYS as Wt, CUSTOM_RESOURCE_RESPONSE_PREFIX as X, expectedOwnerParam as Xn, displaySafe as Xt, findSilentDropProperties as Y, uploadCfnTemplate as Yn, LockManager as Yt, DEFAULT_STATE_PREFIX as Z, PARTITION_TABLE as Zn, S3StateBackend as Zt, computeImplicitDeleteEdges as _, isCrossRegionRedirect as _n, LocalStartServiceError as _r, configBooleanRefusal as _t, DeploymentEventsStore as a, WorkGraph as an, getAwsClients as ar, disableInstanceApiTermination as at, buildFinalSnapshotIdentifier as b, validateAssetBucketName as bn, NestedStackChildDirectDestroyError as br, replayWarn as bt, replayFailedOperations as c, loadPublishableAssetManifest as cn, AssetError as cr, carriesDynamicReference as ct, updatePartialReason as d, stripControlChars as dn, CrossAccountSecretRefusalError as dr, refStateLookupFromResource as dt, importableOutputKeys as en, AssemblyReader as er, interruptWatchListenerCount as et, UNSPECIFIED_SKIP_REASON as f, AssetModeResolver as fn, DependencyError as fr, WAFv2WebACLProvider as ft, IMPLICIT_DELETE_DEPENDENCIES as g, getBootstrapMarkerKey as gn, LocalMigrateError as gr, coerceCfnBoolean as gt, maskingRetryLogger as h, ensureAssetStorage as hn, LocalInvokeBuildError as hr, assertRegionMatch as ht, DeploymentEventsReader as i, stringifyValue as in, AwsClients as ir, slowCcOperationTimeoutMs as it, formatResourceLine as j, getDockerImageBySourceHash as jn, normalizeAwsError as jr, maskSecretsInError as jt, isStatefulRecreateTargetSync as k, runDockerStreaming as kn, formatError as kr, errorCauseChain as kt, replayRollback as l, rewriteTemplateAssetReferences as ln, CdkdError as lr, cfnRefValueFromPhysicalId as lt, withResourceDeadline as m, assertAssetBucketRegion as mn, DynamicReferenceRegionAmbiguousError as mr, resolveExplicitPhysicalId as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, shouldRetainResource as nn, clearBucketRegionCache as nr, startInterruptWatch as nt, planFailedOps as o, buildAssetRedirectMap as on, resetAwsClients as or, isTerminationProtectionPropagationError as ot, deleteSkipReason as p, BOOTSTRAP_MARKER_PREFIX as pn, DeployCancelledError as pr, normalizeAwsTagsToCfn as pt, ProviderRegistry as q, MIGRATE_TMP_PREFIX as qn, DagBuilder as qt, DeployEngine as r, AssetPublisher as rn, resolveBucketRegion as rr, CloudControlProvider as rt, planRollback as s, createAssetRedirectResolver as sn, setAwsClients as sr, IntrinsicFunctionResolver as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, importableOutputs as tn, processStackMessages as tr, isInterruptedWaitError as tt, updatePartialMessage as u, escapeRegExp$1 as un, ConfigError as ur, getAccountInfo as ut, ATOMIC_FINAL_SNAPSHOT_TYPES as v, parseBootstrapMarker as vn, LockError as vr, configStringRefusal as vt, refusesFinalSnapshot as w, dockerSpawnEnvWithSensitive as wn, ResourceUpdateNotSupportedError as wr, STATE_SOURCED_CROSS_GENERATION_RULES as wt, ccRoutedFinalSnapshotError as x, validateContainerRepoName as xn, PartialFailureError as xr, requireConfigArray as xt, PRE_DELETE_SNAPSHOT_TYPES as y, readBootstrapMarkerBody as yn, MissingCdkCliError as yr, readConfigString as yt, collectPublishedOutputNames as z, resolveSkipPrefix as zn, s3BucketDualStackDomainName as zt };
|
|
30029
|
+
//# sourceMappingURL=deploy-engine-Cc6OYj-d.js.map
|