@intentius/chant 0.80.0 → 0.82.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 +35 -0
- package/dist/workspace/lineage-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +144 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -0
- package/dist/workspace/lineage-lock.d.ts +271 -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 +152 -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 +58 -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 +232 -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 +158 -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 +134 -0
- package/src/workspace/lineage-init-dir.test.ts +243 -0
- package/src/workspace/lineage-init.test.ts +231 -0
- package/src/workspace/lineage-init.ts +560 -0
- package/src/workspace/lineage-lock.test.ts +224 -0
- package/src/workspace/lineage-lock.ts +365 -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 +723 -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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first attestor: ssh-signed commits, checked against the signers the
|
|
3
|
+
* base policy lists (#2524 D5, ws-001).
|
|
4
|
+
*
|
|
5
|
+
* It does not ask `git verify-commit`. That would read `gpg.ssh.program`,
|
|
6
|
+
* `gpg.ssh.allowedSignersFile` and the rest from git config, which whoever
|
|
7
|
+
* controls the machine can set, and it passes the commit's own date to
|
|
8
|
+
* ssh-keygen as the verification time. Instead it takes the signature and the
|
|
9
|
+
* signed payload out of the commit object itself and hands them to
|
|
10
|
+
* `ssh-keygen -Y verify` with a signers file built from the base policy, in
|
|
11
|
+
* the `git` namespace.
|
|
12
|
+
*/
|
|
13
|
+
import type { CommitAttestor } from "./attestor.js";
|
|
14
|
+
import { type Signer } from "./policy.js";
|
|
15
|
+
/** A commit object split into its signed payload and its signature. */
|
|
16
|
+
export interface SignedCommit {
|
|
17
|
+
/** The bytes the signature covers: the commit object without its signature header. */
|
|
18
|
+
payload: Buffer;
|
|
19
|
+
/** The armored signature, or undefined when the commit is unsigned. */
|
|
20
|
+
signature?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Split a raw commit object. `header` is `gpgsig` in a SHA-1 repository and
|
|
24
|
+
* `gpgsig-sha256` in a SHA-256 one; git removes exactly that header, with its
|
|
25
|
+
* continuation lines, to get the bytes it signed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function splitSignedCommit(raw: Buffer, header?: string): SignedCommit;
|
|
28
|
+
/**
|
|
29
|
+
* Check a detached ssh signature over `payload` in `namespace` against
|
|
30
|
+
* `signers`. Shared with the rotation check (#2553), which signs signer sets
|
|
31
|
+
* in their own namespace so a commit signature can never stand in for one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifySshSignature(signers: Signer[], payload: Buffer, signature: string, namespace: string): {
|
|
34
|
+
ok: true;
|
|
35
|
+
principal: string;
|
|
36
|
+
key?: string;
|
|
37
|
+
} | {
|
|
38
|
+
ok: false;
|
|
39
|
+
missing: boolean;
|
|
40
|
+
reason: string;
|
|
41
|
+
};
|
|
42
|
+
export declare const sshCommitAttestor: CommitAttestor;
|
|
43
|
+
//# sourceMappingURL=ssh-commit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-commit.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/ssh-commit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAsC,cAAc,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAwB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAI7D,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG,YAAY,CAsB9E;AAmBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAuBjG;AAED,eAAO,MAAM,iBAAiB,EAAE,cAW/B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test support for the trust modules: throwaway git repositories whose commits
|
|
3
|
+
* are signed with throwaway ssh keys. Isolated from the user's git config, so a
|
|
4
|
+
* developer's own signing setup never leaks into a test.
|
|
5
|
+
*/
|
|
6
|
+
export declare const hasSshKeygen: boolean;
|
|
7
|
+
export interface Key {
|
|
8
|
+
name: string;
|
|
9
|
+
/** Private key file. */
|
|
10
|
+
file: string;
|
|
11
|
+
/** `ssh-ed25519 AAAA...`, no comment. */
|
|
12
|
+
pub: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class TestRepo {
|
|
15
|
+
readonly dir: string;
|
|
16
|
+
private readonly home;
|
|
17
|
+
private readonly scratch;
|
|
18
|
+
constructor(label: string);
|
|
19
|
+
env(extra?: Record<string, string>): NodeJS.ProcessEnv;
|
|
20
|
+
git(args: string[], opts?: {
|
|
21
|
+
env?: Record<string, string>;
|
|
22
|
+
input?: string | Buffer;
|
|
23
|
+
}): string;
|
|
24
|
+
key(name: string): Key;
|
|
25
|
+
write(path: string, text: string): void;
|
|
26
|
+
/** Stage everything and commit, signed with `key` when given. Returns the commit id. */
|
|
27
|
+
commit(message: string, key?: Key, env?: Record<string, string>): string;
|
|
28
|
+
head(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Write a commit object by hand: the current index's tree, `HEAD` as parent,
|
|
31
|
+
* and `signature` spliced in as the gpgsig header. Returns the new commit,
|
|
32
|
+
* which HEAD then points at.
|
|
33
|
+
*/
|
|
34
|
+
forgeCommit(message: string, sign: (payload: Buffer) => string): string;
|
|
35
|
+
/** An ssh signature over `payload` in `namespace`, by `key`. */
|
|
36
|
+
sshSign(key: Key, payload: Buffer, namespace: string): string;
|
|
37
|
+
cleanup(): void;
|
|
38
|
+
}
|
|
39
|
+
/** A record kind reading `records/*.md`, and its schema, written into `repo`. */
|
|
40
|
+
export declare function writeRecordKind(repo: TestRepo): string;
|
|
41
|
+
export declare function note(id: string, body?: string): string;
|
|
42
|
+
//# sourceMappingURL=test-repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-repo.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/test-repo.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,eAAO,MAAM,YAAY,SAA2E,CAAC;AAErG,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,QAAQ;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,KAAK,EAAE,MAAM;IASzB,GAAG,CAAC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,MAAM,CAAC,UAAU;IAc1D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GAAG,MAAM;IAIjG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG;IAOtB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvC,wFAAwF;IACxF,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,MAAM;IAO5E,IAAI,IAAI,MAAM;IAId;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM;IAgBvE,gEAAgE;IAChE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAO7D,OAAO,IAAI,IAAI;CAGhB;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAqBtD;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant workspace verify [--base <rev>] [--head <rev>] [--require attested] [--json]`
|
|
3
|
+
* (#2547): check a change against the trust policy at its base. See ./verify.ts.
|
|
4
|
+
*
|
|
5
|
+
* Exit 0 when the change passes, 1 when it does not or cannot be checked.
|
|
6
|
+
*/
|
|
7
|
+
import type { CommandContext } from "../../cli/registry.js";
|
|
8
|
+
export declare function runWorkspaceVerify(ctx: CommandContext): Promise<number>;
|
|
9
|
+
//# sourceMappingURL=verify-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-cli.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/verify-cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAOzD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB7E"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a change against the policy at its base (#2524 D5, Threat model).
|
|
3
|
+
*
|
|
4
|
+
* This is what CI runs on a protected branch: every commit in `base..head` is
|
|
5
|
+
* asked of the attestors with the policy read at base, so nothing the change
|
|
6
|
+
* does to its own copy of the policy counts. A change that edits the policy
|
|
7
|
+
* (the signers file or `.chant/trust.json`) is a protected write: every commit
|
|
8
|
+
* that touches those files must be attested by a signer the base policy
|
|
9
|
+
* trusts, and by an admin when the base policy grants the admin role.
|
|
10
|
+
*
|
|
11
|
+
* Attestation is opt-in (#2525 rule 6). Without a signers file at base the
|
|
12
|
+
* check passes and says so, unless `--require attested` asks for more.
|
|
13
|
+
*/
|
|
14
|
+
import { type CommitAttestor, type ProvenanceLevel } from "./attestor.js";
|
|
15
|
+
import { type BaseSource, type RecordProvenance } from "./provenance.js";
|
|
16
|
+
import { type ExcludedSigner } from "./policy.js";
|
|
17
|
+
export interface CommitVerdict extends RecordProvenance {
|
|
18
|
+
commit: string;
|
|
19
|
+
subject: string;
|
|
20
|
+
/** A merge that changes nothing of its own; its parents are checked instead. */
|
|
21
|
+
skipped?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ProtectedWrite {
|
|
24
|
+
commit: string;
|
|
25
|
+
paths: string[];
|
|
26
|
+
level: ProvenanceLevel;
|
|
27
|
+
principal?: string;
|
|
28
|
+
allowed: boolean;
|
|
29
|
+
reason: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ChangeReport {
|
|
32
|
+
base: string | null;
|
|
33
|
+
baseFrom: BaseSource | null;
|
|
34
|
+
head: string | null;
|
|
35
|
+
policy: {
|
|
36
|
+
active: boolean;
|
|
37
|
+
signersPath: string;
|
|
38
|
+
principals: string[];
|
|
39
|
+
excluded: ExcludedSigner[];
|
|
40
|
+
writers: string[];
|
|
41
|
+
problems: string[];
|
|
42
|
+
};
|
|
43
|
+
require: ProvenanceLevel | null;
|
|
44
|
+
commits: CommitVerdict[];
|
|
45
|
+
protectedPaths: string[];
|
|
46
|
+
/** Protected paths whose content differs between the merge base and head. */
|
|
47
|
+
protectedChanged: string[];
|
|
48
|
+
protectedWrites: ProtectedWrite[];
|
|
49
|
+
notes: string[];
|
|
50
|
+
failures: string[];
|
|
51
|
+
ok: boolean;
|
|
52
|
+
}
|
|
53
|
+
export interface VerifyOptions {
|
|
54
|
+
repo: string;
|
|
55
|
+
base?: string;
|
|
56
|
+
head?: string;
|
|
57
|
+
require?: ProvenanceLevel;
|
|
58
|
+
attestors: readonly CommitAttestor[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Commits in `range` that change any of `paths`, each with the paths it
|
|
62
|
+
* changes. Merges count only for what they change beyond every parent.
|
|
63
|
+
*/
|
|
64
|
+
export declare function commitsTouching(repo: string, range: string, paths: string[]): Map<string, string[]>;
|
|
65
|
+
export declare function verifyChange(opts: VerifyOptions): ChangeReport;
|
|
66
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAA+C,KAAK,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACnH,OAAO,EAAiC,KAAK,cAAc,EAAoB,MAAM,UAAU,CAAC;AAEhG,MAAM,WAAW,aAAc,SAAQ,gBAAgB;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE;QACN,MAAM,EAAE,OAAO,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,EAAE,cAAc,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,EAAE,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CACtC;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAUnG;AAQD,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAqG9D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a workspace read starts, and which chant does it (#2536; #2524 D15,
|
|
3
|
+
* ws-016, ws-021).
|
|
4
|
+
*
|
|
5
|
+
* {@link locateWorkspace} finds the declaration from a directory, in the
|
|
6
|
+
* working tree or in one commit's git objects (`--at <rev>`), and gives the
|
|
7
|
+
* tree every read-contract command reads from.
|
|
8
|
+
*
|
|
9
|
+
* Which chant reads the declaration: the root's. The root names its chant by
|
|
10
|
+
* pinning `@intentius/chant` in the declaration's `pins`. When it pins one,
|
|
11
|
+
* that version reads the declaration, and any other chant refuses with
|
|
12
|
+
* `root-chant-required` (`parseDeclaration`'s `rootChant` option). The CLI
|
|
13
|
+
* first hands the whole command to the pinned chant when the root has it
|
|
14
|
+
* installed ({@link handToRootChant}), so a user sees the refusal only when
|
|
15
|
+
* it isn't. When the root pins no chant, the reader's own chant reads the
|
|
16
|
+
* declaration if it meets `minReader`, and refuses with `reader-too-old`
|
|
17
|
+
* otherwise. Members are always read by their own toolchains.
|
|
18
|
+
*/
|
|
19
|
+
import { type WorkspaceTree } from "./tree.js";
|
|
20
|
+
export interface LocatedWorkspace {
|
|
21
|
+
/** The files, rooted at the workspace root. */
|
|
22
|
+
tree: WorkspaceTree;
|
|
23
|
+
/** The workspace root relative to the git root, `"."` for the git root itself. Absolute outside git. */
|
|
24
|
+
root: string;
|
|
25
|
+
/** The workspace root on disk, where pinned packages and toolchains are installed. Also for `--at`. */
|
|
26
|
+
rootOnDisk: string;
|
|
27
|
+
/** The full commit id for `--at`, or null for the working tree. */
|
|
28
|
+
at: string | null;
|
|
29
|
+
/** The top of the git repository, when there is one. */
|
|
30
|
+
top: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Find the workspace whose declaration is nearest above `cwd`, in the working
|
|
34
|
+
* tree or at revision `at`. Throws a {@link WorkspaceReadError}:
|
|
35
|
+
* `declaration-missing`, or for `--at`, `not-a-git-repository` and
|
|
36
|
+
* `revision-unknown`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function locateWorkspace(cwd: string, at?: string): LocatedWorkspace;
|
|
39
|
+
/**
|
|
40
|
+
* The `bin/chant` of `@intentius/chant` at `version`, installed where the
|
|
41
|
+
* workspace root resolves packages. Undefined when it isn't installed there,
|
|
42
|
+
* or is installed at another version.
|
|
43
|
+
*/
|
|
44
|
+
export declare function rootChantBin(rootOnDisk: string, version: string): string | undefined;
|
|
45
|
+
/** Set in the environment of a command handed to the root's chant, so it is handed on once at most. */
|
|
46
|
+
export declare const HANDED_TO_ROOT_ENV = "CHANT_WORKSPACE_ROOT_CHANT";
|
|
47
|
+
/** The version the declaration at `located` pins for `@intentius/chant`, or undefined. Never throws. */
|
|
48
|
+
export declare function declaredChantPin(located: LocatedWorkspace): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Hand a read-contract command to the root's chant (ws-021). When the
|
|
51
|
+
* declaration above `cwd` (at `at`, for `--at`) pins a chant other than this
|
|
52
|
+
* one, and the root has that chant installed, run the same command line
|
|
53
|
+
* under it and return its exit code. Otherwise return undefined, and this
|
|
54
|
+
* chant runs the command: it reads the declaration itself, or refuses with
|
|
55
|
+
* `root-chant-required` when the pinned chant isn't installed.
|
|
56
|
+
*/
|
|
57
|
+
export declare function handToRootChant(cwd: string, at: string | undefined, argv?: string[]): Promise<number | undefined>;
|
|
58
|
+
//# sourceMappingURL=which-chant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"which-chant.d.ts","sourceRoot":"","sources":["../../src/workspace/which-chant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,OAAO,EAA+C,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAEzF,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,IAAI,EAAE,aAAa,CAAC;IACpB,wGAAwG;IACxG,IAAI,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,wDAAwD;IACxD,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAgC1E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpF;AAED,uGAAuG;AACvG,eAAO,MAAM,kBAAkB,+BAA+B,CAAC;AAE/D,wGAAwG;AACxG,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAY9E;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoB9I"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/chant/schemas/workspace/kinds/v1/workspace-kinds.schema.json",
|
|
4
|
+
"title": "workspace-kinds.json",
|
|
5
|
+
"description": "Member kinds a plugin supplies (#2524 D3, #2535, ws-031). A package publishes this file as data at its ./workspace-kinds subpath. chant reads it with the file system and never imports the package, so reading kinds never loads a lexicon.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"schema",
|
|
9
|
+
"kinds"
|
|
10
|
+
],
|
|
11
|
+
"properties": {
|
|
12
|
+
"$schema": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "An editor hint. chant ignores it."
|
|
15
|
+
},
|
|
16
|
+
"$comment": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "A note for people. chant ignores it."
|
|
19
|
+
},
|
|
20
|
+
"schema": {
|
|
21
|
+
"const": 1,
|
|
22
|
+
"description": "The kinds format version."
|
|
23
|
+
},
|
|
24
|
+
"kinds": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"minItems": 1,
|
|
27
|
+
"items": {
|
|
28
|
+
"$ref": "#/$defs/kind"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"patternProperties": {
|
|
33
|
+
"^x-": true
|
|
34
|
+
},
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"$defs": {
|
|
37
|
+
"kind": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": [
|
|
40
|
+
"name",
|
|
41
|
+
"description",
|
|
42
|
+
"precedence",
|
|
43
|
+
"probe"
|
|
44
|
+
],
|
|
45
|
+
"properties": {
|
|
46
|
+
"name": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"pattern": "^[a-z][a-z0-9-]{0,39}$",
|
|
49
|
+
"description": "The kind's name, as a member's kind field names it. chant, workspace, other and examples are built in and can't be supplied."
|
|
50
|
+
},
|
|
51
|
+
"description": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"minLength": 1,
|
|
54
|
+
"description": "One line saying what the member's directory holds, for listings and error messages."
|
|
55
|
+
},
|
|
56
|
+
"precedence": {
|
|
57
|
+
"type": "integer",
|
|
58
|
+
"minimum": 1,
|
|
59
|
+
"maximum": 999,
|
|
60
|
+
"description": "When the probes of several kinds claim one directory, the highest precedence decides. Two claiming kinds with the same highest precedence are a tie, and a tie fails. The built-in chant kind has 500 and workspace has 1000."
|
|
61
|
+
},
|
|
62
|
+
"probe": {
|
|
63
|
+
"$ref": "#/$defs/probe"
|
|
64
|
+
},
|
|
65
|
+
"outputs": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"uniqueItems": true,
|
|
68
|
+
"description": "The outputs every member of this kind exposes as link targets (#2524 D6, #2539). A member entry of the kind may list more in its own outputs field. Without this field the kind exposes only what each entry lists.",
|
|
69
|
+
"items": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"minLength": 1,
|
|
72
|
+
"maxLength": 255,
|
|
73
|
+
"pattern": "^[^\\u0000-\\u001f]+$"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"patternProperties": {
|
|
78
|
+
"^x-": true
|
|
79
|
+
},
|
|
80
|
+
"additionalProperties": false
|
|
81
|
+
},
|
|
82
|
+
"probe": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"description": "What the probe checks in a member's directory. It runs no code. It passes when any of its clauses does, and it needs at least one.",
|
|
85
|
+
"minProperties": 1,
|
|
86
|
+
"properties": {
|
|
87
|
+
"anyFile": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"minItems": 1,
|
|
90
|
+
"uniqueItems": true,
|
|
91
|
+
"description": "The directory passes when a file matching one of these names sits directly in it. A * in a name matches any run of characters, so *.tf matches every Terraform file.",
|
|
92
|
+
"items": {
|
|
93
|
+
"$ref": "#/$defs/fileName"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"anyBlock": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"description": "The directory passes when a file directly in it, whose name matches one of in, has a line opening an unlabelled block named in blocks: leading space, the name, optional space, then {. No file is parsed.",
|
|
99
|
+
"required": [
|
|
100
|
+
"in",
|
|
101
|
+
"blocks"
|
|
102
|
+
],
|
|
103
|
+
"properties": {
|
|
104
|
+
"in": {
|
|
105
|
+
"type": "array",
|
|
106
|
+
"minItems": 1,
|
|
107
|
+
"uniqueItems": true,
|
|
108
|
+
"items": {
|
|
109
|
+
"$ref": "#/$defs/fileName"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"blocks": {
|
|
113
|
+
"type": "array",
|
|
114
|
+
"minItems": 1,
|
|
115
|
+
"uniqueItems": true,
|
|
116
|
+
"items": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"additionalProperties": false
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"additionalProperties": false
|
|
126
|
+
},
|
|
127
|
+
"fileName": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"description": "A file name, with no directory part. A * matches any run of characters.",
|
|
130
|
+
"pattern": "^(?!\\.\\.?$)[^/\\\\]+$"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
4
4
|
"description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"types": "./dist/cli/index.d.ts",
|
|
50
50
|
"default": "./src/cli/index.ts"
|
|
51
51
|
},
|
|
52
|
+
"./workspace/*.schema.json": "./src/workspace/*.schema.json",
|
|
52
53
|
"./cli/*": {
|
|
53
54
|
"development": "./src/cli/*.ts",
|
|
54
55
|
"types": "./dist/cli/*.d.ts",
|
package/src/audit/discover.ts
CHANGED
|
@@ -34,12 +34,15 @@
|
|
|
34
34
|
* normalized to a JSON string here.
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
import {
|
|
37
|
+
import { readFileSync, statSync } from "fs";
|
|
38
38
|
import { basename, join, relative, resolve } from "path";
|
|
39
39
|
import { parseYAML } from "../yaml";
|
|
40
40
|
import type { LexiconPlugin } from "../lexicon";
|
|
41
41
|
import type { AuditInput, AuditLexicon } from "./core";
|
|
42
42
|
import { isNginxConfigPath } from "./nginx";
|
|
43
|
+
import { walkDiscovery } from "../discovery/walk";
|
|
44
|
+
import { findProjectConfig } from "../project-root";
|
|
45
|
+
import type { DiscoveryGlobs } from "../config";
|
|
43
46
|
import { gitignoreCoversTerraformState, isTerraformStatePath, nestedGitignoreCovering } from "./terraform-state";
|
|
44
47
|
|
|
45
48
|
/** Lexicons the auditor knows how to detect and run checks for. */
|
|
@@ -69,11 +72,8 @@ export async function loadAuditPlugins(names: readonly string[] = AUDIT_LEXICONS
|
|
|
69
72
|
return plugins;
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
const WALK_SKIP = new Set(["node_modules", ".git", "dist"]);
|
|
73
75
|
/** Terraform's local working directory: recorded by the walk, never entered (TF023). */
|
|
74
76
|
const TERRAFORM_WORK_DIR = ".terraform";
|
|
75
|
-
/** Dot-directories the walk descends into anyway (CI lives here). */
|
|
76
|
-
const WALK_DOT_DIRS = new Set([".github", ".forgejo"]);
|
|
77
77
|
/**
|
|
78
78
|
* How many files the local walk takes before it stops. Every file it reaches
|
|
79
79
|
* counts, candidate or not, so a tree with a large `docs/` or `assets/` can hit
|
|
@@ -83,53 +83,54 @@ export const DEFAULT_MAX_WALK_FILES = 1000;
|
|
|
83
83
|
/** Skip absurdly large files before parsing — mirrors the fetch layer's caps. */
|
|
84
84
|
const MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
85
85
|
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
/**
|
|
87
|
+
* The project's `exclude`/`include` globs for the audit walk, read from a
|
|
88
|
+
* `chant.config.json` only. The audit reads repositories it has no reason to
|
|
89
|
+
* trust, so it never runs a `chant.config.ts` to find them.
|
|
90
|
+
*/
|
|
91
|
+
function auditGlobs(root: string): DiscoveryGlobs | undefined {
|
|
92
|
+
const { dir, configPath } = findProjectConfig(root);
|
|
93
|
+
if (!configPath?.endsWith(".json")) return undefined;
|
|
94
|
+
let raw: unknown;
|
|
95
|
+
try {
|
|
96
|
+
raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
97
|
+
} catch {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const list = (v: unknown): string[] => (Array.isArray(v) ? v.filter((x): x is string => typeof x === "string" && x !== "") : []);
|
|
101
|
+
const exclude = list((raw as Record<string, unknown>)?.exclude);
|
|
102
|
+
const include = list((raw as Record<string, unknown>)?.include);
|
|
103
|
+
return exclude.length === 0 && include.length === 0 ? undefined : { root: dir, exclude, include };
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
/**
|
|
93
|
-
*
|
|
107
|
+
* Collect file paths under a root through the one discovery walk
|
|
108
|
+
* (`../discovery/walk.ts`, #2527), sorted per directory.
|
|
109
|
+
*
|
|
110
|
+
* The audit's own departures from the other walkers: `.github` and `.forgejo`
|
|
111
|
+
* are entered, since they hold the CI files it audits; `.terraform/` is
|
|
112
|
+
* recorded but never entered, since it is machine-generated, routinely
|
|
113
|
+
* hundreds of megabytes of provider binaries, and its presence is itself the
|
|
114
|
+
* finding (TF023); and Terraform state paths are left to TF023's own
|
|
115
|
+
* `.gitignore` reading rather than dropped for being git-ignored.
|
|
94
116
|
*
|
|
95
|
-
* Stops at `state.
|
|
117
|
+
* Stops at `state.max` paths. Once full it keeps looking only until it meets
|
|
96
118
|
* one more path it would have taken, which is what sets `truncated`: a tree of
|
|
97
|
-
* exactly `
|
|
98
|
-
* directories, was not truncated.
|
|
99
|
-
* `limit` either way.
|
|
119
|
+
* exactly `max` files, or one whose remaining entries are all skipped
|
|
120
|
+
* directories, was not truncated.
|
|
100
121
|
*/
|
|
101
|
-
function walkFiles(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
out.push(path);
|
|
115
|
-
return true;
|
|
116
|
-
};
|
|
117
|
-
for (const e of entries.sort((a, b) => (a.name < b.name ? -1 : 1))) {
|
|
118
|
-
if (state.truncated) return;
|
|
119
|
-
if (e.name.startsWith(".") && e.isDirectory() && !WALK_DOT_DIRS.has(e.name)) {
|
|
120
|
-
// `.terraform/` is never descended into: it is machine-generated,
|
|
121
|
-
// routinely hundreds of megabytes of provider binaries, and nothing in
|
|
122
|
-
// it is worth reading. Its presence is itself the finding (TF023), so
|
|
123
|
-
// the directory path alone is recorded and `collectCandidates` hands it
|
|
124
|
-
// on with no content.
|
|
125
|
-
if (e.name === TERRAFORM_WORK_DIR && !take(join(dir, e.name))) return;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (WALK_SKIP.has(e.name)) continue;
|
|
129
|
-
const full = join(dir, e.name);
|
|
130
|
-
if (e.isDirectory()) walkFiles(full, out, state);
|
|
131
|
-
else if (!take(full)) return;
|
|
132
|
-
}
|
|
122
|
+
function walkFiles(root: string, state: { max: number; truncated: boolean }, excludeDirs?: readonly string[]): string[] {
|
|
123
|
+
return walkDiscovery({
|
|
124
|
+
walker: "audit",
|
|
125
|
+
root,
|
|
126
|
+
excludeDirs,
|
|
127
|
+
globs: auditGlobs(root),
|
|
128
|
+
sorted: true,
|
|
129
|
+
limit: state,
|
|
130
|
+
takeSkippedDir: (name) => name === TERRAFORM_WORK_DIR,
|
|
131
|
+
keepIgnored: (full) => isTerraformStatePath(relative(root, full)),
|
|
132
|
+
accept: () => true,
|
|
133
|
+
});
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
function readSafe(full: string): string | undefined {
|
|
@@ -625,18 +626,12 @@ export function discoverByDetection(root: string, plugins: DetectPlugin[]): Audi
|
|
|
625
626
|
export interface CandidateWalkOptions {
|
|
626
627
|
/** Files the walk takes before it stops, counting every file. Defaults to {@link DEFAULT_MAX_WALK_FILES}. */
|
|
627
628
|
maxFiles?: number;
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
*/
|
|
635
|
-
export interface NestedGitignoreChange {
|
|
636
|
-
/** The TF023 path, relative to the scan root. */
|
|
637
|
-
path: string;
|
|
638
|
-
/** The nested `.gitignore` that ignores it, relative to the scan root. */
|
|
639
|
-
gitignore: string;
|
|
629
|
+
/**
|
|
630
|
+
* Directories the walk leaves out, absolute: the workspace members and
|
|
631
|
+
* example-group matches below the root, from `workspaceMemberDirs`. The
|
|
632
|
+
* caller resolves them, since that is async and this walk is not.
|
|
633
|
+
*/
|
|
634
|
+
excludeDirs?: readonly string[];
|
|
640
635
|
}
|
|
641
636
|
|
|
642
637
|
/** What the local walk read, plus what it knows about its own limits. */
|
|
@@ -646,8 +641,6 @@ export interface CandidateWalk {
|
|
|
646
641
|
maxFiles: number;
|
|
647
642
|
/** True when the walk stopped at `maxFiles` with files left unread. */
|
|
648
643
|
truncated: boolean;
|
|
649
|
-
/** TF023 paths whose finding changes once nested `.gitignore` files are read. */
|
|
650
|
-
nestedGitignore: NestedGitignoreChange[];
|
|
651
644
|
}
|
|
652
645
|
|
|
653
646
|
/** The walk half of `discoverByDetection`: candidate files read into memory, paths relative to the root. */
|
|
@@ -656,39 +649,34 @@ export function collectCandidates(root: string): RepoFile[] {
|
|
|
656
649
|
}
|
|
657
650
|
|
|
658
651
|
/**
|
|
659
|
-
* `collectCandidates`
|
|
660
|
-
*
|
|
661
|
-
* Neither changes `files`; the CLI prints them on stderr (#2528).
|
|
652
|
+
* `collectCandidates` plus whether the walk stopped at its limit with files
|
|
653
|
+
* left unread, which the audit report states (#2528).
|
|
662
654
|
*/
|
|
663
655
|
export function walkCandidates(root: string, opts: CandidateWalkOptions = {}): CandidateWalk {
|
|
664
|
-
const
|
|
665
|
-
const
|
|
666
|
-
walkFiles(root, all, state);
|
|
656
|
+
const state = { max: opts.maxFiles ?? DEFAULT_MAX_WALK_FILES, truncated: false };
|
|
657
|
+
const all = walkFiles(root, state, opts.excludeDirs);
|
|
667
658
|
// TF023 reads paths, not content: a `.tfstate` can be tens of megabytes of
|
|
668
659
|
// machine-generated JSON, and the finding is that it is in the repository at
|
|
669
|
-
// all. The
|
|
670
|
-
// disk" here
|
|
660
|
+
// all. The `.gitignore` files are what separate "committed" from "merely on
|
|
661
|
+
// disk" here. A Terraform working tree almost always has an ignored
|
|
671
662
|
// `.terraform/` in it, and reporting that would make TF023 fire on every
|
|
672
|
-
// local audit.
|
|
673
|
-
//
|
|
663
|
+
// local audit. Every `.gitignore` from the scan root down to the file's own
|
|
664
|
+
// directory is read (#2528), so auditing from the root and from a
|
|
665
|
+
// subdirectory agree. A fetched repository has no such ambiguity (its file
|
|
666
|
+
// list is the tracked files) and is not filtered.
|
|
674
667
|
const gitignore = readSafe(join(root, ".gitignore")) ?? "";
|
|
675
|
-
// Only the root one decides, for now. The nested ones are read to say which
|
|
676
|
-
// findings the next release, which honours them, will stop reporting.
|
|
677
668
|
const nestedBodies = new Map<string, string | undefined>();
|
|
678
669
|
const nestedGitignoreAt = (dir: string): string | undefined => {
|
|
679
670
|
if (!nestedBodies.has(dir)) nestedBodies.set(dir, readSafe(join(root, dir, ".gitignore")));
|
|
680
671
|
return nestedBodies.get(dir);
|
|
681
672
|
};
|
|
682
673
|
const files: RepoFile[] = [];
|
|
683
|
-
const nestedGitignore: NestedGitignoreChange[] = [];
|
|
684
674
|
for (const full of all) {
|
|
685
675
|
const path = relative(root, full);
|
|
686
676
|
if (isTerraformStatePath(path)) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
if (dir !== undefined) nestedGitignore.push({ path, gitignore: `${dir}/.gitignore` });
|
|
691
|
-
}
|
|
677
|
+
const ignored =
|
|
678
|
+
gitignoreCoversTerraformState(gitignore, path) || nestedGitignoreCovering(path, nestedGitignoreAt) !== undefined;
|
|
679
|
+
if (!ignored) files.push({ path, content: "" });
|
|
692
680
|
continue;
|
|
693
681
|
}
|
|
694
682
|
// `.tf` is read locally so `classifyTerraform` can bundle real content.
|
|
@@ -702,5 +690,5 @@ export function walkCandidates(root: string, opts: CandidateWalkOptions = {}): C
|
|
|
702
690
|
const content = readSafe(full);
|
|
703
691
|
if (content !== undefined) files.push({ path, content });
|
|
704
692
|
}
|
|
705
|
-
return { files, maxFiles: state.
|
|
693
|
+
return { files, maxFiles: state.max, truncated: state.truncated };
|
|
706
694
|
}
|
package/src/audit/report-html.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface RenderHtmlOptions extends BuildModelOptions {
|
|
|
31
31
|
/** Full template override; `{{title}} {{accent}} {{logo}} {{meta}} {{body}} {{footer}}` slots. */
|
|
32
32
|
template?: string;
|
|
33
33
|
notes?: string[];
|
|
34
|
+
/** A truncated local walk (#2528), carried into the embedded JSON report. */
|
|
35
|
+
truncated?: { limit: number; flag: string };
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const DEFAULT_ACCENT = "#7c3aed";
|
|
@@ -194,7 +196,7 @@ export function renderHtml(findings: AuditFinding[], opts: RenderHtmlOptions = {
|
|
|
194
196
|
|
|
195
197
|
// Machine-readable data embedded so the HTML report is also parseable.
|
|
196
198
|
// `<` escaped so the JSON can't break out of the <script> element.
|
|
197
|
-
const dataJson = JSON.stringify(buildReportJson(findings, { snapshot: opts.snapshot }), null, 0).replace(/</g, "\\u003c");
|
|
199
|
+
const dataJson = JSON.stringify(buildReportJson(findings, { snapshot: opts.snapshot, truncated: opts.truncated }), null, 0).replace(/</g, "\\u003c");
|
|
198
200
|
const dataScript = `<script type="application/json" id="chant-audit-report">${dataJson}</script>`;
|
|
199
201
|
|
|
200
202
|
let body: string;
|