@go-to-k/cdkd 0.278.37 → 0.278.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{asg-provider-BTeSlton.js → asg-provider-CJJC8plY.js} +2 -2
- package/dist/{asg-provider-BTeSlton.js.map → asg-provider-CJJC8plY.js.map} +1 -1
- package/dist/cli.js +363 -42
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-bEhHOGVR.js → deploy-engine-BJVpWi-B.js} +5 -4
- package/dist/deploy-engine-BJVpWi-B.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-bEhHOGVR.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
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-
|
|
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-BJVpWi-B.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-
|
|
4
|
+
import { t as ASGProvider } from "./asg-provider-CJJC8plY.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";
|
|
8
|
-
import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachRolePolicyCommand, AttachUserPolicyCommand, CreateAccessKeyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreatePolicyCommand, CreatePolicyVersionCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeletePolicyCommand, DeletePolicyVersionCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachRolePolicyCommand, DetachUserPolicyCommand, GetAccessKeyLastUsedCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetPolicyCommand, GetPolicyVersionCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListEntitiesForPolicyCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListPoliciesCommand, ListPolicyTagsCommand, ListPolicyVersionsCommand, ListUserPoliciesCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagPolicyCommand, TagUserCommand, UntagPolicyCommand, UntagUserCommand, UpdateAccessKeyCommand, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
|
|
8
|
+
import { AddRoleToInstanceProfileCommand, AddUserToGroupCommand, AttachGroupPolicyCommand, AttachRolePolicyCommand, AttachUserPolicyCommand, CreateAccessKeyCommand, CreateGroupCommand, CreateInstanceProfileCommand, CreateLoginProfileCommand, CreatePolicyCommand, CreatePolicyVersionCommand, CreateUserCommand, DeleteAccessKeyCommand, DeleteGroupCommand, DeleteGroupPolicyCommand, DeleteInstanceProfileCommand, DeleteLoginProfileCommand, DeletePolicyCommand, DeletePolicyVersionCommand, DeleteRolePolicyCommand, DeleteUserCommand, DeleteUserPermissionsBoundaryCommand, DeleteUserPolicyCommand, DetachGroupPolicyCommand, DetachRolePolicyCommand, DetachUserPolicyCommand, GetAccessKeyLastUsedCommand, GetGroupCommand, GetGroupPolicyCommand, GetInstanceProfileCommand, GetPolicyCommand, GetPolicyVersionCommand, GetRoleCommand, GetRolePolicyCommand, GetUserCommand, GetUserPolicyCommand, IAMClient, ListAccessKeysCommand, ListAttachedGroupPoliciesCommand, ListAttachedUserPoliciesCommand, ListEntitiesForPolicyCommand, ListGroupPoliciesCommand, ListGroupsForUserCommand, ListPoliciesCommand, ListPolicyTagsCommand, ListPolicyVersionsCommand, ListUserPoliciesCommand, NoSuchEntityException, PutGroupPolicyCommand, PutRolePolicyCommand, PutUserPermissionsBoundaryCommand, PutUserPolicyCommand, RemoveRoleFromInstanceProfileCommand, RemoveUserFromGroupCommand, TagPolicyCommand, TagUserCommand, UntagPolicyCommand, UntagUserCommand, UpdateAccessKeyCommand, UpdateLoginProfileCommand } from "@aws-sdk/client-iam";
|
|
9
9
|
import { CreateQueueCommand, DeleteQueueCommand, GetQueueAttributesCommand, GetQueueUrlCommand, ListQueueTagsCommand, QueueDoesNotExist, SQSClient, SetQueueAttributesCommand, TagQueueCommand, UntagQueueCommand } from "@aws-sdk/client-sqs";
|
|
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, DeleteFunctionCommand, DeleteFunctionConcurrencyCommand, DeleteFunctionEventInvokeConfigCommand, DeleteFunctionUrlConfigCommand, DeleteLayerVersionCommand, GetEventSourceMappingCommand, GetFunctionCommand, GetFunctionConcurrencyCommand, GetFunctionEventInvokeConfigCommand, GetFunctionRecursionConfigCommand, GetFunctionUrlConfigCommand, GetLayerVersionByArnCommand, GetPolicyCommand as GetPolicyCommand$1, LambdaClient, ListTagsCommand, PublishLayerVersionCommand, PutFunctionConcurrencyCommand, PutFunctionEventInvokeConfigCommand, PutFunctionRecursionConfigCommand, RemovePermissionCommand, ResourceNotFoundException, TagResourceCommand as TagResourceCommand$1, UntagResourceCommand as UntagResourceCommand$1, UpdateEventSourceMappingCommand, UpdateFunctionCodeCommand, UpdateFunctionConfigurationCommand, UpdateFunctionUrlConfigCommand, waitUntilFunctionUpdatedV2 } from "@aws-sdk/client-lambda";
|
|
@@ -7600,27 +7600,12 @@ var SNSTopicProvider = class {
|
|
|
7600
7600
|
AttributeValue: dataProtectionPolicy
|
|
7601
7601
|
}));
|
|
7602
7602
|
}
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
AttributeName: `${protocol}SuccessFeedbackRoleArn`,
|
|
7610
|
-
AttributeValue: config["SuccessFeedbackRoleArn"]
|
|
7611
|
-
}));
|
|
7612
|
-
if (config["SuccessFeedbackSampleRate"]) await this.snsClient.send(new SetTopicAttributesCommand({
|
|
7613
|
-
TopicArn: topicArn,
|
|
7614
|
-
AttributeName: `${protocol}SuccessFeedbackSampleRate`,
|
|
7615
|
-
AttributeValue: stringifyValue(config["SuccessFeedbackSampleRate"])
|
|
7616
|
-
}));
|
|
7617
|
-
if (config["FailureFeedbackRoleArn"]) await this.snsClient.send(new SetTopicAttributesCommand({
|
|
7618
|
-
TopicArn: topicArn,
|
|
7619
|
-
AttributeName: `${protocol}FailureFeedbackRoleArn`,
|
|
7620
|
-
AttributeValue: config["FailureFeedbackRoleArn"]
|
|
7621
|
-
}));
|
|
7622
|
-
}
|
|
7623
|
-
}
|
|
7603
|
+
const deliveryStatusAttributes = buildDeliveryStatusAttributeMap(properties["DeliveryStatusLogging"], logicalId, "throw");
|
|
7604
|
+
for (const [attributeName, attributeValue] of deliveryStatusAttributes) await this.snsClient.send(new SetTopicAttributesCommand({
|
|
7605
|
+
TopicArn: topicArn,
|
|
7606
|
+
AttributeName: attributeName,
|
|
7607
|
+
AttributeValue: attributeValue
|
|
7608
|
+
}));
|
|
7624
7609
|
if (Array.isArray(properties["Subscription"])) {
|
|
7625
7610
|
const subscriptions = properties["Subscription"];
|
|
7626
7611
|
for (const sub of subscriptions) await this.subscribeInline(topicArn, sub, logicalId);
|
|
@@ -7727,24 +7712,24 @@ var SNSTopicProvider = class {
|
|
|
7727
7712
|
}
|
|
7728
7713
|
}
|
|
7729
7714
|
if (JSON.stringify(properties["DeliveryStatusLogging"]) !== JSON.stringify(previousProperties["DeliveryStatusLogging"])) {
|
|
7730
|
-
const
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
if (
|
|
7734
|
-
|
|
7735
|
-
AttributeName: `${protocol}SuccessFeedbackRoleArn`,
|
|
7736
|
-
AttributeValue: config["SuccessFeedbackRoleArn"]
|
|
7737
|
-
}));
|
|
7738
|
-
if (config["SuccessFeedbackSampleRate"]) await this.snsClient.send(new SetTopicAttributesCommand({
|
|
7715
|
+
const desiredAttributes = buildDeliveryStatusAttributeMap(properties["DeliveryStatusLogging"], logicalId, "throw");
|
|
7716
|
+
const previousAttributes = buildDeliveryStatusAttributeMap(previousProperties["DeliveryStatusLogging"], logicalId, "skip");
|
|
7717
|
+
for (const [attributeName, attributeValue] of desiredAttributes) {
|
|
7718
|
+
if (previousAttributes.get(attributeName) === attributeValue) continue;
|
|
7719
|
+
await this.snsClient.send(new SetTopicAttributesCommand({
|
|
7739
7720
|
TopicArn: physicalId,
|
|
7740
|
-
AttributeName:
|
|
7741
|
-
AttributeValue:
|
|
7721
|
+
AttributeName: attributeName,
|
|
7722
|
+
AttributeValue: attributeValue
|
|
7742
7723
|
}));
|
|
7743
|
-
|
|
7724
|
+
}
|
|
7725
|
+
for (const attributeName of previousAttributes.keys()) {
|
|
7726
|
+
if (desiredAttributes.has(attributeName)) continue;
|
|
7727
|
+
await this.snsClient.send(new SetTopicAttributesCommand({
|
|
7744
7728
|
TopicArn: physicalId,
|
|
7745
|
-
AttributeName:
|
|
7746
|
-
AttributeValue:
|
|
7729
|
+
AttributeName: attributeName,
|
|
7730
|
+
AttributeValue: deliveryStatusRemovalResetValue(attributeName)
|
|
7747
7731
|
}));
|
|
7732
|
+
this.logger.debug(`Reset removed delivery status attribute ${attributeName} for topic ${physicalId}`);
|
|
7748
7733
|
}
|
|
7749
7734
|
}
|
|
7750
7735
|
if (JSON.stringify(properties["Subscription"]) !== JSON.stringify(previousProperties["Subscription"])) await this.reconcileInlineSubscriptions(physicalId, previousProperties["Subscription"] || [], properties["Subscription"] || [], logicalId);
|
|
@@ -8075,6 +8060,76 @@ const SNS_DELIVERY_STATUS_PROTOCOLS = [
|
|
|
8075
8060
|
"SQS"
|
|
8076
8061
|
];
|
|
8077
8062
|
/**
|
|
8063
|
+
* The per-protocol attribute suffixes an inline `DeliveryStatusLogging`
|
|
8064
|
+
* entry maps to (`<Protocol><Suffix>` flat attribute names on the topic).
|
|
8065
|
+
*/
|
|
8066
|
+
const SNS_DELIVERY_STATUS_ATTRIBUTE_SUFFIXES = [
|
|
8067
|
+
"SuccessFeedbackRoleArn",
|
|
8068
|
+
"SuccessFeedbackSampleRate",
|
|
8069
|
+
"FailureFeedbackRoleArn"
|
|
8070
|
+
];
|
|
8071
|
+
/**
|
|
8072
|
+
* Flatten a CFn `DeliveryStatusLogging` array into the AWS flat attribute
|
|
8073
|
+
* map (`{LambdaSuccessFeedbackRoleArn: '...', ...}`) that
|
|
8074
|
+
* `SetTopicAttributes` consumes one entry at a time.
|
|
8075
|
+
*
|
|
8076
|
+
* Field presence is `!= null`, NOT truthiness, so
|
|
8077
|
+
* `SuccessFeedbackSampleRate: 0` is sent as `'0'` instead of being
|
|
8078
|
+
* silently skipped (the pre-#1160 truthiness gates dropped a 0 sample
|
|
8079
|
+
* rate on create and update alike).
|
|
8080
|
+
*
|
|
8081
|
+
* `onMalformed` picks the failure mode for a malformed container / entry
|
|
8082
|
+
* / unknown protocol: `'throw'` for the DESIRED side (a template error
|
|
8083
|
+
* must fail fast, naming the offending value), `'skip'` for the PREVIOUS
|
|
8084
|
+
* side (cdkd state — refusing a value an older binary recorded would make
|
|
8085
|
+
* the stack permanently undeployable, and an entry whose protocol cannot
|
|
8086
|
+
* be canonicalized maps to no attribute names anyway).
|
|
8087
|
+
*/
|
|
8088
|
+
function buildDeliveryStatusAttributeMap(logging, logicalId, onMalformed) {
|
|
8089
|
+
const map = /* @__PURE__ */ new Map();
|
|
8090
|
+
if (logging == null) return map;
|
|
8091
|
+
if (!Array.isArray(logging)) {
|
|
8092
|
+
if (onMalformed === "skip") return map;
|
|
8093
|
+
throw new Error(`SNS topic ${logicalId}: DeliveryStatusLogging must be an array of {Protocol, ...} objects, got ${JSON.stringify(logging)}`);
|
|
8094
|
+
}
|
|
8095
|
+
for (const entry of logging) {
|
|
8096
|
+
if (entry == null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
8097
|
+
if (onMalformed === "skip") continue;
|
|
8098
|
+
throw new Error(`SNS topic ${logicalId}: DeliveryStatusLogging entries must be {Protocol, ...} objects, got ${JSON.stringify(entry)}`);
|
|
8099
|
+
}
|
|
8100
|
+
const config = entry;
|
|
8101
|
+
let protocol;
|
|
8102
|
+
if (onMalformed === "throw") protocol = normalizeDeliveryStatusProtocolOrThrow(config["Protocol"], logicalId);
|
|
8103
|
+
else {
|
|
8104
|
+
const normalized = normalizeDeliveryStatusProtocol(config["Protocol"]);
|
|
8105
|
+
if (normalized === void 0) continue;
|
|
8106
|
+
protocol = normalized;
|
|
8107
|
+
}
|
|
8108
|
+
for (const suffix of SNS_DELIVERY_STATUS_ATTRIBUTE_SUFFIXES) {
|
|
8109
|
+
const value = config[suffix];
|
|
8110
|
+
if (value == null) continue;
|
|
8111
|
+
map.set(`${protocol}${suffix}`, stringifyValue(value));
|
|
8112
|
+
}
|
|
8113
|
+
}
|
|
8114
|
+
return map;
|
|
8115
|
+
}
|
|
8116
|
+
/**
|
|
8117
|
+
* The `SetTopicAttributes` value that resets a REMOVED per-protocol
|
|
8118
|
+
* delivery status attribute to its CloudFormation-removal state.
|
|
8119
|
+
*
|
|
8120
|
+
* Live CFn A/B (2026-08-10, issue #1160): removing `DeliveryStatusLogging`
|
|
8121
|
+
* from a template clears both RoleArn attributes (AWS accepts `''` as the
|
|
8122
|
+
* clear sentinel — the attribute disappears from `GetTopicAttributes`) and
|
|
8123
|
+
* explicitly resets `SuccessFeedbackSampleRate` to `'0'`. The `''`
|
|
8124
|
+
* sentinel is REJECTED for the sample rate ("value provided is not an
|
|
8125
|
+
* integer between 0-100"), so the numeric reset is the only wire shape
|
|
8126
|
+
* that clears it — the `'0'` attribute itself remains visible on the
|
|
8127
|
+
* topic afterwards, exactly as it does after a CloudFormation removal.
|
|
8128
|
+
*/
|
|
8129
|
+
function deliveryStatusRemovalResetValue(attributeName) {
|
|
8130
|
+
return attributeName.endsWith("SuccessFeedbackSampleRate") ? "0" : "";
|
|
8131
|
+
}
|
|
8132
|
+
/**
|
|
8078
8133
|
* Map a (possibly-mixed-case) protocol string from a CFn template to the
|
|
8079
8134
|
* canonical PascalCase prefix AWS expects on `${Protocol}<Suffix>`
|
|
8080
8135
|
* attribute names.
|
|
@@ -49069,6 +49124,208 @@ function isPlainObject(value) {
|
|
|
49069
49124
|
return typeof value === "object" && value !== null;
|
|
49070
49125
|
}
|
|
49071
49126
|
|
|
49127
|
+
//#endregion
|
|
49128
|
+
//#region src/analyzer/drift-principal-normalize.ts
|
|
49129
|
+
/**
|
|
49130
|
+
* IAM principal-form canonicalization for the drift comparator (issue #1515).
|
|
49131
|
+
*
|
|
49132
|
+
* AWS renders an IAM role / user principal inside a resource policy in TWO
|
|
49133
|
+
* forms and picks between them on its own schedule:
|
|
49134
|
+
*
|
|
49135
|
+
* - the ARN — `arn:aws:iam::<acct>:role/<name>`
|
|
49136
|
+
* - the principal's UNIQUE ID — `AROA…` (role) / `AIDA…` (user)
|
|
49137
|
+
*
|
|
49138
|
+
* The unique-id form is substituted when the referenced principal is
|
|
49139
|
+
* transiently unresolvable at write time (it is being created or replaced) and
|
|
49140
|
+
* AWS re-renders the ARN once it resolves. cdkd's deploy-time
|
|
49141
|
+
* `observedProperties` capture stores whichever form the read returned at that
|
|
49142
|
+
* moment, so a later `cdkd drift` can compare `AROA…` against the ARN for the
|
|
49143
|
+
* very same principal and report PERMANENT phantom drift — `--revert` writes
|
|
49144
|
+
* the recorded form back, AWS re-canonicalizes on write, and the next run
|
|
49145
|
+
* reports the identical difference (the class of issues #1096 / #1498, on a
|
|
49146
|
+
* different property).
|
|
49147
|
+
*
|
|
49148
|
+
* Unlike the order-normalization passes in `drift-normalize.ts`, this one
|
|
49149
|
+
* CANNOT be pure: the mapping between the two forms is not derivable from the
|
|
49150
|
+
* string. So the shape detection here is pure and an injected
|
|
49151
|
+
* {@link PrincipalUniqueIdResolver} does the one lookup, which lets the whole
|
|
49152
|
+
* pass be unit-tested without AWS and keeps the API cost at zero for the
|
|
49153
|
+
* overwhelmingly common case — a policy with no unique-id principal makes NO
|
|
49154
|
+
* AWS call at all.
|
|
49155
|
+
*
|
|
49156
|
+
* Both sides are rewritten to the ARN form, never one side only. The race that
|
|
49157
|
+
* produces the mismatch is symmetric (the 2026-08-10 evidence on the
|
|
49158
|
+
* `drift-revert` fixture had the baseline holding `AROA…` and AWS the ARN, but
|
|
49159
|
+
* the reverse ordering is equally reachable), and normalizing a single side is
|
|
49160
|
+
* the mistake `drift-normalize.ts`'s header already records for the unordered
|
|
49161
|
+
* passes — it manufactures drift on the `properties`-fallback baseline.
|
|
49162
|
+
*
|
|
49163
|
+
* FAILING IS VISIBLE, never silent: when the resolver cannot answer (the role
|
|
49164
|
+
* was deleted — which is exactly when AWS keeps the unique id forever — the
|
|
49165
|
+
* caller lacks `iam:GetRole`, or the ARN names another ACCOUNT / IAM PATH, for
|
|
49166
|
+
* which the name-only `GetRole` API would otherwise answer about the caller's
|
|
49167
|
+
* own same-named role), both sides are left untouched and the drift is still
|
|
49168
|
+
* reported. This pass only ever removes a difference it has PROVEN to be two
|
|
49169
|
+
* spellings of one principal; it can never hide a real principal change.
|
|
49170
|
+
*
|
|
49171
|
+
* One downstream note: because the comparator's inputs are canonicalized,
|
|
49172
|
+
* `cdkd drift --accept` records the ARN form for a policy subtree that drifts
|
|
49173
|
+
* for some OTHER reason while also carrying a canonicalized principal — i.e.
|
|
49174
|
+
* the accepted baseline can hold a spelling AWS did not literally return. That
|
|
49175
|
+
* is benign (it is the form AWS re-canonicalizes to, and a later run
|
|
49176
|
+
* normalizes either way) but it is a real difference from "state records
|
|
49177
|
+
* exactly what AWS said", so it is written down rather than left to be
|
|
49178
|
+
* rediscovered.
|
|
49179
|
+
*
|
|
49180
|
+
* Known bound: a policy carried as a JSON STRING rather than a parsed object is
|
|
49181
|
+
* not walked. Re-serializing a parsed string would risk changing its formatting
|
|
49182
|
+
* and manufacturing a different phantom drift, so the pass is scoped to the
|
|
49183
|
+
* object shape — which is what `AWS::S3::BucketPolicy` and the other
|
|
49184
|
+
* `PolicyDocument`-typed properties carry in cdkd state.
|
|
49185
|
+
*/
|
|
49186
|
+
/**
|
|
49187
|
+
* An IAM unique id as it appears in a rendered policy. The prefix set is
|
|
49188
|
+
* deliberately narrow — `AROA` (role) and `AIDA` (user) are the only two that
|
|
49189
|
+
* can stand in for an ARN at a `Principal.AWS` position; `AGPA` (group),
|
|
49190
|
+
* `AKIA` (access key) and friends are never rendered there.
|
|
49191
|
+
*/
|
|
49192
|
+
const PRINCIPAL_UNIQUE_ID_RE = /^A(?:ROA|IDA)[A-Z0-9]{6,}$/;
|
|
49193
|
+
/** An IAM role / user ARN — the two shapes a unique id can stand in for. */
|
|
49194
|
+
const IAM_PRINCIPAL_ARN_RE = /^arn:[a-z0-9-]+:iam::\d{12}:(role|user)\/(.+)$/;
|
|
49195
|
+
/**
|
|
49196
|
+
* Split an IAM role / user principal ARN into what the lookup API needs, or
|
|
49197
|
+
* `undefined` when the string is not one (a service principal, an
|
|
49198
|
+
* `assumed-role` STS ARN, `*`, …).
|
|
49199
|
+
*
|
|
49200
|
+
* Exported so the resolver in `drift.ts` recognizes exactly the ARNs
|
|
49201
|
+
* {@link collectPrincipalArns} collects — one regex, so the collector and the
|
|
49202
|
+
* lookup cannot drift apart and leave an ARN gathered but never resolvable.
|
|
49203
|
+
*/
|
|
49204
|
+
function parseIamPrincipalArn(arn) {
|
|
49205
|
+
const match = IAM_PRINCIPAL_ARN_RE.exec(arn);
|
|
49206
|
+
if (!match) return void 0;
|
|
49207
|
+
const name = match[2].split("/").pop();
|
|
49208
|
+
if (!name) return void 0;
|
|
49209
|
+
return {
|
|
49210
|
+
kind: match[1],
|
|
49211
|
+
name
|
|
49212
|
+
};
|
|
49213
|
+
}
|
|
49214
|
+
/** Every string at a `Principal` / `NotPrincipal` position, at any depth. */
|
|
49215
|
+
function collectPrincipalStrings(value, out) {
|
|
49216
|
+
if (Array.isArray(value)) {
|
|
49217
|
+
for (const element of value) collectPrincipalStrings(element, out);
|
|
49218
|
+
return;
|
|
49219
|
+
}
|
|
49220
|
+
if (!value || typeof value !== "object") return;
|
|
49221
|
+
for (const [key, member] of Object.entries(value)) {
|
|
49222
|
+
if (key === "Principal" || key === "NotPrincipal") pushPrincipalValue(member, out);
|
|
49223
|
+
collectPrincipalStrings(member, out);
|
|
49224
|
+
}
|
|
49225
|
+
}
|
|
49226
|
+
/**
|
|
49227
|
+
* The strings a `Principal` / `NotPrincipal` value contributes: the bare string
|
|
49228
|
+
* form, and the `AWS` member of the object form (string or array). `Service` /
|
|
49229
|
+
* `Federated` / `CanonicalUser` are deliberately NOT read — none of them can
|
|
49230
|
+
* carry an IAM unique id or a role ARN.
|
|
49231
|
+
*/
|
|
49232
|
+
function pushPrincipalValue(value, out) {
|
|
49233
|
+
if (typeof value === "string") {
|
|
49234
|
+
out.push(value);
|
|
49235
|
+
return;
|
|
49236
|
+
}
|
|
49237
|
+
if (Array.isArray(value)) {
|
|
49238
|
+
for (const element of value) if (typeof element === "string") out.push(element);
|
|
49239
|
+
return;
|
|
49240
|
+
}
|
|
49241
|
+
if (!value || typeof value !== "object") return;
|
|
49242
|
+
const awsMember = value["AWS"];
|
|
49243
|
+
if (typeof awsMember === "string") out.push(awsMember);
|
|
49244
|
+
else if (Array.isArray(awsMember)) {
|
|
49245
|
+
for (const element of awsMember) if (typeof element === "string") out.push(element);
|
|
49246
|
+
}
|
|
49247
|
+
}
|
|
49248
|
+
/**
|
|
49249
|
+
* Both interesting principal kinds in ONE walk — the pass runs per resource on
|
|
49250
|
+
* both comparison sides, so walking the bag twice to answer two questions about
|
|
49251
|
+
* the same strings is pure cost.
|
|
49252
|
+
*/
|
|
49253
|
+
function collectPrincipalForms(value) {
|
|
49254
|
+
const strings = [];
|
|
49255
|
+
collectPrincipalStrings(value, strings);
|
|
49256
|
+
const uniqueIds = /* @__PURE__ */ new Set();
|
|
49257
|
+
const arns = /* @__PURE__ */ new Set();
|
|
49258
|
+
for (const s of strings) if (PRINCIPAL_UNIQUE_ID_RE.test(s)) uniqueIds.add(s);
|
|
49259
|
+
else if (IAM_PRINCIPAL_ARN_RE.test(s)) arns.add(s);
|
|
49260
|
+
return {
|
|
49261
|
+
uniqueIds,
|
|
49262
|
+
arns
|
|
49263
|
+
};
|
|
49264
|
+
}
|
|
49265
|
+
/**
|
|
49266
|
+
* Replace every principal string that is a KNOWN unique id with the ARN it was
|
|
49267
|
+
* proven to stand for. Only `Principal` / `NotPrincipal` positions are touched
|
|
49268
|
+
* — a unique id appearing in, say, a `Condition` value is left alone, where the
|
|
49269
|
+
* two forms are NOT interchangeable.
|
|
49270
|
+
*/
|
|
49271
|
+
function rewritePrincipalUniqueIds(value, arnByUniqueId) {
|
|
49272
|
+
if (Array.isArray(value)) return value.map((el) => rewritePrincipalUniqueIds(el, arnByUniqueId));
|
|
49273
|
+
if (!value || typeof value !== "object") return value;
|
|
49274
|
+
const out = {};
|
|
49275
|
+
for (const [key, member] of Object.entries(value)) out[key] = key === "Principal" || key === "NotPrincipal" ? rewritePrincipalValue(member, arnByUniqueId) : rewritePrincipalUniqueIds(member, arnByUniqueId);
|
|
49276
|
+
return out;
|
|
49277
|
+
}
|
|
49278
|
+
function rewritePrincipalValue(value, arnByUniqueId) {
|
|
49279
|
+
const swap = (s) => typeof s === "string" ? arnByUniqueId.get(s) ?? s : rewritePrincipalUniqueIds(s, arnByUniqueId);
|
|
49280
|
+
if (typeof value === "string") return swap(value);
|
|
49281
|
+
if (Array.isArray(value)) return value.map(swap);
|
|
49282
|
+
if (!value || typeof value !== "object") return value;
|
|
49283
|
+
const out = {};
|
|
49284
|
+
for (const [key, member] of Object.entries(value)) {
|
|
49285
|
+
if (key !== "AWS") {
|
|
49286
|
+
out[key] = rewritePrincipalUniqueIds(member, arnByUniqueId);
|
|
49287
|
+
continue;
|
|
49288
|
+
}
|
|
49289
|
+
out[key] = Array.isArray(member) ? member.map(swap) : swap(member);
|
|
49290
|
+
}
|
|
49291
|
+
return out;
|
|
49292
|
+
}
|
|
49293
|
+
/**
|
|
49294
|
+
* Canonicalize the two comparison sides so that a principal AWS rendered as a
|
|
49295
|
+
* unique id on one side and as an ARN on the other stops reading as drift.
|
|
49296
|
+
*
|
|
49297
|
+
* Short-circuits — with NO resolver call — unless BOTH a unique id and an IAM
|
|
49298
|
+
* ARN are present across the two sides, since a unique id with no candidate ARN
|
|
49299
|
+
* opposite it has nothing to be equal to.
|
|
49300
|
+
*/
|
|
49301
|
+
async function canonicalizePrincipalUniqueIds(baseline, aws, resolve) {
|
|
49302
|
+
const baselineForms = collectPrincipalForms(baseline);
|
|
49303
|
+
const awsForms = collectPrincipalForms(aws);
|
|
49304
|
+
const uniqueIds = /* @__PURE__ */ new Set([...baselineForms.uniqueIds, ...awsForms.uniqueIds]);
|
|
49305
|
+
if (uniqueIds.size === 0) return {
|
|
49306
|
+
baseline,
|
|
49307
|
+
aws
|
|
49308
|
+
};
|
|
49309
|
+
const arns = /* @__PURE__ */ new Set([...baselineForms.arns, ...awsForms.arns]);
|
|
49310
|
+
if (arns.size === 0) return {
|
|
49311
|
+
baseline,
|
|
49312
|
+
aws
|
|
49313
|
+
};
|
|
49314
|
+
const arnByUniqueId = /* @__PURE__ */ new Map();
|
|
49315
|
+
for (const arn of arns) {
|
|
49316
|
+
const uniqueId = await resolve(arn);
|
|
49317
|
+
if (uniqueId !== void 0 && uniqueIds.has(uniqueId)) arnByUniqueId.set(uniqueId, arn);
|
|
49318
|
+
}
|
|
49319
|
+
if (arnByUniqueId.size === 0) return {
|
|
49320
|
+
baseline,
|
|
49321
|
+
aws
|
|
49322
|
+
};
|
|
49323
|
+
return {
|
|
49324
|
+
baseline: rewritePrincipalUniqueIds(baseline, arnByUniqueId),
|
|
49325
|
+
aws: rewritePrincipalUniqueIds(aws, arnByUniqueId)
|
|
49326
|
+
};
|
|
49327
|
+
}
|
|
49328
|
+
|
|
49072
49329
|
//#endregion
|
|
49073
49330
|
//#region src/analyzer/drift-cc-api-deny-list.ts
|
|
49074
49331
|
/**
|
|
@@ -49283,11 +49540,12 @@ async function driftCommand(stacks, options) {
|
|
|
49283
49540
|
registerAllProviders(providerRegistry);
|
|
49284
49541
|
providerRegistry.setCustomResourceResponseBucket(bucket);
|
|
49285
49542
|
const ccApiFallback = new CloudControlProvider();
|
|
49543
|
+
const resolvePrincipalUniqueId = createIamPrincipalUniqueIdResolver(awsClients);
|
|
49286
49544
|
const targetRefs = resolveTargetRefs(stacks, await stateBackend.listStacks(), options);
|
|
49287
49545
|
const reports = [];
|
|
49288
49546
|
for (const ref of targetRefs) {
|
|
49289
49547
|
if (!ref.region) throw new Error(`Stack '${ref.stackName}' has only a legacy state record without a region. Run 'cdkd deploy ${ref.stackName}' (or any cdkd write) to migrate it to the region-scoped layout, then re-run drift detection.`);
|
|
49290
|
-
const report = await runDriftForStack(ref.stackName, ref.region, stateBackend, providerRegistry, ccApiFallback);
|
|
49548
|
+
const report = await runDriftForStack(ref.stackName, ref.region, stateBackend, providerRegistry, ccApiFallback, resolvePrincipalUniqueId);
|
|
49291
49549
|
reports.push(report);
|
|
49292
49550
|
}
|
|
49293
49551
|
if (options.json) writeJsonReport(reports);
|
|
@@ -49349,13 +49607,75 @@ function resolveTargetRefs(stacks, stateRefs, options) {
|
|
|
49349
49607
|
return out;
|
|
49350
49608
|
}
|
|
49351
49609
|
/**
|
|
49610
|
+
* The live half of the #1515 principal canonicalization: resolve an IAM role /
|
|
49611
|
+
* user ARN to that principal's unique id (`AROA…` / `AIDA…`).
|
|
49612
|
+
*
|
|
49613
|
+
* Results are cached per ARN for the whole command — INCLUDING the failures, so
|
|
49614
|
+
* a deleted role (the case where AWS keeps the unique id forever, and therefore
|
|
49615
|
+
* the likeliest one to appear here) costs exactly one API call rather than one
|
|
49616
|
+
* per resource that references it.
|
|
49617
|
+
*
|
|
49618
|
+
* Every failure resolves to `undefined` rather than throwing: a missing
|
|
49619
|
+
* `iam:GetRole` permission, a cross-account principal, or a deleted role must
|
|
49620
|
+
* leave the comparison exactly as it was — the drift is then reported, which is
|
|
49621
|
+
* the safe direction. Drift detection must never fail because a cosmetic
|
|
49622
|
+
* normalization could not run.
|
|
49623
|
+
*
|
|
49624
|
+
* **The response ARN is compared back to the requested one, and that check is
|
|
49625
|
+
* what makes the "never hides a real change" claim true rather than aspirational.**
|
|
49626
|
+
* `GetRole` / `GetUser` are account-local and take a NAME, not an ARN, so the
|
|
49627
|
+
* lookup silently answers about the CALLER's account and about the wrong IAM
|
|
49628
|
+
* path: `arn:aws:iam::<other-acct>:role/Foo` and
|
|
49629
|
+
* `arn:aws:iam::<self>:role/prod/Foo` would both come back as this account's
|
|
49630
|
+
* root-path `Foo`, and the pass would then "prove" two DIFFERENT principals
|
|
49631
|
+
* equal and collapse a genuine drift. Round-tripping the ARN costs nothing and
|
|
49632
|
+
* turns both cases into an unresolved lookup, i.e. drift reported.
|
|
49633
|
+
*/
|
|
49634
|
+
function createIamPrincipalUniqueIdResolver(awsClients) {
|
|
49635
|
+
const cache = /* @__PURE__ */ new Map();
|
|
49636
|
+
let warnedOnDenied = false;
|
|
49637
|
+
return async (arn) => {
|
|
49638
|
+
if (cache.has(arn)) return cache.get(arn);
|
|
49639
|
+
let uniqueId;
|
|
49640
|
+
const principal = parseIamPrincipalArn(arn);
|
|
49641
|
+
if (principal) try {
|
|
49642
|
+
let entityArn;
|
|
49643
|
+
let entityId;
|
|
49644
|
+
if (principal.kind === "role") {
|
|
49645
|
+
const role = (await awsClients.iam.send(new GetRoleCommand({ RoleName: principal.name }))).Role;
|
|
49646
|
+
entityArn = role?.Arn;
|
|
49647
|
+
entityId = role?.RoleId;
|
|
49648
|
+
} else {
|
|
49649
|
+
const user = (await awsClients.iam.send(new GetUserCommand({ UserName: principal.name }))).User;
|
|
49650
|
+
entityArn = user?.Arn;
|
|
49651
|
+
entityId = user?.UserId;
|
|
49652
|
+
}
|
|
49653
|
+
if (entityArn !== void 0 && entityArn.toLowerCase() === arn.toLowerCase()) uniqueId = entityId;
|
|
49654
|
+
else getLogger().debug(`Principal ${arn} resolved to ${entityArn ?? "no entity"} — same name in this account or under another IAM path; leaving the policy principal comparison untouched.`);
|
|
49655
|
+
} catch (error) {
|
|
49656
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
49657
|
+
const name = error instanceof Error ? error.name : "";
|
|
49658
|
+
const status = error?.$metadata?.httpStatusCode;
|
|
49659
|
+
const denied = /^AccessDenied|^NotAuthorized/i.test(name) || status === 403;
|
|
49660
|
+
if (!warnedOnDenied && denied) {
|
|
49661
|
+
warnedOnDenied = true;
|
|
49662
|
+
getLogger().warn(`Cannot read IAM principals (${name || "access denied"}). A resource policy whose principal AWS rendered as a unique id (AROA…/AIDA…) may therefore report drift that is only a spelling difference; grant iam:GetRole / iam:GetUser to resolve it, or re-run with --verbose for the full error.`);
|
|
49663
|
+
}
|
|
49664
|
+
getLogger().debug(`Could not resolve the unique id of principal ${arn} (${message}); leaving the policy principal comparison untouched.`);
|
|
49665
|
+
if (isThrottlingError(error)) return void 0;
|
|
49666
|
+
}
|
|
49667
|
+
cache.set(arn, uniqueId);
|
|
49668
|
+
return uniqueId;
|
|
49669
|
+
};
|
|
49670
|
+
}
|
|
49671
|
+
/**
|
|
49352
49672
|
* Run drift detection for one stack and shape the per-resource outcomes
|
|
49353
49673
|
* into a {@link StackDriftReport}. The state object + etag are stored on
|
|
49354
49674
|
* the report so `--accept` can write back without a re-read, and
|
|
49355
49675
|
* `--revert` can pass the captured AWS-current snapshot to
|
|
49356
49676
|
* `provider.update` as the `previousProperties` argument.
|
|
49357
49677
|
*/
|
|
49358
|
-
async function runDriftForStack(stackName, region, stateBackend, providerRegistry, ccApiFallback) {
|
|
49678
|
+
async function runDriftForStack(stackName, region, stateBackend, providerRegistry, ccApiFallback, resolvePrincipalUniqueId) {
|
|
49359
49679
|
const result = await stateBackend.getState(stackName, region);
|
|
49360
49680
|
if (!result) throw new Error(`No state found for stack '${stackName}' (${region}). Run 'cdkd state list' to see available stacks.`);
|
|
49361
49681
|
return await withStackName(stackName, async () => {
|
|
@@ -49421,7 +49741,8 @@ async function runDriftForStack(stackName, region, stateBackend, providerRegistr
|
|
|
49421
49741
|
const useObserved = resource.observedProperties !== void 0;
|
|
49422
49742
|
const baseline = useObserved ? resource.observedProperties : resource.properties ?? {};
|
|
49423
49743
|
const observedIgnorePaths = useObserved ? undeclaredEmptyObservedKeys(resource.observedProperties, resource.properties ?? {}) : [];
|
|
49424
|
-
const
|
|
49744
|
+
const normalized = await canonicalizePrincipalUniqueIds(baseline, aws, resolvePrincipalUniqueId);
|
|
49745
|
+
const changes = calculateResourceDrift(normalized.baseline, normalized.aws, {
|
|
49425
49746
|
ignorePaths: observedIgnorePaths.length ? [...ignorePaths, ...observedIgnorePaths] : ignorePaths,
|
|
49426
49747
|
unionWalkObjects: useObserved,
|
|
49427
49748
|
unorderedPaths
|
|
@@ -66897,7 +67218,7 @@ function createMigrateCommand() {
|
|
|
66897
67218
|
*/
|
|
66898
67219
|
function buildProgram() {
|
|
66899
67220
|
const program = new Command();
|
|
66900
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.
|
|
67221
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.278.39");
|
|
66901
67222
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
66902
67223
|
const { profile } = actionCommand.optsWithGlobals();
|
|
66903
67224
|
if (profile !== void 0) process.env["AWS_PROFILE"] = profile;
|