@go-to-k/cdkd 0.219.3 → 0.219.4

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
@@ -36484,9 +36484,87 @@ function createDiffCommand() {
36484
36484
  return cmd;
36485
36485
  }
36486
36486
 
36487
+ //#endregion
36488
+ //#region src/analyzer/drift-normalize.ts
36489
+ /**
36490
+ * Order-normalization helpers for the drift comparator.
36491
+ *
36492
+ * `cdkd drift` compares `resource.observedProperties ?? properties` (a
36493
+ * deploy-time AWS snapshot) against a later AWS read, and the comparator in
36494
+ * `drift-calculator.ts` compares arrays POSITIONALLY (no order normalization).
36495
+ * AWS does not guarantee element ordering across reads, so when AWS returns a
36496
+ * CFn tag list ({Key,Value}[]) or an AWS resource-id/ARN array (SubnetIds,
36497
+ * SecurityGroupIds, ...) in a different order between the deploy-time snapshot
36498
+ * and a later drift read, the reorder surfaces as PHANTOM drift even though
36499
+ * nothing actually changed.
36500
+ *
36501
+ * Both kinds are semantically UNORDERED sets, so we canonicalize (sort) them
36502
+ * on BOTH sides before the diff. These two passes were surfaced by dogfooding
36503
+ * the sibling cdk-real-drift (cdkrd) tool, which hit the same false-positive
36504
+ * classes against the same kind of AWS-snapshot baseline.
36505
+ */
36506
+ function canonicalizeTagListsDeep(v) {
36507
+ if (Array.isArray(v)) {
36508
+ const mapped = v.map(canonicalizeTagListsDeep);
36509
+ if (mapped.length > 0 && mapped.every((t) => t && typeof t === "object" && typeof t.Key === "string")) return [...mapped].sort((a, b) => {
36510
+ const ka = a.Key;
36511
+ const kb = b.Key;
36512
+ if (ka !== kb) return ka < kb ? -1 : 1;
36513
+ return JSON.stringify(a) < JSON.stringify(b) ? -1 : 1;
36514
+ });
36515
+ return mapped;
36516
+ }
36517
+ if (v && typeof v === "object") {
36518
+ const out = {};
36519
+ for (const [k, val] of Object.entries(v)) out[k] = canonicalizeTagListsDeep(val);
36520
+ return out;
36521
+ }
36522
+ return v;
36523
+ }
36524
+ const ID_RE = /^[a-z][a-z0-9]*-[0-9a-f]{6,}$/;
36525
+ const isIdLike = (s) => typeof s === "string" && (s.startsWith("arn:") || ID_RE.test(s));
36526
+ function canonicalizeIdArraysDeep(v) {
36527
+ if (Array.isArray(v)) {
36528
+ const mapped = v.map(canonicalizeIdArraysDeep);
36529
+ if (mapped.length > 1 && mapped.every(isIdLike)) return [...mapped].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
36530
+ return mapped;
36531
+ }
36532
+ if (v && typeof v === "object") {
36533
+ const out = {};
36534
+ for (const [k, val] of Object.entries(v)) out[k] = canonicalizeIdArraysDeep(val);
36535
+ return out;
36536
+ }
36537
+ return v;
36538
+ }
36539
+
36487
36540
  //#endregion
36488
36541
  //#region src/analyzer/drift-calculator.ts
36489
36542
  /**
36543
+ * Drift detection between cdkd state-recorded properties and AWS-current
36544
+ * properties.
36545
+ *
36546
+ * cdkd does not go through CloudFormation, so CFn-style drift detection
36547
+ * doesn't apply. Instead, the drift command asks each provider for its
36548
+ * `readCurrentState` snapshot and this module compares it against the
36549
+ * `properties` field saved in state.
36550
+ *
36551
+ * Comparison rules:
36552
+ *
36553
+ * - Only keys present in **state** are compared. AWS reports many
36554
+ * managed-by-AWS fields (timestamps, generated identifiers, account-
36555
+ * wide defaults, etc.) that cdkd never set; treating those as drift
36556
+ * would fire false positives on every resource. Mirrors the diff
36557
+ * calculator's "keys-only-in-old-side ignored" rule, but applied in
36558
+ * the opposite direction (state is now the authoritative side).
36559
+ * - Nested objects are compared structurally — a property change deep
36560
+ * inside (`VersioningConfiguration.Status`) surfaces with the dotted
36561
+ * path so the CLI output points at exactly the leaf that drifted.
36562
+ * - Arrays compare by element-wise structural equality. Re-ordered or
36563
+ * resized arrays surface as a single drift entry on the parent path
36564
+ * (we do not synthesize per-index drift entries — that's not useful
36565
+ * output).
36566
+ */
36567
+ /**
36490
36568
  * Compare cdkd state-recorded properties against AWS-current properties
36491
36569
  * and produce a flat list of property-level drifts.
36492
36570
  *
@@ -36522,6 +36600,8 @@ function calculateResourceDrift(stateProperties, awsProperties, options) {
36522
36600
  const drifts = [];
36523
36601
  const ignore = options?.ignorePaths ?? [];
36524
36602
  const union = options?.unionWalkObjects ?? false;
36603
+ stateProperties = canonicalizeIdArraysDeep(canonicalizeTagListsDeep(stateProperties));
36604
+ awsProperties = canonicalizeIdArraysDeep(canonicalizeTagListsDeep(awsProperties));
36525
36605
  for (const key of Object.keys(stateProperties)) {
36526
36606
  if (isIgnoredPath(key, ignore)) continue;
36527
36607
  diffAt(key, stateProperties[key], awsProperties[key], drifts, ignore, union);
@@ -52772,7 +52852,7 @@ function reorderArgs(argv) {
52772
52852
  async function main() {
52773
52853
  installPipeCloseHandler();
52774
52854
  const program = new Command();
52775
- program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.219.3");
52855
+ program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.219.4");
52776
52856
  program.addCommand(createBootstrapCommand());
52777
52857
  program.addCommand(createSynthCommand());
52778
52858
  program.addCommand(createListCommand());