@go-to-k/cdkd 0.278.33 → 0.278.35

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/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { $ as withRetry, $t as getAwsClients, A as red, At as synthesisStatusMessage, B as isTerminationProtectionPropagationError, Bt as stateBucketExistenceConfirmed, C as isStatefulRecreateTargetSync, Cn as normalizeAwsError, Ct as formatDockerLoginError, D as cyan, Dt as AssetManifestLoader, E as bold, Et as runDockerStreaming, F as ProviderRegistry, Ft as resolveCaptureObservedState, G as normalizeAwsTagsToCfn, Gt as findLargeInlineResources, H as cfnRefValueFromPhysicalId, Ht as CFN_TEMPLATE_BODY_LIMIT, I as findActionableSilentDrops, It as resolveSkipPrefix, J as readConfigString, Jt as AssemblyReader, K as resolveExplicitPhysicalId, Kt as uploadCfnTemplate, L as CloudControlProvider, Lt as resolveStateBucketWithDefault, M as IAMRoleProvider, Mt as getLegacyStateBucketName, N as collectInlinePolicyNamesManagedBySiblings, Nt as resolveApp, O as gray, Ot as getDockerImageBySourceHash, P as clearOnUpdateRemoval, Pt as resolveAutoAssetStorage, Q as describeTypeWithThrottleRetry, Qt as AwsClients, R as slowCcOperationTimeoutMs, Rt as resolveStateBucketWithDefaultAndSource, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, St as buildDockerImage, T as formatResourceLine, Tt as runDockerForeground, U as refStateLookupFromResource, Ut as CFN_TEMPLATE_URL_LIMIT, V as IntrinsicFunctionResolver, Vt as warnDeprecatedNoPrefixCliFlag, W as WAFv2WebACLProvider, Wt as MIGRATE_TMP_PREFIX, X as applyRoleArnIfSet, Y as requireConfigString, Yt as processStackMessages, Z as DiffCalculator, Zt as resolveBucketRegion, _ as createPreDeleteFinalSnapshot, _n as StackHasActiveImportsError, _t as ensureAssetStorage, a as DeploymentEventsStore, at as S3StateBackend, b as unsupportedFinalSnapshotError, bt as validateAssetBucketName, c as replayFailedOperations, cn as LocalMigrateError, ct as AssetPublisher, d as IMPLICIT_DELETE_DEPENDENCIES, dn as MissingCdkCliError, dt as buildAssetRedirectMap, en as resetAwsClients, et as isRetryableTransientError, f as computeImplicitDeleteEdges, fn as NestedStackChildDirectDestroyError, ft as createAssetRedirectResolver, g as ccRoutedFinalSnapshotError, gn as ResourceUpdateNotSupportedError, gt as BOOTSTRAP_MARKER_PREFIX, h as buildFinalSnapshotIdentifier, hn as ResourceTimeoutError, ht as AssetModeResolver, i as DeploymentEventsReader, it as LockManager, j as yellow, jt as getDefaultStateBucketName, k as green, kt as Synthesizer, l as replayRollback, ln as LocalStartServiceError, lt as stringifyValue, m as PRE_DELETE_SNAPSHOT_TYPES, mn as ProvisioningError, mt as rewriteTemplateAssetReferences, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nt as DagBuilder, o as planFailedOps, on as DeployCancelledError, ot as rebuildClientForBucketRegion, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as PartialFailureError, pt as loadPublishableAssetManifest, q as assertRegionMatch, qt as expectedOwnerParam, r as DeployEngine, rn as CdkdError, rt as TemplateParser, s as planRollback, sn as LocalInvokeBuildError$1, st as shouldRetainResource, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as setAwsClients, tt as isThrottlingError, u as withResourceDeadline, ut as WorkGraph, v as isFinalSnapshotError, vn as StackTerminationProtectionError, vt as getBootstrapMarkerKey, w as renderStatefulReason, wn as withErrorHandling, wt as getDockerCmd, x as extractDeploymentEventError, xt as validateContainerRepoName, y as refusesFinalSnapshot, yt as parseBootstrapMarker, z as disableInstanceApiTermination, zt as resolveUseCdkBootstrapAssets } from "./deploy-engine-BfPXYVg-.js";
2
+ import { $ as describeTypeWithThrottleRetry, $t as AwsClients, A as red, At as Synthesizer, B as isTerminationProtectionPropagationError, Bt as resolveUseCdkBootstrapAssets, C as isStatefulRecreateTargetSync, Ct as buildDockerImage, D as cyan, Dt as runDockerStreaming, E as bold, Et as runDockerForeground, F as ProviderRegistry, Ft as resolveAutoAssetStorage, G as normalizeAwsTagsToCfn, Gt as MIGRATE_TMP_PREFIX, H as cfnRefValueFromPhysicalId, Ht as warnDeprecatedNoPrefixCliFlag, I as findActionableSilentDrops, It as resolveCaptureObservedState, J as readConfigString, Jt as expectedOwnerParam, K as resolveExplicitPhysicalId, Kt as findLargeInlineResources, L as CloudControlProvider, Lt as resolveSkipPrefix, M as IAMRoleProvider, Mt as getDefaultStateBucketName, N as collectInlinePolicyNamesManagedBySiblings, Nt as getLegacyStateBucketName, O as gray, Ot as AssetManifestLoader, P as clearOnUpdateRemoval, Pt as resolveApp, Q as DiffCalculator, Qt as resolveBucketRegion, R as slowCcOperationTimeoutMs, Rt as resolveStateBucketWithDefault, S as MULTI_REGION_RECREATE_BLOCKED_TYPES, St as validateContainerRepoName, T as formatResourceLine, Tn as withErrorHandling, Tt as getDockerCmd, U as refStateLookupFromResource, Ut as CFN_TEMPLATE_BODY_LIMIT, V as IntrinsicFunctionResolver, Vt as stateBucketExistenceConfirmed, W as WAFv2WebACLProvider, Wt as CFN_TEMPLATE_URL_LIMIT, X as requireConfigString, Xt as processStackMessages, Y as requireConfigArray, Yt as AssemblyReader, Z as applyRoleArnIfSet, _ as createPreDeleteFinalSnapshot, _n as ResourceUpdateNotSupportedError, _t as BOOTSTRAP_MARKER_PREFIX, a as DeploymentEventsStore, at as LockManager, b as unsupportedFinalSnapshotError, bt as parseBootstrapMarker, c as replayFailedOperations, cn as LocalInvokeBuildError$1, ct as shouldRetainResource, d as IMPLICIT_DELETE_DEPENDENCIES, dt as WorkGraph, en as getAwsClients, et as withRetry, f as computeImplicitDeleteEdges, fn as MissingCdkCliError, ft as buildAssetRedirectMap, g as ccRoutedFinalSnapshotError, gn as ResourceTimeoutError, gt as AssetModeResolver, h as buildFinalSnapshotIdentifier, hn as ProvisioningError, ht as rewriteTemplateAssetReferences, i as DeploymentEventsReader, in as CdkdError, it as TemplateParser, j as yellow, jt as synthesisStatusMessage, k as green, kt as getDockerImageBySourceHash, l as replayRollback, ln as LocalMigrateError, lt as AssetPublisher, m as PRE_DELETE_SNAPSHOT_TYPES, mn as PartialFailureError, mt as loadPublishableAssetManifest, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as setAwsClients, nt as isThrottlingError, o as planFailedOps, ot as S3StateBackend, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as NestedStackChildDirectDestroyError, pt as createAssetRedirectResolver, q as assertRegionMatch, qt as uploadCfnTemplate, r as DeployEngine, rt as DagBuilder, s as planRollback, sn as DeployCancelledError, st as rebuildClientForBucketRegion, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as resetAwsClients, tt as isRetryableTransientError, u as withResourceDeadline, un as LocalStartServiceError, ut as stringifyValue, v as isFinalSnapshotError, vn as StackHasActiveImportsError, vt as ensureAssetStorage, w as renderStatefulReason, wn as normalizeAwsError, wt as formatDockerLoginError, x as extractDeploymentEventError, xt as validateAssetBucketName, y as refusesFinalSnapshot, yn as StackTerminationProtectionError, yt as getBootstrapMarkerKey, z as disableInstanceApiTermination, zt as resolveStateBucketWithDefaultAndSource } from "./deploy-engine-CWZlo2Il.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, f as withSkipPrefix, i as runStackBuffered, n as getLogger, o as PATTERN_B_NAME_OPTIONS, p as withStackName, s as PATTERN_B_NAME_PROPERTIES, u as generateResourceName } from "./logger-BYMEE-BS.js";
4
- import { t as ASGProvider } from "./asg-provider-3kpNYstr.js";
4
+ import { t as ASGProvider } from "./asg-provider-8XxBHtzK.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";
@@ -9689,7 +9689,7 @@ var LambdaUrlProvider = class {
9689
9689
  this.logger.debug(`Creating Lambda URL ${logicalId}`);
9690
9690
  const targetFunctionArn = properties["TargetFunctionArn"];
9691
9691
  if (!targetFunctionArn) throw new ProvisioningError(`TargetFunctionArn is required for Lambda URL ${logicalId}`, resourceType, logicalId);
9692
- const authType = properties["AuthType"] || "NONE";
9692
+ const authType = requireConfigString(properties["AuthType"], "NONE", "AWS::Lambda::Url AuthType");
9693
9693
  try {
9694
9694
  const cors = properties["Cors"];
9695
9695
  const createParams = {
@@ -9733,7 +9733,7 @@ var LambdaUrlProvider = class {
9733
9733
  };
9734
9734
  const updateParams = {
9735
9735
  FunctionName: physicalId,
9736
- AuthType: properties["AuthType"] || "NONE"
9736
+ AuthType: requireConfigString(properties["AuthType"], "NONE", "AWS::Lambda::Url AuthType")
9737
9737
  };
9738
9738
  const invokeMode = clearOnUpdateRemoval(properties["InvokeMode"], previousProperties["InvokeMode"], "BUFFERED");
9739
9739
  if (invokeMode !== void 0) updateParams.InvokeMode = invokeMode;
@@ -12317,11 +12317,18 @@ var DynamoDBGlobalTableProvider = class {
12317
12317
  if (billingMode === "PROVISIONED") createParams.ProvisionedThroughput = derivePerCallProvisionedThroughput(properties, currentRegion);
12318
12318
  const streamSpecInput = properties["StreamSpecification"];
12319
12319
  const needsStream = replicas.some((r) => r["Region"] !== currentRegion) || replicas.length > 1;
12320
- if (streamSpecInput) createParams.StreamSpecification = {
12321
- StreamEnabled: true,
12322
- StreamViewType: streamSpecInput["StreamViewType"] ?? "NEW_AND_OLD_IMAGES"
12323
- };
12324
- else if (needsStream) {
12320
+ if (streamSpecInput != null) {
12321
+ let streamViewType;
12322
+ try {
12323
+ streamViewType = readConfigString(streamSpecInput, "StreamViewType", "NEW_AND_OLD_IMAGES", "AWS::DynamoDB::GlobalTable StreamSpecification");
12324
+ } catch (error) {
12325
+ throw new ProvisioningError(error instanceof Error ? error.message : String(error), resourceType, logicalId, void 0, error instanceof Error ? error : void 0);
12326
+ }
12327
+ createParams.StreamSpecification = {
12328
+ StreamEnabled: true,
12329
+ StreamViewType: streamViewType
12330
+ };
12331
+ } else if (needsStream) {
12325
12332
  this.logger.info(`Auto-enabling streams (NEW_AND_OLD_IMAGES) on ${logicalId} — required for cross-region replication`);
12326
12333
  createParams.StreamSpecification = {
12327
12334
  StreamEnabled: true,
@@ -12577,7 +12584,7 @@ var DynamoDBGlobalTableProvider = class {
12577
12584
  if (properties["StreamSpecification"] !== void 0 && !deepEqual$1(properties["StreamSpecification"], previousProperties["StreamSpecification"])) {
12578
12585
  flatUpdate.StreamSpecification = {
12579
12586
  StreamEnabled: true,
12580
- StreamViewType: properties["StreamSpecification"]["StreamViewType"]
12587
+ StreamViewType: readConfigString(properties["StreamSpecification"], "StreamViewType", "NEW_AND_OLD_IMAGES", "AWS::DynamoDB::GlobalTable StreamSpecification")
12581
12588
  };
12582
12589
  flatChanged = true;
12583
12590
  }
@@ -21934,8 +21941,9 @@ var CloudFrontOAIProvider = class {
21934
21941
  */
21935
21942
  async create(logicalId, resourceType, properties) {
21936
21943
  this.logger.debug(`Creating CloudFront OAI ${logicalId}`);
21937
- const comment = properties["CloudFrontOriginAccessIdentityConfig"]?.["Comment"] ?? "";
21944
+ const config = properties["CloudFrontOriginAccessIdentityConfig"];
21938
21945
  try {
21946
+ const comment = readConfigString(config, "Comment", "", "AWS::CloudFront::CloudFrontOriginAccessIdentity CloudFrontOriginAccessIdentityConfig");
21939
21947
  const oai = (await this.cloudFrontClient.send(new CreateCloudFrontOriginAccessIdentityCommand({ CloudFrontOriginAccessIdentityConfig: {
21940
21948
  CallerReference: logicalId,
21941
21949
  Comment: comment
@@ -21970,8 +21978,9 @@ var CloudFrontOAIProvider = class {
21970
21978
  */
21971
21979
  async update(logicalId, physicalId, resourceType, properties, _previousProperties) {
21972
21980
  this.logger.debug(`Updating CloudFront OAI ${logicalId}: ${physicalId}`);
21973
- const comment = properties["CloudFrontOriginAccessIdentityConfig"]?.["Comment"] ?? "";
21981
+ const config = properties["CloudFrontOriginAccessIdentityConfig"];
21974
21982
  try {
21983
+ const comment = readConfigString(config, "Comment", "", "AWS::CloudFront::CloudFrontOriginAccessIdentity CloudFrontOriginAccessIdentityConfig");
21975
21984
  const getResponse = await this.cloudFrontClient.send(new GetCloudFrontOriginAccessIdentityCommand({ Id: physicalId }));
21976
21985
  const etag = getResponse.ETag;
21977
21986
  if (!etag) throw new Error("GetCloudFrontOriginAccessIdentity did not return ETag");
@@ -25035,7 +25044,12 @@ var ECSProvider = class {
25035
25044
  const newServiceName = properties["ServiceName"];
25036
25045
  const oldServiceName = previousProperties["ServiceName"];
25037
25046
  if (newServiceName && oldServiceName && newServiceName !== oldServiceName) throw new ProvisioningError(`Cannot update ServiceName for ECS service ${logicalId} (immutable property, requires replacement)`, resourceType, logicalId, physicalId);
25038
- const deploymentControllerType = properties["DeploymentController"]?.["Type"] ?? "ECS";
25047
+ let deploymentControllerType;
25048
+ try {
25049
+ deploymentControllerType = readConfigString(properties["DeploymentController"], "Type", "ECS", "AWS::ECS::Service DeploymentController");
25050
+ } catch (error) {
25051
+ throw new ProvisioningError(error instanceof Error ? error.message : String(error), resourceType, logicalId, physicalId, error instanceof Error ? error : void 0);
25052
+ }
25039
25053
  const isEcsController = deploymentControllerType === "ECS";
25040
25054
  const loadBalancersChanged = JSON.stringify(previousProperties["LoadBalancers"] ?? null) !== JSON.stringify(properties["LoadBalancers"] ?? null);
25041
25055
  const serviceRegistriesChanged = JSON.stringify(previousProperties["ServiceRegistries"] ?? null) !== JSON.stringify(properties["ServiceRegistries"] ?? null);
@@ -29919,13 +29933,14 @@ var Route53Provider = class {
29919
29933
  if (!name) throw new ProvisioningError(`Name is required for hosted zone ${logicalId}`, resourceType, logicalId);
29920
29934
  try {
29921
29935
  const hostedZoneConfig = properties["HostedZoneConfig"];
29936
+ const createComment = readConfigString(hostedZoneConfig, "Comment", "", "AWS::Route53::HostedZone HostedZoneConfig");
29922
29937
  const vpcs = properties["VPCs"];
29923
29938
  const firstVpc = vpcs && vpcs.length > 0 ? vpcs[0] : void 0;
29924
29939
  const response = await this.getClient().send(new CreateHostedZoneCommand({
29925
29940
  Name: name,
29926
29941
  CallerReference: `${logicalId}-${Date.now()}`,
29927
- ...hostedZoneConfig && hostedZoneConfig["Comment"] ? { HostedZoneConfig: {
29928
- Comment: hostedZoneConfig["Comment"],
29942
+ ...createComment !== "" ? { HostedZoneConfig: {
29943
+ Comment: createComment,
29929
29944
  ...firstVpc ? { PrivateZone: true } : {}
29930
29945
  } } : firstVpc ? { HostedZoneConfig: { PrivateZone: true } } : {},
29931
29946
  ...firstVpc ? { VPC: {
@@ -29983,7 +29998,8 @@ var Route53Provider = class {
29983
29998
  async updateHostedZone(logicalId, physicalId, resourceType, properties, previousProperties) {
29984
29999
  this.logger.debug(`Updating Route 53 hosted zone ${logicalId}: ${physicalId}`);
29985
30000
  try {
29986
- const comment = properties["HostedZoneConfig"]?.["Comment"] ?? "";
30001
+ const hostedZoneConfig = properties["HostedZoneConfig"];
30002
+ const comment = readConfigString(hostedZoneConfig, "Comment", "", "AWS::Route53::HostedZone HostedZoneConfig");
29987
30003
  await this.getClient().send(new UpdateHostedZoneCommentCommand({
29988
30004
  Id: physicalId,
29989
30005
  Comment: comment
@@ -42382,8 +42398,8 @@ var CodeBuildProvider = class {
42382
42398
  * object literal returned against a declared type IS excess-property checked,
42383
42399
  * which turns each member name into a compile-time fact (issue #1386).
42384
42400
  */
42385
- mapSource(source) {
42386
- if (!source) return { type: "NO_SOURCE" };
42401
+ mapSource(source, containerPath) {
42402
+ if (source == null) return { type: "NO_SOURCE" };
42387
42403
  let buildspec;
42388
42404
  if (source["BuildSpec"] !== void 0) {
42389
42405
  const bs = source["BuildSpec"];
@@ -42393,7 +42409,7 @@ var CodeBuildProvider = class {
42393
42409
  const cfnGitSubmodules = source["GitSubmodulesConfig"];
42394
42410
  const cfnBuildStatus = source["BuildStatusConfig"];
42395
42411
  return {
42396
- type: source["Type"] ?? "NO_SOURCE",
42412
+ type: readConfigString(source, "Type", "NO_SOURCE", containerPath),
42397
42413
  buildspec,
42398
42414
  location: source["Location"],
42399
42415
  gitCloneDepth: source["GitCloneDepth"],
@@ -42411,10 +42427,10 @@ var CodeBuildProvider = class {
42411
42427
  } : void 0
42412
42428
  };
42413
42429
  }
42414
- mapArtifacts(artifacts) {
42415
- if (!artifacts) return { type: "NO_ARTIFACTS" };
42430
+ mapArtifacts(artifacts, containerPath) {
42431
+ if (artifacts == null) return { type: "NO_ARTIFACTS" };
42416
42432
  return {
42417
- type: artifacts["Type"] ?? "NO_ARTIFACTS",
42433
+ type: readConfigString(artifacts, "Type", "NO_ARTIFACTS", containerPath),
42418
42434
  location: artifacts["Location"],
42419
42435
  path: artifacts["Path"],
42420
42436
  name: artifacts["Name"],
@@ -42472,9 +42488,9 @@ var CodeBuildProvider = class {
42472
42488
  };
42473
42489
  }
42474
42490
  const cfnSecondarySources = properties["SecondarySources"];
42475
- const secondarySources = cfnSecondarySources ? cfnSecondarySources.map((s) => this.mapSource(s)) : void 0;
42491
+ const secondarySources = cfnSecondarySources == null ? void 0 : requireConfigArray(cfnSecondarySources, "AWS::CodeBuild::Project SecondarySources").map((s) => this.mapSource(s, "AWS::CodeBuild::Project SecondarySources[]"));
42476
42492
  const cfnSecondaryArtifacts = properties["SecondaryArtifacts"];
42477
- const secondaryArtifacts = cfnSecondaryArtifacts ? cfnSecondaryArtifacts.map((a) => this.mapArtifacts(a)) : void 0;
42493
+ const secondaryArtifacts = cfnSecondaryArtifacts == null ? void 0 : requireConfigArray(cfnSecondaryArtifacts, "AWS::CodeBuild::Project SecondaryArtifacts").map((a) => this.mapArtifacts(a, "AWS::CodeBuild::Project SecondaryArtifacts[]"));
42478
42494
  const cfnSecondarySourceVersions = properties["SecondarySourceVersions"];
42479
42495
  const secondarySourceVersions = cfnSecondarySourceVersions ? cfnSecondarySourceVersions.map((sv) => ({
42480
42496
  sourceIdentifier: sv["SourceIdentifier"],
@@ -42505,10 +42521,10 @@ var CodeBuildProvider = class {
42505
42521
  }
42506
42522
  return {
42507
42523
  name,
42508
- source: this.mapSource(source),
42524
+ source: this.mapSource(source, "AWS::CodeBuild::Project Source"),
42509
42525
  environment: {
42510
- type: environment?.["Type"] ?? "LINUX_CONTAINER",
42511
- computeType: environment?.["ComputeType"] ?? "BUILD_GENERAL1_SMALL",
42526
+ type: readConfigString(environment, "Type", "LINUX_CONTAINER", "AWS::CodeBuild::Project Environment"),
42527
+ computeType: readConfigString(environment, "ComputeType", "BUILD_GENERAL1_SMALL", "AWS::CodeBuild::Project Environment"),
42512
42528
  image: environment?.["Image"],
42513
42529
  environmentVariables: envVars ? envVars.map((v) => ({
42514
42530
  name: v.Name,
@@ -42529,7 +42545,7 @@ var CodeBuildProvider = class {
42529
42545
  } : void 0
42530
42546
  },
42531
42547
  serviceRole,
42532
- artifacts: this.mapArtifacts(artifacts),
42548
+ artifacts: this.mapArtifacts(artifacts, "AWS::CodeBuild::Project Artifacts"),
42533
42549
  tags: tags ? tags.map((t) => ({
42534
42550
  key: t.Key,
42535
42551
  value: t.Value
@@ -49259,48 +49275,128 @@ async function runAccept(reports, stateBackend, stateConfig, awsClients, options
49259
49275
  }
49260
49276
  }
49261
49277
  /**
49262
- * Build the `newProperties` object passed to `provider.update` during
49263
- * `--revert`. Strategy:
49278
+ * A top-level property NAME that carries tags.
49264
49279
  *
49265
- * 1. Start from `awsProperties` (the AWS-current snapshot returned
49266
- * by `readCurrentState`, which `runRevert` already passes as the
49267
- * `previousProperties` argument to `provider.update`).
49268
- * 2. For every top-level key whose subtree contains a drifted path,
49269
- * overwrite it with the corresponding sub-shape from
49270
- * `desiredProperties` (the state-recorded `observedProperties`).
49280
+ * The shape test below is deliberately NOT sufficient on its own: a top-level
49281
+ * `[{ Key, Value }]` list is not tag-exclusive — `LoadBalancerAttributes`,
49282
+ * `TargetGroupAttributes` and SSM `Association.Targets` all match it. No such
49283
+ * property can carry an `aws:`-prefixed or `AmazonECSManaged` key today, so the
49284
+ * carve-out would degrade to the identity of the old wholesale overwrite there
49285
+ * — but borrowing `canonicalizeTagListsDeep`'s heuristic for a WRITE decision
49286
+ * is not justified by its use for a SORT: a sort false positive is harmless, an
49287
+ * append is not.
49288
+ */
49289
+ function isTagListKey(key) {
49290
+ return key === "Tags" || key.endsWith("Tags");
49291
+ }
49292
+ /** A CFn-shaped tag list: a non-empty array whose every element has a string `Key`. */
49293
+ function isCfnTagList(value) {
49294
+ return Array.isArray(value) && value.length > 0 && value.every((t) => isPlainRecord(t) && typeof t.Key === "string");
49295
+ }
49296
+ /** The `Key` of every entry in a CFn tag list, in list order. */
49297
+ function tagKeys(tags) {
49298
+ return tags.map((t) => t["Key"]);
49299
+ }
49300
+ /**
49301
+ * AWS-SERVICE-authored tag keys a `--revert` must not strip (issue #1501).
49271
49302
  *
49272
- * Why "AWS-current base + drifted overlay" instead of "drifted-only
49273
- * partial":
49303
+ * `AmazonECSManaged` is attached by ECS when a capacity provider binds an Auto
49304
+ * Scaling group, and managed scaling stops working without it. That entry is
49305
+ * the load-bearing one.
49274
49306
  *
49275
- * Several providers' `update()` implementations diff
49276
- * `newProperties[K]` against `previousProperties[K]` and treat
49277
- * `newVal === undefined` as "remove K from AWS" (e.g.
49278
- * `SNSTopicProvider` calls `SetTopicAttributes(K, '')`,
49279
- * `IAMRoleProvider.updateManagedPolicies` detaches every previously
49280
- * attached policy when the new arg is undefined). Passing a
49281
- * drifted-only partial would silently clear non-drifted attributes
49282
- * on those providers. Sending the AWS-current value back as the
49283
- * "new" value for non-drifted keys keeps `JSON.stringify(newVal) ===
49284
- * JSON.stringify(oldVal)` so the diff is a no-op — no provider
49285
- * changes required.
49307
+ * The `aws:` prefix is DEFENSIVE rather than load-bearing, and the distinction
49308
+ * is worth stating: AWS reserves the prefix and rejects a write of one, and the
49309
+ * 45 providers that route reads through `normalizeAwsTagsToCfn` strip such keys
49310
+ * on the way in — so an `aws:` key can only reach the AWS side of a comparison
49311
+ * via the Cloud Control `readCurrentState` path, which returns the raw model.
49312
+ * It costs nothing to honor and cdkd can never have authored one.
49313
+ */
49314
+ const SERVICE_MANAGED_TAG_KEYS = /* @__PURE__ */ new Set(["AmazonECSManaged"]);
49315
+ /** Whether a tag key is AWS-service-authored, per {@link SERVICE_MANAGED_TAG_KEYS}. */
49316
+ function isServiceManagedTagKey(key) {
49317
+ return SERVICE_MANAGED_TAG_KEYS.has(key) || key.startsWith("aws:");
49318
+ }
49319
+ /**
49320
+ * Revert a TAG LIST, preserving AWS-SERVICE-authored entries (issue #1501).
49286
49321
  *
49287
- * For non-diff providers (e.g. `SQSQueueProvider` blindly pushes
49288
- * every defined key via `SetQueueAttributes`), the AWS-current
49289
- * value still gets serialised back to the same string AWS already
49290
- * has, so the round-trip is a no-op for the AWS resource state.
49291
- * The one exception is `readCurrentState`'s always-emit
49292
- * placeholder values — e.g. SQS `RedrivePolicy: {}` — which AWS
49293
- * rejects as invalid input even though they're round-tripped. That
49294
- * class of value (Class 2 / structurally-incomplete-when-empty) is
49295
- * handled by per-provider sanitize at the wire-layer; see the SQS
49296
- * provider's `serializeRedrivePolicy` helper for the canonical
49297
- * pattern.
49322
+ * Everything in {@link buildRevertNewProperties} overwrites a drifted top-level
49323
+ * key wholesale, which for `Tags` means "AWS ends up with exactly the tags cdkd
49324
+ * state recorded" — so a service-authored tag added after deploy is stripped.
49325
+ * The concrete case: ECS attaches `AmazonECSManaged` to an ASG when a capacity
49326
+ * provider binds it, and that tag is REQUIRED for managed scaling. Because any
49327
+ * CDK ASG declares at least a `Name` tag, `Tags` is template-DECLARED, so the
49328
+ * #1498 carve-out (undeclared + captured-empty) correctly does not apply — and
49329
+ * the tag list is an ARRAY, which {@link findRevertDroppedAwsKeys}'s walk
49330
+ * compares wholesale and never descends into. Post-revert the ASG kept the
49331
+ * capacity provider with its managed scaling silently broken (verified live
49332
+ * 2026-08-10).
49298
49333
  *
49299
- * The drift comparator never produces array-index segments
49300
- * (`Tags[0].Value`) — array drifts surface as a single entry on the
49301
- * parent path — so `path.split('.', 1)` is always safe to extract the
49302
- * top-level key.
49334
+ * The semantic: the baseline still WINS for every ordinary tag — one it has and
49335
+ * AWS lost is re-added, one whose value differs is reset, and a
49336
+ * user/console-added tag AWS alone has is still REMOVED. Only a
49337
+ * {@link isServiceManagedTagKey} entry survives.
49338
+ *
49339
+ * **This is the issue's option 2, not its option 1, and the choice was settled
49340
+ * by a live test rather than by taste.** Option 1 (revert the whole tag list as
49341
+ * a diff, so ANY out-of-band add survives) was implemented first and failed the
49342
+ * `drift-revert` integ at its final assertion: that fixture injects an
49343
+ * `IntegInjected` tag and requires `--revert` to strip it, i.e. "revert removes
49344
+ * a console-added tag" is an established contract with a test behind it.
49345
+ * Option 1 would redefine revert semantics for a whole property class — which
49346
+ * is exactly the design pass the issue said it needed — so the narrow safeguard
49347
+ * ships instead, fixing the reported breakage while leaving ordinary tag revert
49348
+ * untouched.
49349
+ *
49350
+ * Scope: TOP-LEVEL tag lists, which is where `buildRevertNewProperties`
49351
+ * operates. A tag list nested inside another property (an EC2 launch template's
49352
+ * `TagSpecifications`) still reverts wholesale.
49353
+ *
49354
+ * Order: baseline entries first in baseline order, then the preserved
49355
+ * service-managed entries. Providers apply tags as a set and the drift
49356
+ * comparator canonicalizes tag-list order on both sides
49357
+ * (`drift-normalize.ts`), so the order is for readability / determinism only.
49303
49358
  */
49359
+ function mergeTagListForRevert(baselineTags, awsTags) {
49360
+ const baselineKeys = new Set(tagKeys(baselineTags));
49361
+ const seen = /* @__PURE__ */ new Set();
49362
+ const preserved = awsTags.filter((t) => {
49363
+ const key = t["Key"];
49364
+ if (baselineKeys.has(key) || !isServiceManagedTagKey(key) || seen.has(key)) return false;
49365
+ seen.add(key);
49366
+ return true;
49367
+ });
49368
+ return [...baselineTags, ...preserved];
49369
+ }
49370
+ /**
49371
+ * The AWS-service-authored tag keys a `--revert` will PRESERVE rather than
49372
+ * strip, i.e. those present on the AWS side of a drifted top-level tag list,
49373
+ * absent from the revert baseline, and {@link isServiceManagedTagKey} (issue
49374
+ * #1501).
49375
+ *
49376
+ * Reported in the plan so the carve-out of {@link mergeTagListForRevert} is
49377
+ * visible BEFORE the confirmation prompt: a user who did want the tag gone
49378
+ * learns here that the revert will not do it.
49379
+ *
49380
+ * @returns dotted `<Key>.<TagKey>` paths, sorted, e.g. `['Tags.AmazonECSManaged']`.
49381
+ */
49382
+ function findRevertPreservedTagKeys(drifts, desiredProperties, awsProperties) {
49383
+ const preserved = /* @__PURE__ */ new Set();
49384
+ const driftedTopLevelKeys = /* @__PURE__ */ new Set();
49385
+ for (const d of drifts) {
49386
+ const topLevelKey = d.path.split(".", 1)[0];
49387
+ if (topLevelKey) driftedTopLevelKeys.add(topLevelKey);
49388
+ }
49389
+ for (const key of driftedTopLevelKeys) {
49390
+ if (!(key in desiredProperties)) continue;
49391
+ if (!isTagListKey(key)) continue;
49392
+ const desiredValue = desiredProperties[key];
49393
+ const awsValue = awsProperties[key];
49394
+ if (!(isCfnTagList(desiredValue) || Array.isArray(desiredValue) && desiredValue.length === 0) || !isCfnTagList(awsValue)) continue;
49395
+ const baselineKeys = new Set(tagKeys(desiredValue));
49396
+ for (const tagKey of tagKeys(awsValue)) if (!baselineKeys.has(tagKey) && isServiceManagedTagKey(tagKey)) preserved.add(`${key}.${tagKey}`);
49397
+ }
49398
+ return [...preserved].sort();
49399
+ }
49304
49400
  /**
49305
49401
  * The AWS-authored property paths a `--revert` is about to DROP, for a
49306
49402
  * resource whose state predates observed-capture (issue #1478).
@@ -49377,12 +49473,60 @@ function collectMissingPaths(awsValue, desiredValue, path, out) {
49377
49473
  function isPlainRecord(value) {
49378
49474
  return typeof value === "object" && value !== null && !Array.isArray(value);
49379
49475
  }
49476
+ /**
49477
+ * Build the `newProperties` object passed to `provider.update` during
49478
+ * `--revert`. Strategy:
49479
+ *
49480
+ * 1. Start from `awsProperties` (the AWS-current snapshot returned
49481
+ * by `readCurrentState`, which `runRevert` already passes as the
49482
+ * `previousProperties` argument to `provider.update`).
49483
+ * 2. For every top-level key whose subtree contains a drifted path,
49484
+ * overwrite it with the corresponding sub-shape from
49485
+ * `desiredProperties` (the state-recorded `observedProperties`).
49486
+ *
49487
+ * Why "AWS-current base + drifted overlay" instead of "drifted-only
49488
+ * partial":
49489
+ *
49490
+ * Several providers' `update()` implementations diff
49491
+ * `newProperties[K]` against `previousProperties[K]` and treat
49492
+ * `newVal === undefined` as "remove K from AWS" (e.g.
49493
+ * `SNSTopicProvider` calls `SetTopicAttributes(K, '')`,
49494
+ * `IAMRoleProvider.updateManagedPolicies` detaches every previously
49495
+ * attached policy when the new arg is undefined). Passing a
49496
+ * drifted-only partial would silently clear non-drifted attributes
49497
+ * on those providers. Sending the AWS-current value back as the
49498
+ * "new" value for non-drifted keys keeps `JSON.stringify(newVal) ===
49499
+ * JSON.stringify(oldVal)` so the diff is a no-op — no provider
49500
+ * changes required.
49501
+ *
49502
+ * For non-diff providers (e.g. `SQSQueueProvider` blindly pushes
49503
+ * every defined key via `SetQueueAttributes`), the AWS-current
49504
+ * value still gets serialised back to the same string AWS already
49505
+ * has, so the round-trip is a no-op for the AWS resource state.
49506
+ * The one exception is `readCurrentState`'s always-emit
49507
+ * placeholder values — e.g. SQS `RedrivePolicy: {}` — which AWS
49508
+ * rejects as invalid input even though they're round-tripped. That
49509
+ * class of value (Class 2 / structurally-incomplete-when-empty) is
49510
+ * handled by per-provider sanitize at the wire-layer; see the SQS
49511
+ * provider's `serializeRedrivePolicy` helper for the canonical
49512
+ * pattern.
49513
+ *
49514
+ * The drift comparator never produces array-index segments
49515
+ * (`Tags[0].Value`) — array drifts surface as a single entry on the
49516
+ * parent path — so `path.split('.', 1)` is always safe to extract the
49517
+ * top-level key.
49518
+ */
49380
49519
  function buildRevertNewProperties(drifts, desiredProperties, awsProperties) {
49381
49520
  const result = { ...awsProperties };
49382
49521
  for (const d of drifts) {
49383
49522
  const topLevelKey = d.path.split(".", 1)[0];
49384
49523
  if (!topLevelKey) continue;
49385
- if (topLevelKey in desiredProperties) result[topLevelKey] = desiredProperties[topLevelKey];
49524
+ if (topLevelKey in desiredProperties) {
49525
+ const desiredValue = desiredProperties[topLevelKey];
49526
+ const awsValue = awsProperties[topLevelKey];
49527
+ const baselineIsTagList = isCfnTagList(desiredValue) || Array.isArray(desiredValue) && desiredValue.length === 0;
49528
+ result[topLevelKey] = isTagListKey(topLevelKey) && baselineIsTagList && isCfnTagList(awsValue) ? mergeTagListForRevert(desiredValue, awsValue) : desiredValue;
49529
+ }
49386
49530
  }
49387
49531
  return result;
49388
49532
  }
@@ -49505,6 +49649,15 @@ function printRevertPlan(reports) {
49505
49649
  process.stdout.write(` → provider.update on ${o.logicalId} (${o.resourceType}): revert ${o.changes.length} ${word}\n`);
49506
49650
  for (const change of o.changes) process.stdout.write(` ${change.path}: ${formatScalar(change.awsValue)} -> ${formatScalar(change.stateValue)}\n`);
49507
49651
  const stateResource = report.state.resources[o.logicalId];
49652
+ if (stateResource) {
49653
+ const preserved = findRevertPreservedTagKeys(o.changes, stateResource.observedProperties ?? stateResource.properties ?? {}, o.awsProperties);
49654
+ if (preserved.length > 0) {
49655
+ const tagWord = preserved.length === 1 ? "tag" : "tags";
49656
+ process.stdout.write(` ! reverting this tag list KEEPS ${preserved.length} AWS-authored ${tagWord} the baseline does not carry:\n`);
49657
+ for (const path of preserved) process.stdout.write(` ${path}\n`);
49658
+ process.stdout.write(" Every other tag reverts normally. A service may require these (ECS needs AmazonECSManaged for managed scaling); 'aws:'-prefixed keys are AWS-reserved and cannot be removed by hand.\n");
49659
+ }
49660
+ }
49508
49661
  if (stateResource && stateResource.observedProperties === void 0) {
49509
49662
  const dropped = findRevertDroppedAwsKeys(o.changes, stateResource.properties ?? {}, o.awsProperties);
49510
49663
  if (dropped.length > 0) {
@@ -66463,7 +66616,7 @@ function createMigrateCommand() {
66463
66616
  */
66464
66617
  function buildProgram() {
66465
66618
  const program = new Command();
66466
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.33");
66619
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.35");
66467
66620
  program.hook("preAction", (_thisCommand, actionCommand) => {
66468
66621
  const { profile } = actionCommand.optsWithGlobals();
66469
66622
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;