@intentius/chant 0.80.0 → 0.81.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/discover.d.ts +8 -16
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts +5 -0
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +13 -0
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +4 -5
- package/dist/audit/terraform-state.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +25 -9
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +8 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/import-agents.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/update.d.ts +6 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/vendor.d.ts +5 -0
- package/dist/cli/commands/vendor.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/init.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +7 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/promote.d.ts +7 -4
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/run-generate.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +4 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/vendor.d.ts +8 -3
- package/dist/cli/handlers/vendor.d.ts.map +1 -1
- package/dist/cli/main.d.ts +12 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +12 -7
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +32 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts +10 -0
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +3 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/driver.d.ts +16 -2
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/gate-plan.d.ts +40 -0
- package/dist/components/gate-plan.d.ts.map +1 -0
- package/dist/components/promote.d.ts +60 -7
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/run.d.ts.map +1 -1
- package/dist/components/verbs/build-archive.d.ts +22 -11
- package/dist/components/verbs/build-archive.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/config-static.d.ts +59 -0
- package/dist/config-static.d.ts.map +1 -0
- package/dist/config.d.ts +32 -10
- package/dist/config.d.ts.map +1 -1
- package/dist/content-digest.d.ts +17 -0
- package/dist/content-digest.d.ts.map +1 -0
- package/dist/discovery/files.d.ts +10 -5
- package/dist/discovery/files.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +20 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.d.ts +20 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/fork.d.ts +20 -0
- package/dist/discovery/sandbox/fork.d.ts.map +1 -1
- package/dist/discovery/walk.d.ts +119 -0
- package/dist/discovery/walk.d.ts.map +1 -0
- package/dist/graph-ir.d.ts +4 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/join-key.d.ts +31 -0
- package/dist/join-key.d.ts.map +1 -0
- package/dist/lexicon-module.d.ts +51 -6
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon.d.ts +58 -1
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/build-ledger-store.d.ts.map +1 -1
- package/dist/lifecycle/digest.d.ts +5 -1
- package/dist/lifecycle/digest.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +20 -5
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +64 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/lease.d.ts +8 -1
- package/dist/lifecycle/lease.d.ts.map +1 -1
- package/dist/lifecycle/legacy-digest.d.ts +41 -8
- package/dist/lifecycle/legacy-digest.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts +67 -0
- package/dist/lifecycle/member-ledger.d.ts.map +1 -0
- package/dist/lifecycle/plan-digest.d.ts +4 -3
- package/dist/lifecycle/plan-digest.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +18 -2
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts +90 -5
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +32 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +2 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/propose-upgrade.d.ts +75 -0
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +7 -0
- package/dist/op/gate-name.d.ts.map +1 -1
- package/dist/op/gate-summary.d.ts +16 -0
- package/dist/op/gate-summary.d.ts.map +1 -1
- package/dist/op/gate.d.ts +16 -2
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/project-root.d.ts +26 -0
- package/dist/project-root.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts +37 -0
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -0
- package/dist/workspace/__fixtures__/two-member-workspace.d.ts +11 -0
- package/dist/workspace/__fixtures__/two-member-workspace.d.ts.map +1 -0
- package/dist/workspace/checks/generated.d.ts +156 -0
- package/dist/workspace/checks/generated.d.ts.map +1 -0
- package/dist/workspace/checks/ledgers.d.ts +78 -0
- package/dist/workspace/checks/ledgers.d.ts.map +1 -0
- package/dist/workspace/checks/links.d.ts +25 -0
- package/dist/workspace/checks/links.d.ts.map +1 -0
- package/dist/workspace/checks/pipelines.d.ts +76 -0
- package/dist/workspace/checks/pipelines.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts +161 -0
- package/dist/workspace/checks.d.ts.map +1 -0
- package/dist/workspace/compose-graph.d.ts +115 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -0
- package/dist/workspace/compose-reports.d.ts +68 -0
- package/dist/workspace/compose-reports.d.ts.map +1 -0
- package/dist/workspace/declaration.d.ts +220 -0
- package/dist/workspace/declaration.d.ts.map +1 -0
- package/dist/workspace/declaration.schema.json +434 -0
- package/dist/workspace/generated-files.d.ts +65 -0
- package/dist/workspace/generated-files.d.ts.map +1 -0
- package/dist/workspace/glob.d.ts +13 -0
- package/dist/workspace/glob.d.ts.map +1 -0
- package/dist/workspace/graph-cli.d.ts +75 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -0
- package/dist/workspace/init.d.ts +96 -0
- package/dist/workspace/init.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +38 -0
- package/dist/workspace/jsonc.d.ts.map +1 -0
- package/dist/workspace/kinds.d.ts +192 -0
- package/dist/workspace/kinds.d.ts.map +1 -0
- package/dist/workspace/lineage-check.d.ts +84 -0
- package/dist/workspace/lineage-check.d.ts.map +1 -0
- package/dist/workspace/lineage-cli.d.ts +31 -0
- package/dist/workspace/lineage-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +101 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -0
- package/dist/workspace/lineage-lock.d.ts +258 -0
- package/dist/workspace/lineage-lock.d.ts.map +1 -0
- package/dist/workspace/lineage-merge.d.ts +14 -0
- package/dist/workspace/lineage-merge.d.ts.map +1 -0
- package/dist/workspace/lineage-migrations.d.ts +178 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -0
- package/dist/workspace/lineage-update.d.ts +59 -0
- package/dist/workspace/lineage-update.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts +40 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade.d.ts +146 -0
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -0
- package/dist/workspace/lineage-vendor.d.ts +63 -0
- package/dist/workspace/lineage-vendor.d.ts.map +1 -0
- package/dist/workspace/lineage-version.d.ts +32 -0
- package/dist/workspace/lineage-version.d.ts.map +1 -0
- package/dist/workspace/links.d.ts +150 -0
- package/dist/workspace/links.d.ts.map +1 -0
- package/dist/workspace/ls.d.ts +99 -0
- package/dist/workspace/ls.d.ts.map +1 -0
- package/dist/workspace/member-commands.d.ts +139 -0
- package/dist/workspace/member-commands.d.ts.map +1 -0
- package/dist/workspace/member-handles.d.ts +54 -0
- package/dist/workspace/member-handles.d.ts.map +1 -0
- package/dist/workspace/member-pipeline.d.ts +143 -0
- package/dist/workspace/member-pipeline.d.ts.map +1 -0
- package/dist/workspace/member-run.d.ts +67 -0
- package/dist/workspace/member-run.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +65 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +28 -4
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/root-refusal.d.ts +53 -0
- package/dist/workspace/root-refusal.d.ts.map +1 -0
- package/dist/workspace/status.d.ts +150 -0
- package/dist/workspace/status.d.ts.map +1 -0
- package/dist/workspace/template-manifest.d.ts +90 -0
- package/dist/workspace/template-manifest.d.ts.map +1 -0
- package/dist/workspace/tree.d.ts +36 -0
- package/dist/workspace/tree.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts +67 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +111 -0
- package/dist/workspace/trust/policy.d.ts.map +1 -0
- package/dist/workspace/trust/provenance.d.ts +67 -0
- package/dist/workspace/trust/provenance.d.ts.map +1 -0
- package/dist/workspace/trust/ssh-commit.d.ts +43 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -0
- package/dist/workspace/trust/test-repo.d.ts +42 -0
- package/dist/workspace/trust/test-repo.d.ts.map +1 -0
- package/dist/workspace/trust/verify-cli.d.ts +9 -0
- package/dist/workspace/trust/verify-cli.d.ts.map +1 -0
- package/dist/workspace/trust/verify.d.ts +66 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -0
- package/dist/workspace/which-chant.d.ts +58 -0
- package/dist/workspace/which-chant.d.ts.map +1 -0
- package/dist/workspace/workspace-kinds.schema.json +133 -0
- package/package.json +2 -1
- package/src/audit/discover.ts +66 -78
- package/src/audit/report-html.ts +3 -1
- package/src/audit/report-model.ts +14 -1
- package/src/audit/terraform-state.test.ts +4 -9
- package/src/audit/terraform-state.ts +4 -5
- package/src/cli/commands/audit-truncation.test.ts +167 -0
- package/src/cli/commands/audit.ts +89 -60
- package/src/cli/commands/check-lexicon.ts +24 -0
- package/src/cli/commands/doctor.test.ts +30 -0
- package/src/cli/commands/doctor.ts +18 -0
- package/src/cli/commands/import-agents.ts +6 -2
- package/src/cli/commands/init.ts +22 -3
- package/src/cli/commands/lint.test.ts +17 -23
- package/src/cli/commands/lint.ts +24 -84
- package/src/cli/commands/update.ts +13 -4
- package/src/cli/commands/vendor.ts +11 -6
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +38 -0
- package/src/cli/handlers/build-member.test.ts +127 -0
- package/src/cli/handlers/build.ts +35 -1
- package/src/cli/handlers/components.test.ts +127 -0
- package/src/cli/handlers/components.ts +70 -8
- package/src/cli/handlers/dev.ts +5 -3
- package/src/cli/handlers/fan-out.ts +9 -2
- package/src/cli/handlers/init.ts +54 -1
- package/src/cli/handlers/operator.test.ts +68 -0
- package/src/cli/handlers/operator.ts +37 -9
- package/src/cli/handlers/promote.test.ts +118 -2
- package/src/cli/handlers/promote.ts +82 -16
- package/src/cli/handlers/run-generate-member.test.ts +83 -0
- package/src/cli/handlers/run-generate.test.ts +6 -8
- package/src/cli/handlers/run-generate.ts +36 -1
- package/src/cli/handlers/run.test.ts +47 -0
- package/src/cli/handlers/run.ts +28 -5
- package/src/cli/handlers/vendor.ts +147 -43
- package/src/cli/main.test.ts +105 -1
- package/src/cli/main.ts +230 -17
- package/src/cli/plugins.ts +17 -17
- package/src/cli/registry.ts +32 -0
- package/src/cli/static-config-read.test.ts +208 -0
- package/src/codegen/fetch.test.ts +63 -1
- package/src/codegen/fetch.ts +30 -1
- package/src/components/cli-support.ts +6 -1
- package/src/components/discover.test.ts +27 -57
- package/src/components/discover.ts +13 -68
- package/src/components/driver.test.ts +78 -1
- package/src/components/driver.ts +43 -7
- package/src/components/gate-plan.ts +53 -0
- package/src/components/promote.test.ts +276 -2
- package/src/components/promote.ts +119 -15
- package/src/components/sandbox/driver.ts +8 -8
- package/src/components/sandbox/run.ts +4 -1
- package/src/components/verbs/build-archive.ts +27 -21
- package/src/components/verbs/run-agent.ts +3 -5
- package/src/config-static.test.ts +136 -0
- package/src/config-static.ts +232 -0
- package/src/config.test.ts +2 -2
- package/src/config.ts +48 -15
- package/src/content-digest.test.ts +120 -0
- package/src/content-digest.ts +21 -0
- package/src/discovery/files.test.ts +10 -10
- package/src/discovery/files.ts +25 -81
- package/src/discovery/fold-import.ts +49 -5
- package/src/discovery/index.ts +1 -0
- package/src/discovery/sandbox/driver.ts +73 -35
- package/src/discovery/sandbox/fork-diagnostic.test.ts +136 -13
- package/src/discovery/sandbox/fork.ts +83 -43
- package/src/discovery/sandbox/path-lexicon-multifile.test.ts +285 -0
- package/src/discovery/walk.test.ts +263 -0
- package/src/discovery/walk.ts +334 -0
- package/src/effect-receipt.ts +2 -2
- package/src/graph-ir.ts +4 -1
- package/src/join-key.test.ts +25 -0
- package/src/join-key.ts +39 -0
- package/src/lexicon-module.ts +108 -10
- package/src/lexicon.ts +79 -1
- package/src/lifecycle/build-ledger-store.ts +11 -10
- package/src/lifecycle/digest.ts +9 -5
- package/src/lifecycle/gate-ledger.test.ts +20 -0
- package/src/lifecycle/gate-ledger.ts +28 -6
- package/src/lifecycle/git.test.ts +13 -1
- package/src/lifecycle/git.ts +221 -176
- package/src/lifecycle/lease.ts +25 -10
- package/src/lifecycle/legacy-digest.test.ts +115 -23
- package/src/lifecycle/legacy-digest.ts +60 -19
- package/src/lifecycle/member-ledger.test.ts +319 -0
- package/src/lifecycle/member-ledger.ts +145 -0
- package/src/lifecycle/plan-digest.ts +7 -7
- package/src/lifecycle/release-ledger.test.ts +20 -0
- package/src/lifecycle/release-ledger.ts +23 -7
- package/src/lifecycle/status.test.ts +151 -1
- package/src/lifecycle/status.ts +228 -7
- package/src/op/activities/activity-contracts.ts +37 -0
- package/src/op/activities/index.ts +10 -0
- package/src/op/activities/propose-upgrade.ts +206 -0
- package/src/op/discover.test.ts +14 -4
- package/src/op/discover.ts +19 -27
- package/src/op/gate-name.ts +8 -0
- package/src/op/gate-summary.test.ts +14 -0
- package/src/op/gate-summary.ts +25 -2
- package/src/op/gate.ts +36 -7
- package/src/op/generate-pipeline.test.ts +14 -5
- package/src/project-root.test.ts +66 -1
- package/src/project-root.ts +48 -0
- package/src/workspace/__fixtures__/contract-repo.ts +100 -0
- package/src/workspace/__fixtures__/two-member-workspace.ts +35 -0
- package/src/workspace/behold-kinds.test.ts +162 -0
- package/src/workspace/check-contract.test.ts +127 -0
- package/src/workspace/check.schema.json +347 -0
- package/src/workspace/checks/generated.test.ts +287 -0
- package/src/workspace/checks/generated.ts +475 -0
- package/src/workspace/checks/ledgers.test.ts +139 -0
- package/src/workspace/checks/ledgers.ts +246 -0
- package/src/workspace/checks/links.ts +183 -0
- package/src/workspace/checks/pipelines.test.ts +133 -0
- package/src/workspace/checks/pipelines.ts +225 -0
- package/src/workspace/checks-repo.test.ts +71 -0
- package/src/workspace/checks.test.ts +450 -0
- package/src/workspace/checks.ts +461 -0
- package/src/workspace/compose-graph.test.ts +146 -0
- package/src/workspace/compose-graph.ts +228 -0
- package/src/workspace/compose-reports.test.ts +109 -0
- package/src/workspace/compose-reports.ts +186 -0
- package/src/workspace/declaration.schema.json +434 -0
- package/src/workspace/declaration.test.ts +347 -0
- package/src/workspace/declaration.ts +623 -0
- package/src/workspace/generated-files.test.ts +114 -0
- package/src/workspace/generated-files.ts +94 -0
- package/src/workspace/glob.ts +49 -0
- package/src/workspace/graph-cli.ts +220 -0
- package/src/workspace/graph-contract.test.ts +204 -0
- package/src/workspace/graph.schema.json +662 -0
- package/src/workspace/init.test.ts +223 -0
- package/src/workspace/init.ts +585 -0
- package/src/workspace/jsonc.test.ts +65 -0
- package/src/workspace/jsonc.ts +231 -0
- package/src/workspace/kinds.test.ts +288 -0
- package/src/workspace/kinds.ts +506 -0
- package/src/workspace/lineage-check.ts +264 -0
- package/src/workspace/lineage-cli.ts +114 -0
- package/src/workspace/lineage-init.test.ts +231 -0
- package/src/workspace/lineage-init.ts +365 -0
- package/src/workspace/lineage-lock.test.ts +224 -0
- package/src/workspace/lineage-lock.ts +357 -0
- package/src/workspace/lineage-merge.ts +44 -0
- package/src/workspace/lineage-migrations.test.ts +178 -0
- package/src/workspace/lineage-migrations.ts +343 -0
- package/src/workspace/lineage-update.ts +160 -0
- package/src/workspace/lineage-upgrade-cli.ts +151 -0
- package/src/workspace/lineage-upgrade.test.ts +474 -0
- package/src/workspace/lineage-upgrade.ts +624 -0
- package/src/workspace/lineage-vendor.test.ts +126 -0
- package/src/workspace/lineage-vendor.ts +215 -0
- package/src/workspace/lineage-version.ts +127 -0
- package/src/workspace/links.test.ts +344 -0
- package/src/workspace/links.ts +331 -0
- package/src/workspace/ls-contract.test.ts +200 -0
- package/src/workspace/ls.schema.json +190 -0
- package/src/workspace/ls.ts +254 -0
- package/src/workspace/member-commands.e2e.test.ts +244 -0
- package/src/workspace/member-commands.test.ts +217 -0
- package/src/workspace/member-commands.ts +540 -0
- package/src/workspace/member-handles.test.ts +76 -0
- package/src/workspace/member-handles.ts +228 -0
- package/src/workspace/member-pipeline.test.ts +135 -0
- package/src/workspace/member-pipeline.ts +317 -0
- package/src/workspace/member-run.ts +146 -0
- package/src/workspace/read-contract.test.ts +129 -0
- package/src/workspace/reason-codes.test.ts +113 -0
- package/src/workspace/reason-codes.ts +81 -0
- package/src/workspace/records-cli.ts +86 -14
- package/src/workspace/records-contract.test.ts +5 -0
- package/src/workspace/records.schema.json +32 -2
- package/src/workspace/records.ts +3 -2
- package/src/workspace/root-refusal.ts +97 -0
- package/src/workspace/status-contract.test.ts +308 -0
- package/src/workspace/status.schema.json +210 -0
- package/src/workspace/status.ts +412 -0
- package/src/workspace/template-manifest.test.ts +79 -0
- package/src/workspace/template-manifest.ts +221 -0
- package/src/workspace/tree.ts +132 -0
- package/src/workspace/trust/attestor.ts +93 -0
- package/src/workspace/trust/policy.ts +306 -0
- package/src/workspace/trust/provenance.ts +181 -0
- package/src/workspace/trust/ssh-commit.ts +138 -0
- package/src/workspace/trust/test-repo.ts +138 -0
- package/src/workspace/trust/trust.test.ts +397 -0
- package/src/workspace/trust/verify-cli.ts +56 -0
- package/src/workspace/trust/verify.ts +194 -0
- package/src/workspace/which-chant.test.ts +117 -0
- package/src/workspace/which-chant.ts +151 -0
- package/src/workspace/workspace-kinds.schema.json +133 -0
- package/dist/components/unbound-gate-approval.d.ts +0 -24
- package/dist/components/unbound-gate-approval.d.ts.map +0 -1
- package/dist/discovery/convergence.d.ts +0 -97
- package/dist/discovery/convergence.d.ts.map +0 -1
- package/src/cli/commands/audit-walk-warnings.test.ts +0 -156
- package/src/components/unbound-gate-approval.test.ts +0 -82
- package/src/components/unbound-gate-approval.ts +0 -51
- package/src/discovery/convergence.test.ts +0 -231
- package/src/discovery/convergence.ts +0 -399
- package/src/op/discover-convergence.test.ts +0 -70
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The warning release for chant#2527, which converges the discovery walkers.
|
|
3
|
-
*
|
|
4
|
-
* Five walkers decide which files chant reads: source discovery
|
|
5
|
-
* (`./files.ts`'s `findInfraFiles`, behind build, graph, list and explain),
|
|
6
|
-
* lint (`../cli/commands/lint.ts`), component discovery
|
|
7
|
-
* (`../components/discover.ts`), Op discovery (`../op/discover.ts`) and the
|
|
8
|
-
* audit walk (`../audit/discover.ts`). They disagree about dot-directories,
|
|
9
|
-
* git-ignored files, `dist` and child projects. The next release makes them
|
|
10
|
-
* agree:
|
|
11
|
-
*
|
|
12
|
-
* - dot-directories are skipped, except `.github` and `.forgejo` for audit;
|
|
13
|
-
* - git-ignored files are skipped, nested `.gitignore` files included, with
|
|
14
|
-
* ignore rules evaluated only for paths below the scan root;
|
|
15
|
-
* - `dist` is skipped;
|
|
16
|
-
* - when the scan root is inside a project, a child directory holding a
|
|
17
|
-
* project config is a boundary (a lint-only `chant.config.json` fragment is
|
|
18
|
-
* not one); when it is outside a project, every child project is read; Op
|
|
19
|
-
* discovery always stops at child projects below its root;
|
|
20
|
-
* - the source-root quirk goes: today source and component discovery read
|
|
21
|
-
* the first child project they meet as the project's own source and skip
|
|
22
|
-
* every later one.
|
|
23
|
-
*
|
|
24
|
-
* This release changes none of that. It runs after each walk, classifies the
|
|
25
|
-
* files the walk returned (and, where the next release reads more, the
|
|
26
|
-
* subtrees the walk skipped) under the converged rules, and prints one
|
|
27
|
-
* warning per affected group on stderr, naming the `include` or `exclude`
|
|
28
|
-
* glob (#2519) that keeps today's behaviour. The warning goes away only when
|
|
29
|
-
* that glob is in the project config.
|
|
30
|
-
*/
|
|
31
|
-
/** The walker a warning is about, which is also how the warning names it. */
|
|
32
|
-
export type DiscoveryWalker = "source" | "lint" | "components" | "ops" | "audit";
|
|
33
|
-
/** Why a file's status changes next release. */
|
|
34
|
-
type Cause = "dot-dir" | "dist" | "child-project" | "source-root" | "git-ignored" | "every-child" | "ignored-above-root";
|
|
35
|
-
interface Change {
|
|
36
|
-
file: string;
|
|
37
|
-
/** `skip`: read today, skipped next release. `read`: the reverse. */
|
|
38
|
-
kind: "skip" | "read";
|
|
39
|
-
cause: Cause;
|
|
40
|
-
/** The directory (or, for a lone ignored file, the file) the cause attaches to. */
|
|
41
|
-
anchor: string;
|
|
42
|
-
}
|
|
43
|
-
export interface DiscoveryWalkInput {
|
|
44
|
-
walker: DiscoveryWalker;
|
|
45
|
-
/** The directory the walk started from. */
|
|
46
|
-
root: string;
|
|
47
|
-
/** The files the walk returned, absolute. */
|
|
48
|
-
files: readonly string[];
|
|
49
|
-
/**
|
|
50
|
-
* Source and component discovery: the first child project the walk met,
|
|
51
|
-
* which it read as the project's own source.
|
|
52
|
-
*/
|
|
53
|
-
sourceRoot?: string | null;
|
|
54
|
-
/**
|
|
55
|
-
* Source and component discovery: the child projects the walk skipped
|
|
56
|
-
* because it had already met one. Read next release when the scan root is
|
|
57
|
-
* outside a project.
|
|
58
|
-
*/
|
|
59
|
-
skippedChildren?: readonly string[];
|
|
60
|
-
/** The walker's file filter, applied to what a skipped child holds. */
|
|
61
|
-
fileOk?: (name: string, fullPath: string) => boolean | Promise<boolean>;
|
|
62
|
-
/**
|
|
63
|
-
* Lint only: the files the walk found before its git-ignore filter dropped
|
|
64
|
-
* some, and the paths that filter reported ignored. The filter's call
|
|
65
|
-
* carries the scan root as an extra probe, so no second `git` call is made.
|
|
66
|
-
*/
|
|
67
|
-
lintIgnored?: {
|
|
68
|
-
raw: readonly string[];
|
|
69
|
-
ignored: ReadonlySet<string>;
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Paths `git check-ignore` reports ignored, in one batched call run from
|
|
74
|
-
* `cwd`. A path is reported exactly as given. A tree outside git, a missing
|
|
75
|
-
* `git`, or nothing ignored (exit 1) yields an empty set.
|
|
76
|
-
*/
|
|
77
|
-
export declare function gitIgnoredPaths(paths: readonly string[], cwd: string): Set<string>;
|
|
78
|
-
/** The probe for a directory in a `git check-ignore` batch: a trailing slash makes git match it as a directory. */
|
|
79
|
-
export declare function dirProbe(dir: string): string;
|
|
80
|
-
/**
|
|
81
|
-
* Classify a walk's files under the converged rules and return what changes.
|
|
82
|
-
* Exported for tests; {@link warnDiscoveryChanges} is the entry point.
|
|
83
|
-
*/
|
|
84
|
-
export declare function discoveryChanges(input: DiscoveryWalkInput): Promise<Change[]>;
|
|
85
|
-
/** Forget which warnings were printed. Tests only. */
|
|
86
|
-
export declare function resetDiscoveryWarnings(): void;
|
|
87
|
-
/**
|
|
88
|
-
* Print, on stderr, what the next release's converged walk will read
|
|
89
|
-
* differently from the walk just made (chant#2527). Each group names its
|
|
90
|
-
* files, what changes, and the `include` or `exclude` glob (#2519) that
|
|
91
|
-
* keeps today's behaviour; a group whose glob is already in the project
|
|
92
|
-
* config is not printed. Each warning prints once per process, however many
|
|
93
|
-
* times a command walks the same tree. Returns the lines printed.
|
|
94
|
-
*/
|
|
95
|
-
export declare function warnDiscoveryChanges(input: DiscoveryWalkInput): Promise<string[]>;
|
|
96
|
-
export {};
|
|
97
|
-
//# sourceMappingURL=convergence.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"convergence.d.ts","sourceRoot":"","sources":["../../src/discovery/convergence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAUH,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,KAAK,GAAG,OAAO,CAAC;AAUjF,gDAAgD;AAChD,KAAK,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,eAAe,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,oBAAoB,CAAC;AAEzH,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC;IACb,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,eAAe,CAAC;IACxB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,uEAAuE;IACvE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE;;;;OAIG;IACH,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC;CACxE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAalF;AAED,mHAAmH;AACnH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AA0CD;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA8FnF;AA6DD,sDAAsD;AACtD,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkEvF"}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeAll, describe, expect, test, vi } from "vitest";
|
|
2
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { auditCommand, printAuditResult, type AuditCommandOptions } from "./audit";
|
|
6
|
-
import { loadAuditPlugins } from "../../audit/discover";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* #2528's warning release. `chant audit` warns on stderr about the two changes
|
|
10
|
-
* the next release makes (#2525's exception list), and the report itself stays
|
|
11
|
-
* byte-identical: every test here that runs with a warning also runs the same
|
|
12
|
-
* tree without its cause and compares the JSON.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const NOW = "2026-09-23T00:00:00.000Z";
|
|
16
|
-
const dirs: string[] = [];
|
|
17
|
-
|
|
18
|
-
function tmpRepo(): string {
|
|
19
|
-
const dir = mkdtempSync(join(tmpdir(), "chant-2528-"));
|
|
20
|
-
dirs.push(dir);
|
|
21
|
-
return dir;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true });
|
|
26
|
-
vi.restoreAllMocks();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
let plugins: Awaited<ReturnType<typeof loadAuditPlugins>>;
|
|
30
|
-
|
|
31
|
-
// Loading every audit lexicon is the slow part; once, outside any one test's timeout.
|
|
32
|
-
beforeAll(async () => {
|
|
33
|
-
plugins = await loadAuditPlugins();
|
|
34
|
-
}, 120_000);
|
|
35
|
-
|
|
36
|
-
function audit(path: string, extra: Partial<AuditCommandOptions> = {}) {
|
|
37
|
-
return auditCommand({ path, format: "json", now: NOW, toolVersion: "0.0.0", plugins, ...extra });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Print a result the way the CLI does, and split what reached each stream. */
|
|
41
|
-
function printed(result: Awaited<ReturnType<typeof auditCommand>>): { stdout: string; stderr: string } {
|
|
42
|
-
const out: string[] = [];
|
|
43
|
-
const err: string[] = [];
|
|
44
|
-
vi.spyOn(console, "log").mockImplementation((s: string) => void out.push(s));
|
|
45
|
-
vi.spyOn(console, "error").mockImplementation((s: string) => void err.push(s));
|
|
46
|
-
printAuditResult(result);
|
|
47
|
-
vi.restoreAllMocks();
|
|
48
|
-
return { stdout: out.join("\n"), stderr: err.join("\n") };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
describe("a truncated walk is warned about, not yet reported (#2528)", () => {
|
|
52
|
-
function treeWithTail(): string {
|
|
53
|
-
const dir = tmpRepo();
|
|
54
|
-
mkdirSync(join(dir, "a"), { recursive: true });
|
|
55
|
-
for (let i = 0; i < 5; i++) writeFileSync(join(dir, "a", `${i}.md`), "x");
|
|
56
|
-
writeFileSync(join(dir, "a", "terraform.tfstate"), "{}");
|
|
57
|
-
// Past the limit: a state file TF023 would report if the walk reached it.
|
|
58
|
-
mkdirSync(join(dir, "z"), { recursive: true });
|
|
59
|
-
writeFileSync(join(dir, "z", "terraform.tfstate"), "{}");
|
|
60
|
-
return dir;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
test("the warning names the limit and --max-files, on stderr only", async () => {
|
|
64
|
-
const dir = treeWithTail();
|
|
65
|
-
const result = await audit(dir, { maxFiles: 6 });
|
|
66
|
-
expect(result.warnings).toHaveLength(1);
|
|
67
|
-
const { stdout, stderr } = printed(result);
|
|
68
|
-
expect(stdout).toBe(result.output);
|
|
69
|
-
expect(stderr).toContain(`the scan of ${dir} stopped at 6 files, so part of the tree was not audited.`);
|
|
70
|
-
expect(stderr).toContain("Raise it with --max-files <n>.");
|
|
71
|
-
expect(stderr).toContain("From the next release, text and JSON output will also report a truncated scan.");
|
|
72
|
-
expect(result.findings.map((f) => f.file)).toEqual(["a/terraform.tfstate"]);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("the JSON and text reports are what the same tree gives without the files past the limit", async () => {
|
|
76
|
-
const dir = treeWithTail();
|
|
77
|
-
const truncatedJson = await audit(dir, { maxFiles: 6 });
|
|
78
|
-
const truncatedText = await audit(dir, { maxFiles: 6, format: "stylish" });
|
|
79
|
-
rmSync(join(dir, "z"), { recursive: true, force: true });
|
|
80
|
-
const wholeJson = await audit(dir, { maxFiles: 6 });
|
|
81
|
-
const wholeText = await audit(dir, { maxFiles: 6, format: "stylish" });
|
|
82
|
-
expect(wholeJson.warnings).toBeUndefined();
|
|
83
|
-
expect(truncatedJson.output).toBe(wholeJson.output);
|
|
84
|
-
expect(truncatedText.output).toBe(wholeText.output);
|
|
85
|
-
expect(printed(truncatedJson).stdout).toBe(printed(wholeJson).stdout);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("--max-files raises the limit, and the default walk does not warn on a small tree", async () => {
|
|
89
|
-
const dir = treeWithTail();
|
|
90
|
-
const raised = await audit(dir, { maxFiles: 7 });
|
|
91
|
-
expect(raised.warnings).toBeUndefined();
|
|
92
|
-
expect(raised.findings.map((f) => f.file).sort()).toEqual(["a/terraform.tfstate", "z/terraform.tfstate"]);
|
|
93
|
-
expect((await audit(dir)).warnings).toBeUndefined();
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe("TF023 warns when a nested .gitignore would change its finding (#2528)", () => {
|
|
98
|
-
function nestedTree(nested: string | undefined): string {
|
|
99
|
-
const dir = tmpRepo();
|
|
100
|
-
mkdirSync(join(dir, "infra"), { recursive: true });
|
|
101
|
-
writeFileSync(join(dir, ".gitignore"), "node_modules/\n");
|
|
102
|
-
writeFileSync(join(dir, "infra", "main.tf"), 'resource "null_resource" "a" {}\n');
|
|
103
|
-
writeFileSync(join(dir, "infra", "terraform.tfstate"), "{}");
|
|
104
|
-
if (nested !== undefined) writeFileSync(join(dir, "infra", ".gitignore"), nested);
|
|
105
|
-
return dir;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
test("fires for the file a nested .gitignore ignores, naming both, and TF023 still reports it", async () => {
|
|
109
|
-
const dir = nestedTree("*.tfstate\n");
|
|
110
|
-
const result = await audit(dir);
|
|
111
|
-
expect(result.findings.filter((f) => f.checkId === "TF023").map((f) => f.file)).toEqual(["infra/terraform.tfstate"]);
|
|
112
|
-
expect(result.warnings).toEqual([
|
|
113
|
-
{
|
|
114
|
-
file: "infra/terraform.tfstate",
|
|
115
|
-
message: "TF023 reports this path because chant audit reads only the root .gitignore, but infra/.gitignore ignores it.",
|
|
116
|
-
hint: "From the next release chant audit reads every .gitignore between a file and the scan root, and TF023 will no longer report this path.",
|
|
117
|
-
},
|
|
118
|
-
]);
|
|
119
|
-
const { stdout, stderr } = printed(result);
|
|
120
|
-
expect(stdout).toBe(result.output);
|
|
121
|
-
expect(stderr).toContain("infra/terraform.tfstate");
|
|
122
|
-
expect(stderr).toContain("infra/.gitignore ignores it");
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("does not fire when the nested .gitignore does not cover the file", async () => {
|
|
126
|
-
const result = await audit(nestedTree("*.log\n"));
|
|
127
|
-
expect(result.findings.some((f) => f.checkId === "TF023")).toBe(true);
|
|
128
|
-
expect(result.warnings).toBeUndefined();
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test("does not fire when the root .gitignore already drops the file", async () => {
|
|
132
|
-
const dir = nestedTree("*.tfstate\n");
|
|
133
|
-
writeFileSync(join(dir, ".gitignore"), "*.tfstate\n");
|
|
134
|
-
const result = await audit(dir);
|
|
135
|
-
expect(result.findings.some((f) => f.checkId === "TF023")).toBe(false);
|
|
136
|
-
expect(result.warnings).toBeUndefined();
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test("stdout JSON and the text report are byte-identical with and without the nested .gitignore", async () => {
|
|
140
|
-
const dir = nestedTree("*.tfstate\n");
|
|
141
|
-
const withJson = await audit(dir);
|
|
142
|
-
const withText = await audit(dir, { format: "stylish" });
|
|
143
|
-
const withSarif = await audit(dir, { format: "sarif" });
|
|
144
|
-
rmSync(join(dir, "infra", ".gitignore"));
|
|
145
|
-
const withoutJson = await audit(dir);
|
|
146
|
-
const withoutText = await audit(dir, { format: "stylish" });
|
|
147
|
-
const withoutSarif = await audit(dir, { format: "sarif" });
|
|
148
|
-
expect(withJson.warnings).toHaveLength(1);
|
|
149
|
-
expect(withoutJson.warnings).toBeUndefined();
|
|
150
|
-
expect(withJson.output).toBe(withoutJson.output);
|
|
151
|
-
expect(withText.output).toBe(withoutText.output);
|
|
152
|
-
expect(withSarif.output).toBe(withoutSarif.output);
|
|
153
|
-
expect(printed(withJson).stdout).toBe(printed(withoutJson).stdout);
|
|
154
|
-
JSON.parse(printed(withJson).stdout);
|
|
155
|
-
});
|
|
156
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The warning a release ahead of environment- and plan-bound component gate
|
|
3
|
-
* approvals (chant #2574). The gate decision itself must not change.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
7
|
-
import { CapabilityRegistry } from "./capability";
|
|
8
|
-
import { runComponentDeploy, type DriverComponent } from "./driver";
|
|
9
|
-
import { memoryGateLedgerPort } from "../op/gate";
|
|
10
|
-
import type { GateResolutionRecord, PendingGateRecord } from "../lifecycle/gate-ledger";
|
|
11
|
-
import { resetUnboundGateApprovalWarnings, warnOnUnboundComponentApproval } from "./unbound-gate-approval";
|
|
12
|
-
|
|
13
|
-
const NOW = "2026-09-05T12:00:00.000Z";
|
|
14
|
-
|
|
15
|
-
const component: DriverComponent = {
|
|
16
|
-
name: "search-service",
|
|
17
|
-
deploy: [{ phase: "Apply", steps: [{ kind: "gate", gate: "approve-prod" }, { kind: "ecs-deploy" }] }],
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const pending: PendingGateRecord = {
|
|
21
|
-
version: 1, kind: "pending", op: "search-service", gate: "approve-prod",
|
|
22
|
-
timestamp: "2026-09-05T10:00:00.000Z", expiresAt: "2026-09-07T10:00:00.000Z",
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const unbound: GateResolutionRecord = {
|
|
26
|
-
version: 1, op: "search-service", gate: "approve-prod",
|
|
27
|
-
resolvedBy: "alex", timestamp: "2026-09-05T11:00:00.000Z",
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function registry(calls: string[]): CapabilityRegistry {
|
|
31
|
-
const r = new CapabilityRegistry();
|
|
32
|
-
r.register({ kind: "ecs-deploy", async run() { calls.push("ecs-deploy"); return { ok: true }; } });
|
|
33
|
-
return r;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
describe("warnOnUnboundComponentApproval (#2574)", () => {
|
|
37
|
-
let warn: ReturnType<typeof vi.spyOn>;
|
|
38
|
-
beforeEach(() => {
|
|
39
|
-
resetUnboundGateApprovalWarnings();
|
|
40
|
-
warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
41
|
-
});
|
|
42
|
-
afterEach(() => warn.mockRestore());
|
|
43
|
-
|
|
44
|
-
it("warns once per component and gate when the approval records no plan", () => {
|
|
45
|
-
expect(warnOnUnboundComponentApproval("search-service", "approve-prod", "prod", unbound)).toBe(true);
|
|
46
|
-
expect(warnOnUnboundComponentApproval("search-service", "approve-prod", "staging", unbound)).toBe(false);
|
|
47
|
-
expect(warnOnUnboundComponentApproval("orders-table", "approve-prod", "prod", { ...unbound, op: "orders-table" })).toBe(true);
|
|
48
|
-
expect(warn).toHaveBeenCalledTimes(2);
|
|
49
|
-
const line = String(warn.mock.calls[0]![0]);
|
|
50
|
-
expect(line).toContain('gate "approve-prod" on component "search-service" passed in "prod"');
|
|
51
|
-
expect(line).toContain("From the next chant release");
|
|
52
|
-
expect(line).toContain("chant approve search-service approve-prod");
|
|
53
|
-
expect(line).toContain("issues/2574");
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("says nothing for an approval that records a plan", () => {
|
|
57
|
-
const bound = { ...unbound, planDigest: `sha256:${"a".repeat(64)}` };
|
|
58
|
-
expect(warnOnUnboundComponentApproval("search-service", "approve-prod", "prod", bound)).toBe(false);
|
|
59
|
-
expect(warn).not.toHaveBeenCalled();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("a deploy passes the gate exactly as before, and warns", async () => {
|
|
63
|
-
const calls: string[] = [];
|
|
64
|
-
const result = await runComponentDeploy(
|
|
65
|
-
component, { env: "prod", component: "search-service" }, registry(calls), {}, undefined,
|
|
66
|
-
{ port: memoryGateLedgerPort({ pending: [pending], resolutions: [unbound] }), now: NOW },
|
|
67
|
-
);
|
|
68
|
-
expect(result.status).toBe("ok");
|
|
69
|
-
expect(calls).toEqual(["ecs-deploy"]);
|
|
70
|
-
expect(warn).toHaveBeenCalledTimes(1);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("a gated deploy does not warn", async () => {
|
|
74
|
-
const calls: string[] = [];
|
|
75
|
-
const result = await runComponentDeploy(
|
|
76
|
-
component, { env: "prod", component: "search-service" }, registry(calls), {}, undefined,
|
|
77
|
-
{ port: memoryGateLedgerPort(), now: NOW },
|
|
78
|
-
);
|
|
79
|
-
expect(result.status).toBe("gated");
|
|
80
|
-
expect(warn).not.toHaveBeenCalled();
|
|
81
|
-
});
|
|
82
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The warning a release ahead of environment- and plan-bound component gate
|
|
3
|
-
* approvals (chant #2574).
|
|
4
|
-
*
|
|
5
|
-
* A component gate approval is keyed by the component and the gate name only,
|
|
6
|
-
* so an approval given for one environment, or for one deploy, can pass the
|
|
7
|
-
* same gate later on another environment or on a promote or rollback. The
|
|
8
|
-
* next release binds each approval to the environment and the plan digest it
|
|
9
|
-
* was given for, the way Op gates bind a plan since #2300, and refuses an
|
|
10
|
-
* approval that records neither.
|
|
11
|
-
*
|
|
12
|
-
* This release only says so. When a component gate passes on an approval that
|
|
13
|
-
* records no plan, the driver prints one warning per component and gate, per
|
|
14
|
-
* process. The decision itself is unchanged.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type { GateResolutionRecord } from "../lifecycle/gate-ledger";
|
|
18
|
-
import { approveCommand } from "../op/gate";
|
|
19
|
-
|
|
20
|
-
/** `component\0gate` pairs already warned about in this process. */
|
|
21
|
-
const warned = new Set<string>();
|
|
22
|
-
|
|
23
|
-
/** Forget which gates were warned about. For tests. */
|
|
24
|
-
export function resetUnboundGateApprovalWarnings(): void {
|
|
25
|
-
warned.clear();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Warn once for `component`'s `gate` when the approval that just passed it in
|
|
30
|
-
* `env` records no plan. Returns whether a warning was printed.
|
|
31
|
-
*/
|
|
32
|
-
export function warnOnUnboundComponentApproval(
|
|
33
|
-
component: string,
|
|
34
|
-
gate: string,
|
|
35
|
-
env: string,
|
|
36
|
-
resolution: GateResolutionRecord,
|
|
37
|
-
): boolean {
|
|
38
|
-
if (resolution.planDigest !== undefined) return false;
|
|
39
|
-
const key = `${component}\0${gate}`;
|
|
40
|
-
if (warned.has(key)) return false;
|
|
41
|
-
warned.add(key);
|
|
42
|
-
console.warn(
|
|
43
|
-
`[chant] warning: gate "${gate}" on component "${component}" passed in "${env}" on an approval by ` +
|
|
44
|
-
`${resolution.resolvedBy} at ${resolution.timestamp} that records no environment and no plan. ` +
|
|
45
|
-
"From the next chant release, a component gate approval counts only for the environment and plan " +
|
|
46
|
-
"digest it was given for, and approvals recorded before then are refused. After upgrading, run the " +
|
|
47
|
-
`deploy again and approve the gate it stops at with \`${approveCommand(component, gate)}\`. ` +
|
|
48
|
-
"See https://github.com/INTENTIUS/chant/issues/2574",
|
|
49
|
-
);
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, realpathSync } from "node:fs";
|
|
3
|
-
import { execFileSync } from "node:child_process";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
import { findInfraFiles } from "./files";
|
|
7
|
-
import { resetDiscoveryWarnings, warnDiscoveryChanges } from "./convergence";
|
|
8
|
-
import { discoverComponents } from "../components/discover";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* chant#2527's warning release. Each category of file whose discovery status
|
|
12
|
-
* changes when the walkers converge gets a warning naming the file, the
|
|
13
|
-
* change and the glob that keeps today's behaviour, while the walker's
|
|
14
|
-
* returned list stays exactly what it is today. Lint's category lives in
|
|
15
|
-
* `../cli/commands/lint.test.ts`, the Op category in
|
|
16
|
-
* `../op/discover-convergence.test.ts`.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
let dir: string;
|
|
20
|
-
let stderr: string[];
|
|
21
|
-
|
|
22
|
-
function write(rel: string, body = "export const x = 1;\n"): void {
|
|
23
|
-
mkdirSync(dirname(join(dir, rel)), { recursive: true });
|
|
24
|
-
writeFileSync(join(dir, rel), body);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** A project config (it declares a project-level key, so it is no lint-only fragment). */
|
|
28
|
-
function project(rel = ".", extra: Record<string, unknown> = {}): void {
|
|
29
|
-
write(join(rel, "chant.config.json"), JSON.stringify({ lexicons: ["aws"], ...extra }));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const rel = (files: string[]): string[] => files.map((f) => f.slice(dir.length + 1)).sort();
|
|
33
|
-
|
|
34
|
-
beforeEach(() => {
|
|
35
|
-
dir = realpathSync(mkdtempSync(join(tmpdir(), "chant-2527-")));
|
|
36
|
-
resetDiscoveryWarnings();
|
|
37
|
-
stderr = [];
|
|
38
|
-
vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => void stderr.push(args.join(" ")));
|
|
39
|
-
vi.spyOn(process, "cwd").mockReturnValue(dir);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
afterEach(() => {
|
|
43
|
-
vi.restoreAllMocks();
|
|
44
|
-
rmSync(dir, { recursive: true, force: true });
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe("source discovery warns about files the converged walker reads differently (#2527)", () => {
|
|
48
|
-
test("a .ts file in a dot-directory", async () => {
|
|
49
|
-
project();
|
|
50
|
-
write("src/app.ts");
|
|
51
|
-
write(".cache/gen.ts");
|
|
52
|
-
|
|
53
|
-
expect(rel(await findInfraFiles(dir))).toEqual([".cache/gen.ts", "src/app.ts"]);
|
|
54
|
-
expect(stderr).toEqual([
|
|
55
|
-
"warning: Source discovery (build, graph, list, explain) under the current directory changes in the next release (chant#2527):\n" +
|
|
56
|
-
" .cache/gen.ts: .cache/ is a dot-directory. Every walker skips dot-directories from the next release. " +
|
|
57
|
-
'To keep reading it after the change, add ".cache" to include in chant.config.json, which the next release honours.',
|
|
58
|
-
]);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("a git-ignored .ts file, ignored by a nested .gitignore", async () => {
|
|
62
|
-
execFileSync("git", ["init", "-q"], { cwd: dir });
|
|
63
|
-
project();
|
|
64
|
-
write("src/app.ts");
|
|
65
|
-
write("src/vendored.ts");
|
|
66
|
-
write("src/.gitignore", "vendored.ts\n");
|
|
67
|
-
|
|
68
|
-
expect(rel(await findInfraFiles(dir))).toEqual(["src/app.ts", "src/vendored.ts"]);
|
|
69
|
-
expect(stderr).toHaveLength(1);
|
|
70
|
-
expect(stderr[0]).toContain(
|
|
71
|
-
" src/vendored.ts is git-ignored. Every walker skips git-ignored files from the next release. " +
|
|
72
|
-
'To keep reading it after the change, add "src/vendored.ts" to include in chant.config.json, which the next release honours.',
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("an ignored directory is named once, by its outermost ignored path", async () => {
|
|
77
|
-
execFileSync("git", ["init", "-q"], { cwd: dir });
|
|
78
|
-
project();
|
|
79
|
-
write("src/app.ts");
|
|
80
|
-
write(".gitignore", "vendor/\n");
|
|
81
|
-
for (const name of ["a", "b", "c", "d"]) write(`vendor/lib/${name}.ts`);
|
|
82
|
-
|
|
83
|
-
expect(rel(await findInfraFiles(dir))).toHaveLength(5);
|
|
84
|
-
expect(stderr[0]).toContain(" 4 files under vendor/: vendor/ is git-ignored.");
|
|
85
|
-
expect(stderr[0]).toContain('add "vendor" to include in chant.config.json, which the next release honours.');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("a .ts file under dist", async () => {
|
|
89
|
-
project();
|
|
90
|
-
write("src/app.ts");
|
|
91
|
-
write("dist/out.ts");
|
|
92
|
-
|
|
93
|
-
expect(rel(await findInfraFiles(dir))).toEqual(["dist/out.ts", "src/app.ts"]);
|
|
94
|
-
expect(stderr[0]).toContain(
|
|
95
|
-
" dist/out.ts: dist/ is a dist directory. Every walker skips dist from the next release. " +
|
|
96
|
-
'To keep reading it after the change, add "dist" to include in chant.config.json, which the next release honours.',
|
|
97
|
-
);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test("a nested child project whose chant.config.json declares a project", async () => {
|
|
101
|
-
project();
|
|
102
|
-
write("src/app.ts");
|
|
103
|
-
project("stacks/east");
|
|
104
|
-
write("stacks/east/east.ts");
|
|
105
|
-
// A lint-only fragment is not a boundary: no warning for this one.
|
|
106
|
-
write("stacks/west/chant.config.json", JSON.stringify({ rules: { COR004: "off" } }));
|
|
107
|
-
write("stacks/west/west.ts");
|
|
108
|
-
|
|
109
|
-
expect(rel(await findInfraFiles(dir))).toEqual(["src/app.ts", "stacks/east/east.ts", "stacks/west/west.ts"]);
|
|
110
|
-
expect(stderr).toHaveLength(1);
|
|
111
|
-
expect(stderr[0]).toContain(
|
|
112
|
-
" stacks/east/east.ts: stacks/east/ is a child project with its own chant.config. " +
|
|
113
|
-
"Discovery stops at child projects from the next release. " +
|
|
114
|
-
'To keep reading it after the change, add "stacks/east" to include in chant.config.json, which the next release honours.',
|
|
115
|
-
);
|
|
116
|
-
expect(stderr[0]).not.toContain("west");
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("the first child project met is no longer read as the project's own source (the quirk)", async () => {
|
|
120
|
-
project();
|
|
121
|
-
write("app/chant.config.ts", "export default {};\n");
|
|
122
|
-
write("app/main.ts");
|
|
123
|
-
|
|
124
|
-
expect(rel(await findInfraFiles(dir))).toEqual(["app/chant.config.ts", "app/main.ts"]);
|
|
125
|
-
expect(stderr[0]).toContain(
|
|
126
|
-
" app/chant.config.ts, app/main.ts: app/ is a child project with its own chant.config, " +
|
|
127
|
-
"read today as this project's own source because the walk met it first. " +
|
|
128
|
-
"From the next release discovery stops there, as at any child project. " +
|
|
129
|
-
'To keep reading them after the change, add "app" to include in chant.config.json, which the next release honours.',
|
|
130
|
-
);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("the glob in the config is the fix: with it, nothing is printed and the list is the same", async () => {
|
|
134
|
-
project(".", { include: [".cache", "dist"] });
|
|
135
|
-
write("src/app.ts");
|
|
136
|
-
write(".cache/gen.ts");
|
|
137
|
-
write("dist/out.ts");
|
|
138
|
-
|
|
139
|
-
expect(rel(await findInfraFiles(dir))).toEqual([".cache/gen.ts", "dist/out.ts", "src/app.ts"]);
|
|
140
|
-
expect(stderr).toEqual([]);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("a clean project prints nothing", async () => {
|
|
144
|
-
execFileSync("git", ["init", "-q"], { cwd: dir });
|
|
145
|
-
project();
|
|
146
|
-
write(".gitignore", "node_modules/\n.chant/types/\n");
|
|
147
|
-
write("src/app.ts");
|
|
148
|
-
write("src/lib/util.ts");
|
|
149
|
-
write("node_modules/dep/index.ts");
|
|
150
|
-
// chant init's generated type stubs: read today, never worth a warning.
|
|
151
|
-
write(".chant/types/core/index.d.ts");
|
|
152
|
-
|
|
153
|
-
expect(rel(await findInfraFiles(dir))).toEqual([".chant/types/core/index.d.ts", "src/app.ts", "src/lib/util.ts"]);
|
|
154
|
-
expect(stderr).toEqual([]);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
test("a project-local lexicon named by module path (#2520) prints nothing", async () => {
|
|
158
|
-
execFileSync("git", ["init", "-q"], { cwd: dir });
|
|
159
|
-
write("chant.config.json", JSON.stringify({ lexicons: [{ name: "local", module: "./lexicon/index.ts" }] }));
|
|
160
|
-
write("lexicon/index.ts");
|
|
161
|
-
write("lexicon/rules/r1.ts");
|
|
162
|
-
write("src/app.ts");
|
|
163
|
-
|
|
164
|
-
expect(rel(await findInfraFiles(dir))).toEqual(["lexicon/index.ts", "lexicon/rules/r1.ts", "src/app.ts"]);
|
|
165
|
-
expect(stderr).toEqual([]);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test("a project-local lexicon's config still yields the glob when something else warns", async () => {
|
|
169
|
-
write("chant.config.json", JSON.stringify({ lexicons: [{ name: "local", module: "./lexicon/index.ts" }], include: [".cache"] }));
|
|
170
|
-
write("lexicon/index.ts");
|
|
171
|
-
write(".cache/gen.ts");
|
|
172
|
-
write("dist/out.ts");
|
|
173
|
-
|
|
174
|
-
expect(rel(await findInfraFiles(dir))).toEqual([".cache/gen.ts", "dist/out.ts", "lexicon/index.ts"]);
|
|
175
|
-
expect(stderr).toHaveLength(1);
|
|
176
|
-
expect(stderr[0]).not.toContain(".cache");
|
|
177
|
-
expect(stderr[0]).toContain('add "dist" to include in chant.config.json');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test("a warning prints once per process, however often the tree is walked", async () => {
|
|
181
|
-
project();
|
|
182
|
-
write(".cache/gen.ts");
|
|
183
|
-
await findInfraFiles(dir);
|
|
184
|
-
await findInfraFiles(dir);
|
|
185
|
-
expect(stderr).toHaveLength(1);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
describe("component discovery outside a project reads every child project next release (#2527)", () => {
|
|
190
|
-
test("the second child project's component is named, with the exclude glob", async () => {
|
|
191
|
-
// No config and no .git/package.json at or above `dir`: outside a project.
|
|
192
|
-
write("one/chant.config.ts", "export default {};\n");
|
|
193
|
-
write("one/one.component.ts");
|
|
194
|
-
write("two/chant.config.ts", "export default {};\n");
|
|
195
|
-
write("two/two.component.ts");
|
|
196
|
-
|
|
197
|
-
const { sourceFiles } = await discoverComponents(dir);
|
|
198
|
-
// Today: whichever child the walk met first, and only that one.
|
|
199
|
-
expect(sourceFiles).toHaveLength(1);
|
|
200
|
-
const [read] = rel(sourceFiles);
|
|
201
|
-
const skipped = read.startsWith("one/") ? "two" : "one";
|
|
202
|
-
|
|
203
|
-
expect(stderr).toHaveLength(1);
|
|
204
|
-
expect(stderr[0]).toContain(
|
|
205
|
-
`warning: Component discovery under the current directory changes in the next release (chant#2527):\n` +
|
|
206
|
-
` ${skipped}/${skipped}.component.ts: ${skipped}/ is a child project, skipped today ` +
|
|
207
|
-
"because the walk met another child project first. From the next release every child project is read, " +
|
|
208
|
-
"since the current directory is not inside a chant project. " +
|
|
209
|
-
`To keep skipping it, add "${skipped}" to exclude in chant.config.ts (a new file).`,
|
|
210
|
-
);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
describe("the audit walk (#2527)", () => {
|
|
215
|
-
test("warns about a git-ignored candidate and leaves Terraform state to TF023", async () => {
|
|
216
|
-
execFileSync("git", ["init", "-q"], { cwd: dir });
|
|
217
|
-
write(".gitignore", ".env\n");
|
|
218
|
-
write(".env", "TOKEN=x\n");
|
|
219
|
-
write("k8s/deploy.yaml", "kind: Deployment\n");
|
|
220
|
-
|
|
221
|
-
const lines = await warnDiscoveryChanges({
|
|
222
|
-
walker: "audit",
|
|
223
|
-
root: dir,
|
|
224
|
-
files: [join(dir, ".env"), join(dir, "k8s/deploy.yaml"), join(dir, ".github/workflows/ci.yml")],
|
|
225
|
-
});
|
|
226
|
-
expect(lines).toEqual([
|
|
227
|
-
" .env is git-ignored. Every walker skips git-ignored files from the next release. " +
|
|
228
|
-
'To keep reading it after the change, add ".env" to include in chant.config.ts (a new file), which the next release honours.',
|
|
229
|
-
]);
|
|
230
|
-
});
|
|
231
|
-
});
|