@intentius/chant 0.56.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/import.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/import/ir-utils.d.ts +1 -1
- package/dist/import/ir-utils.d.ts.map +1 -1
- package/dist/import/parser.d.ts +33 -0
- package/dist/import/parser.d.ts.map +1 -1
- 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/dist/stack-output.d.ts +5 -0
- package/dist/stack-output.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/import.ts +6 -0
- 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/import/ir-utils.ts +11 -1
- package/src/import/parser.ts +35 -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/src/stack-output.ts +6 -1
- 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
|
@@ -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
|
-
|
|
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.
|
|
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))]
|
|
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
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
@@ -395,29 +428,37 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
|
|
|
395
428
|
// its own path detector plus a parsed-content marker check (a `.conf` in a
|
|
396
429
|
// shared directory name like conf.d/ only counts once it parses as nginx).
|
|
397
430
|
const nginxFindings = auditNginxConfigs(candidates);
|
|
431
|
+
// TF023 (#2110) — committed Terraform state. Lexicon-independent for the
|
|
432
|
+
// same reason the three above are: it reads the discovered paths, not a
|
|
433
|
+
// parsed root module, so it fires with or without the terraform lexicon.
|
|
434
|
+
const terraformStateFindings = auditTerraformState(candidates);
|
|
398
435
|
|
|
399
436
|
if (plugins.length === 0) {
|
|
400
437
|
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" };
|
|
438
|
+
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
439
|
}
|
|
403
440
|
|
|
404
441
|
const missingLexiconNote = missingLexiconHint(unclaimed);
|
|
405
442
|
|
|
406
|
-
if (inputs.length === 0 && secretsFindings.length === 0 && wranglerFindings.length === 0 && nginxFindings.length === 0) {
|
|
443
|
+
if (inputs.length === 0 && secretsFindings.length === 0 && wranglerFindings.length === 0 && nginxFindings.length === 0 && terraformStateFindings.length === 0) {
|
|
407
444
|
const output = `No auditable files found under ${options.path}.${missingLexiconNote ? ` ${missingLexiconNote}` : ""}`;
|
|
408
445
|
return { success: true, status: "ok", output, findings: [], scanned: [], unclaimed, exitCode: 0 };
|
|
409
446
|
}
|
|
410
447
|
|
|
411
448
|
let findings: AuditFinding[] = [];
|
|
449
|
+
// chant #2111: mutated in place by `auditFiles` so its inline (`# chant-
|
|
450
|
+
// ignore*`) suppressed count reaches the summary without changing
|
|
451
|
+
// `auditFiles`'s `AuditFinding[]` return type; see `SuppressionStats`'s doc.
|
|
452
|
+
const suppressionStats: SuppressionStats = { count: 0 };
|
|
412
453
|
if (inputs.length > 0) {
|
|
413
454
|
try {
|
|
414
|
-
findings = await auditFiles(inputs, { checksProvider: options.checksProvider });
|
|
455
|
+
findings = await auditFiles(inputs, { checksProvider: options.checksProvider, suppressionStats });
|
|
415
456
|
} catch (err) {
|
|
416
457
|
const msg = err instanceof Error ? err.message : String(err);
|
|
417
458
|
return { success: false, output: "", findings: [], scanned, exitCode: 1, error: msg };
|
|
418
459
|
}
|
|
419
460
|
}
|
|
420
|
-
findings = [...findings, ...secretsFindings, ...wranglerFindings, ...nginxFindings];
|
|
461
|
+
findings = [...findings, ...secretsFindings, ...wranglerFindings, ...nginxFindings, ...terraformStateFindings];
|
|
421
462
|
// Resolve the audit catalog once, aggregating the audited lexicons' own
|
|
422
463
|
// metadata over core's static catalog (#687). The lexicons are already loaded
|
|
423
464
|
// by `auditFiles` above, so this is cheap. Core's static catalog (always
|
|
@@ -428,6 +469,11 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
|
|
|
428
469
|
if (tier === "merge-worthy") findings = findings.filter((f) => isMergeWorthy(f, catalog));
|
|
429
470
|
const notes = coverageNotes(inputs);
|
|
430
471
|
if (missingLexiconNote) notes.push(missingLexiconNote);
|
|
472
|
+
if (suppressionStats.count > 0) {
|
|
473
|
+
notes.push(
|
|
474
|
+
`${suppressionStats.count} finding${suppressionStats.count === 1 ? "" : "s"} suppressed via inline chant-ignore comments.`,
|
|
475
|
+
);
|
|
476
|
+
}
|
|
431
477
|
|
|
432
478
|
// Diff-bearing renderers (markdown, html) need action SHAs / image digests
|
|
433
479
|
// resolved up front (sync maps so rendering stays synchronous).
|
|
@@ -495,10 +541,10 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
|
|
|
495
541
|
} catch (err) {
|
|
496
542
|
return { success: false, output, findings, scanned, exitCode: 1, error: `Failed to write ${options.output}: ${err instanceof Error ? err.message : String(err)}` };
|
|
497
543
|
}
|
|
498
|
-
return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode, wroteTo: options.output };
|
|
544
|
+
return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode, wroteTo: options.output, suppressedCount: suppressionStats.count };
|
|
499
545
|
}
|
|
500
546
|
|
|
501
|
-
return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode };
|
|
547
|
+
return { success: true, status: "ok", output, findings, scanned, unclaimed, exitCode, suppressedCount: suppressionStats.count };
|
|
502
548
|
}
|
|
503
549
|
|
|
504
550
|
/** Print an audit result to stdout. */
|
|
@@ -950,19 +950,21 @@ export const x = { [Symbol.for("chant.declarable")]: true, entityType: "X", lexi
|
|
|
950
950
|
});
|
|
951
951
|
});
|
|
952
952
|
|
|
953
|
-
test("
|
|
954
|
-
//
|
|
955
|
-
//
|
|
956
|
-
//
|
|
953
|
+
test("serializer files under ops/ go to <project>/dist/ops even with no --output (#878)", async () => {
|
|
954
|
+
// Whatever a serializer emits under `ops/` must land in
|
|
955
|
+
// `<project>/dist/ops/<name>/`, beside the `op.json` core writes there,
|
|
956
|
+
// even when the build has no --output (an Op-only project often has no
|
|
957
|
+
// primary resource manifest to route). The routing is on the `ops/`
|
|
958
|
+
// prefix alone — it does not know or care what the files are.
|
|
957
959
|
const opSerializer: Serializer = {
|
|
958
960
|
name: "multi",
|
|
959
961
|
rulePrefix: "MULTI",
|
|
960
962
|
serialize: () => ({
|
|
961
963
|
primary: "{}",
|
|
962
964
|
files: {
|
|
963
|
-
"ops/
|
|
964
|
-
"ops/
|
|
965
|
-
"ops/
|
|
965
|
+
"ops/nightly-report/steps.json": "{}\n",
|
|
966
|
+
"ops/nightly-report/notes.md": "# notes\n",
|
|
967
|
+
"ops/nightly-report/nested/extra.txt": "extra\n",
|
|
966
968
|
},
|
|
967
969
|
}),
|
|
968
970
|
};
|
|
@@ -979,8 +981,31 @@ export const x = { [Symbol.for("chant.declarable")]: true, entityType: "X", lexi
|
|
|
979
981
|
} as BuildOptions);
|
|
980
982
|
|
|
981
983
|
expect(result.errors).toEqual([]);
|
|
982
|
-
expect(existsSync(join(testDir, "dist", "ops", "
|
|
983
|
-
expect(existsSync(join(testDir, "dist", "ops", "
|
|
984
|
+
expect(existsSync(join(testDir, "dist", "ops", "nightly-report", "steps.json"))).toBe(true);
|
|
985
|
+
expect(existsSync(join(testDir, "dist", "ops", "nightly-report", "notes.md"))).toBe(true);
|
|
986
|
+
expect(existsSync(join(testDir, "dist", "ops", "nightly-report", "nested", "extra.txt"))).toBe(true);
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
test("an Op entity emits dist/ops/<name>/op.json from core, with no serializer involved (#2118)", async () => {
|
|
990
|
+
await writeFile(
|
|
991
|
+
join(testDir, "deploy.op.ts"),
|
|
992
|
+
`export default { [Symbol.for("chant.declarable")]: true, entityType: "Chant::Op", lexicon: "chant", kind: "resource", attributes: {},` +
|
|
993
|
+
` props: { name: "deploy", overview: "Deploy the thing", labels: { Env: "staging" },` +
|
|
994
|
+
` phases: [{ name: "Apply", steps: [{ kind: "activity", fn: "shellCmd", args: { cmd: "true" } }] }] } };`,
|
|
995
|
+
);
|
|
996
|
+
|
|
997
|
+
const result = await buildCommand({ path: testDir, format: "json", serializers: [] } as BuildOptions);
|
|
998
|
+
|
|
999
|
+
expect(result.errors).toEqual([]);
|
|
1000
|
+
const ir = JSON.parse(readFileSync(join(testDir, "dist", "ops", "deploy", "op.json"), "utf-8"));
|
|
1001
|
+
expect(ir.formatVersion).toBe("2.0");
|
|
1002
|
+
expect(ir.name).toBe("deploy");
|
|
1003
|
+
expect(ir.labels).toEqual({ Env: "staging" });
|
|
1004
|
+
expect(ir).not.toHaveProperty("taskQueue");
|
|
1005
|
+
expect(ir.phases[0].steps[0]).toMatchObject({ kind: "activity", fn: "shellCmd", profile: "fastIdempotent" });
|
|
1006
|
+
// Ops are held out of `partitionByLexicon` (they have no serializer and
|
|
1007
|
+
// need none), so core's own `chant` lexicon never trips the warning.
|
|
1008
|
+
expect(result.warnings.filter((w) => w.includes("No serializer"))).toEqual([]);
|
|
984
1009
|
});
|
|
985
1010
|
|
|
986
1011
|
// ── #284 bug 2: array-of-objects must serialize to valid YAML ──────────
|
|
@@ -1219,6 +1244,264 @@ export const x = { [Symbol.for("chant.declarable")]: true, entityType: "X", lexi
|
|
|
1219
1244
|
30_000,
|
|
1220
1245
|
);
|
|
1221
1246
|
});
|
|
1247
|
+
|
|
1248
|
+
describe("post-synth findings honor inline chant-ignore comments (chant #2111)", () => {
|
|
1249
|
+
/**
|
|
1250
|
+
* A discovered entity carrying a `suppressions` directive by hand, the
|
|
1251
|
+
* generic, duck-typed field `applyInlineSuppressions` reads (see
|
|
1252
|
+
* `../../lint/suppressions.ts`'s module doc). The terraform lexicon
|
|
1253
|
+
* populates this from real `# chant-ignore*` HCL comments
|
|
1254
|
+
* (`lexicons/terraform/src/hcl/suppressions.ts`); this test proves the
|
|
1255
|
+
* core wiring, that `chant build` applies it to ANY lexicon's entities,
|
|
1256
|
+
* without needing a real HCL parse.
|
|
1257
|
+
*/
|
|
1258
|
+
async function writeSuppressibleEntity(ids: string): Promise<void> {
|
|
1259
|
+
await writeFile(
|
|
1260
|
+
join(testDir, "main.ts"),
|
|
1261
|
+
`export const e = {\n` +
|
|
1262
|
+
` lexicon: "test",\n` +
|
|
1263
|
+
` entityType: "TestEntity",\n` +
|
|
1264
|
+
` [Symbol.for("chant.declarable")]: true,\n` +
|
|
1265
|
+
` suppressions: [{ form: "chant-ignore", ids: new Set(${JSON.stringify(ids.split(","))}), file: "main.ts", line: 1, key: "main.ts:1:chant-ignore" }],\n` +
|
|
1266
|
+
`};\n`,
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/** Same shape as `fakePostSynthPlugin` above, except its check attaches `entity` to whatever entity the build discovered, so a suppression directive on that entity has something to match against. */
|
|
1271
|
+
function fakeEntitySuppressionPlugin(checkId: string, severity: "error" | "warning" | "info"): LexiconPlugin {
|
|
1272
|
+
return {
|
|
1273
|
+
name: "fake",
|
|
1274
|
+
serializer: { name: "fake", rulePrefix: "FAKE", serialize: () => "{}" },
|
|
1275
|
+
generate: async () => {},
|
|
1276
|
+
validate: async () => {},
|
|
1277
|
+
coverage: async () => {},
|
|
1278
|
+
package: async () => {},
|
|
1279
|
+
postSynthChecks: () => [
|
|
1280
|
+
{
|
|
1281
|
+
id: checkId,
|
|
1282
|
+
description: "test check",
|
|
1283
|
+
check: (ctx) => {
|
|
1284
|
+
const [key] = [...ctx.entities.keys()];
|
|
1285
|
+
return key ? [{ checkId, severity, message: `${checkId} triggered`, entity: key }] : [];
|
|
1286
|
+
},
|
|
1287
|
+
},
|
|
1288
|
+
],
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
test("an inline chant-ignore naming the finding's checkId suppresses it and reports a suppressed count", async () => {
|
|
1293
|
+
await writeSuppressibleEntity("FAKE005");
|
|
1294
|
+
await writeFile(join(testDir, "chant.config.ts"), `export default {};\n`);
|
|
1295
|
+
|
|
1296
|
+
const result = await buildCommand({
|
|
1297
|
+
path: testDir,
|
|
1298
|
+
format: "json",
|
|
1299
|
+
serializers: [mockSerializer],
|
|
1300
|
+
plugins: [fakeEntitySuppressionPlugin("FAKE005", "error")],
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
expect(result.success).toBe(true);
|
|
1304
|
+
expect(result.errors).toEqual([]);
|
|
1305
|
+
expect(result.warnings.some((w) => w.includes("1 post-synth finding(s) suppressed via inline chant-ignore comments"))).toBe(true);
|
|
1306
|
+
});
|
|
1307
|
+
|
|
1308
|
+
test("an inline chant-ignore naming a different id has no effect", async () => {
|
|
1309
|
+
await writeSuppressibleEntity("FAKE006");
|
|
1310
|
+
await writeFile(join(testDir, "chant.config.ts"), `export default {};\n`);
|
|
1311
|
+
|
|
1312
|
+
const result = await buildCommand({
|
|
1313
|
+
path: testDir,
|
|
1314
|
+
format: "json",
|
|
1315
|
+
serializers: [mockSerializer],
|
|
1316
|
+
plugins: [fakeEntitySuppressionPlugin("FAKE007", "error")],
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
expect(result.success).toBe(false);
|
|
1320
|
+
expect(result.errors.some((e) => e.includes("FAKE007 triggered"))).toBe(true);
|
|
1321
|
+
expect(result.warnings.some((w) => w.includes("suppressed"))).toBe(false);
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
test("ignorable: false in lint.rules denies the ignore and reports the attempt, keeping the finding active", async () => {
|
|
1325
|
+
await writeSuppressibleEntity("FAKE008");
|
|
1326
|
+
await writeFile(
|
|
1327
|
+
join(testDir, "chant.config.ts"),
|
|
1328
|
+
`export default { lint: { rules: { "FAKE008": ["error", { ignorable: false }] } } };\n`,
|
|
1329
|
+
);
|
|
1330
|
+
|
|
1331
|
+
const result = await buildCommand({
|
|
1332
|
+
path: testDir,
|
|
1333
|
+
format: "json",
|
|
1334
|
+
serializers: [mockSerializer],
|
|
1335
|
+
plugins: [fakeEntitySuppressionPlugin("FAKE008", "error")],
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
expect(result.success).toBe(false);
|
|
1339
|
+
expect(result.errors.some((e) => e.includes("FAKE008 triggered"))).toBe(true);
|
|
1340
|
+
expect(result.warnings.some((w) => w.includes("SUPP003") && w.includes("ignorable: false"))).toBe(true);
|
|
1341
|
+
});
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* chant #2113: `lint.presets` filters WHICH post-synth check ids are
|
|
1346
|
+
* reported at all, ahead of `lint.rules`' severity overrides (proven
|
|
1347
|
+
* above). A plugin with no `lintPresets()` is unaffected (the common case
|
|
1348
|
+
* today); one that ships presets defaults to `recommended` and is
|
|
1349
|
+
* overridden per-lexicon via `lint.presets: { <name>: "<preset>" }`.
|
|
1350
|
+
*/
|
|
1351
|
+
describe("post-synth findings honor lint.presets (chant #2113)", () => {
|
|
1352
|
+
async function writeTrivialEntity(): Promise<void> {
|
|
1353
|
+
await writeFile(
|
|
1354
|
+
join(testDir, "main.ts"),
|
|
1355
|
+
`export const e = { lexicon: "test", entityType: "TestEntity", [Symbol.for("chant.declarable")]: true };\n`,
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
/** A `LexiconPlugin` whose one post-synth check always fires, with `recommended`/`all` presets. `recommended` excludes the check's own id, `all` includes it. */
|
|
1360
|
+
function fakePresetPlugin(): LexiconPlugin {
|
|
1361
|
+
return {
|
|
1362
|
+
name: "fakepreset",
|
|
1363
|
+
serializer: { name: "fakepreset", rulePrefix: "FP", serialize: () => "{}" },
|
|
1364
|
+
generate: async () => {},
|
|
1365
|
+
validate: async () => {},
|
|
1366
|
+
coverage: async () => {},
|
|
1367
|
+
package: async () => {},
|
|
1368
|
+
postSynthChecks: () => [
|
|
1369
|
+
{
|
|
1370
|
+
id: "FP001",
|
|
1371
|
+
description: "a report-only check, always fires",
|
|
1372
|
+
check: () => [{ checkId: "FP001", severity: "warning" as const, message: "FP001 triggered" }],
|
|
1373
|
+
},
|
|
1374
|
+
],
|
|
1375
|
+
lintPresets: () => ({ recommended: [], all: ["FP001"] }),
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
test("with no lint.presets config, the default preset (recommended) excludes the finding", async () => {
|
|
1380
|
+
await writeTrivialEntity();
|
|
1381
|
+
const result = await buildCommand({ path: testDir, format: "json", serializers: [mockSerializer], plugins: [fakePresetPlugin()] });
|
|
1382
|
+
expect(result.warnings.join("\n")).not.toContain("FP001 triggered");
|
|
1383
|
+
expect(result.warnings.some((w) => w.includes("not reported: excluded by the active lint.presets preset"))).toBe(true);
|
|
1384
|
+
});
|
|
1385
|
+
|
|
1386
|
+
test('lint.presets: { fakepreset: "all" } includes the finding', async () => {
|
|
1387
|
+
await writeTrivialEntity();
|
|
1388
|
+
await writeFile(
|
|
1389
|
+
join(testDir, "chant.config.ts"),
|
|
1390
|
+
`export default { lint: { presets: { fakepreset: "all" } } };\n`,
|
|
1391
|
+
);
|
|
1392
|
+
const result = await buildCommand({ path: testDir, format: "json", serializers: [mockSerializer], plugins: [fakePresetPlugin()] });
|
|
1393
|
+
expect(result.warnings.join("\n")).toContain("FP001 triggered");
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
test("an explicit lint.rules entry re-enables the rule even under the excluding (recommended) preset", async () => {
|
|
1397
|
+
await writeTrivialEntity();
|
|
1398
|
+
await writeFile(
|
|
1399
|
+
join(testDir, "chant.config.ts"),
|
|
1400
|
+
`export default { lint: { rules: { "FP001": "warning" } } };\n`,
|
|
1401
|
+
);
|
|
1402
|
+
const result = await buildCommand({ path: testDir, format: "json", serializers: [mockSerializer], plugins: [fakePresetPlugin()] });
|
|
1403
|
+
expect(result.warnings.join("\n")).toContain("FP001 triggered");
|
|
1404
|
+
});
|
|
1405
|
+
});
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
// #2122 (epic #2114 sub-issue 6) — OPS012/OPS013/OPS014 are core-owned
|
|
1409
|
+
// post-synth checks over the Op model, run unscoped by `coreOpChecks()`
|
|
1410
|
+
// regardless of which plugins/lexicons are configured. This is the
|
|
1411
|
+
// end-to-end path acceptance criterion 3 needs: `chant build` over a real
|
|
1412
|
+
// ConvergeOp-shaped fixture with a destructive gated dispatch rule fails
|
|
1413
|
+
// with the OPS014 refusal, with zero plugins/lexicons loaded.
|
|
1414
|
+
describe("buildCommand — OPS014 (op-model post-synth checks, #2122)", () => {
|
|
1415
|
+
let testDir: string;
|
|
1416
|
+
|
|
1417
|
+
const mockSerializer: Serializer = {
|
|
1418
|
+
name: "test",
|
|
1419
|
+
rulePrefix: "TEST",
|
|
1420
|
+
serialize: (entities) => JSON.stringify({ resources: [...entities.keys()] }, null, 2),
|
|
1421
|
+
};
|
|
1422
|
+
|
|
1423
|
+
beforeEach(async () => {
|
|
1424
|
+
testDir = join(tmpdir(), `chant-ops014-test-${Date.now()}-${Math.random()}`);
|
|
1425
|
+
await mkdir(testDir, { recursive: true });
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
afterEach(async () => {
|
|
1429
|
+
await rm(testDir, { recursive: true, force: true });
|
|
1430
|
+
});
|
|
1431
|
+
|
|
1432
|
+
test("fails build with the OPS014 refusal on a ConvergeOp dispatching a destructive, gated op", async () => {
|
|
1433
|
+
// The destructive dispatch target: a gated `nativeApply` with
|
|
1434
|
+
// `deleteMode: "gated"` — classified destructive by
|
|
1435
|
+
// `../../op/op-verb-class.ts`, gate or not.
|
|
1436
|
+
await writeFile(
|
|
1437
|
+
join(testDir, "prune-staging.op.ts"),
|
|
1438
|
+
`
|
|
1439
|
+
export const pruneStaging = {
|
|
1440
|
+
[Symbol.for("chant.declarable")]: true,
|
|
1441
|
+
entityType: "Chant::Op",
|
|
1442
|
+
lexicon: "chant",
|
|
1443
|
+
kind: "resource",
|
|
1444
|
+
props: {
|
|
1445
|
+
name: "prune-staging",
|
|
1446
|
+
overview: "test",
|
|
1447
|
+
phases: [
|
|
1448
|
+
{ name: "Approve", steps: [{ kind: "gate", signalName: "approve-x" }] },
|
|
1449
|
+
{ name: "Apply", steps: [
|
|
1450
|
+
{ kind: "activity", fn: "nativeApply", args: { target: "kubectl", env: "staging", output: "dist", deleteMode: "gated" } },
|
|
1451
|
+
] },
|
|
1452
|
+
],
|
|
1453
|
+
},
|
|
1454
|
+
};
|
|
1455
|
+
`,
|
|
1456
|
+
);
|
|
1457
|
+
|
|
1458
|
+
// The ConvergeOp-shaped Op: dial "apply", one rule dispatching the
|
|
1459
|
+
// destructive target above.
|
|
1460
|
+
await writeFile(
|
|
1461
|
+
join(testDir, "converge.op.ts"),
|
|
1462
|
+
`
|
|
1463
|
+
export const converge = {
|
|
1464
|
+
[Symbol.for("chant.declarable")]: true,
|
|
1465
|
+
entityType: "Chant::Op",
|
|
1466
|
+
lexicon: "chant",
|
|
1467
|
+
kind: "resource",
|
|
1468
|
+
props: {
|
|
1469
|
+
name: "converge",
|
|
1470
|
+
overview: "test",
|
|
1471
|
+
labels: { Converge: "true", Env: "staging", Dial: "apply" },
|
|
1472
|
+
phases: [
|
|
1473
|
+
{ name: "Observe", steps: [{ kind: "activity", fn: "lifecycleDiff", args: { env: "staging" }, id: "diff" }] },
|
|
1474
|
+
{ name: "Converge", steps: [{ kind: "activity", fn: "convergeTick", args: { rules: [
|
|
1475
|
+
{
|
|
1476
|
+
id: "drift-prune",
|
|
1477
|
+
when: { kind: "field-comparison", field: "status", op: "eq", value: "drifted" },
|
|
1478
|
+
then: { kind: "run", op: "prune-staging" },
|
|
1479
|
+
why: "Prune drifted resources.",
|
|
1480
|
+
},
|
|
1481
|
+
] } }] },
|
|
1482
|
+
],
|
|
1483
|
+
},
|
|
1484
|
+
};
|
|
1485
|
+
`,
|
|
1486
|
+
);
|
|
1487
|
+
|
|
1488
|
+
const result = await buildCommand({
|
|
1489
|
+
path: testDir,
|
|
1490
|
+
format: "json",
|
|
1491
|
+
serializers: [mockSerializer],
|
|
1492
|
+
plugins: [],
|
|
1493
|
+
});
|
|
1494
|
+
|
|
1495
|
+
expect(result.success).toBe(false);
|
|
1496
|
+
// build.ts's plain error strings carry the diagnostic's message text, not
|
|
1497
|
+
// its checkId — OPS014's own message names what it refused and why (see
|
|
1498
|
+
// ../../lint/rules/op/ops014-converge-rule-refusals.ts).
|
|
1499
|
+
expect(
|
|
1500
|
+
result.errors.some(
|
|
1501
|
+
(e) => e.includes("destructive") && e.includes("prune-staging") && e.includes("refused in v1"),
|
|
1502
|
+
),
|
|
1503
|
+
).toBe(true);
|
|
1504
|
+
});
|
|
1222
1505
|
});
|
|
1223
1506
|
|
|
1224
1507
|
// ── #284 bug 1: -o extension drives format when --format is absent ────────
|