@intentius/chant 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +36 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +26 -9
- 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/carve-bridge.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 +13 -0
- 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 +12 -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/plugins.d.ts +22 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +40 -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 +24 -22
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +21 -6
- 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 +73 -37
- 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 +10 -22
- 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/detectLexicon.d.ts +13 -0
- package/dist/detectLexicon.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 +273 -16
- 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 +79 -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 +149 -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 +85 -30
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/change-signal.d.ts +91 -0
- package/dist/op/change-signal.d.ts.map +1 -0
- package/dist/op/composites/apply-op.d.ts +118 -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-name.d.ts +40 -0
- package/dist/op/gate-name.d.ts.map +1 -0
- package/dist/op/gate-summary.d.ts +43 -0
- package/dist/op/gate-summary.d.ts.map +1 -0
- 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 +29 -9
- 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 +185 -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 +93 -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 +96 -29
- 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/terraform/bridge.d.ts +26 -7
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve-provider.d.ts +28 -2
- package/dist/terraform/carve-provider.d.ts.map +1 -1
- package/dist/terraform/data-source-shape.d.ts +77 -0
- package/dist/terraform/data-source-shape.d.ts.map +1 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/providers/kubernetes.d.ts +5 -0
- package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +16 -4
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.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 +84 -18
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +202 -18
- 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 +191 -11
- package/src/cli/commands/audit.ts +78 -28
- package/src/cli/commands/build.test.ts +330 -9
- package/src/cli/commands/build.ts +170 -24
- package/src/cli/commands/carve-bridge.test.ts +237 -14
- package/src/cli/commands/carve-bridge.ts +21 -17
- package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
- 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 +194 -1
- package/src/cli/commands/lint.ts +205 -7
- 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 +341 -55
- package/src/cli/handlers/run.test.ts +568 -1295
- package/src/cli/handlers/run.ts +446 -912
- package/src/cli/main.test.ts +22 -16
- package/src/cli/main.ts +66 -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/plugins.test.ts +68 -2
- package/src/cli/plugins.ts +39 -0
- package/src/cli/registry.ts +40 -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 +4 -3
- package/src/components/__fixtures__/neo4j-fanout.json +1 -1
- 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 +28 -12
- package/src/components/cli-support.ts +60 -47
- package/src/components/component-schema.test.ts +18 -2
- package/src/components/component.schema.json +18 -5
- package/src/components/component.test.ts +2 -2
- package/src/components/component.ts +27 -7
- package/src/components/config-defaults.test.ts +2 -2
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +109 -20
- package/src/components/driver.ts +201 -84
- 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/neo4j-fanout.pilot.ts +3 -3
- 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.test.ts +19 -0
- package/src/components/verbs/run-agent.ts +12 -24
- 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/detectLexicon.ts +18 -1
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.test.ts +1 -1
- 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 +82 -2
- 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 +3 -3
- 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 +296 -16
- 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 +154 -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/pipeline-change-gate.test.ts +2 -2
- 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 +27 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -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 +161 -0
- package/src/op/activities/reconcile.ts +354 -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 +125 -41
- package/src/op/change-signal.test.ts +117 -0
- package/src/op/change-signal.ts +169 -0
- package/src/op/composites/apply-op.ts +218 -0
- package/src/op/composites/composites.test.ts +379 -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 +110 -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 +29 -14
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate-name.test.ts +65 -0
- package/src/op/gate-name.ts +60 -0
- package/src/op/gate-summary.ts +84 -0
- 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 +48 -8
- package/src/op/local-executor.test.ts +178 -34
- package/src/op/local-executor.ts +371 -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 +292 -0
- package/src/op/op-ir.ts +419 -0
- package/src/op/op-verb-class.test.ts +2 -2
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +28 -7
- package/src/op/operator.test.ts +543 -6
- package/src/op/operator.ts +203 -20
- 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 +106 -26
- 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/terraform/aws-resources.test.ts +13 -4
- package/src/terraform/bridge.test.ts +22 -9
- package/src/terraform/bridge.ts +89 -28
- package/src/terraform/carve-provider.ts +38 -2
- package/src/terraform/data-source-shape.ts +95 -0
- package/src/terraform/graph.ts +35 -7
- package/src/terraform/providers/kubernetes.ts +48 -2
- package/src/terraform/tier-map.ts +21 -6
- package/src/terraform/types.ts +8 -0
- 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,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PipelineAuditOp composite — the live include/component audit of GitLab
|
|
3
|
+
* pipelines as a chant Op with an optional schedule (#303).
|
|
4
|
+
*
|
|
5
|
+
* The gitlab post-synth checks (#297) own everything answerable from the
|
|
6
|
+
* deterministic build. This Op owns *only* the checks that require live
|
|
7
|
+
* resolution against a moving upstream truth — a pinned component/include ref
|
|
8
|
+
* that no longer resolves, an archived or moved upstream project, or a new
|
|
9
|
+
* advisory covering a component/image in use. It sits at **observe** on the
|
|
10
|
+
* lifecycle dial, with a finding-mode (`report | issue | merge-request`) as the
|
|
11
|
+
* **reconcile** step — for GitLab the PR mode is a merge request.
|
|
12
|
+
*
|
|
13
|
+
* Runs one-shot on the local Op executor via `chant run`; a `schedule` puts
|
|
14
|
+
* the cadence on the Op itself (#2120).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* export const { op } = PipelineAuditOp({
|
|
19
|
+
* name: "pipeline-audit",
|
|
20
|
+
* schedule: "0 6 * * *",
|
|
21
|
+
* onFinding: "merge-request",
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @see #297 — the deterministic counterpart this freshens.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { Op, phase } from "../builders";
|
|
29
|
+
import type { OpResource } from "../resource";
|
|
30
|
+
import type { PipelineAuditMode } from "../activities/pipeline-audit";
|
|
31
|
+
|
|
32
|
+
export interface PipelineAuditOpConfig {
|
|
33
|
+
/** Op name (kebab-case). Names the Op's output directory and is what `chant run` takes. */
|
|
34
|
+
name: string;
|
|
35
|
+
/** Cron expression. When set, it lands on the Op as `schedule`; omit for one-shot. */
|
|
36
|
+
schedule?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Path to the emitted `.gitlab-ci.yml` to audit at run time.
|
|
39
|
+
* @default ".gitlab-ci.yml"
|
|
40
|
+
*/
|
|
41
|
+
pipelineFile?: string;
|
|
42
|
+
/**
|
|
43
|
+
* What to produce on findings. Default: "report".
|
|
44
|
+
* @default "report"
|
|
45
|
+
*/
|
|
46
|
+
onFinding?: PipelineAuditMode;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface PipelineAuditOpResources {
|
|
50
|
+
/** Op resource — the audit Op, emitted on `chant build`. */
|
|
51
|
+
op: InstanceType<typeof OpResource>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function PipelineAuditOp(config: PipelineAuditOpConfig): PipelineAuditOpResources {
|
|
55
|
+
const onFinding = config.onFinding ?? "report";
|
|
56
|
+
|
|
57
|
+
const op = Op({
|
|
58
|
+
name: config.name,
|
|
59
|
+
overview: "Resolve pipeline include/component/image references against live upstreams and report drift",
|
|
60
|
+
labels: {
|
|
61
|
+
Audit: "true",
|
|
62
|
+
Surface: "gitlab-pipeline",
|
|
63
|
+
},
|
|
64
|
+
...(config.schedule ? { schedule: { cron: config.schedule, overlap: "skip" as const } } : {}),
|
|
65
|
+
phases: [
|
|
66
|
+
phase("Audit", [
|
|
67
|
+
{
|
|
68
|
+
kind: "activity",
|
|
69
|
+
fn: "pipelineSupplyChainAudit",
|
|
70
|
+
args: { pipelineFile: config.pipelineFile ?? ".gitlab-ci.yml", mode: onFinding },
|
|
71
|
+
outcomeAttribute: { name: "Findings", from: "findings" },
|
|
72
|
+
},
|
|
73
|
+
]),
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return { op };
|
|
78
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { ReconcileOp } from "./reconcile-op";
|
|
3
|
+
|
|
4
|
+
/** Reach into the generated Op's phases → the reconcilePr step. */
|
|
5
|
+
function reconcileStep(op: unknown): Record<string, unknown> {
|
|
6
|
+
const config = (op as { props: Record<string, unknown> }).props;
|
|
7
|
+
const phases = config.phases as Array<{ name: string; steps: Array<Record<string, unknown>> }>;
|
|
8
|
+
const reconcile = phases.find((p) => p.name === "Reconcile");
|
|
9
|
+
if (!reconcile) throw new Error("no Reconcile phase");
|
|
10
|
+
return reconcile.steps[0];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe("ReconcileOp composite — PR/issue URL outcome (#8)", () => {
|
|
14
|
+
test("pull-request mode (default) exposes prUrl as the PR outcome attribute", () => {
|
|
15
|
+
const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod" });
|
|
16
|
+
const step = reconcileStep(op);
|
|
17
|
+
expect(step.fn).toBe("reconcilePr");
|
|
18
|
+
expect((step.args as { mode: string }).mode).toBe("pull-request");
|
|
19
|
+
expect(step.outcomeAttribute).toEqual({ name: "PR", from: "prUrl" });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("issue mode exposes issueUrl as the Issue outcome attribute", () => {
|
|
23
|
+
const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod", onDrift: "issue" });
|
|
24
|
+
const step = reconcileStep(op);
|
|
25
|
+
expect((step.args as { mode: string }).mode).toBe("issue");
|
|
26
|
+
expect(step.outcomeAttribute).toEqual({ name: "Issue", from: "issueUrl" });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("report mode opens nothing, so carries no URL outcome", () => {
|
|
30
|
+
const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod", onDrift: "report" });
|
|
31
|
+
const step = reconcileStep(op);
|
|
32
|
+
expect((step.args as { mode: string }).mode).toBe("report");
|
|
33
|
+
expect(step.outcomeAttribute).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("ReconcileOp composite — cadence on the op (#2120)", () => {
|
|
38
|
+
function opProps(op: unknown): Record<string, unknown> {
|
|
39
|
+
return (op as { props: Record<string, unknown> }).props;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
test("one-shot form carries no schedule", () => {
|
|
43
|
+
const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod" });
|
|
44
|
+
expect(opProps(op).schedule).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("a cron lands on the op as { cron, overlap: \"skip\" }", () => {
|
|
48
|
+
const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod", schedule: "0 * * * *" });
|
|
49
|
+
expect(opProps(op).schedule).toEqual({ cron: "0 * * * *", overlap: "skip" });
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReconcileOp composite — the cloud → code workflow as an Op.
|
|
3
|
+
*
|
|
4
|
+
* Keeps source tracking reality: when live drifts from declarations, open a PR
|
|
5
|
+
* that regenerates the affected TypeScript. Mirrors the {@link WatchOp} shape.
|
|
6
|
+
*
|
|
7
|
+
* Phases: snapshot → plan → regenerate (live import) → open PR. The
|
|
8
|
+
* regenerate-and-PR step is the `reconcilePr` activity (#122), which derives
|
|
9
|
+
* the change set from `chant lifecycle plan` and opens a reviewable PR.
|
|
10
|
+
*
|
|
11
|
+
* Runs one-shot on the local Op executor for a `chant run`; with a `schedule`
|
|
12
|
+
* the cadence rides on the Op itself (#2120) for whichever runtime honours it.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // one-shot, local executor
|
|
17
|
+
* export const { op } = ReconcileOp({ name: "prod-reconcile", env: "prod" });
|
|
18
|
+
*
|
|
19
|
+
* // hourly
|
|
20
|
+
* export const { op } = ReconcileOp({
|
|
21
|
+
* name: "prod-reconcile",
|
|
22
|
+
* env: "prod",
|
|
23
|
+
* schedule: "0 * * * *",
|
|
24
|
+
* scope: { owned: true },
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @see #112 — stateless-authoritative state model + live import
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { Op, phase, activity } from "../builders";
|
|
32
|
+
import type { OpResource } from "../resource";
|
|
33
|
+
import type { ReconcileMode } from "../activities/reconcile";
|
|
34
|
+
|
|
35
|
+
export interface ReconcileOpConfig {
|
|
36
|
+
/** Op name (kebab-case). Names the Op's output directory and is what `chant run` takes. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** Environment to reconcile (e.g. "prod"). */
|
|
39
|
+
env: string;
|
|
40
|
+
/**
|
|
41
|
+
* Cron expression. When set, it lands on the Op as `schedule`; omit for
|
|
42
|
+
* one-shot `chant run` on the local executor.
|
|
43
|
+
*/
|
|
44
|
+
schedule?: string;
|
|
45
|
+
/**
|
|
46
|
+
* What to produce on drift. Default: "pull-request".
|
|
47
|
+
* @default "pull-request"
|
|
48
|
+
*/
|
|
49
|
+
onDrift?: ReconcileMode;
|
|
50
|
+
/** Restrict reconciliation to chant-owned resources. */
|
|
51
|
+
scope?: { owned?: boolean };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ReconcileOpResources {
|
|
55
|
+
/** Op resource — the snapshot→plan→regenerate→PR Op. */
|
|
56
|
+
op: InstanceType<typeof OpResource>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function ReconcileOp(config: ReconcileOpConfig): ReconcileOpResources {
|
|
60
|
+
const onDrift = config.onDrift ?? "pull-request";
|
|
61
|
+
const owned = config.scope?.owned ?? false;
|
|
62
|
+
|
|
63
|
+
// The reconcile's headline output is the opened PR (or issue, or the comment
|
|
64
|
+
// it posted on the triggering pull request) URL. Expose it as an outcome
|
|
65
|
+
// attribute so it prints in `chant run` and lands on the ledger. `report`
|
|
66
|
+
// mode opens nothing, so it has no URL outcome.
|
|
67
|
+
const reconcileOutcome =
|
|
68
|
+
onDrift === "pull-request"
|
|
69
|
+
? { name: "PR", from: "prUrl" }
|
|
70
|
+
: onDrift === "issue"
|
|
71
|
+
? { name: "Issue", from: "issueUrl" }
|
|
72
|
+
: onDrift === "comment"
|
|
73
|
+
? { name: "Comment", from: "commentUrl" }
|
|
74
|
+
: undefined;
|
|
75
|
+
|
|
76
|
+
const op = Op({
|
|
77
|
+
name: config.name,
|
|
78
|
+
overview: `Reconcile the ${config.env} environment into source (cloud → code)`,
|
|
79
|
+
labels: {
|
|
80
|
+
Reconcile: "true",
|
|
81
|
+
Env: config.env,
|
|
82
|
+
},
|
|
83
|
+
...(config.schedule ? { schedule: { cron: config.schedule, overlap: "skip" as const } } : {}),
|
|
84
|
+
phases: [
|
|
85
|
+
phase("Snapshot", [activity("lifecycleSnapshot", { env: config.env })]),
|
|
86
|
+
phase("Plan", [
|
|
87
|
+
{
|
|
88
|
+
kind: "activity",
|
|
89
|
+
fn: "lifecycleDiff",
|
|
90
|
+
args: { env: config.env, live: true },
|
|
91
|
+
outcomeAttribute: { name: "Drift", from: "drifted" },
|
|
92
|
+
},
|
|
93
|
+
]),
|
|
94
|
+
phase("Reconcile", [
|
|
95
|
+
// reconcilePr derives the change set from `chant lifecycle plan`,
|
|
96
|
+
// regenerates via `chant import --from`, and opens a PR. Surface the
|
|
97
|
+
// opened PR/issue URL as an outcome so `chant run` prints it — the
|
|
98
|
+
// reconcile's result is the link.
|
|
99
|
+
{
|
|
100
|
+
kind: "activity" as const,
|
|
101
|
+
fn: "reconcilePr",
|
|
102
|
+
args: { env: config.env, mode: onDrift, owned },
|
|
103
|
+
...(reconcileOutcome ? { outcomeAttribute: reconcileOutcome } : {}),
|
|
104
|
+
},
|
|
105
|
+
]),
|
|
106
|
+
],
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return { op };
|
|
110
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WatchOp composite — periodic state observation as an Op.
|
|
3
|
+
*
|
|
4
|
+
* Composes existing pieces:
|
|
5
|
+
* - The local executor (`../local-executor.ts`) runs the phases in order and
|
|
6
|
+
* files each step's record under the phase it belongs to
|
|
7
|
+
* - The pre-built lifecycleSnapshot + lifecycleDiff activities
|
|
8
|
+
* - `schedule` puts the cadence on the Op itself (#2120)
|
|
9
|
+
*
|
|
10
|
+
* The cron is Op data, not a resource: `chant operator` ticks on it, the
|
|
11
|
+
* github/gitlab/forgejo generators render it as a CI cron, and a hosting
|
|
12
|
+
* lexicon hands it to its own scheduler.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* export const { op } = WatchOp({
|
|
17
|
+
* name: "prod-watch",
|
|
18
|
+
* env: "prod",
|
|
19
|
+
* schedule: "0,15,30,45 * * * *", // every 15 minutes
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @see #31 — Continuous observation (the issue this composite addresses)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { Op, phase, activity } from "../builders";
|
|
27
|
+
import { receiptCheckInput } from "../receipt-store";
|
|
28
|
+
import type { OpResource } from "../resource";
|
|
29
|
+
import type { EffectReceiptDeclaration } from "../../effect-receipt";
|
|
30
|
+
|
|
31
|
+
export interface WatchOpConfig {
|
|
32
|
+
/** Op name (kebab-case). Names the Op's output directory and is what `chant run` takes. */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Environment to snapshot + diff (e.g. "prod"). */
|
|
35
|
+
env: string;
|
|
36
|
+
/**
|
|
37
|
+
* Cron expression controlling how often the watch runs. Omit for a
|
|
38
|
+
* one-shot `chant run` on the local executor.
|
|
39
|
+
* @example "0,15,30,45 * * * *" — every 15 minutes
|
|
40
|
+
* @example "0 * * * *" — hourly
|
|
41
|
+
*/
|
|
42
|
+
schedule?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Run `chant lifecycle diff --live` (queries cloud APIs) instead of the
|
|
45
|
+
* default digest-only diff. Recommended for real drift detection.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
live?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Effect receipts to check for staleness between change windows (#1834,
|
|
51
|
+
* epic #1703). Typed references only — import each EffectReceipt const.
|
|
52
|
+
* Read-only: the watch reads each receipt through the receipt store
|
|
53
|
+
* (provided by the receipt row's lexicon, #1835) and reports absent or
|
|
54
|
+
* differing values as findings. It never runs an effect and never writes
|
|
55
|
+
* a receipt — the `effect()` step is the sole writer.
|
|
56
|
+
*/
|
|
57
|
+
receipts?: EffectReceiptDeclaration[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface WatchOpResources {
|
|
61
|
+
/** Op resource — the snapshot+diff Op, emitted on `chant build`. */
|
|
62
|
+
op: InstanceType<typeof OpResource>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function WatchOp(config: WatchOpConfig): WatchOpResources {
|
|
66
|
+
const live = config.live ?? true;
|
|
67
|
+
|
|
68
|
+
const op = Op({
|
|
69
|
+
name: config.name,
|
|
70
|
+
overview: `Periodically snapshot and diff the ${config.env} environment`,
|
|
71
|
+
labels: {
|
|
72
|
+
Watch: "true",
|
|
73
|
+
Env: config.env,
|
|
74
|
+
},
|
|
75
|
+
...(config.schedule ? { schedule: { cron: config.schedule, overlap: "skip" as const } } : {}),
|
|
76
|
+
phases: [
|
|
77
|
+
phase("Snapshot", [activity("lifecycleSnapshot", { env: config.env })]),
|
|
78
|
+
phase("Diff", [
|
|
79
|
+
// outcomeAttribute surfaces lifecycleDiff's `drifted` boolean as the
|
|
80
|
+
// run's `Drift` outcome on the run ledger, so a reader of the ledger
|
|
81
|
+
// can pick out the runs that detected drift.
|
|
82
|
+
{
|
|
83
|
+
kind: "activity",
|
|
84
|
+
fn: "lifecycleDiff",
|
|
85
|
+
args: { env: config.env, live },
|
|
86
|
+
outcomeAttribute: { name: "Drift", from: "drifted" },
|
|
87
|
+
},
|
|
88
|
+
]),
|
|
89
|
+
// Receipt staleness (#1834): read-only over the receipt store — absent
|
|
90
|
+
// or differing receipts surface as findings (and a StaleReceipts run
|
|
91
|
+
// outcome); nothing runs and nothing is written.
|
|
92
|
+
...(config.receipts && config.receipts.length > 0
|
|
93
|
+
? [
|
|
94
|
+
phase("Receipts", [
|
|
95
|
+
{
|
|
96
|
+
kind: "activity" as const,
|
|
97
|
+
fn: "receiptStaleness",
|
|
98
|
+
args: { receipts: config.receipts.map(receiptCheckInput) },
|
|
99
|
+
outcomeAttribute: { name: "StaleReceipts", from: "stale" },
|
|
100
|
+
},
|
|
101
|
+
]),
|
|
102
|
+
]
|
|
103
|
+
: []),
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return { op };
|
|
108
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { WorkflowAuditOp } from "./workflow-audit-op";
|
|
3
|
+
|
|
4
|
+
function opProps(op: unknown): Record<string, unknown> {
|
|
5
|
+
return (op as { props: Record<string, unknown> }).props;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
describe("WorkflowAuditOp composite (#292)", () => {
|
|
9
|
+
test("one-shot form: op only, no cadence", () => {
|
|
10
|
+
const { op } = WorkflowAuditOp({ name: "actions-audit" });
|
|
11
|
+
expect(op).toBeDefined();
|
|
12
|
+
expect(opProps(op).schedule).toBeUndefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("scheduled form: the cron rides on the op (#2120)", () => {
|
|
16
|
+
const { op } = WorkflowAuditOp({
|
|
17
|
+
name: "actions-audit",
|
|
18
|
+
schedule: "0 6 * * *",
|
|
19
|
+
onFinding: "pull-request",
|
|
20
|
+
});
|
|
21
|
+
expect(opProps(op).schedule).toEqual({ cron: "0 6 * * *", overlap: "skip" });
|
|
22
|
+
const step = (opProps(op).phases as Array<{ steps: Array<{ args: { mode: string } }> }>)[0].steps[0];
|
|
23
|
+
expect(step.args.mode).toBe("pull-request");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkflowAuditOp composite — the live supply-chain audit of GitHub workflows
|
|
3
|
+
* as a chant Op with an optional schedule (#292).
|
|
4
|
+
*
|
|
5
|
+
* The github post-synth checks (#286-#291) own everything answerable from the
|
|
6
|
+
* deterministic build. This Op owns *only* the checks that require live
|
|
7
|
+
* resolution against a moving upstream truth — stale SHA pins, impostor refs,
|
|
8
|
+
* symbolic-ref confusion, pin/comment mismatch, advisories, archived upstreams.
|
|
9
|
+
* It sits at **observe** on the lifecycle dial, with a finding-mode (mirroring
|
|
10
|
+
* `ReconcileOp`: `report | issue | pull-request`) as the **reconcile** step.
|
|
11
|
+
*
|
|
12
|
+
* Runs one-shot on the local Op executor via `chant run`; a `schedule` puts
|
|
13
|
+
* the cadence on the Op itself (#2120), for continuous re-audit between
|
|
14
|
+
* change windows.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // one-shot, local executor
|
|
19
|
+
* export const { op } = WorkflowAuditOp({ name: "actions-audit" });
|
|
20
|
+
*
|
|
21
|
+
* // daily, opening a PR that bumps a stale pin
|
|
22
|
+
* export const { op } = WorkflowAuditOp({
|
|
23
|
+
* name: "actions-audit",
|
|
24
|
+
* schedule: "0 6 * * *",
|
|
25
|
+
* onFinding: "pull-request",
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @see #286 — the deterministic counterpart this freshens.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { Op, phase } from "../builders";
|
|
33
|
+
import type { OpResource } from "../resource";
|
|
34
|
+
import type { WorkflowAuditMode } from "../activities/workflow-audit";
|
|
35
|
+
|
|
36
|
+
export interface WorkflowAuditOpConfig {
|
|
37
|
+
/** Op name (kebab-case). Names the Op's output directory and is what `chant run` takes. */
|
|
38
|
+
name: string;
|
|
39
|
+
/**
|
|
40
|
+
* Cron expression. When set, it lands on the Op as `schedule` for
|
|
41
|
+
* continuous re-audit; omit for one-shot `chant run` on the local executor.
|
|
42
|
+
*/
|
|
43
|
+
schedule?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Directory of emitted workflow files to audit at run time.
|
|
46
|
+
* @default ".github/workflows"
|
|
47
|
+
*/
|
|
48
|
+
workflowsDir?: string;
|
|
49
|
+
/**
|
|
50
|
+
* What to produce on findings. Default: "report".
|
|
51
|
+
* @default "report"
|
|
52
|
+
*/
|
|
53
|
+
onFinding?: WorkflowAuditMode;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface WorkflowAuditOpResources {
|
|
57
|
+
/** Op resource — generates the audit workflow on `chant build`. */
|
|
58
|
+
op: InstanceType<typeof OpResource>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function WorkflowAuditOp(config: WorkflowAuditOpConfig): WorkflowAuditOpResources {
|
|
62
|
+
const onFinding = config.onFinding ?? "report";
|
|
63
|
+
|
|
64
|
+
const op = Op({
|
|
65
|
+
name: config.name,
|
|
66
|
+
overview: "Resolve workflow action references against live upstreams and report supply-chain drift",
|
|
67
|
+
labels: {
|
|
68
|
+
Audit: "true",
|
|
69
|
+
Surface: "github-workflows",
|
|
70
|
+
},
|
|
71
|
+
...(config.schedule ? { schedule: { cron: config.schedule, overlap: "skip" as const } } : {}),
|
|
72
|
+
phases: [
|
|
73
|
+
phase("Audit", [
|
|
74
|
+
{
|
|
75
|
+
kind: "activity",
|
|
76
|
+
fn: "workflowSupplyChainAudit",
|
|
77
|
+
args: { workflowsDir: config.workflowsDir ?? ".github/workflows", mode: onFinding },
|
|
78
|
+
// Surface the finding count as the run's `Findings` outcome on the
|
|
79
|
+
// run ledger, so a reader can pick out the audits that found
|
|
80
|
+
// something.
|
|
81
|
+
outcomeAttribute: { name: "Findings", from: "findings" },
|
|
82
|
+
},
|
|
83
|
+
]),
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return { op };
|
|
88
|
+
}
|
package/src/op/converge-rule.ts
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* The issue's illustrative sketch writes a rule's condition as a JS arrow
|
|
6
6
|
* function (`s => s.status === "drifted"`). That reads well but can't
|
|
7
7
|
* actually ship: a rule is evaluated per-tick against live, freshly-observed
|
|
8
|
-
* data inside
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* data inside an activity, and an activity's arguments — including whatever a
|
|
9
|
+
* `ConvergeOp` composite bakes into the Op it builds — must be plain JSON (see
|
|
10
|
+
* `step-output-ref.ts`'s module doc on why a value crossing an activity
|
|
11
|
+
* boundary can't carry a closure). A rule
|
|
12
12
|
* "outside the evaluable subset" is one of the build-time refusals #1484
|
|
13
13
|
* names explicitly, which only makes sense if there IS an evaluable subset
|
|
14
14
|
* to be outside of — so rules here are data: a small comparison language
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
* produces" refusal, satisfied for free. {@link isWellFormedPredicate} is the
|
|
26
26
|
* runtime backstop for a rule assembled by hand (bypassing `when()`/the
|
|
27
27
|
* comparison builders) rather than authored through them, and is what a
|
|
28
|
-
* build-time check (
|
|
28
|
+
* build-time check (OPS014, ../lint/rules/op/ops014-converge-rule-refusals.ts)
|
|
29
|
+
* re-validates the serialized rule table against.
|
|
29
30
|
*/
|
|
30
31
|
|
|
31
32
|
// ── Predicates ───────────────────────────────────────────────────────────────
|
|
@@ -76,8 +77,9 @@ const FIELD_TRUTHINESS_OPS: ReadonlySet<string> = new Set(["truthy", "falsy"]);
|
|
|
76
77
|
|
|
77
78
|
/**
|
|
78
79
|
* Structural validator for a value claiming to be a {@link SymptomPredicate}
|
|
79
|
-
* — the runtime backstop
|
|
80
|
-
* re-checks a serialized
|
|
80
|
+
* — the runtime backstop OPS014
|
|
81
|
+
* (../lint/rules/op/ops014-converge-rule-refusals.ts) re-checks a serialized
|
|
82
|
+
* rule table against, since nothing forces a rule
|
|
81
83
|
* assembled by hand (rather than through the builders below) to match this
|
|
82
84
|
* shape. Recurses through `allOf`/`anyOf`; `fieldWhitelist`, when given,
|
|
83
85
|
* additionally refuses a field name the symptom record doesn't actually
|
|
@@ -152,9 +154,9 @@ export function evaluatePredicate<S>(predicate: SymptomPredicate<S>, symptom: S)
|
|
|
152
154
|
* Does a predicate reference the given symptom field anywhere in it,
|
|
153
155
|
* recursing through `allOf`/`anyOf`? The build-time backstop for a claim
|
|
154
156
|
* about a *category* of rule (e.g. "a rule reading `adoptCount`") rather
|
|
155
|
-
* than a single comparison —
|
|
156
|
-
* (
|
|
157
|
-
*
|
|
157
|
+
* than a single comparison — OPS014's adopt-safety check
|
|
158
|
+
* (../lint/rules/op/ops014-converge-rule-refusals.ts) uses this to refuse a
|
|
159
|
+
* rule that both reads `adoptCount` and dispatches a
|
|
158
160
|
* mutating op, rather than merely documenting that authors shouldn't write
|
|
159
161
|
* one.
|
|
160
162
|
*/
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron tests (#2120) — the validator ported from TMP010, and the matcher
|
|
3
|
+
* `chant operator` ticks on.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, test, expect } from "vitest";
|
|
7
|
+
import { isValidCronExpression, cronSyntaxMessage, cronMatches, cronDueBetween } from "./cron";
|
|
8
|
+
|
|
9
|
+
/** Local-time date literal, so a matcher reading `getHours()` sees what the test wrote. */
|
|
10
|
+
function at(y: number, m: number, d: number, h: number, min: number): Date {
|
|
11
|
+
return new Date(y, m - 1, d, h, min, 0, 0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("isValidCronExpression — the shared parser", () => {
|
|
15
|
+
test("accepts 5- and 6-field expressions", () => {
|
|
16
|
+
expect(isValidCronExpression("*/10 * * * *")).toBe(true);
|
|
17
|
+
expect(isValidCronExpression("0 6 * * 1")).toBe(true);
|
|
18
|
+
expect(isValidCronExpression("0 0 6 * * *")).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("rejects the wrong field count", () => {
|
|
22
|
+
expect(isValidCronExpression("* * * *")).toBe(false);
|
|
23
|
+
expect(isValidCronExpression("* * * * * * *")).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("rejects prose and named fields", () => {
|
|
27
|
+
expect(isValidCronExpression("every ten minutes")).toBe(false);
|
|
28
|
+
expect(isValidCronExpression("0 6 * * MON")).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("tolerates surrounding whitespace and repeated separators", () => {
|
|
32
|
+
expect(isValidCronExpression(" 0 6 * * * ")).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("the message names the expression, so the Op refusal and a lexicon's cron check read alike", () => {
|
|
36
|
+
expect(cronSyntaxMessage("nope")).toBe(
|
|
37
|
+
'cron expression "nope" does not look like valid 5- or 6-field cron syntax',
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("cronMatches", () => {
|
|
43
|
+
test("every minute", () => {
|
|
44
|
+
expect(cronMatches("* * * * *", at(2026, 9, 6, 13, 37))).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("a step fires on the multiples and nothing else", () => {
|
|
48
|
+
expect(cronMatches("*/10 * * * *", at(2026, 9, 6, 13, 30))).toBe(true);
|
|
49
|
+
expect(cronMatches("*/10 * * * *", at(2026, 9, 6, 13, 31))).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("a list fires on each member", () => {
|
|
53
|
+
for (const m of [0, 15, 30, 45]) {
|
|
54
|
+
expect(cronMatches("0,15,30,45 * * * *", at(2026, 9, 6, 1, m))).toBe(true);
|
|
55
|
+
}
|
|
56
|
+
expect(cronMatches("0,15,30,45 * * * *", at(2026, 9, 6, 1, 16))).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("a range fires inside it only", () => {
|
|
60
|
+
expect(cronMatches("0 9-17 * * *", at(2026, 9, 6, 9, 0))).toBe(true);
|
|
61
|
+
expect(cronMatches("0 9-17 * * *", at(2026, 9, 6, 17, 0))).toBe(true);
|
|
62
|
+
expect(cronMatches("0 9-17 * * *", at(2026, 9, 6, 18, 0))).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("a bare number in a field means only that value", () => {
|
|
66
|
+
expect(cronMatches("0 6 * * *", at(2026, 9, 6, 6, 0))).toBe(true);
|
|
67
|
+
expect(cronMatches("0 6 * * *", at(2026, 9, 6, 7, 0))).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("day-of-week — 2026-09-07 is a Monday", () => {
|
|
71
|
+
expect(cronMatches("0 6 * * 1", at(2026, 9, 7, 6, 0))).toBe(true);
|
|
72
|
+
expect(cronMatches("0 6 * * 1", at(2026, 9, 8, 6, 0))).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("day-of-week 7 is Sunday, like 0 — 2026-09-06 is a Sunday", () => {
|
|
76
|
+
expect(cronMatches("0 6 * * 7", at(2026, 9, 6, 6, 0))).toBe(true);
|
|
77
|
+
expect(cronMatches("0 6 * * 0", at(2026, 9, 6, 6, 0))).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("dom and dow both restricted: either one matching is enough", () => {
|
|
81
|
+
// The 1st of the month, or any Monday.
|
|
82
|
+
expect(cronMatches("0 6 1 * 1", at(2026, 9, 1, 6, 0))).toBe(true);
|
|
83
|
+
expect(cronMatches("0 6 1 * 1", at(2026, 9, 7, 6, 0))).toBe(true);
|
|
84
|
+
expect(cronMatches("0 6 1 * 1", at(2026, 9, 8, 6, 0))).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("a 6-field expression drops the seconds field", () => {
|
|
88
|
+
expect(cronMatches("30 0 6 * * *", at(2026, 9, 6, 6, 0))).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("a Quartz extension the evaluator cannot read matches everything rather than nothing", () => {
|
|
92
|
+
expect(cronMatches("0 6 L * ?", at(2026, 9, 6, 6, 0))).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("a malformed expression matches nothing", () => {
|
|
96
|
+
expect(cronMatches("not a cron", at(2026, 9, 6, 6, 0))).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("cronDueBetween", () => {
|
|
101
|
+
test("a firing minute inside the window is due", () => {
|
|
102
|
+
expect(cronDueBetween("*/10 * * * *", at(2026, 9, 6, 13, 22), at(2026, 9, 6, 13, 35))).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("a window with no firing minute is not due", () => {
|
|
106
|
+
expect(cronDueBetween("*/10 * * * *", at(2026, 9, 6, 13, 31), at(2026, 9, 6, 13, 39))).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("the window is half-open: the `after` minute itself does not count again", () => {
|
|
110
|
+
expect(cronDueBetween("*/10 * * * *", at(2026, 9, 6, 13, 30), at(2026, 9, 6, 13, 30))).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("the upper bound counts", () => {
|
|
114
|
+
expect(cronDueBetween("*/10 * * * *", at(2026, 9, 6, 13, 39), at(2026, 9, 6, 13, 40))).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("several missed fires collapse into one due answer", () => {
|
|
118
|
+
expect(cronDueBetween("* * * * *", at(2026, 9, 6, 13, 0), at(2026, 9, 6, 13, 30))).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("a window longer than the scan cap is due without scanning", () => {
|
|
122
|
+
expect(cronDueBetween("0 6 1 1 *", at(2020, 1, 1, 0, 0), at(2026, 9, 6, 0, 0))).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("a backwards window is never due", () => {
|
|
126
|
+
expect(cronDueBetween("* * * * *", at(2026, 9, 6, 13, 30), at(2026, 9, 6, 13, 0))).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
});
|