@go-to-k/cdkd 0.43.0 → 0.44.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
@@ -38050,6 +38050,128 @@ function isPlainObject(value) {
38050
38050
  return typeof value === "object" && value !== null;
38051
38051
  }
38052
38052
 
38053
+ // src/analyzer/drift-cc-api-deny-list.ts
38054
+ var CC_API_FALLBACK_DENY_LIST = {
38055
+ // AWS::IAM::ManagedPolicy: PolicyDocument round-trips through CC API
38056
+ // URL-encoded; cdkd state stores it as a parsed JSON object. Without
38057
+ // a per-type decoder, every comparison sees a string-vs-object
38058
+ // mismatch and fires drift on every run. The IAM Role provider's
38059
+ // first-class readCurrentState handles its inline AssumeRolePolicy
38060
+ // the same way (URL-decode + JSON-parse); the same fix pattern is
38061
+ // needed for ManagedPolicy when an SDK provider is added.
38062
+ "AWS::IAM::ManagedPolicy": "PolicyDocument is URL-encoded JSON in CC API responses, but cdkd state stores it as a parsed object \u2014 needs per-type decode",
38063
+ // AWS::ApiGateway::RestApi: the `Body` property (OpenAPI spec object
38064
+ // when supplied via `Body` rather than `BodyS3Location`) is write-only
38065
+ // — `GetRestApi` does NOT return it, but cdkd state preserves the
38066
+ // object the user passed in. CC API GetResource inherits this — the
38067
+ // returned shape omits `Body`, so every drift run flags it as
38068
+ // missing-on-AWS. Comparison silently dropping it would also be
38069
+ // wrong; the right move is a dedicated SDK provider that knows to
38070
+ // skip `Body` entirely.
38071
+ "AWS::ApiGateway::RestApi": "Body / BodyS3Location are write-only inputs not returned by CC API GetResource; cdkd state preserves them",
38072
+ // AWS::CloudFormation::Stack: nested stacks aren't supported by cdkd's
38073
+ // provider registry at all; the deploy / destroy paths reject them.
38074
+ // Listing here is defense-in-depth — if a user manually crafts state
38075
+ // with one, drift via CC API would compare CFn-template-input
38076
+ // properties against CC API's stack-output shape (CC API's
38077
+ // `AWS::CloudFormation::Stack` reports outputs / status, not the
38078
+ // template parameters cdkd would have stored).
38079
+ "AWS::CloudFormation::Stack": "CC API returns runtime stack state (outputs/status), not the template parameters cdkd state stores",
38080
+ // AWS::EC2::LaunchTemplate: `LaunchTemplateData` ships with deeply
38081
+ // structured sub-objects that CC API normalizes into a versioned shape
38082
+ // — every UpdateLaunchTemplate (and even GetLaunchTemplate) bumps the
38083
+ // returned default version, and CC API attaches a synthetic
38084
+ // `LatestVersionNumber` / `DefaultVersionNumber` next to the template
38085
+ // data that drift would surface as drift on the parent. Until an SDK
38086
+ // provider strips those, deny.
38087
+ "AWS::EC2::LaunchTemplate": "CC API returns version-bumped LaunchTemplateData with synthetic LatestVersionNumber that diverges from the CFn input shape"
38088
+ };
38089
+
38090
+ // src/analyzer/cc-api-strip.ts
38091
+ var ALWAYS_STRIPPED_FIELDS = /* @__PURE__ */ new Set([
38092
+ // Timestamps — AWS-managed, change on every modification. Names are
38093
+ // unambiguous: no CFn template ever exposes a "CreationDate" /
38094
+ // "LastModifiedTime" as a settable input.
38095
+ "CreationDate",
38096
+ "CreationTime",
38097
+ "CreatedTime",
38098
+ "CreatedDate",
38099
+ "CreatedAt",
38100
+ "LastModifiedDate",
38101
+ "LastModifiedTime",
38102
+ "LastModified",
38103
+ "LastUpdatedTime",
38104
+ "LastUpdatedDate",
38105
+ "UpdatedAt",
38106
+ // Owner / account / principal info — derived from the calling
38107
+ // principal, never user-set in a CFn template. `CreatedBy` /
38108
+ // `OwnerArn` are unique enough that no settable CFn property
38109
+ // collides with them.
38110
+ "OwnerId",
38111
+ "OwnerAccountId",
38112
+ "CreatedBy",
38113
+ "OwnerArn",
38114
+ // Lambda-specific generated identifiers. `RevisionId` rotates on
38115
+ // every operation; `LastUpdateStatus*` mirror runtime state. None
38116
+ // are settable in a CFn template.
38117
+ "RevisionId",
38118
+ "LastUpdateStatus",
38119
+ "LastUpdateStatusReason",
38120
+ "LastUpdateStatusReasonCode",
38121
+ // CloudFormation/Cloud Control passthrough metadata — never
38122
+ // appears as a settable input in a CFn template body.
38123
+ "StackId",
38124
+ "PhysicalResourceId",
38125
+ "LogicalResourceId"
38126
+ // Notes on intentional EXCLUSIONS:
38127
+ //
38128
+ // `State` / `Status` / `StateReason` / `StatusReason` — these
38129
+ // names ARE used by some CFn types as settable nested properties
38130
+ // (e.g. `AWS::ECS::CapacityProvider.AutoScalingGroupProvider.ManagedScaling.Status`,
38131
+ // `AWS::S3::Bucket.VersioningConfiguration.Status`). Stripping them
38132
+ // globally would cause false-positive drift on a clean stack.
38133
+ // The comparator already ignores AWS-only top-level `Status` values
38134
+ // because state doesn't carry them; only the nested-name-collision
38135
+ // cases would have leaked through, and excluding them here protects
38136
+ // those.
38137
+ //
38138
+ // `Arn` — many CFn types accept `Arn` as a settable property and
38139
+ // cdkd state may record it at create time. Drift on `Arn` is
38140
+ // genuine drift the user wants to see.
38141
+ //
38142
+ // `VersionId` / `GenerationId` / `ETag` — narrow utility (only S3
38143
+ // / KMS / ImageBuilder use these in their Get* responses), and at
38144
+ // least `VersionId` IS a settable input on `AWS::S3::Bucket`'s
38145
+ // versioning config. Per-provider readCurrentState handles them.
38146
+ //
38147
+ // `AccountId` / `StackName` — also collide with settable inputs
38148
+ // on a few CFn types (`AWS::CloudWatch::CrossAccountSharingRule.AccountId`,
38149
+ // `AWS::CloudFormation::HookDefaultVersion.StackName`).
38150
+ //
38151
+ // `StartTime` / `EndTime` — used as settable inputs in scheduling
38152
+ // shapes (e.g. `AWS::AutoScaling::ScheduledAction.StartTime`).
38153
+ ]);
38154
+ function stripCcApiAwsManagedFields(resourceType, awsProps) {
38155
+ return stripWalk(awsProps);
38156
+ }
38157
+ function stripWalk(value) {
38158
+ if (value === null || value === void 0)
38159
+ return value;
38160
+ if (Array.isArray(value)) {
38161
+ return value.map(stripWalk);
38162
+ }
38163
+ if (typeof value === "object") {
38164
+ const out = {};
38165
+ for (const [key, child] of Object.entries(value)) {
38166
+ if (ALWAYS_STRIPPED_FIELDS.has(key))
38167
+ continue;
38168
+ out[key] = stripWalk(child);
38169
+ }
38170
+ return out;
38171
+ }
38172
+ return value;
38173
+ }
38174
+
38053
38175
  // src/cli/commands/drift.ts
38054
38176
  var DriftDetectedError = class _DriftDetectedError extends CdkdError {
38055
38177
  silent = true;
@@ -38092,6 +38214,7 @@ async function driftCommand(stacks, options) {
38092
38214
  const providerRegistry = new ProviderRegistry();
38093
38215
  registerAllProviders(providerRegistry);
38094
38216
  providerRegistry.setCustomResourceResponseBucket(bucket);
38217
+ const ccApiFallback = new CloudControlProvider();
38095
38218
  const stateRefs = await stateBackend.listStacks();
38096
38219
  const targetRefs = resolveTargetRefs(stacks, stateRefs, options);
38097
38220
  const reports = [];
@@ -38105,7 +38228,8 @@ async function driftCommand(stacks, options) {
38105
38228
  ref.stackName,
38106
38229
  ref.region,
38107
38230
  stateBackend,
38108
- providerRegistry
38231
+ providerRegistry,
38232
+ ccApiFallback
38109
38233
  );
38110
38234
  reports.push(report);
38111
38235
  }
@@ -38176,7 +38300,7 @@ function resolveTargetRefs(stacks, stateRefs, options) {
38176
38300
  }
38177
38301
  return out;
38178
38302
  }
38179
- async function runDriftForStack(stackName, region, stateBackend, providerRegistry) {
38303
+ async function runDriftForStack(stackName, region, stateBackend, providerRegistry, ccApiFallback) {
38180
38304
  const result = await stateBackend.getState(stackName, region);
38181
38305
  if (!result) {
38182
38306
  throw new Error(
@@ -38202,27 +38326,39 @@ async function runDriftForStack(stackName, region, stateBackend, providerRegistr
38202
38326
  });
38203
38327
  continue;
38204
38328
  }
38205
- let readCurrentState = provider.readCurrentState?.bind(provider);
38206
- if (!readCurrentState) {
38207
- const ccApiProvider = providerRegistry.getCloudControlProvider?.();
38208
- if (ccApiProvider?.readCurrentState) {
38209
- readCurrentState = ccApiProvider.readCurrentState.bind(ccApiProvider);
38329
+ let aws;
38330
+ if (provider.readCurrentState) {
38331
+ aws = await provider.readCurrentState(
38332
+ resource.physicalId,
38333
+ logicalId,
38334
+ resource.resourceType,
38335
+ resource.properties ?? {}
38336
+ );
38337
+ } else {
38338
+ if (CC_API_FALLBACK_DENY_LIST[resource.resourceType]) {
38339
+ outcomes.push({
38340
+ kind: "unsupported",
38341
+ logicalId,
38342
+ resourceType: resource.resourceType
38343
+ });
38344
+ continue;
38210
38345
  }
38211
- }
38212
- if (!readCurrentState) {
38213
- outcomes.push({
38214
- kind: "unsupported",
38346
+ const ccApiAws = await ccApiFallback.readCurrentState(
38347
+ resource.physicalId,
38215
38348
  logicalId,
38216
- resourceType: resource.resourceType
38217
- });
38218
- continue;
38349
+ resource.resourceType,
38350
+ resource.properties ?? {}
38351
+ );
38352
+ if (ccApiAws === void 0) {
38353
+ outcomes.push({
38354
+ kind: "unsupported",
38355
+ logicalId,
38356
+ resourceType: resource.resourceType
38357
+ });
38358
+ continue;
38359
+ }
38360
+ aws = stripCcApiAwsManagedFields(resource.resourceType, ccApiAws);
38219
38361
  }
38220
- const aws = await readCurrentState(
38221
- resource.physicalId,
38222
- logicalId,
38223
- resource.resourceType,
38224
- resource.properties ?? {}
38225
- );
38226
38362
  if (aws === void 0) {
38227
38363
  outcomes.push({
38228
38364
  kind: "unsupported",
@@ -41760,7 +41896,7 @@ function reorderArgs(argv) {
41760
41896
  }
41761
41897
  async function main() {
41762
41898
  const program = new Command14();
41763
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.43.0");
41899
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.44.0");
41764
41900
  program.addCommand(createBootstrapCommand());
41765
41901
  program.addCommand(createSynthCommand());
41766
41902
  program.addCommand(createListCommand());