@go-to-k/cdkd 0.268.0 → 0.268.2

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 WorkGraph, $t as MissingCdkCliError, A as slowCcOperationTimeoutMs, At as warnDeprecatedNoPrefixCliFlag, B as applyRoleArnIfSet, Bt as resolveBucketRegion, C as yellow, Ct as resolveAutoAssetStorage, D as ProviderRegistry, Dt as resolveStateBucketWithDefaultAndSource, E as clearOnUpdateRemoval, Et as resolveStateBucketWithDefault, F as refStateLookupFromResource, Ft as uploadCfnTemplate, G as DagBuilder, H as describeTypeWithThrottleRetry, Ht as getAwsClients, I as WAFv2WebACLProvider, It as expectedOwnerParam, J as S3StateBackend, K as TemplateParser, Kt as CdkdError, L as normalizeAwsTagsToCfn, Lt as AssemblyReader, M as isTerminationProtectionPropagationError, Mt as CFN_TEMPLATE_URL_LIMIT, N as IntrinsicFunctionResolver, Nt as MIGRATE_TMP_PREFIX, O as findActionableSilentDrops, Ot as resolveUseCdkBootstrapAssets, P as cfnRefValueFromPhysicalId, Pt as findLargeInlineResources, Q as stringifyValue, R as resolveExplicitPhysicalId, Rt as processStackMessages, S as red, St as resolveApp, T as collectInlinePolicyNamesManagedBySiblings, Tt as resolveSkipPrefix, U as withRetry, Ut as resetAwsClients, V as DiffCalculator, Vt as AwsClients, W as isRetryableTransientError, Wt as setAwsClients, X as shouldRetainResource, Xt as LocalMigrateError, Y as rebuildClientForBucketRegion, Yt as LocalInvokeBuildError$1, Z as AssetPublisher, Zt as LocalStartServiceError, _ as formatResourceLine, _t as getDockerImageBySourceHash, a as DeploymentEventsStore, an as StackHasActiveImportsError, at as BOOTSTRAP_MARKER_PREFIX, b as gray, bt as getDefaultStateBucketName, c as replayFailedOperations, ct as parseBootstrapMarker, d as IMPLICIT_DELETE_DEPENDENCIES, dn as normalizeAwsError, dt as buildDockerImage, en as NestedStackChildDirectDestroyError, et as buildAssetRedirectMap, f as computeImplicitDeleteEdges, fn as withErrorHandling, ft as formatDockerLoginError, g as renderStatefulReason, gt as AssetManifestLoader, h as isStatefulRecreateTargetSync, ht as runDockerStreaming, i as DeploymentEventsReader, in as ResourceUpdateNotSupportedError, it as AssetModeResolver, j as disableInstanceApiTermination, jt as CFN_TEMPLATE_BODY_LIMIT, k as CloudControlProvider, kt as stateBucketExistenceConfirmed, l as replayRollback, lt as validateAssetBucketName, m as MULTI_REGION_RECREATE_BLOCKED_TYPES, mt as runDockerForeground, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as ProvisioningError, nt as loadPublishableAssetManifest, o as planFailedOps, on as StackTerminationProtectionError, ot as ensureAssetStorage, p as extractDeploymentEventError, pt as getDockerCmd, q as LockManager, r as DeployEngine, rn as ResourceTimeoutError, rt as rewriteTemplateAssetReferences, s as planRollback, st as getBootstrapMarkerKey, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as PartialFailureError, tt as createAssetRedirectResolver, u as withResourceDeadline, ut as validateContainerRepoName, v as bold, vt as Synthesizer, w as IAMRoleProvider, wt as resolveCaptureObservedState, x as green, xt as getLegacyStateBucketName, y as cyan, yt as synthesisStatusMessage, z as assertRegionMatch } from "./deploy-engine-B5cRuFij.js";
2
+ import { $ as WorkGraph, A as slowCcOperationTimeoutMs, At as warnDeprecatedNoPrefixCliFlag, B as applyRoleArnIfSet, Bt as resolveBucketRegion, C as yellow, Ct as resolveAutoAssetStorage, D as ProviderRegistry, Dt as resolveStateBucketWithDefaultAndSource, E as clearOnUpdateRemoval, Et as resolveStateBucketWithDefault, F as refStateLookupFromResource, Ft as uploadCfnTemplate, G as DagBuilder, H as describeTypeWithThrottleRetry, Ht as getAwsClients, I as WAFv2WebACLProvider, It as expectedOwnerParam, J as S3StateBackend, K as TemplateParser, Kt as CdkdError, L as normalizeAwsTagsToCfn, Lt as AssemblyReader, M as isTerminationProtectionPropagationError, Mt as CFN_TEMPLATE_URL_LIMIT, N as IntrinsicFunctionResolver, Nt as MIGRATE_TMP_PREFIX, O as findActionableSilentDrops, Ot as resolveUseCdkBootstrapAssets, P as cfnRefValueFromPhysicalId, Pt as findLargeInlineResources, Q as stringifyValue, Qt as LocalStartServiceError, R as resolveExplicitPhysicalId, Rt as processStackMessages, S as red, St as resolveApp, T as collectInlinePolicyNamesManagedBySiblings, Tt as resolveSkipPrefix, U as withRetry, Ut as resetAwsClients, V as DiffCalculator, Vt as AwsClients, W as isRetryableTransientError, Wt as setAwsClients, X as shouldRetainResource, Xt as LocalInvokeBuildError$1, Y as rebuildClientForBucketRegion, Yt as DeployCancelledError, Z as AssetPublisher, Zt as LocalMigrateError, _ as formatResourceLine, _t as getDockerImageBySourceHash, a as DeploymentEventsStore, an as ResourceUpdateNotSupportedError, at as BOOTSTRAP_MARKER_PREFIX, b as gray, bt as getDefaultStateBucketName, c as replayFailedOperations, ct as parseBootstrapMarker, d as IMPLICIT_DELETE_DEPENDENCIES, dt as buildDockerImage, en as MissingCdkCliError, et as buildAssetRedirectMap, f as computeImplicitDeleteEdges, fn as normalizeAwsError, ft as formatDockerLoginError, g as renderStatefulReason, gt as AssetManifestLoader, h as isStatefulRecreateTargetSync, ht as runDockerStreaming, i as DeploymentEventsReader, in as ResourceTimeoutError, it as AssetModeResolver, j as disableInstanceApiTermination, jt as CFN_TEMPLATE_BODY_LIMIT, k as CloudControlProvider, kt as stateBucketExistenceConfirmed, l as replayRollback, lt as validateAssetBucketName, m as MULTI_REGION_RECREATE_BLOCKED_TYPES, mt as runDockerForeground, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as PartialFailureError, nt as loadPublishableAssetManifest, o as planFailedOps, on as StackHasActiveImportsError, ot as ensureAssetStorage, p as extractDeploymentEventError, pn as withErrorHandling, pt as getDockerCmd, q as LockManager, r as DeployEngine, rn as ProvisioningError, rt as rewriteTemplateAssetReferences, s as planRollback, sn as StackTerminationProtectionError, st as getBootstrapMarkerKey, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as NestedStackChildDirectDestroyError, tt as createAssetRedirectResolver, u as withResourceDeadline, ut as validateContainerRepoName, v as bold, vt as Synthesizer, w as IAMRoleProvider, wt as resolveCaptureObservedState, x as green, xt as getLegacyStateBucketName, y as cyan, yt as synthesisStatusMessage, z as assertRegionMatch } from "./deploy-engine-BEjF-h_6.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-ZylgRJOY.js";
4
+ import { t as ASGProvider } from "./asg-provider-gaXfXSH0.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, DeleteBucketIntelligentTieringConfigurationCommand, DeleteBucketInventoryConfigurationCommand, DeleteBucketLifecycleCommand, DeleteBucketMetricsConfigurationCommand, DeleteBucketPolicyCommand, DeleteBucketReplicationCommand, DeleteBucketTaggingCommand, DeleteBucketWebsiteCommand, DeleteObjectsCommand, GetBucketAccelerateConfigurationCommand, GetBucketCorsCommand, GetBucketEncryptionCommand, GetBucketLifecycleConfigurationCommand, GetBucketLocationCommand, GetBucketLoggingCommand, GetBucketNotificationConfigurationCommand, 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";
@@ -15617,30 +15617,13 @@ var EC2Provider = class {
15617
15617
  VpcId: properties["VpcId"] ?? void 0
15618
15618
  }))).GroupId;
15619
15619
  try {
15620
- await this.applyTags(groupId, properties, logicalId);
15621
15620
  const ingressRules = properties["SecurityGroupIngress"];
15622
- if (ingressRules && Array.isArray(ingressRules)) for (const rule of ingressRules) await this.ec2Client.send(new AuthorizeSecurityGroupIngressCommand({
15623
- GroupId: groupId,
15624
- IpPermissions: [this.buildIpPermission(rule)]
15625
- }));
15626
15621
  const egressRules = properties["SecurityGroupEgress"];
15627
- if (egressRules && Array.isArray(egressRules)) {
15628
- try {
15629
- await this.ec2Client.send(new RevokeSecurityGroupEgressCommand({
15630
- GroupId: groupId,
15631
- IpPermissions: [{
15632
- IpProtocol: "-1",
15633
- IpRanges: [{ CidrIp: "0.0.0.0/0" }]
15634
- }]
15635
- }));
15636
- } catch (error) {
15637
- if (!this.isNotFoundError(error)) throw error;
15638
- }
15639
- for (const rule of egressRules) await this.ec2Client.send(new AuthorizeSecurityGroupEgressCommand({
15640
- GroupId: groupId,
15641
- IpPermissions: [this.buildIpPermission(rule, "egress")]
15642
- }));
15643
- }
15622
+ await Promise.all([
15623
+ this.applyTags(groupId, properties, logicalId),
15624
+ this.authorizeInlineIngress(groupId, ingressRules),
15625
+ this.applyInlineEgress(groupId, egressRules)
15626
+ ]);
15644
15627
  } catch (innerError) {
15645
15628
  try {
15646
15629
  await this.ec2Client.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));
@@ -15663,6 +15646,79 @@ var EC2Provider = class {
15663
15646
  throw new ProvisioningError(`Failed to create SecurityGroup ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
15664
15647
  }
15665
15648
  }
15649
+ /**
15650
+ * Authorize a freshly-created security group's inline
15651
+ * `SecurityGroupIngress` rules in a SINGLE `AuthorizeSecurityGroupIngress`
15652
+ * call.
15653
+ *
15654
+ * The API takes an `IpPermissions` ARRAY; the previous per-rule loop paid
15655
+ * one round trip per rule for no benefit. AWS applies the whole list
15656
+ * atomically, so the resulting rule set is byte-identical — the only
15657
+ * behavior difference is that a bad rule now rejects the batch instead of
15658
+ * being preceded by its already-applied siblings, and the caller deletes
15659
+ * the half-wired group in either case.
15660
+ */
15661
+ async authorizeInlineIngress(groupId, ingressRules) {
15662
+ if (!Array.isArray(ingressRules) || ingressRules.length === 0) return;
15663
+ await this.ec2Client.send(new AuthorizeSecurityGroupIngressCommand({
15664
+ GroupId: groupId,
15665
+ IpPermissions: ingressRules.map((rule) => this.buildIpPermission(rule))
15666
+ }));
15667
+ }
15668
+ /**
15669
+ * Apply a freshly-created security group's inline `SecurityGroupEgress`
15670
+ * rules.
15671
+ *
15672
+ * When a template specifies egress explicitly, CloudFormation replaces the
15673
+ * AWS-default "allow all egress" rule (`-1` / `0.0.0.0/0`) with the
15674
+ * supplied set, so cdkd revokes the default first and then authorizes the
15675
+ * template's rules. Both steps are preserved, including for an EMPTY
15676
+ * `SecurityGroupEgress: []` — that is a deliberate "no egress at all",
15677
+ * which requires the revoke and no authorize.
15678
+ *
15679
+ * Two round trips are saved where they are provably redundant:
15680
+ *
15681
+ * - The whole revoke+authorize pair is SKIPPED when the templated egress
15682
+ * is exactly the rule AWS already created by default. `isDefaultEgressRule`
15683
+ * is the exact comparator (protocol `-1`, `CidrIp 0.0.0.0/0`, no IPv6
15684
+ * range / peer group / prefix list / description, ports absent or `-1`)
15685
+ * and is the SAME predicate the drift reverse-mapper uses to recognize
15686
+ * the AWS default, so the two cannot disagree about what "default" means.
15687
+ * AWS creates exactly ONE default egress rule and it is IPv4-only (there
15688
+ * is no `::/0` default), which is why a single-element match is the right
15689
+ * shape. NOTE this deliberately does NOT fire for the CDK L2
15690
+ * `allowAllOutbound: true` shape, which stamps
15691
+ * `Description: 'Allow all outbound traffic by default'` — the AWS
15692
+ * default rule carries no description, so skipping there would leave the
15693
+ * group in a state CloudFormation would not produce AND would surface as
15694
+ * permanent phantom drift (`readCurrentState` would report no
15695
+ * Description while state records one).
15696
+ * - The remaining authorize is a SINGLE batched call rather than one per
15697
+ * rule (see {@link authorizeInlineIngress}).
15698
+ */
15699
+ async applyInlineEgress(groupId, egressRules) {
15700
+ if (!Array.isArray(egressRules)) return;
15701
+ if (egressRules.length === 1 && isDefaultEgressRule(egressRules[0])) {
15702
+ this.logger.debug(`SecurityGroup ${groupId} egress equals the AWS default allow-all rule; skipping the redundant revoke + re-authorize`);
15703
+ return;
15704
+ }
15705
+ try {
15706
+ await this.ec2Client.send(new RevokeSecurityGroupEgressCommand({
15707
+ GroupId: groupId,
15708
+ IpPermissions: [{
15709
+ IpProtocol: "-1",
15710
+ IpRanges: [{ CidrIp: "0.0.0.0/0" }]
15711
+ }]
15712
+ }));
15713
+ } catch (error) {
15714
+ if (!this.isNotFoundError(error)) throw error;
15715
+ }
15716
+ if (egressRules.length === 0) return;
15717
+ await this.ec2Client.send(new AuthorizeSecurityGroupEgressCommand({
15718
+ GroupId: groupId,
15719
+ IpPermissions: egressRules.map((rule) => this.buildIpPermission(rule, "egress"))
15720
+ }));
15721
+ }
15666
15722
  async updateSecurityGroup(logicalId, physicalId, resourceType, properties, previousProperties) {
15667
15723
  this.logger.debug(`Updating SecurityGroup ${logicalId}: ${physicalId}`);
15668
15724
  try {
@@ -42953,6 +43009,39 @@ async function promptMigrationConfirm(renames, opts) {
42953
43009
  rl.close();
42954
43010
  }
42955
43011
  }
43012
+ /**
43013
+ * Build the `DeployEngineOptions.onCurrentStateLoaded` gate that runs the
43014
+ * prefix-migration check, or `undefined` when the check is inactive
43015
+ * (`skipPrefix === false`, i.e. the user opted back in to legacy prefixing).
43016
+ *
43017
+ * Why a gate rather than a pre-lock `getState`: prefix-skipping has been the
43018
+ * default since v0.94.0, so the previous shape issued an S3 GET on EVERY
43019
+ * deploy of EVERY stack — including brand-new stacks with no state at all —
43020
+ * and the deploy engine then read the very same object again immediately
43021
+ * after taking the lock. Running as the engine's post-lock gate reuses that
43022
+ * read. The contract the check actually depends on ("surface this before any
43023
+ * provider call runs") is preserved: the engine invokes the gate immediately
43024
+ * after loading state and before parsing, diffing, or provisioning anything.
43025
+ * Reading under the lock is also strictly more authoritative — no concurrent
43026
+ * deploy can mutate the state between the check and the diff it predicts.
43027
+ *
43028
+ * Declining the prompt raises {@link DeployCancelledError}, which the deploy
43029
+ * CLI unwinds quietly (no error output, no FAILED run event) — matching the
43030
+ * plain early `return` the pre-lock version used.
43031
+ *
43032
+ * The gate is scoped to `stackName`: nested-stack children inherit the parent
43033
+ * engine's option object, and the check is deliberately top-level-only (it was
43034
+ * never applied to children).
43035
+ */
43036
+ function createPrefixMigrationGate(opts) {
43037
+ if (!opts.skipPrefix) return void 0;
43038
+ return async (gateStackName, state) => {
43039
+ if (gateStackName !== opts.stackName) return;
43040
+ const pending = findPendingPrefixRenames(opts.stackName, state);
43041
+ if (pending.length === 0) return;
43042
+ if (!await promptMigrationConfirm(pending, { ...opts.yes !== void 0 && { yes: opts.yes } })) throw new DeployCancelledError();
43043
+ };
43044
+ }
42956
43045
 
42957
43046
  //#endregion
42958
43047
  //#region src/cli/commands/deploy.ts
@@ -43190,13 +43279,11 @@ async function deployCommand(stacks, options) {
43190
43279
  });
43191
43280
  let runResult = "SUCCEEDED";
43192
43281
  try {
43193
- if (skipPrefix) {
43194
- const existing = await stackStateBackend.getState(stackInfo.stackName, stackRegion);
43195
- const pending = findPendingPrefixRenames(stackInfo.stackName, existing?.state);
43196
- if (pending.length > 0) {
43197
- if (!await promptMigrationConfirm(pending, { yes: options.yes })) return;
43198
- }
43199
- }
43282
+ const migrationGate = createPrefixMigrationGate({
43283
+ stackName: stackInfo.stackName,
43284
+ skipPrefix,
43285
+ yes: options.yes
43286
+ });
43200
43287
  let recreateViaCcApiTargets;
43201
43288
  let recreateViaSdkProviderTargets;
43202
43289
  if (options.recreateViaCcApi?.length || options.recreateViaSdkProvider?.length) {
@@ -43248,6 +43335,7 @@ async function deployCommand(stacks, options) {
43248
43335
  ...options.roleArn && { roleArn: options.roleArn },
43249
43336
  ...assetRedirect && { assetRedirect },
43250
43337
  ...eventRecorder && { eventRecorder },
43338
+ ...migrationGate && { onCurrentStateLoaded: migrationGate },
43251
43339
  ...recreateViaCcApiTargets && recreateViaCcApiTargets.size > 0 && { recreateViaCcApiTargets },
43252
43340
  ...recreateViaSdkProviderTargets && recreateViaSdkProviderTargets.size > 0 && { recreateViaSdkProviderTargets },
43253
43341
  ...options.replace && { replace: true },
@@ -43296,6 +43384,7 @@ async function deployCommand(stacks, options) {
43296
43384
  deleted: deployResult.deleted
43297
43385
  }, deployResult.durationMs);
43298
43386
  } catch (deployError) {
43387
+ if (deployError instanceof DeployCancelledError) return;
43299
43388
  runResult = "FAILED";
43300
43389
  recordRunFailed(eventRecorder, stackInfo.stackName, deployError);
43301
43390
  throw deployError;
@@ -62613,7 +62702,7 @@ function createMigrateCommand() {
62613
62702
  */
62614
62703
  function buildProgram() {
62615
62704
  const program = new Command();
62616
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.268.0");
62705
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.268.2");
62617
62706
  program.hook("preAction", (_thisCommand, actionCommand) => {
62618
62707
  const { profile } = actionCommand.optsWithGlobals();
62619
62708
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;