@go-to-k/cdkd 0.282.7 → 0.283.0

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 configStringRefusal, $t as resolveStateBucketWithDefaultAndSource, A as green, An as NestedStackChildDirectDestroyError, At as BOOTSTRAP_MARKER_PREFIX, B as slowCcOperationTimeoutMs, Bt as runDockerForeground, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ct as stringifyValue, D as bold, Dn as LocalStartServiceError, Dt as loadPublishableAssetManifest, E as formatResourceLine, En as LocalMigrateError, Et as createAssetRedirectResolver, F as clearOnUpdateRemoval, Fn as StackHasActiveImportsError, Ft as validateContainerRepoName, G as getAccountInfo, Gt as synthesisStatusMessage, H as isTerminationProtectionPropagationError, Hn as withErrorHandling, Ht as AssetManifestLoader, I as ProviderRegistry, In as StackTerminationProtectionError, It as buildDenyExternalAccessPolicy, J as normalizeAwsTagsToCfn, Jt as resolveApp, K as refStateLookupFromResource, Kt as getDefaultStateBucketName, L as findActionableSilentDrops, Lt as buildDockerImage, M as yellow, Mn as ProvisioningError, Mt as getBootstrapMarkerKey, N as IAMRoleProvider, Nn as ResourceTimeoutError, Nt as parseBootstrapMarker, O as cyan, Ot as rewriteTemplateAssetReferences, P as collectInlinePolicyNamesManagedBySiblings, Pn as ResourceUpdateNotSupportedError, Pt as validateAssetBucketName, Q as configBooleanRefusal, Qt as resolveStateBucketWithDefault, R as findSilentDropProperties, Rt as formatDockerLoginError, S as extractDeploymentEventError, St as AssetPublisher, T as renderStatefulReason, Tn as LocalInvokeBuildError$1, Tt as buildAssetRedirectMap, U as IntrinsicFunctionResolver, Ut as getDockerImageBySourceHash, V as disableInstanceApiTermination, Vn as normalizeAwsError, Vt as runDockerStreaming, W as cfnRefValueFromPhysicalId, Wt as Synthesizer, X as assertRegionMatch, Xt as resolveCaptureObservedState, Y as resolveExplicitPhysicalId, Yt as resolveAutoAssetStorage, Z as coerceCfnBoolean, Zt as resolveSkipPrefix, _ as createPreDeleteFinalSnapshot, _n as getAwsClients, _t as TemplateParser, a as DeploymentEventsStore, an as MIGRATE_TMP_PREFIX, at as s3BucketArn, b as unsupportedFinalSnapshotError, bt as rebuildClientForBucketRegion, c as replayFailedOperations, cn as expectedOwnerParam, ct as s3BucketRegionalDomainName, d as IMPLICIT_DELETE_DEPENDENCIES, dn as derivePartitionAndUrlSuffix, dt as DiffCalculator, en as resolveUseCdkBootstrapAssets, et as readConfigString, f as computeImplicitDeleteEdges, fn as AssemblyReader, ft as describeTypeWithThrottleRetry, g as ccRoutedFinalSnapshotError, gn as AwsClients, gt as DagBuilder, h as buildFinalSnapshotIdentifier, hn as resolveBucketRegion, ht as isThrottlingError, i as DeploymentEventsReader, in as CFN_TEMPLATE_URL_LIMIT, it as requireConfigString, j as red, jn as PartialFailureError, jt as ensureAssetStorage, k as gray, kn as MissingCdkCliError, kt as AssetModeResolver, l as replayRollback, ln as PARTITION_TABLE, lt as s3BucketWebsiteUrl, m as PRE_DELETE_SNAPSHOT_TYPES, mt as isRetryableTransientError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as warnDeprecatedNoPrefixCliFlag, nt as requireConfigArray, o as planFailedOps, on as findLargeInlineResources, ot as s3BucketDomainName, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as processStackMessages, pt as withRetry, q as WAFv2WebACLProvider, qt as getLegacyStateBucketName, r as DeployEngine, rn as CFN_TEMPLATE_BODY_LIMIT, rt as requireConfigObject, s as planRollback, sn as uploadCfnTemplate, st as s3BucketDualStackDomainName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as stateBucketExistenceConfirmed, tt as replayWarn, u as withResourceDeadline, un as canonicalizeRegion, ut as applyRoleArnIfSet, v as isFinalSnapshotError, vn as resetAwsClients, vt as LockManager, w as isStatefulRecreateTargetSync, wn as DeployCancelledError, wt as WorkGraph, x as makeCanonicalizePropertiesFn, xn as CdkdError, xt as shouldRetainResource, y as refusesFinalSnapshot, yn as setAwsClients, yt as S3StateBackend, z as CloudControlProvider, zt as getDockerCmd } from "./deploy-engine-NA36xDvk.js";
2
+ import { $ as configStringRefusal, $t as resolveStateBucketWithDefaultAndSource, A as green, An as NestedStackChildDirectDestroyError, At as BOOTSTRAP_MARKER_PREFIX, B as slowCcOperationTimeoutMs, Bt as runDockerForeground, C as MULTI_REGION_RECREATE_BLOCKED_TYPES, Ct as stringifyValue, D as bold, Dn as LocalStartServiceError, Dt as loadPublishableAssetManifest, E as formatResourceLine, En as LocalMigrateError, Et as createAssetRedirectResolver, F as clearOnUpdateRemoval, Fn as StackHasActiveImportsError, Ft as validateContainerRepoName, G as getAccountInfo, Gt as synthesisStatusMessage, H as isTerminationProtectionPropagationError, Hn as withErrorHandling, Ht as AssetManifestLoader, I as ProviderRegistry, In as StackTerminationProtectionError, It as buildDenyExternalAccessPolicy, J as normalizeAwsTagsToCfn, Jt as resolveApp, K as refStateLookupFromResource, Kt as getDefaultStateBucketName, L as findActionableSilentDrops, Lt as buildDockerImage, M as yellow, Mn as ProvisioningError, Mt as getBootstrapMarkerKey, N as IAMRoleProvider, Nn as ResourceTimeoutError, Nt as parseBootstrapMarker, O as cyan, Ot as rewriteTemplateAssetReferences, P as collectInlinePolicyNamesManagedBySiblings, Pn as ResourceUpdateNotSupportedError, Pt as validateAssetBucketName, Q as configBooleanRefusal, Qt as resolveStateBucketWithDefault, R as findSilentDropProperties, Rt as formatDockerLoginError, S as extractDeploymentEventError, St as AssetPublisher, T as renderStatefulReason, Tn as LocalInvokeBuildError$1, Tt as buildAssetRedirectMap, U as IntrinsicFunctionResolver, Ut as getDockerImageBySourceHash, V as disableInstanceApiTermination, Vn as normalizeAwsError, Vt as runDockerStreaming, W as cfnRefValueFromPhysicalId, Wt as Synthesizer, X as assertRegionMatch, Xt as resolveCaptureObservedState, Y as resolveExplicitPhysicalId, Yt as resolveAutoAssetStorage, Z as coerceCfnBoolean, Zt as resolveSkipPrefix, _ as createPreDeleteFinalSnapshot, _n as getAwsClients, _t as TemplateParser, a as DeploymentEventsStore, an as MIGRATE_TMP_PREFIX, at as s3BucketArn, b as unsupportedFinalSnapshotError, bt as rebuildClientForBucketRegion, c as replayFailedOperations, cn as expectedOwnerParam, ct as s3BucketRegionalDomainName, d as IMPLICIT_DELETE_DEPENDENCIES, dn as derivePartitionAndUrlSuffix, dt as DiffCalculator, en as resolveUseCdkBootstrapAssets, et as readConfigString, f as computeImplicitDeleteEdges, fn as AssemblyReader, ft as describeTypeWithThrottleRetry, g as ccRoutedFinalSnapshotError, gn as AwsClients, gt as DagBuilder, h as buildFinalSnapshotIdentifier, hn as resolveBucketRegion, ht as isThrottlingError, i as DeploymentEventsReader, in as CFN_TEMPLATE_URL_LIMIT, it as requireConfigString, j as red, jn as PartialFailureError, jt as ensureAssetStorage, k as gray, kn as MissingCdkCliError, kt as AssetModeResolver, l as replayRollback, ln as PARTITION_TABLE, lt as s3BucketWebsiteUrl, m as PRE_DELETE_SNAPSHOT_TYPES, mt as isRetryableTransientError, n as DEFAULT_RESOURCE_WARN_AFTER_MS, nn as warnDeprecatedNoPrefixCliFlag, nt as requireConfigArray, o as planFailedOps, on as findLargeInlineResources, ot as s3BucketDomainName, p as ATOMIC_FINAL_SNAPSHOT_TYPES, pn as processStackMessages, pt as withRetry, q as WAFv2WebACLProvider, qt as getLegacyStateBucketName, r as DeployEngine, rn as CFN_TEMPLATE_BODY_LIMIT, rt as requireConfigObject, s as planRollback, sn as uploadCfnTemplate, st as s3BucketDualStackDomainName, t as DEFAULT_RESOURCE_TIMEOUT_MS, tn as stateBucketExistenceConfirmed, tt as replayWarn, u as withResourceDeadline, un as canonicalizeRegion, ut as applyRoleArnIfSet, v as isFinalSnapshotError, vn as resetAwsClients, vt as LockManager, w as isStatefulRecreateTargetSync, wn as DeployCancelledError, wt as WorkGraph, x as makeCanonicalizePropertiesFn, xn as CdkdError, xt as shouldRetainResource, y as refusesFinalSnapshot, yn as setAwsClients, yt as S3StateBackend, z as CloudControlProvider, zt as getDockerCmd } from "./deploy-engine-CEzMNZTA.js";
3
3
  import { a as getLiveRenderer, c as PATTERN_B_RESOURCE_TYPES, d as generateResourceNameWithFallback, 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-DulIbRCK.js";
4
+ import { t as ASGProvider } from "./asg-provider-BNuwJ11q.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";
@@ -10,7 +10,7 @@ import { CreateQueueCommand, DeleteQueueCommand, GetQueueAttributesCommand, GetQ
10
10
  import { CreateTopicCommand, DeleteTopicCommand, GetSubscriptionAttributesCommand, GetTopicAttributesCommand, InvalidParameterException, ListSubscriptionsByTopicCommand, ListTagsForResourceCommand, ListTopicsCommand, NotFoundException, SNSClient, SetTopicAttributesCommand, SubscribeCommand, TagResourceCommand, UnsubscribeCommand, UntagResourceCommand } from "@aws-sdk/client-sns";
11
11
  import { AddPermissionCommand, CreateEventSourceMappingCommand, CreateFunctionCommand, CreateFunctionUrlConfigCommand, DeleteEventSourceMappingCommand, DeleteFunctionCodeSigningConfigCommand, DeleteFunctionCommand, DeleteFunctionConcurrencyCommand, DeleteFunctionEventInvokeConfigCommand, DeleteFunctionUrlConfigCommand, DeleteLayerVersionCommand, GetEventSourceMappingCommand, GetFunctionCodeSigningConfigCommand, GetFunctionCommand, GetFunctionConcurrencyCommand, GetFunctionEventInvokeConfigCommand, GetFunctionRecursionConfigCommand, GetFunctionUrlConfigCommand, GetLayerVersionByArnCommand, GetPolicyCommand as GetPolicyCommand$1, GetRuntimeManagementConfigCommand, LambdaClient, ListTagsCommand, PublishLayerVersionCommand, PutFunctionCodeSigningConfigCommand, PutFunctionConcurrencyCommand, PutFunctionEventInvokeConfigCommand, PutFunctionRecursionConfigCommand, PutRuntimeManagementConfigCommand, RemovePermissionCommand, ResourceNotFoundException, TagResourceCommand as TagResourceCommand$1, UntagResourceCommand as UntagResourceCommand$1, UpdateEventSourceMappingCommand, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand, UpdateFunctionUrlConfigCommand, waitUntilFunctionActiveV2, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
12
12
  import { AssumeRoleCommand, GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
13
- import { AllocateAddressCommand, AssociateAddressCommand, AssociateIamInstanceProfileCommand, AssociateRouteTableCommand, AttachInternetGatewayCommand, AuthorizeSecurityGroupEgressCommand, AuthorizeSecurityGroupIngressCommand, CreateInternetGatewayCommand, CreateNatGatewayCommand, CreateNetworkAclCommand, CreateNetworkAclEntryCommand, CreateRouteCommand, CreateRouteTableCommand, CreateSecurityGroupCommand, CreateSubnetCommand, CreateTagsCommand, CreateVpcCommand, DeleteInternetGatewayCommand, DeleteNatGatewayCommand, DeleteNetworkAclCommand, DeleteNetworkAclEntryCommand, DeleteNetworkInterfaceCommand, DeleteRouteCommand, DeleteRouteTableCommand, DeleteSecurityGroupCommand, DeleteSubnetCommand, DeleteTagsCommand, DeleteVpcCommand, DescribeAddressesCommand, DescribeAvailabilityZonesCommand, DescribeIamInstanceProfileAssociationsCommand, DescribeInstanceAttributeCommand, DescribeInstanceCreditSpecificationsCommand, DescribeInstancesCommand, DescribeInternetGatewaysCommand, DescribeNatGatewaysCommand, DescribeNetworkAclsCommand, DescribeNetworkInterfacesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVolumesCommand, DescribeVpcAttributeCommand, DescribeVpcsCommand, DetachInternetGatewayCommand, DisassociateAddressCommand, DisassociateRouteTableCommand, EC2Client, ModifyInstanceAttributeCommand, ModifyInstanceCreditSpecificationCommand, ModifyInstanceMetadataOptionsCommand, ModifySubnetAttributeCommand, ModifyVpcAttributeCommand, MonitorInstancesCommand, ReleaseAddressCommand, ReplaceNetworkAclAssociationCommand, RevokeSecurityGroupEgressCommand, RevokeSecurityGroupIngressCommand, RunInstancesCommand, TerminateInstancesCommand, UnmonitorInstancesCommand, waitUntilInstanceRunning, waitUntilInstanceTerminated, waitUntilNatGatewayAvailable, waitUntilNatGatewayDeleted } from "@aws-sdk/client-ec2";
13
+ import { AllocateAddressCommand, AssociateAddressCommand, AssociateIamInstanceProfileCommand, AssociateRouteTableCommand, AttachInternetGatewayCommand, AuthorizeSecurityGroupEgressCommand, AuthorizeSecurityGroupIngressCommand, CreateInternetGatewayCommand, CreateNatGatewayCommand, CreateNetworkAclCommand, CreateNetworkAclEntryCommand, CreateRouteCommand, CreateRouteTableCommand, CreateSecurityGroupCommand, CreateSubnetCommand, CreateTagsCommand, CreateVpcCommand, DeleteInternetGatewayCommand, DeleteNatGatewayCommand, DeleteNetworkAclCommand, DeleteNetworkAclEntryCommand, DeleteNetworkInterfaceCommand, DeleteRouteCommand, DeleteRouteTableCommand, DeleteSecurityGroupCommand, DeleteSubnetCommand, DeleteTagsCommand, DeleteVpcCommand, DescribeAddressesCommand, DescribeAvailabilityZonesCommand, DescribeIamInstanceProfileAssociationsCommand, DescribeInstanceAttributeCommand, DescribeInstanceCreditSpecificationsCommand, DescribeInstancesCommand, DescribeInternetGatewaysCommand, DescribeNatGatewaysCommand, DescribeNetworkAclsCommand, DescribeNetworkInterfacesCommand, DescribeRouteTablesCommand, DescribeSecurityGroupRulesCommand, DescribeSecurityGroupsCommand, DescribeSubnetsCommand, DescribeVolumesCommand, DescribeVpcAttributeCommand, DescribeVpcsCommand, DetachInternetGatewayCommand, DisassociateAddressCommand, DisassociateRouteTableCommand, EC2Client, ModifyInstanceAttributeCommand, ModifyInstanceCreditSpecificationCommand, ModifyInstanceMetadataOptionsCommand, ModifySubnetAttributeCommand, ModifyVpcAttributeCommand, MonitorInstancesCommand, ReleaseAddressCommand, ReplaceNetworkAclAssociationCommand, RevokeSecurityGroupEgressCommand, RevokeSecurityGroupIngressCommand, RunInstancesCommand, TerminateInstancesCommand, UnmonitorInstancesCommand, waitUntilInstanceRunning, waitUntilInstanceTerminated, waitUntilNatGatewayAvailable, waitUntilNatGatewayDeleted } from "@aws-sdk/client-ec2";
14
14
  import { CreateTableCommand, DeleteResourcePolicyCommand, DeleteTableCommand, DescribeContinuousBackupsCommand, DescribeContributorInsightsCommand, DescribeKinesisStreamingDestinationCommand, DescribeTableCommand, DescribeTimeToLiveCommand, DisableKinesisStreamingDestinationCommand, DynamoDBClient, EnableKinesisStreamingDestinationCommand, GetResourcePolicyCommand, ListTagsOfResourceCommand, PutResourcePolicyCommand, ResourceNotFoundException as ResourceNotFoundException$1, TagResourceCommand as TagResourceCommand$2, UntagResourceCommand as UntagResourceCommand$2, UpdateContinuousBackupsCommand, UpdateContributorInsightsCommand, UpdateTableCommand, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";
15
15
  import { CloudFormationClient, CreateChangeSetCommand, DeleteChangeSetCommand, DeleteStackCommand, DescribeChangeSetCommand, DescribeStackEventsCommand, DescribeStackResourcesCommand, DescribeStacksCommand, ExecuteChangeSetCommand, GetTemplateCommand, UpdateStackCommand, waitUntilChangeSetCreateComplete, waitUntilStackDeleteComplete, waitUntilStackImportComplete, waitUntilStackUpdateComplete } from "@aws-sdk/client-cloudformation";
16
16
  import { APIGatewayClient, CreateAuthorizerCommand, CreateDeploymentCommand, CreateResourceCommand, CreateStageCommand, DeleteAuthorizerCommand, DeleteDeploymentCommand, DeleteMethodCommand, DeleteResourceCommand, DeleteStageCommand, GetAccountCommand, GetAuthorizerCommand, GetDeploymentCommand, GetMethodCommand, GetResourceCommand, GetStageCommand, NotFoundException as NotFoundException$1, PutIntegrationCommand, PutIntegrationResponseCommand, PutMethodCommand, PutMethodResponseCommand, TagResourceCommand as TagResourceCommand$3, UntagResourceCommand as UntagResourceCommand$3, UpdateAccountCommand, UpdateAuthorizerCommand, UpdateMethodCommand, UpdateStageCommand } from "@aws-sdk/client-api-gateway";
@@ -20380,6 +20380,43 @@ const SG_INGRESS_IP_PROTOCOL_DEFAULT = "-1";
20380
20380
  /** The refusal path both the create guard and the canonicalizer report under. */
20381
20381
  const SG_INGRESS_IP_PROTOCOL_PATH = "AWS::EC2::SecurityGroupIngress IpProtocol";
20382
20382
  /**
20383
+ * Page ceiling for {@link EC2Provider.lookupIngressRuleId}'s
20384
+ * `DescribeSecurityGroupRules` walk (issue #1761).
20385
+ *
20386
+ * The walk asks for {@link SG_RULE_PAGE_SIZE} rules per page, so 20 pages cover
20387
+ * 20,000 rules on a single security group — far beyond any real one (AWS's
20388
+ * default quota is 60 rules per SG, 1000 at the maximum quota increase). That
20389
+ * arithmetic only holds because the request pins `MaxResults`; without it AWS
20390
+ * applies its own default page size and the bound would mean an unknown number
20391
+ * of rules. The bound exists only so a pathological / looping `NextToken` cannot
20392
+ * hang a deploy; reaching it records nothing rather than answering from a
20393
+ * partial view.
20394
+ */
20395
+ const MAX_SG_RULE_PAGES = 20;
20396
+ /**
20397
+ * `MaxResults` for that walk. `DescribeSecurityGroupRules` accepts 5-1000; the
20398
+ * ceiling is what makes {@link MAX_SG_RULE_PAGES}'s "20,000 rules" true and
20399
+ * keeps the common case (a group with a handful of rules) to ONE round trip.
20400
+ */
20401
+ const SG_RULE_PAGE_SIZE = 1e3;
20402
+ /**
20403
+ * The `sgr-…` security-group rule id, anchored.
20404
+ *
20405
+ * The twin of `SG_RULE_ID_PATTERN` in `src/cli/commands/export.ts`, restated
20406
+ * rather than imported for the same reason that file restates
20407
+ * `ROUTE_DESTINATION_KEYS` instead of importing it from here: neither module may
20408
+ * pull the other's graph (the export command would drag in this provider and its
20409
+ * SDK client).
20410
+ *
20411
+ * Anchoring is what discriminates. `startsWith('sgr-')` also accepts
20412
+ * `sgr-0abc|tcp|443|443` — a composite wearing the identifier's prefix — which
20413
+ * on the import path reaches AWS as a malformed id and raises
20414
+ * `InvalidSecurityGroupRuleId.Malformed`, an error `isNotFoundError` does not
20415
+ * match, so `verifyExplicit` would THROW and abort the whole `cdkd import` run
20416
+ * instead of declining that one row.
20417
+ */
20418
+ const SG_RULE_ID_PATTERN$1 = /^sgr-[0-9a-f]+$/;
20419
+ /**
20383
20420
  * Resolve the `IpProtocol` an `AWS::EC2::SecurityGroupIngress` rule actually
20384
20421
  * SENDS, plus the bag that describes it (issue #1633).
20385
20422
  *
@@ -21713,25 +21750,29 @@ var EC2Provider = class {
21713
21750
  }
21714
21751
  ], onUnusableProtocol ? { onRefusal: onUnusableProtocol } : void 0);
21715
21752
  try {
21716
- await this.ec2Client.send(new AuthorizeSecurityGroupIngressCommand({
21753
+ const ruleId = singleSecurityGroupRuleId((await this.ec2Client.send(new AuthorizeSecurityGroupIngressCommand({
21717
21754
  GroupId: groupId,
21718
21755
  IpPermissions: [{
21719
21756
  ...this.buildIpPermission(properties),
21720
21757
  IpProtocol: ipProtocol
21721
21758
  }]
21722
- }));
21759
+ }))).SecurityGroupRules);
21723
21760
  this.logger.debug(`Successfully created SecurityGroupIngress ${logicalId}: ${physicalId}`);
21724
21761
  return {
21725
21762
  physicalId,
21726
- attributes: {},
21763
+ attributes: ruleId ? { Id: ruleId } : {},
21727
21764
  ...effectiveProperties && { effectiveProperties }
21728
21765
  };
21729
21766
  } catch (error) {
21730
21767
  if (error instanceof Error && error.message.includes("already exists")) {
21731
21768
  this.logger.debug(`SecurityGroupIngress ${logicalId} already exists, treating as success`);
21769
+ const existingRuleId = await this.lookupIngressRuleId(logicalId, groupId, {
21770
+ ...properties,
21771
+ IpProtocol: ipProtocol
21772
+ });
21732
21773
  return {
21733
21774
  physicalId,
21734
- attributes: {},
21775
+ attributes: existingRuleId ? { Id: existingRuleId } : {},
21735
21776
  ...effectiveProperties && { effectiveProperties }
21736
21777
  };
21737
21778
  }
@@ -21739,6 +21780,70 @@ var EC2Provider = class {
21739
21780
  throw new ProvisioningError(`Failed to create SecurityGroupIngress ${logicalId}: ${error instanceof Error ? error.message : String(error)}`, resourceType, logicalId, void 0, cause);
21740
21781
  }
21741
21782
  }
21783
+ /**
21784
+ * Best-effort lookup of the `sgr-...` id of an ALREADY-EXISTING ingress rule
21785
+ * (issue #1761).
21786
+ *
21787
+ * Only the idempotent "already exists" arm of {@link createSecurityGroupIngress}
21788
+ * calls this: the successful arm reads the id straight off
21789
+ * `AuthorizeSecurityGroupIngress`'s own response, which is what keeps the
21790
+ * mutating path free of the issue #1710 orphan hazard.
21791
+ *
21792
+ * **Never throws.** A `DescribeSecurityGroupRules` failure (permissions,
21793
+ * throttle, a rule that no longer matches) degrades to `undefined`, which
21794
+ * records no attribute — `cdkd export` then refuses that one resource with
21795
+ * its own actionable message, which is strictly better than failing a deploy
21796
+ * that AWS already considers satisfied.
21797
+ *
21798
+ * Returns a value only when EXACTLY ONE non-egress rule on the group matches
21799
+ * the requested `(protocol, ports, source)` triple. Zero matches means the
21800
+ * "already exists" error came from a rule cdkd cannot pin down; two or more
21801
+ * means the identifier would be ambiguous, and adopting an ambiguous id is
21802
+ * the #1658 failure mode (a state row that looks adopted but names the wrong
21803
+ * AWS object).
21804
+ *
21805
+ * **Paginated, unlike every other `Describe*` in this file.** That is not an
21806
+ * inconsistency to tidy away: the "exactly one" verdict above is a statement
21807
+ * about the WHOLE group, so a truncated first page turns a genuine 2-match
21808
+ * into a false "exactly one" and records the wrong `sgr-` id — the precise
21809
+ * outcome the ambiguity fence exists to prevent. A group can hold thousands
21810
+ * of rules (the account-level quota is per-SG, not per-page), so truncation
21811
+ * is reachable. `MAX_SG_RULE_PAGES` bounds the walk; exhausting it is treated
21812
+ * as "could not see the whole group" and records nothing, same as a throw.
21813
+ */
21814
+ async lookupIngressRuleId(logicalId, groupId, properties) {
21815
+ try {
21816
+ const rules = [];
21817
+ let nextToken;
21818
+ let pages = 0;
21819
+ do {
21820
+ if (pages >= MAX_SG_RULE_PAGES) {
21821
+ this.logger.debug(`SecurityGroupIngress ${logicalId}: DescribeSecurityGroupRules on ${groupId} still paginating after ${MAX_SG_RULE_PAGES} pages — cannot prove the match is unique, so not recording an Id attribute`);
21822
+ return;
21823
+ }
21824
+ const resp = await this.ec2Client.send(new DescribeSecurityGroupRulesCommand({
21825
+ Filters: [{
21826
+ Name: "group-id",
21827
+ Values: [groupId]
21828
+ }],
21829
+ MaxResults: SG_RULE_PAGE_SIZE,
21830
+ ...nextToken && { NextToken: nextToken }
21831
+ }));
21832
+ rules.push(...resp.SecurityGroupRules ?? []);
21833
+ nextToken = resp.NextToken;
21834
+ pages += 1;
21835
+ } while (nextToken);
21836
+ const ids = rules.filter((rule) => rule.IsEgress !== true && securityGroupRuleMatchesCfnIngress(rule, properties)).map((rule) => rule.SecurityGroupRuleId).filter((id) => typeof id === "string" && id.trim() !== "");
21837
+ if (ids.length !== 1) {
21838
+ this.logger.debug(`SecurityGroupIngress ${logicalId}: ${ids.length} existing rule(s) on ${groupId} match the requested protocol/ports/source — not recording an Id attribute`);
21839
+ return;
21840
+ }
21841
+ return ids[0];
21842
+ } catch (error) {
21843
+ this.logger.debug(`SecurityGroupIngress ${logicalId}: could not look up the existing rule id on ${groupId} (${error instanceof Error ? error.message : String(error)}) — not recording an Id attribute`);
21844
+ return;
21845
+ }
21846
+ }
21742
21847
  async updateSecurityGroupIngress(logicalId, physicalId, resourceType, properties, previousProperties) {
21743
21848
  this.logger.debug(`Updating SecurityGroupIngress ${logicalId}: ${physicalId}`);
21744
21849
  if (JSON.stringify(properties) === JSON.stringify(previousProperties)) return {
@@ -22681,13 +22786,28 @@ var EC2Provider = class {
22681
22786
  /**
22682
22787
  * Adopt an existing EC2 networking resource into cdkd state.
22683
22788
  *
22684
- * Supported types: `AWS::EC2::VPC`, `AWS::EC2::Subnet`,
22685
- * `AWS::EC2::SecurityGroup`. Other EC2 types this provider creates
22686
- * (RouteTable, Route, InternetGateway, VPCGatewayAttachment,
22687
- * NetworkAcl, Instance) return `null` from import — most have no
22688
- * stable identity to look up by tag (Routes are derived; SGIngress
22689
- * is rule-level), and the typical adoption story is "find the VPC,
22690
- * cdkd reconstructs the rest at deploy time".
22789
+ * Every arm here is OVERRIDE-ONLY: `import()` returns `null` unless the
22790
+ * caller passed `--resource <logicalId>=<physicalId>`, and `verifyExplicit`
22791
+ * then confirms that id against AWS. Supported types:
22792
+ *
22793
+ * - `AWS::EC2::VPC`, `AWS::EC2::Subnet`, `AWS::EC2::SecurityGroup` verified
22794
+ * by id, recorded verbatim with no attributes.
22795
+ * - `AWS::EC2::NatGateway` verified by id, ignoring a gateway already in
22796
+ * `deleted` / `deleting` state.
22797
+ * - `AWS::EC2::EIP` — accepts an allocation id, a public IP, or the composite
22798
+ * `<publicIp>|<allocationId>`, and records the composite plus the
22799
+ * `AllocationId` / `PublicIp` attributes.
22800
+ * - `AWS::EC2::SecurityGroupIngress` — accepts the `sgr-...` rule id
22801
+ * (CloudFormation's own identifier for the type), declines an EGRESS rule
22802
+ * id, and records cdkd's composite `<groupId>|<ipProtocol>|<fromPort>|<toPort>`
22803
+ * plus the rule id as the `Id` attribute (issue #1761).
22804
+ *
22805
+ * The remaining EC2 types this provider creates (RouteTable, Route,
22806
+ * InternetGateway, VPCGatewayAttachment, NetworkAcl, NetworkAclEntry,
22807
+ * SubnetRouteTableAssociation, SubnetNetworkAclAssociation, Instance) return
22808
+ * `null` — Routes and associations are derived from their parent, and the
22809
+ * typical adoption story is "find the VPC, cdkd reconstructs the rest at
22810
+ * deploy time".
22691
22811
  *
22692
22812
  * There is no `aws:cdk:path` tag lookup: AWS rejects `aws:`-prefixed tag
22693
22813
  * writes, so that tag never exists on a real resource and a
@@ -23273,6 +23393,39 @@ var EC2Provider = class {
23273
23393
  physicalId,
23274
23394
  attributes: {}
23275
23395
  } : null;
23396
+ case "AWS::EC2::SecurityGroupIngress": {
23397
+ if (!SG_RULE_ID_PATTERN$1.test(physicalId)) return null;
23398
+ const rule = (await this.ec2Client.send(new DescribeSecurityGroupRulesCommand({ SecurityGroupRuleIds: [physicalId] }))).SecurityGroupRules?.[0];
23399
+ if (!rule || rule.IsEgress === true) return null;
23400
+ if (!rule.GroupId || !rule.IpProtocol || !rule.SecurityGroupRuleId) return null;
23401
+ const segments = [
23402
+ {
23403
+ name: "groupId",
23404
+ value: rule.GroupId
23405
+ },
23406
+ {
23407
+ name: "ipProtocol",
23408
+ value: rule.IpProtocol
23409
+ },
23410
+ {
23411
+ name: "fromPort",
23412
+ value: rule.FromPort ?? "-1"
23413
+ },
23414
+ {
23415
+ name: "toPort",
23416
+ value: rule.ToPort ?? "-1"
23417
+ }
23418
+ ];
23419
+ const refusal = compositeIdSeparatorRefusal("AWS::EC2::SecurityGroupIngress", logicalId, segments);
23420
+ if (refusal !== void 0) {
23421
+ this.logger.warn(`${refusal} Skipping import.`);
23422
+ return null;
23423
+ }
23424
+ return {
23425
+ physicalId: packCompositeId("AWS::EC2::SecurityGroupIngress", logicalId, segments),
23426
+ attributes: { Id: rule.SecurityGroupRuleId }
23427
+ };
23428
+ }
23276
23429
  case "AWS::EC2::NatGateway": return (await this.ec2Client.send(new DescribeNatGatewaysCommand({ NatGatewayIds: [physicalId] }))).NatGateways?.find((g) => g.State !== "deleted" && g.State !== "deleting") ? {
23277
23430
  physicalId,
23278
23431
  attributes: {}
@@ -23393,6 +23546,93 @@ function flattenIpPermissions(perms, direction) {
23393
23546
  function sgProtocolKey(value) {
23394
23547
  return canonicalizeIpProtocolValue(value ?? "-1");
23395
23548
  }
23549
+ /**
23550
+ * The single `sgr-...` id an `AuthorizeSecurityGroupIngress` response reports
23551
+ * for a standalone `AWS::EC2::SecurityGroupIngress` (issue #1761).
23552
+ *
23553
+ * Pure by design: {@link EC2Provider.createSecurityGroupIngress} calls it
23554
+ * between the mutating Authorize and its return, where an `await` of anything
23555
+ * that can throw would re-create the issue #1710 orphan class.
23556
+ *
23557
+ * `undefined` unless the response carries EXACTLY ONE rule id. AWS mints one
23558
+ * rule per source entry, and cdkd sends one `IpPermission` per CFn resource —
23559
+ * but a template declaring both `CidrIp` and `CidrIpv6` on the same ingress
23560
+ * resource makes `buildIpPermission` emit two sources and AWS answers with two
23561
+ * rules. Neither is "the" CloudFormation identifier for the resource, so
23562
+ * recording nothing (and letting `cdkd export` refuse with its own message) is
23563
+ * the only answer that cannot silently name the wrong rule.
23564
+ */
23565
+ function singleSecurityGroupRuleId(rules) {
23566
+ const ids = (rules ?? []).map((rule) => rule.SecurityGroupRuleId).filter((id) => typeof id === "string" && id.trim() !== "");
23567
+ return ids.length === 1 ? ids[0] : void 0;
23568
+ }
23569
+ /**
23570
+ * A CFn `FromPort` / `ToPort` in the NUMBER form `DescribeSecurityGroupRules`
23571
+ * reports, for {@link securityGroupRuleMatchesCfnIngress}'s compare.
23572
+ *
23573
+ * An identity compare against `properties['FromPort'] as number` was wrong for
23574
+ * the same reason issue #1513 documents one property over: a YAML / JSON
23575
+ * template may spell a port as the STRING `"443"`, and `buildIpPermission`
23576
+ * passes it through to AWS unchanged, so such a rule deploys fine and would
23577
+ * then never match its own AWS-side row.
23578
+ *
23579
+ * Absent, `null`, and blank (INCLUDING whitespace-only) are AWS's `-1`, "all
23580
+ * ports". Everything that is not a number or a numeric string is `NaN`, which
23581
+ * compares unequal to everything — so the lookup records nothing rather than
23582
+ * matching some unrelated rule.
23583
+ *
23584
+ * A bare `Number(value)` was NOT enough for that last sentence, which an earlier
23585
+ * cut of this function claimed anyway: `Number` maps `' '` and `[]` to `0`,
23586
+ * `true` to `1`, and `['443']` to `443`. A whitespace-only port would then have
23587
+ * matched an ICMP **type-0** rule — a different rule, silently recorded — which
23588
+ * is the exact outcome the claim promised it could not produce.
23589
+ */
23590
+ function cfnIngressPortValue(value) {
23591
+ if (value === void 0 || value === null) return -1;
23592
+ if (typeof value === "number") return Number.isFinite(value) ? value : NaN;
23593
+ if (typeof value === "string") {
23594
+ const trimmed = value.trim();
23595
+ if (trimmed === "") return -1;
23596
+ const parsed = Number(trimmed);
23597
+ return Number.isFinite(parsed) ? parsed : NaN;
23598
+ }
23599
+ return NaN;
23600
+ }
23601
+ /**
23602
+ * Does a `DescribeSecurityGroupRules` rule describe the same ingress rule the
23603
+ * given CFn `AWS::EC2::SecurityGroupIngress` properties ask for?
23604
+ *
23605
+ * Deliberately NOT expressed via {@link sgRuleKey}: that key includes
23606
+ * `SourceSecurityGroupOwnerId` and `Description`, both of which AWS fills in on
23607
+ * the read side even when the template omits them, so a whole-key compare
23608
+ * would report "no match" for the ordinary same-account SG-to-SG rule this
23609
+ * lookup exists to find. Matching the fields the template actually pins —
23610
+ * protocol, port range, and whichever ONE source key it declares — is what
23611
+ * makes the comparison decidable from a partial template.
23612
+ *
23613
+ * The protocol goes through {@link sgProtocolKey} on BOTH sides, not a raw
23614
+ * compare: AWS substitutes the canonical NAME for the four protocols that have
23615
+ * one, so a template declaring `IpProtocol: 6` (or `'6'`) is read back as
23616
+ * `'tcp'` and would otherwise match nothing (the issue #1643 fold, one call site
23617
+ * further along).
23618
+ *
23619
+ * Ports are compared with AWS's own `-1` ("all") spelling on both sides, since
23620
+ * an omitted `FromPort` / `ToPort` reads back as `-1`, and the template side is
23621
+ * NUMERICALLY coerced — see {@link cfnIngressPortValue}.
23622
+ */
23623
+ function securityGroupRuleMatchesCfnIngress(rule, properties) {
23624
+ if (sgProtocolKey(rule.IpProtocol) !== sgProtocolKey(properties["IpProtocol"])) return false;
23625
+ if ((rule.FromPort ?? -1) !== cfnIngressPortValue(properties["FromPort"])) return false;
23626
+ if ((rule.ToPort ?? -1) !== cfnIngressPortValue(properties["ToPort"])) return false;
23627
+ const sources = [
23628
+ [properties["CidrIp"], rule.CidrIpv4],
23629
+ [properties["CidrIpv6"], rule.CidrIpv6],
23630
+ [properties["SourceSecurityGroupId"], rule.ReferencedGroupInfo?.GroupId],
23631
+ [properties["SourcePrefixListId"], rule.PrefixListId]
23632
+ ];
23633
+ for (const [declared, actual] of sources) if (declared !== void 0 && declared !== null && declared !== actual) return false;
23634
+ return true;
23635
+ }
23396
23636
  function sgRuleKey(rule, direction) {
23397
23637
  const peerKey = direction === "egress" ? rule["DestinationSecurityGroupId"] : rule["SourceSecurityGroupId"];
23398
23638
  const prefixKey = direction === "egress" ? rule["DestinationPrefixListId"] : rule["SourcePrefixListId"];
@@ -59473,7 +59713,7 @@ function readStringProperty(properties, key, resourceType) {
59473
59713
  * entry reads the value cdkd recorded in state (`attributes`), and refuses when
59474
59714
  * it is absent rather than guessing.
59475
59715
  *
59476
- * ## Live measurement (us-east-1, 2026-08-13)
59716
+ * ## Live measurement (us-east-1, 2026-08-13; the SG-ingress row 2026-08-14)
59477
59717
  *
59478
59718
  * Every field below is BOTH the type's single-field `primaryIdentifier` AND
59479
59719
  * `readOnlyProperties`, which is why each resolution returns an EMPTY
@@ -59485,7 +59725,19 @@ function readStringProperty(properties, key, resourceType) {
59485
59725
  * | `AWS::AppSync::DataSource` | `DataSourceArn` | `attributes.DataSourceArn` |
59486
59726
  * | `AWS::AppSync::Resolver` | `ResolverArn` | `attributes.ResolverArn` |
59487
59727
  * | `AWS::S3Tables::Table` | `TableARN` | `attributes.TableARN` |
59488
- * | `AWS::EC2::SecurityGroupIngress` | `Id` | NOTHING (issue #1761) |
59728
+ * | `AWS::EC2::SecurityGroupIngress` | `Id` | `attributes.Id` (issue #1761) |
59729
+ *
59730
+ * The SG-ingress row is measured the same way as the rest, and separately
59731
+ * against a real CloudFormation stack because the three strings that name one
59732
+ * resource can disagree (issue #1771 found CFn reporting an EIP as the bare
59733
+ * public IP while Cloud Control reports the composite, and the two disagreeing
59734
+ * on field ORDER for `AWS::EC2::VPCGatewayAttachment`). For this type they all
59735
+ * AGREE: `describe-type` says `primaryIdentifier` / `readOnlyProperties` are
59736
+ * both exactly `["/properties/Id"]` with a full `create`/`delete`/`list`/
59737
+ * `read`/`update` handler set and `ProvisioningType: FULLY_MUTABLE`, and a live
59738
+ * stack carrying a standalone ingress rule reports `PhysicalResourceId`
59739
+ * `sgr-02345615af6d2db0d`, with `Ref` and `Fn::GetAtt .Id` both returning that
59740
+ * same value.
59489
59741
  *
59490
59742
  * All four declare a `read` handler, so CFn genuinely does accept them for
59491
59743
  * IMPORT — unlike `AWS::Glue::Table`, the type issue #1659's title names, which
@@ -59510,13 +59762,70 @@ const COMPOSITE_PHYSICAL_ID_IDENTIFIERS = {
59510
59762
  physicalIdShape: "<tableBucketARN>|<namespace>|<name>",
59511
59763
  arnServiceSegment: "s3tables"
59512
59764
  }),
59513
- "AWS::EC2::SecurityGroupIngress": {
59765
+ "AWS::EC2::SecurityGroupIngress": recordedRuleIdIdentifier()
59766
+ };
59767
+ /**
59768
+ * The `sgr-…` shape, anchored. Shape-only — the hex body's LENGTH is not
59769
+ * pinned, because this exists to tell the identifier apart from the two other
59770
+ * strings that can sit in the same state row, not to validate an id AWS itself
59771
+ * minted:
59772
+ *
59773
+ * - cdkd's own composite physicalId, which starts `sg-` (the parent group) and
59774
+ * carries `|` separators; and
59775
+ * - a bare `sg-…` group id, which a hand-edited row could put under
59776
+ * `attributes.Id`.
59777
+ *
59778
+ * Anchoring is what does the discriminating: `^sgr-[0-9a-f]+$` cannot match
59779
+ * either, because `|` and the composite's trailing segments have nowhere to go.
59780
+ * A bare `startsWith('sgr-')` would accept `sgr-abc|tcp|443|443`.
59781
+ *
59782
+ * Measured live (us-east-1, 2026-08-14) from a CloudFormation stack carrying a
59783
+ * standalone ingress rule: `PhysicalResourceId` = `sgr-02345615af6d2db0d`, and
59784
+ * both `Ref` and `Fn::GetAtt .Id` return that same value.
59785
+ */
59786
+ const SG_RULE_ID_PATTERN = /^sgr-[0-9a-f]+$/;
59787
+ /**
59788
+ * The {@link CompositePhysicalIdIdentifier} for `AWS::EC2::SecurityGroupIngress`.
59789
+ *
59790
+ * The `recordedArnIdentifier` sibling of the family, differing only in that the
59791
+ * identifier is an `sgr-` rule id rather than an ARN — so it gets its own
59792
+ * builder rather than an `isUsable` callback threaded through that one, which
59793
+ * would make the ARN family's every message ("which is not a <service> ARN",
59794
+ * "so cdkd records <field>") conditional on a shape it no longer owns.
59795
+ *
59796
+ * Two accepted sources, validated by the SAME predicate — the point #1771
59797
+ * made about the EIP splitter's segment binding applies here verbatim:
59798
+ * validating one side is not a discriminator.
59799
+ *
59800
+ * 1. `attributes.Id`, which every writer produces today — a fresh deploy, a
59801
+ * `cdkd import --resource <logicalId>=sgr-…`, and the recursive
59802
+ * `--migrate-from-cloudformation` walk (which hands CFn's
59803
+ * `PhysicalResourceId` to `EC2Provider.import` as `knownPhysicalId`, and
59804
+ * that value IS the `sgr-` id — measured above).
59805
+ * 2. A physicalId that is ALREADY the bare rule id. **No cdkd path writes this
59806
+ * shape today** — unlike `AWS::S3Tables::Table`, whose Cloud-Control import
59807
+ * genuinely records the bare ARN — so it is accepted defensively rather than
59808
+ * because it is live: CFn's `PhysicalResourceId` for the type is exactly
59809
+ * this string, so a row hand-repaired from a CFn console listing, or written
59810
+ * by some future Cloud-Control routing of the type, carries an unambiguous
59811
+ * identifier that it would be perverse to refuse. Such a row is separately
59812
+ * BROKEN for `cdkd destroy` (`deleteSecurityGroupIngress` needs the 4-part
59813
+ * tuple), which is another reason to let the export hand it to CFn rather
59814
+ * than strand it.
59815
+ */
59816
+ function recordedRuleIdIdentifier() {
59817
+ const isUsableIdentifier = (value) => SG_RULE_ID_PATTERN.test(value.trim());
59818
+ return {
59514
59819
  field: "Id",
59515
- resolve: ({ logicalId }) => {
59516
- throw new Error(`cdkd's physical id for AWS::EC2::SecurityGroupIngress is the composite '<groupId>|<ipProtocol>|<fromPort>|<toPort>', but CloudFormation IMPORT identifies the rule by the 'sgr-...' security-group rule id AWS assigns, which cdkd does not record in state (tracked in https://github.com/go-to-k/cdkd/issues/1761). Remove '${logicalId}' from the stack before exporting (the rule stays in AWS and can be re-declared in CloudFormation afterwards), or destroy it first and let CloudFormation create it fresh.`);
59820
+ resolve: ({ logicalId, physicalId, attributes }) => {
59821
+ const recorded = attributes["Id"];
59822
+ if (typeof recorded === "string" && isUsableIdentifier(recorded)) return recorded.trim();
59823
+ if (isUsableIdentifier(physicalId)) return physicalId.trim();
59824
+ const recordedNote = typeof recorded === "string" && recorded.trim() ? `attributes.Id is recorded as '${recorded.trim()}', which is not an 'sgr-…' security-group rule id` : `attributes.Id is missing or empty`;
59825
+ throw new Error(`cdkd's physical id for AWS::EC2::SecurityGroupIngress is the composite '<groupId>|<ipProtocol>|<fromPort>|<toPort>', but CloudFormation IMPORT identifies the rule by the 'sgr-...' security-group rule id AWS assigns, which cdkd state does not record usably for '${logicalId}' (${recordedNote}). Two causes, with different remedies. (1) The rule declares MORE THAN ONE source — e.g. both CidrIp and CidrIpv6 on the same resource — so AWS minted one rule per source and cdkd deliberately recorded neither id, because neither is 'the' identifier for this resource. Re-deploying does not help; split it into one AWS::EC2::SecurityGroupIngress resource per source, which is also the shape CloudFormation will manage after the export. (2) Otherwise the rule was deployed by a cdkd older than https://github.com/go-to-k/cdkd/issues/1761, which did not record the id at all. AWS returns it only from AuthorizeSecurityGroupIngress itself, so a no-op re-deploy will NOT heal the record either: change any property of the rule (cdkd revokes and re-authorizes, minting a fresh id, with a momentary traffic interruption) or destroy and re-deploy it, then re-run cdkd export. In both cases you can instead remove '${logicalId}' from the stack before exporting — the rule stays in AWS and can be re-declared in CloudFormation afterwards.`);
59517
59826
  }
59518
- }
59519
- };
59827
+ };
59828
+ }
59520
59829
  /**
59521
59830
  * Build the {@link CompositePhysicalIdIdentifier} for a type whose CFn
59522
59831
  * identifier is an ARN cdkd records in `attributes` under the SAME name as the
@@ -75943,7 +76252,7 @@ function createMigrateCommand() {
75943
76252
  */
75944
76253
  function buildProgram() {
75945
76254
  const program = new Command();
75946
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.282.7");
76255
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.283.0");
75947
76256
  program.hook("preAction", (_thisCommand, actionCommand) => {
75948
76257
  const { profile } = actionCommand.optsWithGlobals();
75949
76258
  if (profile !== void 0) process.env["AWS_PROFILE"] = profile;