@intentius/chant 0.57.0 → 0.58.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/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +20 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +14 -8
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +28 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +26 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +20 -21
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +3 -3
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +66 -36
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +9 -15
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +104 -14
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +71 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +89 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +84 -29
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +113 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +23 -7
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +184 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +30 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +79 -27
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +61 -17
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +91 -15
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +189 -11
- package/src/cli/commands/audit.ts +73 -27
- package/src/cli/commands/build.test.ts +292 -9
- package/src/cli/commands/build.ts +156 -24
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +48 -0
- package/src/cli/commands/lint.ts +123 -0
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +260 -55
- package/src/cli/handlers/run.test.ts +431 -1287
- package/src/cli/handlers/run.ts +365 -915
- package/src/cli/main.test.ts +23 -15
- package/src/cli/main.ts +88 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/registry.ts +26 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +3 -2
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +10 -5
- package/src/components/cli-support.ts +52 -44
- package/src/components/component.schema.json +2 -2
- package/src/components/component.ts +3 -3
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +92 -22
- package/src/components/driver.ts +193 -83
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.ts +11 -17
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +81 -1
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +2 -2
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +120 -14
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +143 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +1 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +81 -0
- package/src/op/activities/reconcile.ts +187 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +123 -39
- package/src/op/composites/apply-op.ts +208 -0
- package/src/op/composites/composites.test.ts +366 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +107 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +26 -11
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +39 -6
- package/src/op/local-executor.test.ts +163 -34
- package/src/op/local-executor.ts +370 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +281 -0
- package/src/op/op-ir.ts +417 -0
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +26 -5
- package/src/op/operator.test.ts +175 -6
- package/src/op/operator.ts +63 -16
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +84 -24
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The claimed-field set (#2160) — which properties this declaration ever set.
|
|
3
|
+
*
|
|
4
|
+
* chant's ownership question has always been answered per resource, from a
|
|
5
|
+
* marker: is this thing mine. The finer question was never asked. A live
|
|
6
|
+
* property tree carries fields nobody declared — an autoscaler's replica count,
|
|
7
|
+
* a controller's annotation, a value a person typed into a console — and the
|
|
8
|
+
* deep diff (./lifecycle/deep-diff.ts) reported every one of them as a
|
|
9
|
+
* difference, because a difference is all a two-way comparison can produce.
|
|
10
|
+
*
|
|
11
|
+
* Every lexicon has been paying for that in hand-written knowledge.
|
|
12
|
+
* `DeepNormalizationHooks.prune` is where the noise goes, and three of the four
|
|
13
|
+
* hooks exist because the live tree holds fields the declaration never
|
|
14
|
+
* mentions. Kubernetes is the one substrate that escapes it: the API server
|
|
15
|
+
* records a field manager per field (`metadata.managedFields`), so a foreign
|
|
16
|
+
* write is a fact about the object rather than a rule somebody maintains.
|
|
17
|
+
* `lexicons/gcp/src/deep-observe.ts` says why nobody else can do that — "a REST
|
|
18
|
+
* payload carries no field ownership" — and answers with a static per-kind
|
|
19
|
+
* table instead.
|
|
20
|
+
*
|
|
21
|
+
* The declaration is the table they are missing. A `ResourceDeclarable`'s
|
|
22
|
+
* `props` are exactly the fields chant set, they are available on every
|
|
23
|
+
* substrate, and they come from the same build that produced the entity.
|
|
24
|
+
* Nothing has to come back from the provider.
|
|
25
|
+
*
|
|
26
|
+
* ## The grammar is the diff's grammar
|
|
27
|
+
*
|
|
28
|
+
* A claim is a set of property paths in the form `flattenDeepProperties`
|
|
29
|
+
* produces: `spec.replicas`, `Tags[#env].Value`, `ingress[0].fromPort`. Same
|
|
30
|
+
* hooks, same normalization, same flattening — so a path in the claim and a
|
|
31
|
+
* path in the diff are the same string or they are different fields. Deriving
|
|
32
|
+
* the claim any other way (walking raw props, say) would give a set that agrees
|
|
33
|
+
* with the diff for most trees and disagrees for exactly the ones the hooks
|
|
34
|
+
* were written for.
|
|
35
|
+
*
|
|
36
|
+
* ## Membership is exact, deliberately
|
|
37
|
+
*
|
|
38
|
+
* A claimed path is matched exactly, never by its index-erased pattern
|
|
39
|
+
* (`Tags[].Value`). The pattern is the right test for
|
|
40
|
+
* {@link import("./deep-observation").DeepNode.counterpart}, which asks a
|
|
41
|
+
* shape question ("did source declare tag values at all") before array order is
|
|
42
|
+
* canonical. Classification asks a value question, and it pairs a declared
|
|
43
|
+
* value with a live one at the same path. A pattern match would answer
|
|
44
|
+
* "declared" for a path that has no declared value to compare against, which is
|
|
45
|
+
* neither of the two declared classifications and would quietly become a third
|
|
46
|
+
* meaning of "drift".
|
|
47
|
+
*
|
|
48
|
+
* ## What the claim does not decide
|
|
49
|
+
*
|
|
50
|
+
* It does not prune. A field chant never declared still reaches the diff, still
|
|
51
|
+
* appears in the report, and still carries its live value — it is reported as
|
|
52
|
+
* unclaimed rather than dropped, because chant #1191 already lost a
|
|
53
|
+
* console-added label by pruning what it could not attribute. What the claim
|
|
54
|
+
* changes is the verdict: unclaimed is not drift, and drift is the only thing
|
|
55
|
+
* that may become an update.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
import {
|
|
59
|
+
deepValueEqual,
|
|
60
|
+
flattenDeepProperties,
|
|
61
|
+
normalizeDeepProperties,
|
|
62
|
+
type DeepNormalizationHooks,
|
|
63
|
+
} from "./deep-observation";
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The set of property paths one declaration claims — every path its `props`
|
|
67
|
+
* flatten to, in the diff's own grammar.
|
|
68
|
+
*
|
|
69
|
+
* Opaque on purpose: {@link isClaimed} is the only membership test, so a
|
|
70
|
+
* consumer cannot accidentally invent a looser one (see the module doc on
|
|
71
|
+
* pattern matching).
|
|
72
|
+
*/
|
|
73
|
+
export interface ClaimedFieldSet {
|
|
74
|
+
/** Flattened property paths, exactly as the diff addresses them. */
|
|
75
|
+
readonly paths: ReadonlySet<string>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* How one LIVE value relates to the claim. Three answers where a two-way diff
|
|
80
|
+
* had two:
|
|
81
|
+
*
|
|
82
|
+
* - `declared-equal` — chant set this field and the cloud agrees. Nothing to say.
|
|
83
|
+
* - `declared-changed` — chant set this field and the cloud holds something
|
|
84
|
+
* else. This is drift, and it is the only classification that may become an
|
|
85
|
+
* update.
|
|
86
|
+
* - `undeclared` — the field has a value and chant never set it. Somebody else
|
|
87
|
+
* holds it. Reported, never proposed, never counted as drift.
|
|
88
|
+
*
|
|
89
|
+
* A declared path with no live value at all is not in this enumeration: there
|
|
90
|
+
* is no live value to classify. The diff keeps reporting that case as `absent`.
|
|
91
|
+
*/
|
|
92
|
+
export type FieldClaim = "declared-equal" | "declared-changed" | "undeclared";
|
|
93
|
+
|
|
94
|
+
/** Which source answered "who holds this field". */
|
|
95
|
+
export type FieldClaimSource =
|
|
96
|
+
/**
|
|
97
|
+
* The substrate named the manager. Kubernetes' `metadata.managedFields`, and
|
|
98
|
+
* nowhere else today — strictly better than the claim, because it says who.
|
|
99
|
+
*/
|
|
100
|
+
| "field-manager"
|
|
101
|
+
/**
|
|
102
|
+
* The declaration answered: the path is not in the claimed-field set, so
|
|
103
|
+
* chant never set it. Says that it is somebody else's without saying whose,
|
|
104
|
+
* which is the best any substrate without ownership metadata can do.
|
|
105
|
+
*/
|
|
106
|
+
| "claimed-fields";
|
|
107
|
+
|
|
108
|
+
/** An empty claim — a declaration with no props, and the safe default. */
|
|
109
|
+
export const NO_CLAIMED_FIELDS: ClaimedFieldSet = { paths: new Set<string>() };
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Build a claim from an already-normalized declared property tree.
|
|
113
|
+
*
|
|
114
|
+
* `options` must be the same {@link FlattenDeepOptions} the diff flattens the
|
|
115
|
+
* declared side with, or the two disagree about keyed list segments.
|
|
116
|
+
*/
|
|
117
|
+
export function claimedFieldsOfTree(
|
|
118
|
+
declared: Record<string, unknown>,
|
|
119
|
+
options: { entityType: string; hooks?: DeepNormalizationHooks },
|
|
120
|
+
): ClaimedFieldSet {
|
|
121
|
+
const flat = flattenDeepProperties(declared, {
|
|
122
|
+
entityType: options.entityType,
|
|
123
|
+
side: "declared",
|
|
124
|
+
...(options.hooks ? { hooks: options.hooks } : {}),
|
|
125
|
+
});
|
|
126
|
+
return { paths: new Set(flat.keys()) };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build a claim straight from a declaration's raw `props` — the entry point for
|
|
131
|
+
* a consumer that has an entity and no diff.
|
|
132
|
+
*
|
|
133
|
+
* Normalizes with the lexicon's own hooks first, exactly as the diff does, so
|
|
134
|
+
* pruned and masked paths land the same way on both routes. `livePaths` is the
|
|
135
|
+
* counterpart set (`deepPathSet` over the live tree) where the caller has one:
|
|
136
|
+
* without it the pass runs one-sided and any hook gated on
|
|
137
|
+
* {@link import("./deep-observation").DeepNode.counterpart} sees `"unknown"`,
|
|
138
|
+
* which is the honest answer and prunes nothing default-related.
|
|
139
|
+
*/
|
|
140
|
+
export function claimedFieldsOfProps(
|
|
141
|
+
props: Record<string, unknown>,
|
|
142
|
+
options: {
|
|
143
|
+
entityType: string;
|
|
144
|
+
hooks?: DeepNormalizationHooks;
|
|
145
|
+
livePaths?: ReadonlySet<string>;
|
|
146
|
+
},
|
|
147
|
+
): ClaimedFieldSet {
|
|
148
|
+
const normalized = normalizeDeepProperties(props, {
|
|
149
|
+
entityType: options.entityType,
|
|
150
|
+
side: "declared",
|
|
151
|
+
...(options.hooks ? { hooks: options.hooks } : {}),
|
|
152
|
+
...(options.livePaths ? { counterpartPaths: options.livePaths } : {}),
|
|
153
|
+
});
|
|
154
|
+
return claimedFieldsOfTree(normalized, options);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** True when this declaration set the property at `path`. */
|
|
158
|
+
export function isClaimed(claimed: ClaimedFieldSet | undefined, path: string): boolean {
|
|
159
|
+
return claimed !== undefined && claimed.paths.has(path);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* The claim as a sorted array — the wire form, for
|
|
164
|
+
* {@link import("./deep-observation").DeepResourceObservation.claimedFields}
|
|
165
|
+
* and for anything serializing a result to JSON.
|
|
166
|
+
*/
|
|
167
|
+
export function claimedFieldPaths(claimed: ClaimedFieldSet): string[] {
|
|
168
|
+
return [...claimed.paths].sort();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Rebuild a claim from its wire form. */
|
|
172
|
+
export function claimedFieldsFromPaths(paths: Iterable<string>): ClaimedFieldSet {
|
|
173
|
+
return { paths: new Set(paths) };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Classify one live value against the claim.
|
|
178
|
+
*
|
|
179
|
+
* `declaredValue` is only read when the path is claimed; pass whatever the
|
|
180
|
+
* declared tree holds there (including `undefined`, which is a legal declared
|
|
181
|
+
* value on a claimed path only in the sense that the flattener never emits it).
|
|
182
|
+
*/
|
|
183
|
+
export function classifyLiveField(input: {
|
|
184
|
+
claimed: ClaimedFieldSet | undefined;
|
|
185
|
+
path: string;
|
|
186
|
+
declaredValue: unknown;
|
|
187
|
+
liveValue: unknown;
|
|
188
|
+
}): FieldClaim {
|
|
189
|
+
if (!isClaimed(input.claimed, input.path)) return "undeclared";
|
|
190
|
+
return deepValueEqual(input.declaredValue, input.liveValue) ? "declared-equal" : "declared-changed";
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Who holds an undeclared live field, and which source said so.
|
|
195
|
+
*
|
|
196
|
+
* The manager wins where the substrate records one: "owned by `hpa-controller`"
|
|
197
|
+
* and "chant never set it" are the same verdict with very different amounts of
|
|
198
|
+
* information in them, and an operator can act on the first. The claim is the
|
|
199
|
+
* fallback, and it answers on every substrate.
|
|
200
|
+
*/
|
|
201
|
+
export function heldBy(fieldOwners: Record<string, string> | undefined, path: string): {
|
|
202
|
+
holder?: string;
|
|
203
|
+
source: FieldClaimSource;
|
|
204
|
+
} {
|
|
205
|
+
const manager = fieldOwners?.[path];
|
|
206
|
+
if (manager) return { holder: manager, source: "field-manager" };
|
|
207
|
+
return { source: "claimed-fields" };
|
|
208
|
+
}
|
|
@@ -9,8 +9,8 @@ import { formatError, formatInfo } from "./format";
|
|
|
9
9
|
* out (chant #1108) so every command that discovers project source before
|
|
10
10
|
* running it resolves `chant.config.ts`'s declared `buildParams` the exact
|
|
11
11
|
* same way: `chant build` (`../commands/build.ts`'s `buildCommand`), the
|
|
12
|
-
* component deploy driver (`./handlers/run.ts`'s `chant run --components`
|
|
13
|
-
*
|
|
12
|
+
* component deploy driver (`./handlers/run.ts`'s `chant run --components`),
|
|
13
|
+
* and generate mode (`./handlers/build.ts`'s
|
|
14
14
|
* `chant build --components --generate <lexicon>`).
|
|
15
15
|
*
|
|
16
16
|
* Before #1108, only `buildCommand` ran this sequence — `chant run
|
package/src/cli/command-group.ts
CHANGED
|
@@ -57,6 +57,20 @@ export interface CommandGroup {
|
|
|
57
57
|
description: string;
|
|
58
58
|
/** Verbs in this group. */
|
|
59
59
|
commands: CommandGroupCommand[];
|
|
60
|
+
/**
|
|
61
|
+
* The verb to run when the group name is given on its own — `chant acp`
|
|
62
|
+
* rather than `chant acp serve` (#2125). Named here rather than assumed to
|
|
63
|
+
* be the first verb, because a group whose bare form should be a usage
|
|
64
|
+
* error (`chant kube`) must stay one: omitting this field is how a group
|
|
65
|
+
* says it has no default.
|
|
66
|
+
*
|
|
67
|
+
* The token after the group name decides which reading applies, and that
|
|
68
|
+
* decision belongs to the caller that still holds the raw argv
|
|
69
|
+
* (`../cli/main.ts`'s `tryPluginCommand`): with a default verb, `chant acp
|
|
70
|
+
* --durable-requests` has no verb token to consume, so the flag is the
|
|
71
|
+
* default verb's argument rather than a verb it does not have.
|
|
72
|
+
*/
|
|
73
|
+
defaultVerb?: string;
|
|
60
74
|
}
|
|
61
75
|
|
|
62
76
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pretend-provider-lock-metadata
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
resource "null_resource" "root" {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
resource "null_resource" "foo" {}
|
|
@@ -8,8 +8,16 @@
|
|
|
8
8
|
"dist/"
|
|
9
9
|
],
|
|
10
10
|
"exports": {
|
|
11
|
-
".":
|
|
12
|
-
|
|
11
|
+
".": {
|
|
12
|
+
"development": "./src/index.ts",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./src/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"./*": {
|
|
17
|
+
"development": "./src/*.ts",
|
|
18
|
+
"types": "./dist/*.d.ts",
|
|
19
|
+
"default": "./src/*.ts"
|
|
20
|
+
},
|
|
13
21
|
"./manifest": "./dist/manifest.json",
|
|
14
22
|
"./meta": "./dist/meta.json",
|
|
15
23
|
"./types": "./dist/types/index.d.ts"
|
|
@@ -18,8 +26,9 @@
|
|
|
18
26
|
"generate": "npx tsx src/codegen/generate-cli.ts",
|
|
19
27
|
"validate": "npx tsx src/validate-cli.ts",
|
|
20
28
|
"docs": "npx tsx src/codegen/docs-cli.ts",
|
|
21
|
-
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
22
|
-
"prepack": "npm run generate && npm run validate && npm run build"
|
|
29
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete",
|
|
30
|
+
"prepack": "npm run generate && npm run bundle && npm run validate && npm run build",
|
|
31
|
+
"bundle": "tsx src/package-cli.ts"
|
|
23
32
|
},
|
|
24
33
|
"devDependencies": {
|
|
25
34
|
"@intentius/chant": "*",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { generate, writeGeneratedFiles } from "./codegen/generate";
|
|
3
|
+
import { packageLexicon } from "./codegen/package";
|
|
4
|
+
import { writeBundleSpec } from "@intentius/chant/codegen/package";
|
|
5
|
+
import { join, dirname } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
const srcDir = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
// 1. Generate src/generated/ files (writeGeneratedFiles resolves its own target)
|
|
11
|
+
const genResult = await generate({ verbose: true });
|
|
12
|
+
writeGeneratedFiles(genResult);
|
|
13
|
+
|
|
14
|
+
// 2. Run package pipeline and write dist/
|
|
15
|
+
const { spec, stats } = await packageLexicon({ verbose: true });
|
|
16
|
+
|
|
17
|
+
const distDir = join(dirname(srcDir), "dist");
|
|
18
|
+
writeBundleSpec(spec, distDir);
|
|
19
|
+
|
|
20
|
+
console.error(`Packaged ${stats.resources} resources, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
|
|
21
|
+
console.error(`dist/ written to ${distDir}`);
|
|
@@ -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
|
|
271
|
-
// The install line names
|
|
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:
|
|
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("
|
|
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([
|
|
327
|
-
expect(result.output).not.toContain("
|
|
328
|
-
|
|
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,51 @@ describe("auditCommand", () => {
|
|
|
441
470
|
expect(valid).toBe(true);
|
|
442
471
|
});
|
|
443
472
|
|
|
473
|
+
describe("TF001's missing-resource shape renders in all three reporters (chant #2113)", () => {
|
|
474
|
+
const dir = join(tmpdir(), `chant-audit-tf-missing-${process.pid}`);
|
|
475
|
+
|
|
476
|
+
function setup(): void {
|
|
477
|
+
mkdirSync(join(dir, "infra"), { recursive: true });
|
|
478
|
+
writeFileSync(join(dir, "infra/main.tf"), 'terraform {\n required_version = ">= 1.5.0"\n}\n');
|
|
479
|
+
}
|
|
480
|
+
function teardown(): void {
|
|
481
|
+
rmSync(dir, { recursive: true, force: true });
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
test("stylish names the missing kind and scope instead of falling back to entity", async () => {
|
|
485
|
+
setup();
|
|
486
|
+
const result = await auditCommand({ path: dir, format: "stylish" });
|
|
487
|
+
expect(result.output).toContain("(missing backend in audit-root)");
|
|
488
|
+
teardown();
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test("json carries `missing` on the finding", async () => {
|
|
492
|
+
setup();
|
|
493
|
+
const result = await auditCommand({ path: dir, format: "json" });
|
|
494
|
+
const doc = JSON.parse(result.output) as { findings: Array<{ checkId: string; missing?: { kind: string; scope: string } }> };
|
|
495
|
+
const tf001 = doc.findings.find((f) => f.checkId === "TF001");
|
|
496
|
+
expect(tf001?.missing).toEqual({ kind: "backend", scope: "audit-root" });
|
|
497
|
+
teardown();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
test("sarif carries `missing` in the result's properties, and still validates against the SARIF schema", async () => {
|
|
501
|
+
setup();
|
|
502
|
+
const result = await auditCommand({ path: dir, format: "sarif" });
|
|
503
|
+
const doc = JSON.parse(result.output) as {
|
|
504
|
+
runs: Array<{ results: Array<{ ruleId: string; properties?: { missing?: { kind: string; scope: string } } }> }>;
|
|
505
|
+
};
|
|
506
|
+
const tf001 = doc.runs[0].results.find((r) => r.ruleId === "TF001");
|
|
507
|
+
expect(tf001?.properties?.missing).toEqual({ kind: "backend", scope: "audit-root" });
|
|
508
|
+
|
|
509
|
+
const ajv = new Ajv({ strict: false, allErrors: true });
|
|
510
|
+
const validate = ajv.compile(loadSarifSchema() as object);
|
|
511
|
+
const valid = validate(doc);
|
|
512
|
+
if (!valid) throw new Error(ajv.errorsText(validate.errors));
|
|
513
|
+
expect(valid).toBe(true);
|
|
514
|
+
teardown();
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
|
|
444
518
|
test("sarif schema validation also holds for the empty-result case (no findings)", async () => {
|
|
445
519
|
const repo = fileURLToPath(new URL("./__fixtures__/audit-fountain-clean", import.meta.url));
|
|
446
520
|
const result = await auditCommand({ path: repo, format: "sarif" });
|
|
@@ -555,6 +629,82 @@ describe("secrets detection (#443)", () => {
|
|
|
555
629
|
});
|
|
556
630
|
});
|
|
557
631
|
|
|
632
|
+
describe("Terraform HCL suppression (chant #2111)", () => {
|
|
633
|
+
function tmpRepo(): string {
|
|
634
|
+
const dir = join(tmpdir(), `chant-audit-tf-suppress-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
|
635
|
+
mkdirSync(dir, { recursive: true });
|
|
636
|
+
mkdirSync(join(dir, "infra"), { recursive: true });
|
|
637
|
+
return dir;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const BACKENDLESS = 'terraform {\n required_version = ">= 1.5.0"\n}\n';
|
|
641
|
+
|
|
642
|
+
async function auditTerraform(dir: string): Promise<Awaited<ReturnType<typeof auditCommand>>> {
|
|
643
|
+
const all = await loadAuditPlugins();
|
|
644
|
+
return auditCommand({ path: dir, plugins: all.filter((p) => p.name === "terraform"), format: "json" });
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
test("chant-ignore-block suppresses TF001 through chant audit", async () => {
|
|
648
|
+
const dir = tmpRepo();
|
|
649
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF001\n${BACKENDLESS}`);
|
|
650
|
+
const result = await auditTerraform(dir);
|
|
651
|
+
expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
|
|
652
|
+
expect(result.suppressedCount).toBe(1);
|
|
653
|
+
rmSync(dir, { recursive: true, force: true });
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
test("a plain chant-ignore on the same block also suppresses TF001 through chant audit", async () => {
|
|
657
|
+
const dir = tmpRepo();
|
|
658
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore: TF001\n${BACKENDLESS}`);
|
|
659
|
+
const result = await auditTerraform(dir);
|
|
660
|
+
expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
|
|
661
|
+
expect(result.suppressedCount).toBe(1);
|
|
662
|
+
rmSync(dir, { recursive: true, force: true });
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
test('"all" suppresses TF001 through chant audit', async () => {
|
|
666
|
+
const dir = tmpRepo();
|
|
667
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: all\n${BACKENDLESS}`);
|
|
668
|
+
const result = await auditTerraform(dir);
|
|
669
|
+
expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
|
|
670
|
+
rmSync(dir, { recursive: true, force: true });
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
test("chant-ignore-file at the top of the file suppresses TF001 through chant audit", async () => {
|
|
674
|
+
const dir = tmpRepo();
|
|
675
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-file: TF001\n${BACKENDLESS}`);
|
|
676
|
+
const result = await auditTerraform(dir);
|
|
677
|
+
expect(result.findings.map((f) => f.checkId)).not.toContain("TF001");
|
|
678
|
+
rmSync(dir, { recursive: true, force: true });
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
test("a chant-ignore-file NOT at the top has no effect and is reported through chant audit", async () => {
|
|
682
|
+
const dir = tmpRepo();
|
|
683
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# a header\n# chant-ignore-file: TF001\n${BACKENDLESS}`);
|
|
684
|
+
const result = await auditTerraform(dir);
|
|
685
|
+
expect(result.findings.map((f) => f.checkId)).toContain("TF001"); // still fires
|
|
686
|
+
expect(result.findings.map((f) => f.checkId)).toContain("SUPP002");
|
|
687
|
+
rmSync(dir, { recursive: true, force: true });
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
test("a directive naming a different rule id does not suppress TF001 through chant audit", async () => {
|
|
691
|
+
const dir = tmpRepo();
|
|
692
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF010\n${BACKENDLESS}`);
|
|
693
|
+
const result = await auditTerraform(dir);
|
|
694
|
+
expect(result.findings.map((f) => f.checkId)).toContain("TF001");
|
|
695
|
+
rmSync(dir, { recursive: true, force: true });
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
test("an already-expired suppression no longer suppresses TF001 and is reported through chant audit", async () => {
|
|
699
|
+
const dir = tmpRepo();
|
|
700
|
+
writeFileSync(join(dir, "infra", "main.tf"), `# chant-ignore-block: TF001 exp:2020-01-01\n${BACKENDLESS}`);
|
|
701
|
+
const result = await auditTerraform(dir);
|
|
702
|
+
expect(result.findings.map((f) => f.checkId)).toContain("TF001"); // still fires: expired
|
|
703
|
+
expect(result.findings.map((f) => f.checkId)).toContain("SUPP001");
|
|
704
|
+
rmSync(dir, { recursive: true, force: true });
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
|
|
558
708
|
describe("Wrangler config audit (#446)", () => {
|
|
559
709
|
function tmpRepo(): string {
|
|
560
710
|
const dir = join(tmpdir(), `chant-audit-wrangler-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -649,3 +799,31 @@ describe("nginx config audit (#1979)", () => {
|
|
|
649
799
|
rmSync(dir, { recursive: true, force: true });
|
|
650
800
|
});
|
|
651
801
|
});
|
|
802
|
+
|
|
803
|
+
describe("committed Terraform state (TF023, #2110)", () => {
|
|
804
|
+
function tmpRepo(): string {
|
|
805
|
+
const dir = join(tmpdir(), `chant-audit-tfstate-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
|
806
|
+
mkdirSync(dir, { recursive: true });
|
|
807
|
+
return dir;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
test("fires end to end on a directory with a tracked state file, with no lexicon installed", async () => {
|
|
811
|
+
const dir = tmpRepo();
|
|
812
|
+
writeFileSync(join(dir, "main.tf"), 'resource "null_resource" "a" {}\n');
|
|
813
|
+
writeFileSync(join(dir, "terraform.tfstate"), JSON.stringify({ version: 4, resources: [] }));
|
|
814
|
+
const result = await auditCommand({ path: dir, plugins: [] });
|
|
815
|
+
expect(result.findings.map((f) => f.checkId)).toContain("TF023");
|
|
816
|
+
rmSync(dir, { recursive: true, force: true });
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
test("says nothing when the state is ignored rather than committed", async () => {
|
|
820
|
+
const dir = tmpRepo();
|
|
821
|
+
writeFileSync(join(dir, ".gitignore"), "*.tfstate\n.terraform/\n");
|
|
822
|
+
writeFileSync(join(dir, "main.tf"), 'resource "null_resource" "a" {}\n');
|
|
823
|
+
writeFileSync(join(dir, "terraform.tfstate"), JSON.stringify({ version: 4, resources: [] }));
|
|
824
|
+
mkdirSync(join(dir, ".terraform"), { recursive: true });
|
|
825
|
+
const result = await auditCommand({ path: dir, plugins: [] });
|
|
826
|
+
expect(result.findings.map((f) => f.checkId)).not.toContain("TF023");
|
|
827
|
+
rmSync(dir, { recursive: true, force: true });
|
|
828
|
+
});
|
|
829
|
+
});
|