@intentius/chant 0.62.0 → 0.63.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.
Files changed (107) hide show
  1. package/dist/cli/handlers/operator.d.ts +13 -0
  2. package/dist/cli/handlers/operator.d.ts.map +1 -1
  3. package/dist/cli/handlers/run.d.ts.map +1 -1
  4. package/dist/cli/main.d.ts.map +1 -1
  5. package/dist/cli/registry.d.ts +2 -0
  6. package/dist/cli/registry.d.ts.map +1 -1
  7. package/dist/components/cli-support.d.ts +3 -0
  8. package/dist/components/cli-support.d.ts.map +1 -1
  9. package/dist/components/driver-output.d.ts.map +1 -1
  10. package/dist/components/driver.d.ts +12 -0
  11. package/dist/components/driver.d.ts.map +1 -1
  12. package/dist/fold/fold.d.ts.map +1 -1
  13. package/dist/fold/subset.d.ts +10 -0
  14. package/dist/fold/subset.d.ts.map +1 -1
  15. package/dist/lifecycle/gate-ledger.d.ts +61 -0
  16. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  17. package/dist/lifecycle/index.d.ts +1 -0
  18. package/dist/lifecycle/index.d.ts.map +1 -1
  19. package/dist/lifecycle/plan-digest.d.ts +33 -0
  20. package/dist/lifecycle/plan-digest.d.ts.map +1 -0
  21. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  22. package/dist/op/activities/lexicon-upgrade.d.ts +14 -2
  23. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  24. package/dist/op/activities/lifecycle.d.ts +27 -0
  25. package/dist/op/activities/lifecycle.d.ts.map +1 -1
  26. package/dist/op/activities/reconcile.d.ts +196 -27
  27. package/dist/op/activities/reconcile.d.ts.map +1 -1
  28. package/dist/op/builders.d.ts +6 -0
  29. package/dist/op/builders.d.ts.map +1 -1
  30. package/dist/op/composites/apply-op.d.ts +6 -0
  31. package/dist/op/composites/apply-op.d.ts.map +1 -1
  32. package/dist/op/composites/reconcile-op.d.ts.map +1 -1
  33. package/dist/op/gate-summary.d.ts +16 -0
  34. package/dist/op/gate-summary.d.ts.map +1 -1
  35. package/dist/op/gate.d.ts +104 -13
  36. package/dist/op/gate.d.ts.map +1 -1
  37. package/dist/op/index.d.ts +3 -2
  38. package/dist/op/index.d.ts.map +1 -1
  39. package/dist/op/local-executor.d.ts +17 -0
  40. package/dist/op/local-executor.d.ts.map +1 -1
  41. package/dist/op/local-output.d.ts.map +1 -1
  42. package/dist/op/op-ir.d.ts +8 -1
  43. package/dist/op/op-ir.d.ts.map +1 -1
  44. package/dist/op/runtime.d.ts +2 -0
  45. package/dist/op/runtime.d.ts.map +1 -1
  46. package/dist/op/types.d.ts +19 -0
  47. package/dist/op/types.d.ts.map +1 -1
  48. package/dist/terraform/__fixtures__/build-graph.d.ts +8 -0
  49. package/dist/terraform/__fixtures__/build-graph.d.ts.map +1 -1
  50. package/dist/terraform/graph.d.ts +18 -2
  51. package/dist/terraform/graph.d.ts.map +1 -1
  52. package/dist/terraform/parse.d.ts.map +1 -1
  53. package/dist/terraform/types.d.ts +7 -0
  54. package/dist/terraform/types.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/cli/handlers/operator.test.ts +130 -0
  57. package/src/cli/handlers/operator.ts +56 -2
  58. package/src/cli/handlers/run.ts +19 -0
  59. package/src/cli/main.ts +2 -0
  60. package/src/cli/registry.ts +2 -0
  61. package/src/components/cli-support.ts +29 -4
  62. package/src/components/driver-output.ts +10 -0
  63. package/src/components/driver.test.ts +31 -0
  64. package/src/components/driver.ts +54 -8
  65. package/src/discovery/fold-import.test.ts +55 -0
  66. package/src/fold/fold.test.ts +152 -0
  67. package/src/fold/fold.ts +102 -2
  68. package/src/fold/subset-doc-parity.test.ts +35 -1
  69. package/src/fold/subset.ts +10 -0
  70. package/src/lifecycle/gate-ledger.test.ts +133 -1
  71. package/src/lifecycle/gate-ledger.ts +108 -0
  72. package/src/lifecycle/index.ts +1 -0
  73. package/src/lifecycle/plan-digest.test.ts +49 -0
  74. package/src/lifecycle/plan-digest.ts +86 -0
  75. package/src/lifecycle/run-ledger.ts +1 -0
  76. package/src/op/activities/lexicon-upgrade.test.ts +24 -12
  77. package/src/op/activities/lexicon-upgrade.ts +19 -3
  78. package/src/op/activities/lifecycle.ts +51 -2
  79. package/src/op/activities/reconcile.test.ts +512 -26
  80. package/src/op/activities/reconcile.ts +307 -34
  81. package/src/op/builders.ts +7 -1
  82. package/src/op/composites/apply-op.ts +16 -0
  83. package/src/op/composites/composites.test.ts +15 -2
  84. package/src/op/composites/reconcile-op.test.ts +18 -0
  85. package/src/op/composites/reconcile-op.ts +7 -1
  86. package/src/op/gate-summary.test.ts +33 -0
  87. package/src/op/gate-summary.ts +31 -0
  88. package/src/op/gate.test.ts +111 -1
  89. package/src/op/gate.ts +181 -23
  90. package/src/op/index.ts +5 -2
  91. package/src/op/local-executor.test.ts +226 -3
  92. package/src/op/local-executor.ts +61 -12
  93. package/src/op/local-output.test.ts +38 -0
  94. package/src/op/local-output.ts +24 -1
  95. package/src/op/op-ir.test.ts +22 -0
  96. package/src/op/op-ir.ts +9 -0
  97. package/src/op/runtime.ts +2 -0
  98. package/src/op/types.ts +19 -0
  99. package/src/terraform/__fixtures__/build-graph.ts +42 -0
  100. package/src/terraform/__fixtures__/carve-locals-data.test.ts +138 -0
  101. package/src/terraform/__fixtures__/depth-estate/main.tf +141 -0
  102. package/src/terraform/__fixtures__/depth-estate/terraform.tfstate +17 -0
  103. package/src/terraform/__fixtures__/depth-estate.test.ts +162 -0
  104. package/src/terraform/graph.test.ts +148 -1
  105. package/src/terraform/graph.ts +144 -6
  106. package/src/terraform/parse.ts +4 -1
  107. package/src/terraform/types.ts +7 -0
@@ -1,5 +1,6 @@
1
1
  import { exec } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
+ import { computePlanDigest } from "../../lifecycle/plan-digest";
3
4
 
4
5
  const execAsync = promisify(exec);
5
6
 
@@ -39,6 +40,40 @@ export interface LifecycleDiffResult {
39
40
  * `chant lifecycle diff --live`).
40
41
  */
41
42
  drifted: boolean;
43
+ /**
44
+ * This diff's identity (#2300) — the change set `chant lifecycle diff`
45
+ * reported, hashed. `ApplyOp` hands it to its gate step's `plan`, so an
46
+ * approval binds to the change set the approver read rather than to the
47
+ * next run of the Op.
48
+ *
49
+ * Computed over {@link normalizeDiffChangeSet}'s canonical form of
50
+ * `output`, so incidental whitespace does not read as a changed plan, while
51
+ * any added, removed or reworded row does.
52
+ */
53
+ planDigest: string;
54
+ }
55
+
56
+ /**
57
+ * The change set half of a `chant lifecycle diff` render, canonicalised for
58
+ * digesting (#2300).
59
+ *
60
+ * The diff render is line-oriented: section headers and the resource rows
61
+ * under them. Two runs over an unchanged environment print the same lines, so
62
+ * the lines are the change set. Normalising is deliberately minimal — CRLF to
63
+ * LF, trailing whitespace off each line, blank lines dropped — because
64
+ * anything more aggressive would start discarding rows, and a digest that
65
+ * discards rows is a digest that approves changes nobody saw.
66
+ *
67
+ * Unlike a terraform plan there is no timestamp to strip: the diff render
68
+ * carries none. If one is ever added it has to be dropped here, or every
69
+ * approval would be stale the moment it was written.
70
+ */
71
+ export function normalizeDiffChangeSet(output: string): string[] {
72
+ return output
73
+ .replace(/\r\n/g, "\n")
74
+ .split("\n")
75
+ .map((line) => line.replace(/\s+$/, ""))
76
+ .filter((line) => line !== "");
42
77
  }
43
78
 
44
79
  /**
@@ -59,6 +94,20 @@ function detectDrift(output: string): boolean {
59
94
  return DRIFT_HEADERS.some((h) => output.includes(`${h} (`) || output.includes(`\n${h}`));
60
95
  }
61
96
 
97
+ /**
98
+ * The identity of one `chant lifecycle diff` result (#2300). The environment
99
+ * and the `--live` flag are hashed alongside the change set because they say
100
+ * what the change set is *of*: the same rows against `staging` are not an
101
+ * approval to apply against `prod`.
102
+ */
103
+ function lifecycleDiffDigest(args: LifecycleDiffArgs, output: string): string {
104
+ return computePlanDigest("lifecycle-diff", {
105
+ env: args.env,
106
+ live: args.live === true,
107
+ changeSet: normalizeDiffChangeSet(output),
108
+ });
109
+ }
110
+
62
111
  /**
63
112
  * Run `chant lifecycle diff <env>` and return the output + structured drift
64
113
  * flag. Read-only; intended for use inside watch/observation Ops.
@@ -75,11 +124,11 @@ export async function lifecycleDiff(args: LifecycleDiffArgs, signal?: AbortSigna
75
124
  const { stdout, stderr } = await execAsync(`chant lifecycle diff ${args.env}${liveFlag}`, { signal });
76
125
  const output = `${stdout}${stderr}`.trim();
77
126
  if (output) console.log(output);
78
- return { output, exitCode: 0, drifted: detectDrift(output) };
127
+ return { output, exitCode: 0, drifted: detectDrift(output), planDigest: lifecycleDiffDigest(args, output) };
79
128
  } catch (err) {
80
129
  const e = err as { code?: number; stdout?: string; stderr?: string };
81
130
  const output = `${e.stdout ?? ""}${e.stderr ?? ""}`.trim();
82
131
  if (output) console.error(output);
83
- return { output, exitCode: e.code ?? 1, drifted: detectDrift(output) };
132
+ return { output, exitCode: e.code ?? 1, drifted: detectDrift(output), planDigest: lifecycleDiffDigest(args, output) };
84
133
  }
85
134
  }