@intentius/chant 0.57.0 → 0.59.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 (558) hide show
  1. package/dist/audit/catalog.d.ts +51 -1
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +36 -1
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts +26 -9
  6. package/dist/audit/discover.d.ts.map +1 -1
  7. package/dist/audit/lineage.d.ts +10 -0
  8. package/dist/audit/lineage.d.ts.map +1 -0
  9. package/dist/audit/prior-art.d.ts +385 -0
  10. package/dist/audit/prior-art.d.ts.map +1 -0
  11. package/dist/audit/proof.d.ts +16 -0
  12. package/dist/audit/proof.d.ts.map +1 -1
  13. package/dist/audit/report-html.d.ts.map +1 -1
  14. package/dist/audit/report-model.d.ts +8 -1
  15. package/dist/audit/report-model.d.ts.map +1 -1
  16. package/dist/audit/report.d.ts.map +1 -1
  17. package/dist/audit/rules-doc.d.ts +3 -0
  18. package/dist/audit/rules-doc.d.ts.map +1 -1
  19. package/dist/audit/secrets.d.ts +15 -0
  20. package/dist/audit/secrets.d.ts.map +1 -1
  21. package/dist/audit/terraform-state.d.ts +46 -0
  22. package/dist/audit/terraform-state.d.ts.map +1 -0
  23. package/dist/build.d.ts +17 -1
  24. package/dist/build.d.ts.map +1 -1
  25. package/dist/claimed-fields.d.ts +161 -0
  26. package/dist/claimed-fields.d.ts.map +1 -0
  27. package/dist/cli/build-params-cli.d.ts +2 -2
  28. package/dist/cli/command-group.d.ts +14 -0
  29. package/dist/cli/command-group.d.ts.map +1 -1
  30. package/dist/cli/commands/audit.d.ts +17 -1
  31. package/dist/cli/commands/audit.d.ts.map +1 -1
  32. package/dist/cli/commands/build.d.ts.map +1 -1
  33. package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
  34. package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
  35. package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
  36. package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
  37. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
  38. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
  39. package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
  40. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  41. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  42. package/dist/cli/commands/init.d.ts.map +1 -1
  43. package/dist/cli/commands/lint.d.ts +13 -0
  44. package/dist/cli/commands/lint.d.ts.map +1 -1
  45. package/dist/cli/commands/onboard.d.ts +2 -0
  46. package/dist/cli/commands/onboard.d.ts.map +1 -1
  47. package/dist/cli/handlers/build.d.ts.map +1 -1
  48. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  49. package/dist/cli/handlers/operator.d.ts +82 -16
  50. package/dist/cli/handlers/operator.d.ts.map +1 -1
  51. package/dist/cli/handlers/run.d.ts +49 -42
  52. package/dist/cli/handlers/run.d.ts.map +1 -1
  53. package/dist/cli/main.d.ts +12 -1
  54. package/dist/cli/main.d.ts.map +1 -1
  55. package/dist/cli/mcp/op-tools.d.ts +16 -1
  56. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  57. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  58. package/dist/cli/mcp/resources/context.d.ts.map +1 -1
  59. package/dist/cli/plugins.d.ts +22 -0
  60. package/dist/cli/plugins.d.ts.map +1 -1
  61. package/dist/cli/registry.d.ts +40 -9
  62. package/dist/cli/registry.d.ts.map +1 -1
  63. package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
  64. package/dist/components/auto-release.d.ts +10 -20
  65. package/dist/components/auto-release.d.ts.map +1 -1
  66. package/dist/components/capability.d.ts +4 -4
  67. package/dist/components/cli-support.d.ts +24 -22
  68. package/dist/components/cli-support.d.ts.map +1 -1
  69. package/dist/components/component.d.ts +21 -6
  70. package/dist/components/component.d.ts.map +1 -1
  71. package/dist/components/driver-output.d.ts.map +1 -1
  72. package/dist/components/driver.d.ts +73 -37
  73. package/dist/components/driver.d.ts.map +1 -1
  74. package/dist/components/index.d.ts +1 -2
  75. package/dist/components/index.d.ts.map +1 -1
  76. package/dist/components/manifest-persistence.d.ts +1 -9
  77. package/dist/components/manifest-persistence.d.ts.map +1 -1
  78. package/dist/components/run-progress.d.ts +6 -6
  79. package/dist/components/run-progress.d.ts.map +1 -1
  80. package/dist/components/verbs/run-agent.d.ts +10 -22
  81. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  82. package/dist/components/verbs/verify.d.ts +2 -2
  83. package/dist/deep-observation.d.ts +17 -0
  84. package/dist/deep-observation.d.ts.map +1 -1
  85. package/dist/detectLexicon.d.ts +13 -0
  86. package/dist/detectLexicon.d.ts.map +1 -1
  87. package/dist/discovery/files.d.ts +4 -4
  88. package/dist/discovery/fold-import.d.ts.map +1 -1
  89. package/dist/discovery/param-deps.d.ts +33 -0
  90. package/dist/discovery/param-deps.d.ts.map +1 -1
  91. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  92. package/dist/discovery/sandbox/config-wire.d.ts +2 -2
  93. package/dist/fold/foldable-helpers.d.ts +5 -1
  94. package/dist/fold/foldable-helpers.d.ts.map +1 -1
  95. package/dist/fold-provenance.d.ts +236 -0
  96. package/dist/fold-provenance.d.ts.map +1 -0
  97. package/dist/graph-ops.d.ts +1 -1
  98. package/dist/held-elsewhere.d.ts +85 -0
  99. package/dist/held-elsewhere.d.ts.map +1 -0
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/kubectl-context.d.ts +3 -3
  103. package/dist/lexicon-config.d.ts +4 -4
  104. package/dist/lexicon-plugin-helpers.d.ts +1 -1
  105. package/dist/lexicon.d.ts +273 -16
  106. package/dist/lexicon.d.ts.map +1 -1
  107. package/dist/lifecycle/change-set.d.ts +13 -0
  108. package/dist/lifecycle/change-set.d.ts.map +1 -1
  109. package/dist/lifecycle/deep-diff.d.ts +133 -6
  110. package/dist/lifecycle/deep-diff.d.ts.map +1 -1
  111. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  112. package/dist/lifecycle/gate-ledger.d.ts +79 -3
  113. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  114. package/dist/lifecycle/index.d.ts +1 -0
  115. package/dist/lifecycle/index.d.ts.map +1 -1
  116. package/dist/lifecycle/release-ledger.d.ts +2 -2
  117. package/dist/lifecycle/run-ledger.d.ts +53 -0
  118. package/dist/lifecycle/run-ledger.d.ts.map +1 -0
  119. package/dist/lifecycle/symptoms.d.ts +3 -3
  120. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  121. package/dist/lint/config.d.ts +81 -2
  122. package/dist/lint/config.d.ts.map +1 -1
  123. package/dist/lint/post-synth.d.ts +55 -2
  124. package/dist/lint/post-synth.d.ts.map +1 -1
  125. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
  126. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
  127. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
  128. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
  129. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
  130. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
  131. package/dist/lint/rules/comp/index.d.ts +1 -1
  132. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  133. package/dist/lint/rules/op/index.d.ts +16 -0
  134. package/dist/lint/rules/op/index.d.ts.map +1 -0
  135. package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
  136. package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
  137. package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
  138. package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
  139. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
  140. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
  141. package/dist/lint/rules/op/support.d.ts +12 -0
  142. package/dist/lint/rules/op/support.d.ts.map +1 -0
  143. package/dist/lint/suppressions.d.ts +108 -0
  144. package/dist/lint/suppressions.d.ts.map +1 -0
  145. package/dist/live-endpoint.d.ts +1 -1
  146. package/dist/op/activities/activity-contracts.d.ts +54 -0
  147. package/dist/op/activities/activity-contracts.d.ts.map +1 -0
  148. package/dist/op/activities/apply.d.ts +262 -0
  149. package/dist/op/activities/apply.d.ts.map +1 -0
  150. package/dist/op/activities/build.d.ts +13 -0
  151. package/dist/op/activities/build.d.ts.map +1 -0
  152. package/dist/op/activities/converge.d.ts +110 -0
  153. package/dist/op/activities/converge.d.ts.map +1 -0
  154. package/dist/op/activities/env-teardown.d.ts +76 -0
  155. package/dist/op/activities/env-teardown.d.ts.map +1 -0
  156. package/dist/op/activities/guard-validate.d.ts +64 -0
  157. package/dist/op/activities/guard-validate.d.ts.map +1 -0
  158. package/dist/op/activities/http-check.d.ts +34 -0
  159. package/dist/op/activities/http-check.d.ts.map +1 -0
  160. package/dist/op/activities/index.d.ts +31 -0
  161. package/dist/op/activities/index.d.ts.map +1 -0
  162. package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
  163. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
  164. package/dist/op/activities/lifecycle.d.ts +42 -0
  165. package/dist/op/activities/lifecycle.d.ts.map +1 -0
  166. package/dist/op/activities/pipeline-audit.d.ts +84 -0
  167. package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
  168. package/dist/op/activities/policy.d.ts +17 -0
  169. package/dist/op/activities/policy.d.ts.map +1 -0
  170. package/dist/op/activities/reconcile.d.ts +149 -0
  171. package/dist/op/activities/reconcile.d.ts.map +1 -0
  172. package/dist/op/activities/shell.d.ts +13 -0
  173. package/dist/op/activities/shell.d.ts.map +1 -0
  174. package/dist/op/activities/teardown.d.ts +10 -0
  175. package/dist/op/activities/teardown.d.ts.map +1 -0
  176. package/dist/op/activities/util.d.ts +7 -0
  177. package/dist/op/activities/util.d.ts.map +1 -0
  178. package/dist/op/activities/wait.d.ts +28 -0
  179. package/dist/op/activities/wait.d.ts.map +1 -0
  180. package/dist/op/activities/workflow-audit.d.ts +92 -0
  181. package/dist/op/activities/workflow-audit.d.ts.map +1 -0
  182. package/dist/op/activity-contract-registry.d.ts +76 -0
  183. package/dist/op/activity-contract-registry.d.ts.map +1 -0
  184. package/dist/op/activity-contract.d.ts +25 -18
  185. package/dist/op/activity-contract.d.ts.map +1 -1
  186. package/dist/op/activity-failure.d.ts +28 -0
  187. package/dist/op/activity-failure.d.ts.map +1 -0
  188. package/dist/op/activity-profiles.d.ts +118 -0
  189. package/dist/op/activity-profiles.d.ts.map +1 -0
  190. package/dist/op/activity-registry.d.ts +22 -38
  191. package/dist/op/activity-registry.d.ts.map +1 -1
  192. package/dist/op/activity-runtime.d.ts +3 -14
  193. package/dist/op/activity-runtime.d.ts.map +1 -1
  194. package/dist/op/builders.d.ts +85 -30
  195. package/dist/op/builders.d.ts.map +1 -1
  196. package/dist/op/change-signal.d.ts +91 -0
  197. package/dist/op/change-signal.d.ts.map +1 -0
  198. package/dist/op/composites/apply-op.d.ts +118 -0
  199. package/dist/op/composites/apply-op.d.ts.map +1 -0
  200. package/dist/op/composites/converge-op.d.ts +120 -0
  201. package/dist/op/composites/converge-op.d.ts.map +1 -0
  202. package/dist/op/composites/index.d.ts +26 -0
  203. package/dist/op/composites/index.d.ts.map +1 -0
  204. package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
  205. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
  206. package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
  207. package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
  208. package/dist/op/composites/reconcile-op.d.ts +57 -0
  209. package/dist/op/composites/reconcile-op.d.ts.map +1 -0
  210. package/dist/op/composites/watch-op.d.ts +60 -0
  211. package/dist/op/composites/watch-op.d.ts.map +1 -0
  212. package/dist/op/composites/workflow-audit-op.d.ts +57 -0
  213. package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
  214. package/dist/op/converge-rule.d.ts +12 -10
  215. package/dist/op/converge-rule.d.ts.map +1 -1
  216. package/dist/op/cron.d.ts +51 -0
  217. package/dist/op/cron.d.ts.map +1 -0
  218. package/dist/op/discover.d.ts +9 -0
  219. package/dist/op/discover.d.ts.map +1 -1
  220. package/dist/op/duration.d.ts +11 -0
  221. package/dist/op/duration.d.ts.map +1 -0
  222. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  223. package/dist/op/gate-name.d.ts +40 -0
  224. package/dist/op/gate-name.d.ts.map +1 -0
  225. package/dist/op/gate-summary.d.ts +43 -0
  226. package/dist/op/gate-summary.d.ts.map +1 -0
  227. package/dist/op/gate.d.ts +90 -0
  228. package/dist/op/gate.d.ts.map +1 -0
  229. package/dist/op/generate-pipeline.d.ts +9 -0
  230. package/dist/op/generate-pipeline.d.ts.map +1 -1
  231. package/dist/op/index.d.ts +29 -9
  232. package/dist/op/index.d.ts.map +1 -1
  233. package/dist/op/local-executor.d.ts +114 -28
  234. package/dist/op/local-executor.d.ts.map +1 -1
  235. package/dist/op/local-output.d.ts +11 -1
  236. package/dist/op/local-output.d.ts.map +1 -1
  237. package/dist/op/op-ir.d.ts +185 -0
  238. package/dist/op/op-ir.d.ts.map +1 -0
  239. package/dist/op/op-verb-class.d.ts +10 -2
  240. package/dist/op/op-verb-class.d.ts.map +1 -1
  241. package/dist/op/operator.d.ts +93 -5
  242. package/dist/op/operator.d.ts.map +1 -1
  243. package/dist/op/receipt-store.d.ts +1 -1
  244. package/dist/op/receipt-store.d.ts.map +1 -1
  245. package/dist/op/resource.d.ts +15 -1
  246. package/dist/op/resource.d.ts.map +1 -1
  247. package/dist/op/runtime.d.ts +200 -0
  248. package/dist/op/runtime.d.ts.map +1 -0
  249. package/dist/op/runtimes/local.d.ts +29 -0
  250. package/dist/op/runtimes/local.d.ts.map +1 -0
  251. package/dist/op/step-output-ref.d.ts +15 -13
  252. package/dist/op/step-output-ref.d.ts.map +1 -1
  253. package/dist/op/types.d.ts +96 -29
  254. package/dist/op/types.d.ts.map +1 -1
  255. package/dist/ownership.d.ts +1 -1
  256. package/dist/provenance.d.ts +21 -0
  257. package/dist/provenance.d.ts.map +1 -1
  258. package/dist/serializer-walker.d.ts.map +1 -1
  259. package/dist/terraform/bridge.d.ts +26 -7
  260. package/dist/terraform/bridge.d.ts.map +1 -1
  261. package/dist/terraform/carve-provider.d.ts +28 -2
  262. package/dist/terraform/carve-provider.d.ts.map +1 -1
  263. package/dist/terraform/data-source-shape.d.ts +77 -0
  264. package/dist/terraform/data-source-shape.d.ts.map +1 -0
  265. package/dist/terraform/graph.d.ts.map +1 -1
  266. package/dist/terraform/providers/kubernetes.d.ts +5 -0
  267. package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
  268. package/dist/terraform/tier-map.d.ts +16 -4
  269. package/dist/terraform/tier-map.d.ts.map +1 -1
  270. package/dist/terraform/types.d.ts +8 -0
  271. package/dist/terraform/types.d.ts.map +1 -1
  272. package/package.json +6 -1
  273. package/src/audit/catalog.test.ts +79 -3
  274. package/src/audit/catalog.ts +111 -13
  275. package/src/audit/core.test.ts +26 -0
  276. package/src/audit/core.ts +84 -18
  277. package/src/audit/discover.test.ts +39 -0
  278. package/src/audit/discover.ts +202 -18
  279. package/src/audit/lineage.ts +100 -0
  280. package/src/audit/prior-art.ts +153 -0
  281. package/src/audit/proof.test.ts +67 -0
  282. package/src/audit/proof.ts +70 -0
  283. package/src/audit/report-html.ts +9 -4
  284. package/src/audit/report-model.ts +16 -2
  285. package/src/audit/report.test.ts +33 -0
  286. package/src/audit/report.ts +5 -3
  287. package/src/audit/rules-doc.test.ts +34 -2
  288. package/src/audit/rules-doc.ts +82 -9
  289. package/src/audit/secrets.ts +15 -3
  290. package/src/audit/terraform-state.test.ts +144 -0
  291. package/src/audit/terraform-state.ts +131 -0
  292. package/src/build.ts +31 -1
  293. package/src/claimed-fields.test.ts +145 -0
  294. package/src/claimed-fields.ts +208 -0
  295. package/src/cli/build-params-cli.ts +2 -2
  296. package/src/cli/command-group.ts +14 -0
  297. package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
  298. package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
  299. package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
  300. package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
  301. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
  302. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
  303. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
  304. package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
  305. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
  306. package/src/cli/commands/audit.test.ts +191 -11
  307. package/src/cli/commands/audit.ts +78 -28
  308. package/src/cli/commands/build.test.ts +330 -9
  309. package/src/cli/commands/build.ts +170 -24
  310. package/src/cli/commands/carve-bridge.test.ts +237 -14
  311. package/src/cli/commands/carve-bridge.ts +21 -17
  312. package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
  313. package/src/cli/commands/check-lexicon-docs.ts +1 -1
  314. package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
  315. package/src/cli/commands/check-lexicon-examples.ts +42 -10
  316. package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
  317. package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
  318. package/src/cli/commands/init-lexicon.test.ts +97 -2
  319. package/src/cli/commands/init-lexicon.ts +4 -2
  320. package/src/cli/commands/init.test.ts +35 -1
  321. package/src/cli/commands/init.ts +14 -3
  322. package/src/cli/commands/lint.test.ts +194 -1
  323. package/src/cli/commands/lint.ts +205 -7
  324. package/src/cli/commands/onboard.test.ts +75 -0
  325. package/src/cli/commands/onboard.ts +54 -23
  326. package/src/cli/handlers/build.test.ts +81 -1
  327. package/src/cli/handlers/build.ts +15 -1
  328. package/src/cli/handlers/graph.test.ts +3 -3
  329. package/src/cli/handlers/lifecycle.test.ts +195 -12
  330. package/src/cli/handlers/lifecycle.ts +123 -6
  331. package/src/cli/handlers/misc.ts +1 -1
  332. package/src/cli/handlers/operator.test.ts +183 -11
  333. package/src/cli/handlers/operator.ts +341 -55
  334. package/src/cli/handlers/run.test.ts +568 -1295
  335. package/src/cli/handlers/run.ts +446 -912
  336. package/src/cli/main.test.ts +22 -16
  337. package/src/cli/main.ts +66 -33
  338. package/src/cli/mcp/op-tools.ts +147 -88
  339. package/src/cli/mcp/resource-handlers.ts +10 -37
  340. package/src/cli/mcp/resources/context.ts +11 -12
  341. package/src/cli/mcp/server.test.ts +25 -27
  342. package/src/cli/mcp/server.ts +2 -2
  343. package/src/cli/plugins.test.ts +68 -2
  344. package/src/cli/plugins.ts +39 -0
  345. package/src/cli/registry.ts +40 -9
  346. package/src/codegen/docs.ts +1 -1
  347. package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
  348. package/src/codegen/generate-post-synth-barrel.ts +1 -1
  349. package/src/components/README.md +4 -3
  350. package/src/components/__fixtures__/neo4j-fanout.json +1 -1
  351. package/src/components/auto-release.test.ts +4 -20
  352. package/src/components/auto-release.ts +17 -42
  353. package/src/components/capability.ts +4 -4
  354. package/src/components/cli-support.test.ts +28 -12
  355. package/src/components/cli-support.ts +60 -47
  356. package/src/components/component-schema.test.ts +18 -2
  357. package/src/components/component.schema.json +18 -5
  358. package/src/components/component.test.ts +2 -2
  359. package/src/components/component.ts +27 -7
  360. package/src/components/config-defaults.test.ts +2 -2
  361. package/src/components/driver-output.ts +14 -2
  362. package/src/components/driver.test.ts +109 -20
  363. package/src/components/driver.ts +201 -84
  364. package/src/components/index.ts +1 -6
  365. package/src/components/manifest-persistence.test.ts +2 -20
  366. package/src/components/manifest-persistence.ts +4 -24
  367. package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
  368. package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
  369. package/src/components/run-progress.ts +6 -6
  370. package/src/components/verbs/run-agent.test.ts +19 -0
  371. package/src/components/verbs/run-agent.ts +12 -24
  372. package/src/components/verbs/verify.ts +2 -2
  373. package/src/deep-observation.test.ts +75 -0
  374. package/src/deep-observation.ts +48 -0
  375. package/src/detectLexicon.ts +18 -1
  376. package/src/discovery/collect.test.ts +3 -3
  377. package/src/discovery/files.ts +4 -4
  378. package/src/discovery/fold-import.test.ts +1 -1
  379. package/src/discovery/fold-import.ts +105 -2
  380. package/src/discovery/param-deps.test.ts +112 -1
  381. package/src/discovery/param-deps.ts +193 -0
  382. package/src/discovery/sandbox/bundle.ts +15 -1
  383. package/src/discovery/sandbox/config-wire.test.ts +2 -2
  384. package/src/discovery/sandbox/config-wire.ts +2 -2
  385. package/src/fold/fold.test.ts +56 -0
  386. package/src/fold/foldable-helpers.ts +82 -2
  387. package/src/fold-provenance-exclusion.test.ts +186 -0
  388. package/src/fold-provenance.test.ts +495 -0
  389. package/src/fold-provenance.ts +441 -0
  390. package/src/graph-ops.test.ts +3 -3
  391. package/src/graph-ops.ts +1 -1
  392. package/src/held-elsewhere.test.ts +102 -0
  393. package/src/held-elsewhere.ts +114 -0
  394. package/src/index.ts +3 -0
  395. package/src/kubectl-context.ts +3 -3
  396. package/src/lexicon-config.test.ts +5 -5
  397. package/src/lexicon-config.ts +4 -4
  398. package/src/lexicon-plugin-helpers.ts +1 -1
  399. package/src/lexicon.ts +296 -16
  400. package/src/lifecycle/change-set.test.ts +49 -0
  401. package/src/lifecycle/change-set.ts +67 -0
  402. package/src/lifecycle/converge-ledger.ts +1 -1
  403. package/src/lifecycle/deep-diff.test.ts +267 -14
  404. package/src/lifecycle/deep-diff.ts +217 -14
  405. package/src/lifecycle/deep-observe.test.ts +3 -1
  406. package/src/lifecycle/deep-observe.ts +16 -6
  407. package/src/lifecycle/gate-ledger.test.ts +74 -2
  408. package/src/lifecycle/gate-ledger.ts +154 -36
  409. package/src/lifecycle/index.ts +1 -0
  410. package/src/lifecycle/release-ledger.ts +2 -2
  411. package/src/lifecycle/run-ledger.test.ts +268 -0
  412. package/src/lifecycle/run-ledger.ts +201 -0
  413. package/src/lifecycle/symptoms.ts +3 -3
  414. package/src/lint/config.test.ts +82 -1
  415. package/src/lint/config.ts +112 -3
  416. package/src/lint/pipeline-change-gate.test.ts +2 -2
  417. package/src/lint/policy.test.ts +1 -1
  418. package/src/lint/post-synth.test.ts +31 -0
  419. package/src/lint/post-synth.ts +54 -1
  420. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
  421. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
  422. package/src/lint/rules/comp/comp.test.ts +27 -1
  423. package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
  424. package/src/lint/rules/comp/index.ts +3 -3
  425. package/src/lint/rules/op/index.ts +23 -0
  426. package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
  427. package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
  428. package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
  429. package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
  430. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
  431. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
  432. package/src/lint/rules/op/support.ts +11 -0
  433. package/src/lint/suppressions.test.ts +163 -0
  434. package/src/lint/suppressions.ts +204 -0
  435. package/src/live-endpoint.ts +1 -1
  436. package/src/op/activities/activity-contracts.ts +66 -0
  437. package/src/op/activities/apply.test.ts +567 -0
  438. package/src/op/activities/apply.ts +662 -0
  439. package/src/op/activities/build.ts +26 -0
  440. package/src/op/activities/converge.test.ts +330 -0
  441. package/src/op/activities/converge.ts +449 -0
  442. package/src/op/activities/env-teardown.test.ts +187 -0
  443. package/src/op/activities/env-teardown.ts +171 -0
  444. package/src/op/activities/guard-validate.test.ts +139 -0
  445. package/src/op/activities/guard-validate.ts +223 -0
  446. package/src/op/activities/http-check.test.ts +48 -0
  447. package/src/op/activities/http-check.ts +55 -0
  448. package/src/op/activities/index.ts +119 -0
  449. package/src/op/activities/lexicon-upgrade.test.ts +492 -0
  450. package/src/op/activities/lexicon-upgrade.ts +673 -0
  451. package/src/op/activities/lifecycle.ts +85 -0
  452. package/src/op/activities/pipeline-audit.test.ts +67 -0
  453. package/src/op/activities/pipeline-audit.ts +201 -0
  454. package/src/op/activities/policy.test.ts +19 -0
  455. package/src/op/activities/policy.ts +37 -0
  456. package/src/op/activities/reconcile.test.ts +161 -0
  457. package/src/op/activities/reconcile.ts +354 -0
  458. package/src/op/activities/shell.ts +26 -0
  459. package/src/op/activities/teardown.ts +22 -0
  460. package/src/op/activities/util.ts +6 -0
  461. package/src/op/activities/wait.ts +69 -0
  462. package/src/op/activities/workflow-audit.test.ts +90 -0
  463. package/src/op/activities/workflow-audit.ts +203 -0
  464. package/src/op/activity-contract-registry.test.ts +98 -0
  465. package/src/op/activity-contract-registry.ts +114 -0
  466. package/src/op/activity-contract.test.ts +1 -1
  467. package/src/op/activity-contract.ts +37 -33
  468. package/src/op/activity-failure.ts +34 -0
  469. package/src/op/activity-profiles.test.ts +56 -0
  470. package/src/op/activity-profiles.ts +116 -0
  471. package/src/op/activity-registry.test.ts +37 -28
  472. package/src/op/activity-registry.ts +27 -56
  473. package/src/op/activity-runtime.ts +3 -47
  474. package/src/op/builders-exports.test.ts +0 -49
  475. package/src/op/builders-typed.test.ts +164 -0
  476. package/src/op/builders.ts +125 -41
  477. package/src/op/change-signal.test.ts +117 -0
  478. package/src/op/change-signal.ts +169 -0
  479. package/src/op/composites/apply-op.ts +218 -0
  480. package/src/op/composites/composites.test.ts +379 -0
  481. package/src/op/composites/converge-op.test.ts +168 -0
  482. package/src/op/composites/converge-op.ts +214 -0
  483. package/src/op/composites/index.ts +26 -0
  484. package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
  485. package/src/op/composites/lexicon-upgrade-op.ts +134 -0
  486. package/src/op/composites/pipeline-audit-op.test.ts +25 -0
  487. package/src/op/composites/pipeline-audit-op.ts +78 -0
  488. package/src/op/composites/reconcile-op.test.ts +51 -0
  489. package/src/op/composites/reconcile-op.ts +110 -0
  490. package/src/op/composites/watch-op.ts +108 -0
  491. package/src/op/composites/workflow-audit-op.test.ts +25 -0
  492. package/src/op/composites/workflow-audit-op.ts +88 -0
  493. package/src/op/converge-rule.ts +12 -10
  494. package/src/op/cron.test.ts +128 -0
  495. package/src/op/cron.ts +149 -0
  496. package/src/op/discover-root.test.ts +105 -1
  497. package/src/op/discover.test.ts +6 -2
  498. package/src/op/discover.ts +84 -16
  499. package/src/op/duration.ts +21 -0
  500. package/src/op/effect-step.test.ts +29 -14
  501. package/src/op/emulator-lifecycle.ts +1 -2
  502. package/src/op/gate-name.test.ts +65 -0
  503. package/src/op/gate-name.ts +60 -0
  504. package/src/op/gate-summary.ts +84 -0
  505. package/src/op/gate.ts +155 -0
  506. package/src/op/generate-pipeline.test.ts +65 -3
  507. package/src/op/generate-pipeline.ts +19 -2
  508. package/src/op/index.ts +48 -8
  509. package/src/op/local-executor.test.ts +178 -34
  510. package/src/op/local-executor.ts +371 -102
  511. package/src/op/local-output.test.ts +95 -11
  512. package/src/op/local-output.ts +33 -4
  513. package/src/op/op-ir.test.ts +292 -0
  514. package/src/op/op-ir.ts +419 -0
  515. package/src/op/op-verb-class.test.ts +2 -2
  516. package/src/op/op-verb-class.ts +19 -5
  517. package/src/op/op.test.ts +28 -7
  518. package/src/op/operator.test.ts +543 -6
  519. package/src/op/operator.ts +203 -20
  520. package/src/op/receipt-store.ts +1 -1
  521. package/src/op/resource.ts +20 -2
  522. package/src/op/runtime.ts +203 -0
  523. package/src/op/runtimes/local.test.ts +181 -0
  524. package/src/op/runtimes/local.ts +212 -0
  525. package/src/op/step-output-ref.ts +15 -13
  526. package/src/op/types.ts +106 -26
  527. package/src/ownership.ts +1 -1
  528. package/src/provenance.test.ts +6 -0
  529. package/src/provenance.ts +21 -1
  530. package/src/serializer-walker.test.ts +42 -0
  531. package/src/serializer-walker.ts +21 -2
  532. package/src/terraform/aws-resources.test.ts +13 -4
  533. package/src/terraform/bridge.test.ts +22 -9
  534. package/src/terraform/bridge.ts +89 -28
  535. package/src/terraform/carve-provider.ts +38 -2
  536. package/src/terraform/data-source-shape.ts +95 -0
  537. package/src/terraform/graph.ts +35 -7
  538. package/src/terraform/providers/kubernetes.ts +48 -2
  539. package/src/terraform/tier-map.ts +21 -6
  540. package/src/terraform/types.ts +8 -0
  541. package/dist/cli/handlers/op-progress.d.ts +0 -90
  542. package/dist/cli/handlers/op-progress.d.ts.map +0 -1
  543. package/dist/cli/handlers/run-client.d.ts +0 -127
  544. package/dist/cli/handlers/run-client.d.ts.map +0 -1
  545. package/dist/cli/handlers/run-report.d.ts +0 -5
  546. package/dist/cli/handlers/run-report.d.ts.map +0 -1
  547. package/dist/components/temporal-codegen-loader.d.ts +0 -27
  548. package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
  549. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
  550. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
  551. package/src/cli/handlers/op-progress.test.ts +0 -268
  552. package/src/cli/handlers/op-progress.ts +0 -248
  553. package/src/cli/handlers/run-client.test.ts +0 -82
  554. package/src/cli/handlers/run-client.ts +0 -219
  555. package/src/cli/handlers/run-report.test.ts +0 -62
  556. package/src/cli/handlers/run-report.ts +0 -122
  557. package/src/components/temporal-codegen-loader.ts +0 -41
  558. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
@@ -97,6 +97,7 @@ export async function packageLexicon(options?: { verbose?: boolean; force?: bool
97
97
  buildManifest: (genResult) => ({
98
98
  name: "fixture",
99
99
  version: "0.0.1",
100
+ chantVersion: ">=0.1.0",
100
101
  }),
101
102
  srcDir,
102
103
  collectSkills: () => new Map(),
@@ -221,6 +221,35 @@ describe("auditCommand", () => {
221
221
  expect(none.exitCode).toBe(0);
222
222
  });
223
223
 
224
+ test("--fail-on error is a severity floor, decoupled from tier: a warning-severity finding does not fail it, an error-severity one does (chant #2113)", async () => {
225
+ const onlyWarning = await auditCommand({
226
+ path: REPO,
227
+ failOn: "error",
228
+ checksProvider: async () => [
229
+ {
230
+ id: "TEST900",
231
+ description: "always fires a warning, for the --fail-on error floor test",
232
+ check: () => [{ checkId: "TEST900", severity: "warning" as const, message: "a new rule shipped at warning" }],
233
+ },
234
+ ],
235
+ });
236
+ expect(onlyWarning.findings.some((f) => f.checkId === "TEST900")).toBe(true);
237
+ expect(onlyWarning.exitCode).toBe(0);
238
+
239
+ const withAnError = await auditCommand({
240
+ path: REPO,
241
+ failOn: "error",
242
+ checksProvider: async () => [
243
+ {
244
+ id: "TEST901",
245
+ description: "always fires an error, for the --fail-on error floor test",
246
+ check: () => [{ checkId: "TEST901", severity: "error" as const, message: "an actual error" }],
247
+ },
248
+ ],
249
+ });
250
+ expect(withAnError.exitCode).toBe(1);
251
+ });
252
+
224
253
  test("--tier merge-worthy filters out report-only findings", async () => {
225
254
  const all = await auditCommand({ path: REPO, tier: "all" });
226
255
  const mw = await auditCommand({ path: REPO, tier: "merge-worthy" });
@@ -267,12 +296,11 @@ describe("auditCommand", () => {
267
296
  expect(result.output).toContain("k8s/deploy.yaml -> k8s");
268
297
  expect(result.output).toContain("infra/stack.json -> aws");
269
298
  expect(result.output).toContain("Dockerfile -> docker");
270
- expect(result.output).toContain("infra/main.tf -> terraform (not audited; see chant carve)");
271
- // The install line names only the lexicons the files wanted, never terraform.
299
+ expect(result.output).toContain("infra/main.tf -> terraform");
300
+ // The install line names every lexicon the files wanted, terraform included.
272
301
  expect(result.output).toContain(
273
- `npx -p @intentius/chant -p @intentius/chant-lexicon-github -p @intentius/chant-lexicon-docker -p @intentius/chant-lexicon-aws -p @intentius/chant-lexicon-k8s chant audit ${MIXED}`,
302
+ `npx -p @intentius/chant -p @intentius/chant-lexicon-github -p @intentius/chant-lexicon-docker -p @intentius/chant-lexicon-terraform -p @intentius/chant-lexicon-aws -p @intentius/chant-lexicon-k8s chant audit ${MIXED}`,
274
303
  );
275
- expect(result.output).not.toContain("chant-lexicon-terraform");
276
304
  });
277
305
 
278
306
  test("zero lexicons with --json: status no-lexicons plus the unclaimed list and install line", async () => {
@@ -282,7 +310,7 @@ describe("auditCommand", () => {
282
310
  const json = JSON.parse(result.output);
283
311
  expect(json.status).toBe("no-lexicons");
284
312
  expect(json.findings).toEqual([]);
285
- expect(json.missingLexicons).toEqual(["github", "docker", "aws", "k8s"]);
313
+ expect(json.missingLexicons).toEqual(["github", "docker", "terraform", "aws", "k8s"]);
286
314
  expect(json.unclaimed).toContainEqual({ path: "k8s/deploy.yaml", lexicon: "k8s" });
287
315
  expect(json.unclaimed).toContainEqual({ path: "infra/main.tf", lexicon: "terraform" });
288
316
  expect(json.install).toMatch(/^npx -p @intentius\/chant /);
@@ -307,9 +335,9 @@ describe("auditCommand", () => {
307
335
  expect(result.status).toBe("ok");
308
336
  expect(result.exitCode).toBe(0);
309
337
  expect(result.scanned).toEqual([".github/workflows/ci.yml"]);
310
- expect(result.output).toMatch(/^Note: 3 files look like docker\/aws\/k8s but those lexicons are not installed, so they were skipped \(npm i @intentius\/chant-lexicon-docker @intentius\/chant-lexicon-aws @intentius\/chant-lexicon-k8s\)\./);
311
- expect(result.output).toContain("1 Terraform file skipped; the audit does not read HCL (see chant carve).");
338
+ expect(result.output).toMatch(/^Note: 4 files look like docker\/terraform\/aws\/k8s but those lexicons are not installed, so they were skipped \(npm i @intentius\/chant-lexicon-docker @intentius\/chant-lexicon-terraform @intentius\/chant-lexicon-aws @intentius\/chant-lexicon-k8s\)\./);
312
339
  expect(result.unclaimed).toContainEqual({ path: "k8s/deploy.yaml", lexicon: "k8s" });
340
+ expect(result.unclaimed).toContainEqual({ path: "infra/main.tf", lexicon: "terraform" });
313
341
  });
314
342
 
315
343
  test("partial with --json: status ok and the unclaimed files ride along", async () => {
@@ -320,12 +348,13 @@ describe("auditCommand", () => {
320
348
  expect(json.unclaimed.map((u: { lexicon: string }) => u.lexicon).sort()).toEqual(["aws", "docker", "k8s", "terraform"]);
321
349
  });
322
350
 
323
- test("all lexicons loaded: no coverage note, no unclaimed (terraform aside)", async () => {
351
+ test("every installable lexicon loaded: nothing is unclaimed, and the terraform root is scanned as one bundle (#2083)", async () => {
324
352
  const result = await auditCommand({ path: MIXED, plugins: await loadAuditPlugins() });
325
353
  expect(result.status).toBe("ok");
326
- expect(result.unclaimed).toEqual([{ path: "infra/main.tf", lexicon: "terraform" }]);
327
- expect(result.output).not.toContain("not installed");
328
- expect(result.scanned.sort()).toEqual([".github/workflows/ci.yml", "Dockerfile", "infra/stack.json", "k8s/deploy.yaml"]);
354
+ expect(result.unclaimed).toEqual([]);
355
+ expect(result.output).not.toContain("looks like terraform");
356
+ // `infra` is the terraform root-module bundle (one input per directory of `.tf` files).
357
+ expect(result.scanned.sort()).toEqual([".github/workflows/ci.yml", "Dockerfile", "infra", "infra/stack.json", "k8s/deploy.yaml"]);
329
358
  });
330
359
 
331
360
  test("installLine puts every lexicon on the same npx -p path", () => {
@@ -441,6 +470,53 @@ describe("auditCommand", () => {
441
470
  expect(valid).toBe(true);
442
471
  });
443
472
 
473
+ // The scope is the discovered root module's own directory (`infra`), which
474
+ // is what the terraform plugin names an audited scope after since #2217.
475
+ describe("TF001's missing-resource shape renders in all three reporters (chant #2113)", () => {
476
+ const dir = join(tmpdir(), `chant-audit-tf-missing-${process.pid}`);
477
+
478
+ function setup(): void {
479
+ mkdirSync(join(dir, "infra"), { recursive: true });
480
+ writeFileSync(join(dir, "infra/main.tf"), 'terraform {\n required_version = ">= 1.5.0"\n}\n');
481
+ }
482
+ function teardown(): void {
483
+ rmSync(dir, { recursive: true, force: true });
484
+ }
485
+
486
+ test("stylish names the missing kind and scope instead of falling back to entity", async () => {
487
+ setup();
488
+ const result = await auditCommand({ path: dir, format: "stylish" });
489
+ expect(result.output).toContain("(missing backend in infra)");
490
+ teardown();
491
+ });
492
+
493
+ test("json carries `missing` on the finding", async () => {
494
+ setup();
495
+ const result = await auditCommand({ path: dir, format: "json" });
496
+ const doc = JSON.parse(result.output) as { findings: Array<{ checkId: string; missing?: { kind: string; scope: string } }> };
497
+ const tf001 = doc.findings.find((f) => f.checkId === "TF001");
498
+ expect(tf001?.missing).toEqual({ kind: "backend", scope: "infra" });
499
+ teardown();
500
+ });
501
+
502
+ test("sarif carries `missing` in the result's properties, and still validates against the SARIF schema", async () => {
503
+ setup();
504
+ const result = await auditCommand({ path: dir, format: "sarif" });
505
+ const doc = JSON.parse(result.output) as {
506
+ runs: Array<{ results: Array<{ ruleId: string; properties?: { missing?: { kind: string; scope: string } } }> }>;
507
+ };
508
+ const tf001 = doc.runs[0].results.find((r) => r.ruleId === "TF001");
509
+ expect(tf001?.properties?.missing).toEqual({ kind: "backend", scope: "infra" });
510
+
511
+ const ajv = new Ajv({ strict: false, allErrors: true });
512
+ const validate = ajv.compile(loadSarifSchema() as object);
513
+ const valid = validate(doc);
514
+ if (!valid) throw new Error(ajv.errorsText(validate.errors));
515
+ expect(valid).toBe(true);
516
+ teardown();
517
+ });
518
+ });
519
+
444
520
  test("sarif schema validation also holds for the empty-result case (no findings)", async () => {
445
521
  const repo = fileURLToPath(new URL("./__fixtures__/audit-fountain-clean", import.meta.url));
446
522
  const result = await auditCommand({ path: repo, format: "sarif" });
@@ -555,6 +631,82 @@ describe("secrets detection (#443)", () => {
555
631
  });
556
632
  });
557
633
 
634
+ describe("Terraform HCL suppression (chant #2111)", () => {
635
+ function tmpRepo(): string {
636
+ const dir = join(tmpdir(), `chant-audit-tf-suppress-${process.pid}-${Math.random().toString(36).slice(2)}`);
637
+ mkdirSync(dir, { recursive: true });
638
+ mkdirSync(join(dir, "infra"), { recursive: true });
639
+ return dir;
640
+ }
641
+
642
+ const BACKENDLESS = 'terraform {\n required_version = ">= 1.5.0"\n}\n';
643
+
644
+ async function auditTerraform(dir: string): Promise<Awaited<ReturnType<typeof auditCommand>>> {
645
+ const all = await loadAuditPlugins();
646
+ return auditCommand({ path: dir, plugins: all.filter((p) => p.name === "terraform"), format: "json" });
647
+ }
648
+
649
+ test("chant-ignore-block suppresses TF001 through chant audit", async () => {
650
+ const dir = tmpRepo();
651
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF001\n${BACKENDLESS}`);
652
+ const result = await auditTerraform(dir);
653
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
654
+ expect(result.suppressedCount).toBe(1);
655
+ rmSync(dir, { recursive: true, force: true });
656
+ });
657
+
658
+ test("a plain chant-ignore on the same block also suppresses TF001 through chant audit", async () => {
659
+ const dir = tmpRepo();
660
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore: TF001\n${BACKENDLESS}`);
661
+ const result = await auditTerraform(dir);
662
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
663
+ expect(result.suppressedCount).toBe(1);
664
+ rmSync(dir, { recursive: true, force: true });
665
+ });
666
+
667
+ test('"all" suppresses TF001 through chant audit', async () => {
668
+ const dir = tmpRepo();
669
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: all\n${BACKENDLESS}`);
670
+ const result = await auditTerraform(dir);
671
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
672
+ rmSync(dir, { recursive: true, force: true });
673
+ });
674
+
675
+ test("chant-ignore-file at the top of the file suppresses TF001 through chant audit", async () => {
676
+ const dir = tmpRepo();
677
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-file: TF001\n${BACKENDLESS}`);
678
+ const result = await auditTerraform(dir);
679
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
680
+ rmSync(dir, { recursive: true, force: true });
681
+ });
682
+
683
+ test("a chant-ignore-file NOT at the top has no effect and is reported through chant audit", async () => {
684
+ const dir = tmpRepo();
685
+ writeFileSync(join(dir, "infra", "main.tf"), `# a header\n# chant-ignore-file: TF001\n${BACKENDLESS}`);
686
+ const result = await auditTerraform(dir);
687
+ expect(result.findings.map((f) => f.checkId)).toContain("TF001"); // still fires
688
+ expect(result.findings.map((f) => f.checkId)).toContain("SUPP002");
689
+ rmSync(dir, { recursive: true, force: true });
690
+ });
691
+
692
+ test("a directive naming a different rule id does not suppress TF001 through chant audit", async () => {
693
+ const dir = tmpRepo();
694
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF010\n${BACKENDLESS}`);
695
+ const result = await auditTerraform(dir);
696
+ expect(result.findings.map((f) => f.checkId)).toContain("TF001");
697
+ rmSync(dir, { recursive: true, force: true });
698
+ });
699
+
700
+ test("an already-expired suppression no longer suppresses TF001 and is reported through chant audit", async () => {
701
+ const dir = tmpRepo();
702
+ writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF001 exp:2020-01-01\n${BACKENDLESS}`);
703
+ const result = await auditTerraform(dir);
704
+ expect(result.findings.map((f) => f.checkId)).toContain("TF001"); // still fires: expired
705
+ expect(result.findings.map((f) => f.checkId)).toContain("SUPP001");
706
+ rmSync(dir, { recursive: true, force: true });
707
+ });
708
+ });
709
+
558
710
  describe("Wrangler config audit (#446)", () => {
559
711
  function tmpRepo(): string {
560
712
  const dir = join(tmpdir(), `chant-audit-wrangler-${process.pid}-${Math.random().toString(36).slice(2)}`);
@@ -649,3 +801,31 @@ describe("nginx config audit (#1979)", () => {
649
801
  rmSync(dir, { recursive: true, force: true });
650
802
  });
651
803
  });
804
+
805
+ describe("committed Terraform state (TF023, #2110)", () => {
806
+ function tmpRepo(): string {
807
+ const dir = join(tmpdir(), `chant-audit-tfstate-${process.pid}-${Math.random().toString(36).slice(2)}`);
808
+ mkdirSync(dir, { recursive: true });
809
+ return dir;
810
+ }
811
+
812
+ test("fires end to end on a directory with a tracked state file, with no lexicon installed", async () => {
813
+ const dir = tmpRepo();
814
+ writeFileSync(join(dir, "main.tf"), 'resource "null_resource" "a" {}\n');
815
+ writeFileSync(join(dir, "terraform.tfstate"), JSON.stringify({ version: 4, resources: [] }));
816
+ const result = await auditCommand({ path: dir, plugins: [] });
817
+ expect(result.findings.map((f) => f.checkId)).toContain("TF023");
818
+ rmSync(dir, { recursive: true, force: true });
819
+ });
820
+
821
+ test("says nothing when the state is ignored rather than committed", async () => {
822
+ const dir = tmpRepo();
823
+ writeFileSync(join(dir, ".gitignore"), "*.tfstate\n.terraform/\n");
824
+ writeFileSync(join(dir, "main.tf"), 'resource "null_resource" "a" {}\n');
825
+ writeFileSync(join(dir, "terraform.tfstate"), JSON.stringify({ version: 4, resources: [] }));
826
+ mkdirSync(join(dir, ".terraform"), { recursive: true });
827
+ const result = await auditCommand({ path: dir, plugins: [] });
828
+ expect(result.findings.map((f) => f.checkId)).not.toContain("TF023");
829
+ rmSync(dir, { recursive: true, force: true });
830
+ });
831
+ });
@@ -7,12 +7,13 @@
7
7
 
8
8
  import { existsSync, readFileSync, statSync, writeFileSync } from "fs";
9
9
  import { join } from "path";
10
- import { auditFiles, type AuditInput, type AuditFinding, type ChecksProvider } from "../../audit/core";
10
+ import { auditFiles, type AuditInput, type AuditFinding, type ChecksProvider, type SuppressionStats } from "../../audit/core";
11
11
  import { AUDIT_LEXICONS, classifyFiles, collectCandidates, loadAuditPlugins, unclaimedFiles, type DetectPlugin, type RepoFile, type UnclaimedFile } from "../../audit/discover";
12
12
  import { RULE_CATALOG, resolveAuditCatalog, type RuleMeta } from "../../audit/catalog";
13
13
  import { scanForSecrets, parseSecretsConfig, type SecretsScanOptions } from "../../audit/secrets";
14
14
  import { auditWranglerConfigs } from "../../audit/wrangler";
15
15
  import { auditNginxConfigs } from "../../audit/nginx";
16
+ import { auditTerraformState } from "../../audit/terraform-state";
16
17
  import { renderMarkdown } from "../../audit/report";
17
18
  import { renderHtml, type ReportTheme } from "../../audit/report-html";
18
19
  import { buildReportJson, REPORT_SCHEMA_VERSION, type AuditSnapshot } from "../../audit/report-model";
@@ -23,7 +24,17 @@ import type { Severity } from "../../lint/rule";
23
24
 
24
25
  export type AuditFormat = "stylish" | "json" | "sarif" | "markdown" | "html";
25
26
  export type AuditTier = "merge-worthy" | "all";
26
- export type AuditFailOn = "merge-worthy" | "warning" | "none";
27
+ /**
28
+ * `"error"` (chant #2113) is the minimum-failure-severity floor tflint's
29
+ * `--minimum-failure-severity` maps onto (`error | warning | notice`): unlike
30
+ * `"merge-worthy"`/`"warning"` above (which key off a rule's catalog `tier`
31
+ * or a finding's severity being at-or-above warning), `"error"` fails only on
32
+ * an `error`-severity finding, decoupling what CI fails a build over from
33
+ * what a rule ships reporting by default. It's the lever that lets a new
34
+ * rule ship at `warning` and be promoted to `error` later without a pipeline
35
+ * pinned to `--fail-on error` breaking the moment the rule starts firing.
36
+ */
37
+ export type AuditFailOn = "merge-worthy" | "warning" | "error" | "none";
27
38
 
28
39
  export interface AuditCommandOptions {
29
40
  /** Repo root/dir to scan, or an https:// repo URL to fetch and audit. */
@@ -79,6 +90,12 @@ export interface AuditCommandResult {
79
90
  unclaimed?: UnclaimedFile[];
80
91
  /** Where `output` belongs; diagnostics go to stderr, reports to stdout (default). */
81
92
  stream?: "stdout" | "stderr";
93
+ /**
94
+ * Findings an inline `# chant-ignore*` comment suppressed (chant #2111),
95
+ * counted, never dropped silently, mirroring `chant build`'s equivalent
96
+ * summary line.
97
+ */
98
+ suppressedCount?: number;
82
99
  }
83
100
 
84
101
  /** Exit code when the audit had no lexicons to look with. Distinct from 1 (findings / failure). */
@@ -89,9 +106,9 @@ function lexiconPackage(name: string): string {
89
106
  return `@intentius/chant-lexicon-${name}`;
90
107
  }
91
108
 
92
- /** Missing audit lexicons the unclaimed files pointed at, in first-seen order. `terraform` is not installable. */
109
+ /** Missing audit lexicons the unclaimed files pointed at, in first-seen order. */
93
110
  function wantedLexicons(unclaimed: UnclaimedFile[]): string[] {
94
- return [...new Set(unclaimed.map((u) => u.lexicon))].filter((l) => l !== "terraform");
111
+ return [...new Set(unclaimed.map((u) => u.lexicon))];
95
112
  }
96
113
 
97
114
  /**
@@ -107,17 +124,10 @@ export function installLine(lexicons: string[], target: string): string {
107
124
  /** One-line coverage hint for the partial case: some lexicons loaded, others wanted by files on disk. */
108
125
  function missingLexiconHint(unclaimed: UnclaimedFile[]): string | undefined {
109
126
  const wanted = wantedLexicons(unclaimed);
110
- const tf = unclaimed.filter((u) => u.lexicon === "terraform").length;
111
- const parts: string[] = [];
112
- if (wanted.length > 0) {
113
- const n = unclaimed.length - tf;
114
- parts.push(
115
- `${n} file${n === 1 ? " looks" : "s look"} like ${wanted.join("/")} but ${wanted.length === 1 ? "that lexicon is" : "those lexicons are"} not installed, so ${n === 1 ? "it was" : "they were"} skipped` +
116
- ` (npm i ${wanted.map(lexiconPackage).join(" ")}).`,
117
- );
118
- }
119
- if (tf > 0) parts.push(`${tf} Terraform file${tf === 1 ? "" : "s"} skipped; the audit does not read HCL (see chant carve).`);
120
- return parts.length > 0 ? parts.join(" ") : undefined;
127
+ if (wanted.length === 0) return undefined;
128
+ const n = unclaimed.length;
129
+ return `${n} file${n === 1 ? " looks" : "s look"} like ${wanted.join("/")} but ${wanted.length === 1 ? "that lexicon is" : "those lexicons are"} not installed, so ${n === 1 ? "it was" : "they were"} skipped` +
130
+ ` (npm i ${wanted.map(lexiconPackage).join(" ")}).`;
121
131
  }
122
132
 
123
133
  /** Human-readable diagnostic for the zero-lexicon case. */
@@ -129,11 +139,10 @@ function renderNoLexicons(target: string, unclaimed: UnclaimedFile[]): string {
129
139
  if (unclaimed.length > 0) {
130
140
  lines.push("", "Files that wanted a lexicon:");
131
141
  for (const u of unclaimed) {
132
- const note = u.lexicon === "terraform" ? "terraform (not audited; see chant carve)" : u.lexicon;
133
- lines.push(` ${u.path} -> ${note}`);
142
+ lines.push(` ${u.path} -> ${u.lexicon}`);
134
143
  }
135
144
  } else {
136
- lines.push("", "No file under the target looked like CI, Kubernetes, Helm, Docker, CloudFormation, ARM, Config Connector, or fountain either.");
145
+ lines.push("", "No file under the target looked like CI, Kubernetes, Helm, Docker, CloudFormation, ARM, Config Connector, fountain, or Terraform either.");
137
146
  }
138
147
  lines.push("", "Run it with the lexicons those files need:");
139
148
  lines.push(` ${installLine(wanted.length > 0 ? wanted : [...AUDIT_LEXICONS], target)}`);
@@ -197,6 +206,7 @@ function exitCodeFor(findings: AuditFinding[], failOn: AuditFailOn, catalog: Rec
197
206
  if (failOn === "warning") {
198
207
  return findings.some((f) => f.severity === "error" || f.severity === "warning") ? 1 : 0;
199
208
  }
209
+ if (failOn === "error") return findings.some((f) => f.severity === "error") ? 1 : 0;
200
210
  return 0;
201
211
  }
202
212
 
@@ -252,7 +262,15 @@ function renderStylish(findings: AuditFinding[], scanned: string[], notes: strin
252
262
  lines.push("", title);
253
263
  for (const f of list) {
254
264
  const loc = f.line ? `${f.file}:${f.line}` : f.file;
255
- const where = f.entity ? `${loc} (${f.entity})` : loc;
265
+ // A `missing` finding (chant #2113) has nothing present to anchor
266
+ // `entity` to. The whole point is that `f.missing.kind` does not
267
+ // exist in `f.missing.scope`, so it renders that absence directly
268
+ // instead of falling back to `entity` (which such a check rarely sets).
269
+ const where = f.missing
270
+ ? `${loc} (missing ${f.missing.kind} in ${f.missing.scope})`
271
+ : f.entity
272
+ ? `${loc} (${f.entity})`
273
+ : loc;
256
274
  const title = catalog[f.checkId]?.title ?? f.checkId;
257
275
  lines.push(` [${f.checkId}] ${f.severity} ${where} — ${title}`);
258
276
  }
@@ -280,11 +298,21 @@ function renderSarif(findings: AuditFinding[], catalog: Record<string, RuleMeta>
280
298
  shortDescription: { text: m?.title ?? id },
281
299
  ...(m?.remediation ? { help: { text: m.remediation } } : {}),
282
300
  helpUri: m?.authority?.[0]?.url,
283
- ...(m?.category ? { properties: { category: m.category, dimension: m.category } } : {}),
301
+ // `priorArt` credits the upstream tools whose rules check the same thing
302
+ // (audit/prior-art.ts) — tool key, upstream rule id, doc URL, relation.
303
+ ...(m?.category || m?.lineage?.length
304
+ ? {
305
+ properties: {
306
+ ...(m?.category ? { category: m.category, dimension: m.category } : {}),
307
+ ...(m?.lineage?.length ? { priorArt: m.lineage } : {}),
308
+ },
309
+ }
310
+ : {}),
284
311
  };
285
312
  });
286
313
  const results = findings.map((f) => {
287
314
  const tier = catalog[f.checkId]?.tier;
315
+ const properties = { ...(tier ? { tier } : {}), ...(f.missing ? { missing: f.missing } : {}) };
288
316
  return {
289
317
  ruleId: f.checkId,
290
318
  level: sarifLevel(f.severity),
@@ -297,7 +325,12 @@ function renderSarif(findings: AuditFinding[], catalog: Record<string, RuleMeta>
297
325
  },
298
326
  },
299
327
  ],
300
- ...(tier ? { properties: { tier } } : {}),
328
+ // `f.missing` (chant #2113) is Snyk policy-engine's "missing-resource"
329
+ // archetype: nothing at `f.file` actually declares the absent thing, so
330
+ // there is no line to point SARIF's region at either. `missing` rides
331
+ // in the property bag (SARIF's core schema has no dedicated slot for an
332
+ // absence finding) rather than pretending a region exists.
333
+ ...(Object.keys(properties).length > 0 ? { properties } : {}),
301
334
  };
302
335
  });
303
336
  return JSON.stringify(
@@ -375,7 +408,11 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
375
408
  // shape alone can't disambiguate them.
376
409
  candidates = collectCandidates(options.path);
377
410
  }
378
- const inputs = classifyFiles(candidates, plugins);
411
+ // A local target hands its directory to the classifier, so an input whose
412
+ // path names a directory carries the directory itself (#2217): terraform's
413
+ // parse-to-graph follows a root module's local `module` calls from there. A
414
+ // URL target has no local tree, and never fetches `.tf` in the first place.
415
+ const inputs = classifyFiles(candidates, plugins, isUrl ? {} : { baseDir: options.path });
379
416
  const unclaimed = unclaimedFiles(candidates, inputs, plugins);
380
417
  const scanned = inputs.map((i) => i.path);
381
418
 
@@ -395,29 +432,37 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
395
432
  // its own path detector plus a parsed-content marker check (a `.conf` in a
396
433
  // shared directory name like conf.d/ only counts once it parses as nginx).
397
434
  const nginxFindings = auditNginxConfigs(candidates);
435
+ // TF023 (#2110) — committed Terraform state. Lexicon-independent for the
436
+ // same reason the three above are: it reads the discovered paths, not a
437
+ // parsed root module, so it fires with or without the terraform lexicon.
438
+ const terraformStateFindings = auditTerraformState(candidates);
398
439
 
399
440
  if (plugins.length === 0) {
400
441
  const output = format === "json" ? renderNoLexiconsJson(options.path, unclaimed) : renderNoLexicons(options.path, unclaimed);
401
- return { success: true, status: "no-lexicons", output, findings: [...secretsFindings, ...wranglerFindings, ...nginxFindings], scanned: [], unclaimed, exitCode: NO_LEXICONS_EXIT_CODE, stream: format === "json" ? "stdout" : "stderr" };
442
+ return { success: true, status: "no-lexicons", output, findings: [...secretsFindings, ...wranglerFindings, ...nginxFindings, ...terraformStateFindings], scanned: [], unclaimed, exitCode: NO_LEXICONS_EXIT_CODE, stream: format === "json" ? "stdout" : "stderr" };
402
443
  }
403
444
 
404
445
  const missingLexiconNote = missingLexiconHint(unclaimed);
405
446
 
406
- if (inputs.length === 0 && secretsFindings.length === 0 && wranglerFindings.length === 0 && nginxFindings.length === 0) {
447
+ if (inputs.length === 0 && secretsFindings.length === 0 && wranglerFindings.length === 0 && nginxFindings.length === 0 && terraformStateFindings.length === 0) {
407
448
  const output = `No auditable files found under ${options.path}.${missingLexiconNote ? ` ${missingLexiconNote}` : ""}`;
408
449
  return { success: true, status: "ok", output, findings: [], scanned: [], unclaimed, exitCode: 0 };
409
450
  }
410
451
 
411
452
  let findings: AuditFinding[] = [];
453
+ // chant #2111: mutated in place by `auditFiles` so its inline (`# chant-
454
+ // ignore*`) suppressed count reaches the summary without changing
455
+ // `auditFiles`'s `AuditFinding[]` return type; see `SuppressionStats`'s doc.
456
+ const suppressionStats: SuppressionStats = { count: 0 };
412
457
  if (inputs.length > 0) {
413
458
  try {
414
- findings = await auditFiles(inputs, { checksProvider: options.checksProvider });
459
+ findings = await auditFiles(inputs, { checksProvider: options.checksProvider, suppressionStats });
415
460
  } catch (err) {
416
461
  const msg = err instanceof Error ? err.message : String(err);
417
462
  return { success: false, output: "", findings: [], scanned, exitCode: 1, error: msg };
418
463
  }
419
464
  }
420
- findings = [...findings, ...secretsFindings, ...wranglerFindings, ...nginxFindings];
465
+ findings = [...findings, ...secretsFindings, ...wranglerFindings, ...nginxFindings, ...terraformStateFindings];
421
466
  // Resolve the audit catalog once, aggregating the audited lexicons' own
422
467
  // metadata over core's static catalog (#687). The lexicons are already loaded
423
468
  // by `auditFiles` above, so this is cheap. Core's static catalog (always
@@ -428,6 +473,11 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
428
473
  if (tier === "merge-worthy") findings = findings.filter((f) => isMergeWorthy(f, catalog));
429
474
  const notes = coverageNotes(inputs);
430
475
  if (missingLexiconNote) notes.push(missingLexiconNote);
476
+ if (suppressionStats.count > 0) {
477
+ notes.push(
478
+ `${suppressionStats.count} finding${suppressionStats.count === 1 ? "" : "s"} suppressed via inline chant-ignore comments.`,
479
+ );
480
+ }
431
481
 
432
482
  // Diff-bearing renderers (markdown, html) need action SHAs / image digests
433
483
  // resolved up front (sync maps so rendering stays synchronous).
@@ -495,10 +545,10 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
495
545
  } catch (err) {
496
546
  return { success: false, output, findings, scanned, exitCode: 1, error: `Failed to write ${options.output}: ${err instanceof Error ? err.message : String(err)}` };
497
547
  }
498
- return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode, wroteTo: options.output };
548
+ return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode, wroteTo: options.output, suppressedCount: suppressionStats.count };
499
549
  }
500
550
 
501
- return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode };
551
+ return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode, suppressedCount: suppressionStats.count };
502
552
  }
503
553
 
504
554
  /** Print an audit result to stdout. */