@go-to-k/cdkd 0.51.9 → 0.52.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
@@ -13792,10 +13792,15 @@ var SNSTopicProvider = class {
13792
13792
  * `create()`'s behavior of only sending Tags when the template carries
13793
13793
  * them).
13794
13794
  *
13795
- * `DeliveryStatusLogging` is intentionally omitted: it fans out into
13796
- * per-protocol attributes (`{Protocol}SuccessFeedbackRoleArn`, etc.) whose
13797
- * round-trip back to the CFn array shape needs more thought than fits in
13798
- * this PR.
13795
+ * `DeliveryStatusLogging` is reverse-mapped from per-protocol flat
13796
+ * attributes (`{Protocol}SuccessFeedbackRoleArn` etc.) back to the CFn
13797
+ * array shape `[{Protocol, SuccessFeedbackRoleArn?, SuccessFeedbackSampleRate?,
13798
+ * FailureFeedbackRoleArn?}]`. Walks the known protocol prefix list
13799
+ * (`HTTP` / `HTTPS` / `SQS` / `Lambda` / `Firehose` / `Application`); a
13800
+ * protocol is included in the result iff at least one of its three
13801
+ * sub-attributes is set on the topic. Entries are sorted by `Protocol`
13802
+ * for stable positional compare (AWS does not preserve template order
13803
+ * across `GetTopicAttributes` calls).
13799
13804
  *
13800
13805
  * `Subscription` is omitted because CDK manages it via separate
13801
13806
  * `AWS::SNS::Subscription` resources, not as a Topic property.
@@ -13844,6 +13849,7 @@ var SNSTopicProvider = class {
13844
13849
  }
13845
13850
  }
13846
13851
  }
13852
+ result["DeliveryStatusLogging"] = mapDeliveryStatusLogging(attrs);
13847
13853
  try {
13848
13854
  const tagsResp = await this.snsClient.send(
13849
13855
  new ListTagsForResourceCommand({ ResourceArn: physicalId })
@@ -13858,16 +13864,13 @@ var SNSTopicProvider = class {
13858
13864
  return result;
13859
13865
  }
13860
13866
  /**
13861
- * `DeliveryStatusLogging` fans out to per-protocol attributes
13862
- * (`{Protocol}SuccessFeedbackRoleArn` etc.) whose round-trip back to the
13863
- * CFn array shape is not yet implemented; `Subscription` is managed via
13864
- * separate `AWS::SNS::Subscription` resources rather than the Topic
13865
- * itself. Both are absent from `readCurrentState`, so tell the drift
13866
- * comparator to skip them and avoid the guaranteed false-positive that
13867
- * would fire on every clean run when the user did template either.
13867
+ * Only `Subscription` remains drift-unknown CDK manages topic
13868
+ * subscriptions via separate `AWS::SNS::Subscription` resources, so the
13869
+ * inline `Topic.Subscription` property is intentionally not surfaced.
13870
+ * `DeliveryStatusLogging` is now reverse-mapped (see `readCurrentState`).
13868
13871
  */
13869
13872
  getDriftUnknownPaths() {
13870
- return ["DeliveryStatusLogging", "Subscription"];
13873
+ return ["Subscription"];
13871
13874
  }
13872
13875
  /**
13873
13876
  * Adopt an existing SNS topic into cdkd state.
@@ -13927,6 +13930,33 @@ var SNSTopicProvider = class {
13927
13930
  return null;
13928
13931
  }
13929
13932
  };
13933
+ var SNS_DELIVERY_STATUS_PROTOCOLS = [
13934
+ "Application",
13935
+ "Firehose",
13936
+ "HTTP",
13937
+ "HTTPS",
13938
+ "Lambda",
13939
+ "SQS"
13940
+ ];
13941
+ function mapDeliveryStatusLogging(attrs) {
13942
+ const result = [];
13943
+ for (const protocol of SNS_DELIVERY_STATUS_PROTOCOLS) {
13944
+ const success = attrs[`${protocol}SuccessFeedbackRoleArn`];
13945
+ const sample = attrs[`${protocol}SuccessFeedbackSampleRate`];
13946
+ const failure = attrs[`${protocol}FailureFeedbackRoleArn`];
13947
+ if (success === void 0 && sample === void 0 && failure === void 0)
13948
+ continue;
13949
+ const entry = { Protocol: protocol };
13950
+ if (success !== void 0)
13951
+ entry["SuccessFeedbackRoleArn"] = success;
13952
+ if (sample !== void 0)
13953
+ entry["SuccessFeedbackSampleRate"] = sample;
13954
+ if (failure !== void 0)
13955
+ entry["FailureFeedbackRoleArn"] = failure;
13956
+ result.push(entry);
13957
+ }
13958
+ return result;
13959
+ }
13930
13960
 
13931
13961
  // src/provisioning/providers/sns-subscription-provider.ts
13932
13962
  import {
@@ -17029,11 +17059,15 @@ var DynamoDBTableProvider = class {
17029
17059
  // src/provisioning/providers/logs-loggroup-provider.ts
17030
17060
  import {
17031
17061
  CreateLogGroupCommand,
17062
+ DeleteIndexPolicyCommand,
17032
17063
  DeleteLogGroupCommand,
17033
17064
  DescribeIndexPoliciesCommand,
17034
17065
  DescribeLogGroupsCommand,
17035
17066
  GetDataProtectionPolicyCommand,
17036
17067
  ListTagsForResourceCommand as ListTagsForResourceCommand2,
17068
+ PutBearerTokenAuthenticationCommand,
17069
+ PutIndexPolicyCommand,
17070
+ PutLogGroupDeletionProtectionCommand,
17037
17071
  PutRetentionPolicyCommand,
17038
17072
  DeleteRetentionPolicyCommand,
17039
17073
  TagResourceCommand as TagResourceCommand5,
@@ -17086,6 +17120,9 @@ var LogsLogGroupProvider = class {
17086
17120
  if (properties["LogGroupClass"]) {
17087
17121
  createParams.logGroupClass = properties["LogGroupClass"];
17088
17122
  }
17123
+ if (properties["DeletionProtectionEnabled"] !== void 0) {
17124
+ createParams.deletionProtectionEnabled = properties["DeletionProtectionEnabled"];
17125
+ }
17089
17126
  if (properties["Tags"]) {
17090
17127
  const cfnTags = properties["Tags"];
17091
17128
  createParams.tags = Object.fromEntries(cfnTags.map((t) => [t.Key, t.Value]));
@@ -17109,6 +17146,30 @@ var LogsLogGroupProvider = class {
17109
17146
  })
17110
17147
  );
17111
17148
  }
17149
+ const fieldIndexPolicies = properties["FieldIndexPolicies"];
17150
+ if (fieldIndexPolicies && fieldIndexPolicies.length > 0) {
17151
+ if (fieldIndexPolicies.length > 1) {
17152
+ this.logger.debug(
17153
+ `Log group ${logicalId} declares ${fieldIndexPolicies.length} FieldIndexPolicies; AWS only supports one log-group-level field index policy. Applying the first.`
17154
+ );
17155
+ }
17156
+ const first = fieldIndexPolicies[0];
17157
+ const policyDocument = typeof first === "string" ? first : JSON.stringify(first);
17158
+ await this.logsClient.send(
17159
+ new PutIndexPolicyCommand({
17160
+ logGroupIdentifier: logGroupName,
17161
+ policyDocument
17162
+ })
17163
+ );
17164
+ }
17165
+ if (properties["BearerTokenAuthenticationEnabled"] !== void 0) {
17166
+ await this.logsClient.send(
17167
+ new PutBearerTokenAuthenticationCommand({
17168
+ logGroupIdentifier: logGroupName,
17169
+ bearerTokenAuthenticationEnabled: properties["BearerTokenAuthenticationEnabled"]
17170
+ })
17171
+ );
17172
+ }
17112
17173
  this.logger.debug(`Successfully created log group ${logicalId}: ${logGroupName}`);
17113
17174
  const arn = await this.buildArn(logGroupName);
17114
17175
  return {
@@ -17141,7 +17202,10 @@ var LogsLogGroupProvider = class {
17141
17202
  /**
17142
17203
  * Update a CloudWatch Logs log group
17143
17204
  *
17144
- * Only RetentionInDays can be updated. LogGroupName is immutable (requires replacement).
17205
+ * Mutable: `RetentionInDays`, `DataProtectionPolicy`, `Tags`,
17206
+ * `DeletionProtectionEnabled`, `BearerTokenAuthenticationEnabled`,
17207
+ * `FieldIndexPolicies`. `LogGroupName` / `KmsKeyId` / `LogGroupClass`
17208
+ * are immutable on AWS-side and require replacement.
17145
17209
  */
17146
17210
  async update(logicalId, physicalId, _resourceType, properties, previousProperties) {
17147
17211
  this.logger.debug(`Updating log group ${logicalId}: ${physicalId}`);
@@ -17180,6 +17244,70 @@ var LogsLogGroupProvider = class {
17180
17244
  );
17181
17245
  }
17182
17246
  }
17247
+ if (properties["DeletionProtectionEnabled"] !== previousProperties["DeletionProtectionEnabled"]) {
17248
+ const next = properties["DeletionProtectionEnabled"];
17249
+ if (next !== void 0) {
17250
+ await this.logsClient.send(
17251
+ new PutLogGroupDeletionProtectionCommand({
17252
+ logGroupIdentifier: physicalId,
17253
+ deletionProtectionEnabled: next
17254
+ })
17255
+ );
17256
+ } else {
17257
+ await this.logsClient.send(
17258
+ new PutLogGroupDeletionProtectionCommand({
17259
+ logGroupIdentifier: physicalId,
17260
+ deletionProtectionEnabled: false
17261
+ })
17262
+ );
17263
+ }
17264
+ }
17265
+ if (properties["BearerTokenAuthenticationEnabled"] !== previousProperties["BearerTokenAuthenticationEnabled"]) {
17266
+ const next = properties["BearerTokenAuthenticationEnabled"];
17267
+ if (next !== void 0) {
17268
+ await this.logsClient.send(
17269
+ new PutBearerTokenAuthenticationCommand({
17270
+ logGroupIdentifier: physicalId,
17271
+ bearerTokenAuthenticationEnabled: next
17272
+ })
17273
+ );
17274
+ } else {
17275
+ await this.logsClient.send(
17276
+ new PutBearerTokenAuthenticationCommand({
17277
+ logGroupIdentifier: physicalId,
17278
+ bearerTokenAuthenticationEnabled: false
17279
+ })
17280
+ );
17281
+ }
17282
+ }
17283
+ const newFieldIndex = properties["FieldIndexPolicies"];
17284
+ const oldFieldIndex = previousProperties["FieldIndexPolicies"];
17285
+ if (JSON.stringify(newFieldIndex) !== JSON.stringify(oldFieldIndex)) {
17286
+ if (newFieldIndex && newFieldIndex.length > 0) {
17287
+ if (newFieldIndex.length > 1) {
17288
+ this.logger.debug(
17289
+ `Log group ${physicalId} declares ${newFieldIndex.length} FieldIndexPolicies; AWS only supports one log-group-level field index policy. Applying the first.`
17290
+ );
17291
+ }
17292
+ const first = newFieldIndex[0];
17293
+ const policyDocument = typeof first === "string" ? first : JSON.stringify(first);
17294
+ await this.logsClient.send(
17295
+ new PutIndexPolicyCommand({
17296
+ logGroupIdentifier: physicalId,
17297
+ policyDocument
17298
+ })
17299
+ );
17300
+ } else {
17301
+ try {
17302
+ await this.logsClient.send(
17303
+ new DeleteIndexPolicyCommand({ logGroupIdentifier: physicalId })
17304
+ );
17305
+ } catch (err) {
17306
+ if (!(err instanceof ResourceNotFoundException7))
17307
+ throw err;
17308
+ }
17309
+ }
17310
+ }
17183
17311
  const newTags = properties["Tags"];
17184
17312
  const oldTags = previousProperties["Tags"];
17185
17313
  if (JSON.stringify(newTags) !== JSON.stringify(oldTags)) {
@@ -17296,14 +17424,15 @@ var LogsLogGroupProvider = class {
17296
17424
  * `AWS::Logs::ResourcePolicy` resource type — account-wide, not
17297
17425
  * per-log-group).
17298
17426
  *
17299
- * Known limitation: cdkd's `create()` / `update()` flows do NOT yet
17300
- * apply `FieldIndexPolicies` / `DeletionProtectionEnabled` /
17301
- * `BearerTokenAuthenticationEnabled` they're in `handledProperties`
17302
- * to prevent CC API fallback but no actual `PutIndexPolicy` /
17303
- * `PutLogGroupDeletionProtection` / `PutBearerTokenAuthentication`
17304
- * calls fire. Surfacing these in `readCurrentState` means a user
17305
- * who templates them will see drift on the first run; a follow-up
17306
- * needs to wire the create/update flow.
17427
+ * Write-side coverage: `FieldIndexPolicies` is applied via
17428
+ * `PutIndexPolicy` (CloudWatch Logs allows at most one log-group-level
17429
+ * field index policy at a time, so the CFn array is effectively 0-or-1
17430
+ * the first entry is applied and a debug log notes any additional
17431
+ * entries are ignored). `DeletionProtectionEnabled` is forwarded as
17432
+ * part of `CreateLogGroup` and updated via
17433
+ * `PutLogGroupDeletionProtection`. `BearerTokenAuthenticationEnabled`
17434
+ * is applied via `PutBearerTokenAuthentication` after the log group
17435
+ * exists (it is not part of `CreateLogGroupRequest`).
17307
17436
  *
17308
17437
  * Tags are read via `ListTagsForResource` (using the log-group ARN from
17309
17438
  * the same `DescribeLogGroups` response). CDK's `aws:*` auto-tags are
@@ -33961,10 +34090,10 @@ var KMSProvider = class {
33961
34090
  * Dispatches by resource type:
33962
34091
  * - `AWS::KMS::Key` → `DescribeKey`. Surfaces `Description`, `KeySpec`,
33963
34092
  * `KeyUsage`, `Enabled`, `MultiRegion`, `Origin`. `KeyPolicy` is
33964
- * intentionally NOT retrieved `GetKeyPolicy` is a separate call
33965
- * and the policy body needs JSON parsing for comparison; deferred
33966
- * to a follow-up. `EnableKeyRotation` / `RotationPeriodInDays`
33967
- * would require `GetKeyRotationStatus`; also deferred.
34093
+ * additionally retrieved via `GetKeyPolicy` (URL-decoded JSON-parsed)
34094
+ * and `EnableKeyRotation` / `RotationPeriodInDays` via
34095
+ * `GetKeyRotationStatus` (Class 1 discriminator-gated on `KeySpec`
34096
+ * since asymmetric keys reject the call).
33968
34097
  * - `AWS::KMS::Alias` → `ListAliases` filtered to the alias name.
33969
34098
  * Surfaces `AliasName`, `TargetKeyId`. `ListAliases` is paginated
33970
34099
  * since there's no direct "describe one alias" API.
@@ -45210,7 +45339,7 @@ function reorderArgs(argv) {
45210
45339
  }
45211
45340
  async function main() {
45212
45341
  const program = new Command14();
45213
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.51.9");
45342
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.52.0");
45214
45343
  program.addCommand(createBootstrapCommand());
45215
45344
  program.addCommand(createSynthCommand());
45216
45345
  program.addCommand(createListCommand());