@intentius/chant 0.100.0 → 0.102.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/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/cli/build-options.d.ts +2 -0
- package/dist/cli/build-options.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.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/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +9 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +9 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +33 -2
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +30 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +78 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +15 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-digest.d.ts +26 -5
- package/dist/lifecycle/plan-digest.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +4 -4
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +12 -11
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +1 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activities/propose-upgrade.d.ts +2 -0
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +3 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +8 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/serializer.d.ts +8 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +77 -0
- package/dist/telemetry-attribution.d.ts.map +1 -0
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +88 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +73 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/changes-cli.d.ts.map +1 -1
- package/dist/workspace/changes.d.ts +8 -1
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks/links.d.ts +1 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/live.d.ts +40 -0
- package/dist/workspace/checks/live.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts +26 -2
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +73 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/conformance/index.d.ts +67 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +12 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +368 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +1 -1
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/declaration.d.ts +119 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +368 -4
- package/dist/workspace/export-cli.d.ts +12 -0
- package/dist/workspace/export-cli.d.ts.map +1 -0
- package/dist/workspace/export.d.ts +145 -0
- package/dist/workspace/export.d.ts.map +1 -0
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.d.ts.map +1 -0
- package/dist/workspace/import.d.ts +73 -0
- package/dist/workspace/import.d.ts.map +1 -0
- package/dist/workspace/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +8 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +149 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +24 -6
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
- package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-adopt.d.ts +106 -0
- package/dist/workspace/lineage-adopt.d.ts.map +1 -0
- package/dist/workspace/lineage-check.d.ts +9 -2
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-cli.d.ts +6 -1
- package/dist/workspace/lineage-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-hash-index.d.ts +110 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +10 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +149 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.d.ts +15 -3
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-provenance.d.ts +18 -0
- package/dist/workspace/lineage-provenance.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +30 -1
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/lineage-versions.d.ts +116 -0
- package/dist/workspace/lineage-versions.d.ts.map +1 -0
- package/dist/workspace/links.d.ts +31 -5
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/ls-generated.d.ts +37 -0
- package/dist/workspace/ls-generated.d.ts.map +1 -0
- package/dist/workspace/ls.d.ts +4 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/nested-graph.d.ts +56 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -0
- package/dist/workspace/nesting.d.ts +21 -0
- package/dist/workspace/nesting.d.ts.map +1 -0
- package/dist/workspace/pin-cli.d.ts +10 -0
- package/dist/workspace/pin-cli.d.ts.map +1 -0
- package/dist/workspace/pin-integrity.d.ts +51 -0
- package/dist/workspace/pin-integrity.d.ts.map +1 -0
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +47 -3
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +7 -11
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +57 -2
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +5 -2
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +23 -4
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +58 -5
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/returns.d.ts +129 -0
- package/dist/workspace/returns.d.ts.map +1 -0
- package/dist/workspace/runs-cli.d.ts +164 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +423 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/status-gates.d.ts +15 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +10 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +52 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/template-manifest.d.ts +11 -3
- package/dist/workspace/template-manifest.d.ts.map +1 -1
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts +8 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/dsse.d.ts +58 -0
- package/dist/workspace/trust/dsse.d.ts.map +1 -0
- package/dist/workspace/trust/evidence-cli.d.ts +66 -0
- package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
- package/dist/workspace/trust/evidence.d.ts +93 -0
- package/dist/workspace/trust/evidence.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +54 -1
- package/dist/workspace/trust/policy.d.ts.map +1 -1
- package/dist/workspace/trust/provenance.d.ts +21 -1
- package/dist/workspace/trust/provenance.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts +132 -0
- package/dist/workspace/trust/rotation.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +33 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/signers-cli.d.ts +49 -0
- package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
- package/dist/workspace/trust/ssh-commit.d.ts +12 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts +13 -0
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify.d.ts +15 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-scope.d.ts +259 -0
- package/dist/workspace/write-scope.d.ts.map +1 -0
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/build.ts +8 -0
- package/src/cli/build-options.ts +4 -1
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/build.ts +2 -0
- package/src/cli/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +87 -1
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +69 -25
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +6 -6
- package/src/cli/handlers/fan-out.ts +2 -1
- package/src/cli/handlers/graph.test.ts +42 -0
- package/src/cli/handlers/graph.ts +22 -0
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.ts +88 -4
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +85 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +33 -0
- package/src/cli/main.ts +168 -17
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -4
- package/src/cli/registry.ts +33 -2
- package/src/cli/serve-mcp-workspace.test.ts +1 -1
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/release-wiring.test.ts +5 -1
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/components/fan-out-output.test.ts +1 -1
- package/src/components/fan-out.test.ts +1 -1
- package/src/components/promote.test.ts +1 -1
- package/src/config.test.ts +21 -0
- package/src/config.ts +27 -0
- package/src/content-digest.test.ts +2 -2
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +79 -3
- package/src/lifecycle/gate-ledger.test.ts +14 -0
- package/src/lifecycle/gate-ledger.ts +18 -1
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/plan-digest.test.ts +54 -3
- package/src/lifecycle/plan-digest.ts +38 -8
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- package/src/op/activities/activity-contracts.ts +1 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/index.ts +3 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activities/propose-upgrade.ts +8 -5
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/gate-approval.test.ts +91 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +34 -8
- package/src/op/index.ts +3 -1
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +8 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +73 -11
- package/src/provenance.ts +35 -0
- package/src/serializer.ts +9 -0
- package/src/telemetry-attribution.test.ts +91 -0
- package/src/telemetry-attribution.ts +145 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/agent-cli.ts +138 -0
- package/src/workspace/agent.schema.json +378 -0
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/box-factory.test.ts +320 -0
- package/src/workspace/box-factory.ts +103 -0
- package/src/workspace/changes-cli.ts +5 -0
- package/src/workspace/changes.schema.json +171 -1
- package/src/workspace/changes.ts +61 -4
- package/src/workspace/check-live.test.ts +192 -0
- package/src/workspace/check.schema.json +64 -0
- package/src/workspace/checks/boxes.test.ts +2 -0
- package/src/workspace/checks/links.ts +23 -2
- package/src/workspace/checks/live.ts +113 -0
- package/src/workspace/checks.test.ts +2 -2
- package/src/workspace/checks.ts +49 -8
- package/src/workspace/compose-graph.test.ts +47 -0
- package/src/workspace/compose-graph.ts +127 -3
- package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +578 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
- package/src/workspace/conformance/index.mjs +30 -3
- package/src/workspace/conformance/index.ts +103 -15
- package/src/workspace/conformance/vitest.ts +44 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
- package/src/workspace/conformance/writer.test.ts +156 -0
- package/src/workspace/conformance/writer.ts +880 -0
- package/src/workspace/decide.ts +7 -1
- package/src/workspace/declaration.schema.json +368 -4
- package/src/workspace/declaration.ts +270 -1
- package/src/workspace/declared-kinds.test.ts +33 -0
- package/src/workspace/evidence.schema.json +279 -0
- package/src/workspace/export-cli.ts +180 -0
- package/src/workspace/export-import.test.ts +282 -0
- package/src/workspace/export.ts +486 -0
- package/src/workspace/graph-cli.ts +51 -2
- package/src/workspace/graph-contract.test.ts +89 -4
- package/src/workspace/graph.schema.json +453 -1
- package/src/workspace/identity.test.ts +196 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/import.ts +325 -0
- package/src/workspace/intent-cli.ts +64 -10
- package/src/workspace/intent-record.schema.json +208 -0
- package/src/workspace/intent-record.ts +35 -1
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +718 -7
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +495 -32
- package/src/workspace/kinds.test.ts +5 -5
- package/src/workspace/kinds.ts +62 -33
- package/src/workspace/lineage-adopt-cli.ts +103 -0
- package/src/workspace/lineage-adopt.test.ts +552 -0
- package/src/workspace/lineage-adopt.ts +452 -0
- package/src/workspace/lineage-check.ts +26 -5
- package/src/workspace/lineage-cli.ts +12 -2
- package/src/workspace/lineage-hash-index.ts +305 -0
- package/src/workspace/lineage-init.test.ts +9 -0
- package/src/workspace/lineage-init.ts +29 -9
- package/src/workspace/lineage-lock.ts +54 -0
- package/src/workspace/lineage-migrations.test.ts +27 -0
- package/src/workspace/lineage-migrations.ts +44 -14
- package/src/workspace/lineage-provenance.ts +40 -0
- package/src/workspace/lineage-upgrade-cli.ts +9 -5
- package/src/workspace/lineage-upgrade.test.ts +92 -1
- package/src/workspace/lineage-upgrade.ts +111 -16
- package/src/workspace/lineage-versions.ts +348 -0
- package/src/workspace/links.test.ts +121 -2
- package/src/workspace/links.ts +97 -6
- package/src/workspace/ls-contract.test.ts +84 -1
- package/src/workspace/ls-generated.ts +111 -0
- package/src/workspace/ls.schema.json +19 -0
- package/src/workspace/ls.ts +8 -1
- package/src/workspace/member-commands.ts +3 -1
- package/src/workspace/nested-graph.test.ts +176 -0
- package/src/workspace/nested-graph.ts +169 -0
- package/src/workspace/nesting.ts +37 -0
- package/src/workspace/pin-cli.test.ts +71 -0
- package/src/workspace/pin-cli.ts +57 -0
- package/src/workspace/pin-integrity.test.ts +121 -0
- package/src/workspace/pin-integrity.ts +104 -0
- package/src/workspace/points-write.schema.json +2 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/read-contract.test.ts +24 -0
- package/src/workspace/reason-codes.test.ts +20 -2
- package/src/workspace/reason-codes.ts +53 -3
- package/src/workspace/record-sessions.ts +12 -14
- package/src/workspace/records-amend.schema.json +6 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +195 -22
- package/src/workspace/records-close.schema.json +7 -2
- package/src/workspace/records-close.ts +10 -2
- package/src/workspace/records-formats.test.ts +13 -5
- package/src/workspace/records-new.schema.json +6 -0
- package/src/workspace/records-review.schema.json +6 -0
- package/src/workspace/records-sessions.test.ts +23 -6
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.test.ts +65 -8
- package/src/workspace/records-write.ts +92 -6
- package/src/workspace/records.schema.json +127 -4
- package/src/workspace/records.ts +123 -5
- package/src/workspace/returns.ts +328 -0
- package/src/workspace/runs-cli.ts +381 -0
- package/src/workspace/runs-write.schema.json +583 -0
- package/src/workspace/runs.schema.json +810 -0
- package/src/workspace/runs.test.ts +242 -0
- package/src/workspace/runs.ts +709 -0
- package/src/workspace/signers.schema.json +206 -0
- package/src/workspace/status-contract.test.ts +5 -0
- package/src/workspace/status-gates.ts +24 -9
- package/src/workspace/status.schema.json +127 -2
- package/src/workspace/status.ts +21 -1
- package/src/workspace/symbols.ts +180 -0
- package/src/workspace/template-manifest.ts +22 -4
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/attestor.ts +15 -0
- package/src/workspace/trust/dsse.ts +134 -0
- package/src/workspace/trust/evidence-cli.ts +195 -0
- package/src/workspace/trust/evidence.test.ts +241 -0
- package/src/workspace/trust/evidence.ts +207 -0
- package/src/workspace/trust/policy.ts +110 -3
- package/src/workspace/trust/provenance.ts +41 -4
- package/src/workspace/trust/record-seal.test.ts +1 -1
- package/src/workspace/trust/rotation.test.ts +258 -0
- package/src/workspace/trust/rotation.ts +336 -0
- package/src/workspace/trust/seal.ts +63 -1
- package/src/workspace/trust/signers-cli.ts +178 -0
- package/src/workspace/trust/ssh-commit.ts +53 -4
- package/src/workspace/trust/test-repo.ts +18 -0
- package/src/workspace/trust/trust.test.ts +8 -2
- package/src/workspace/trust/verify-cli.ts +1 -0
- package/src/workspace/trust/verify.ts +22 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +133 -8
- package/src/workspace/work-evidence.schema.json +6 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-scope.test.ts +466 -0
- package/src/workspace/write-scope.ts +573 -0
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns: the record an import writes when a copy of the workspace comes
|
|
3
|
+
* back (#2552, #2524 D10, ws-004, ws-073).
|
|
4
|
+
*
|
|
5
|
+
* `chant workspace import` writes `.chant/returns/<id>.json` at the workspace
|
|
6
|
+
* root, beside the lock. It names the export the copy started from, the
|
|
7
|
+
* copy's HEAD when the copy is a git repository of its own, and every path
|
|
8
|
+
* the import wrote or removed. For each written path whose bytes are the
|
|
9
|
+
* copy's own (no host value was switched back into it), it also carries the
|
|
10
|
+
* origin: the raw commit object that last changed the file in the copy, and
|
|
11
|
+
* the raw tree objects from that commit's root tree down to the file. Those
|
|
12
|
+
* objects hash to the ids that name them, so anyone can check offline that
|
|
13
|
+
* the commit, with its original signature, holds exactly the bytes the
|
|
14
|
+
* workspace now has. Nothing is re-signed: the signature is the one the
|
|
15
|
+
* author made where the copy lived.
|
|
16
|
+
*
|
|
17
|
+
* The commit is judged by the attestors of #2547 with the policy at base. A
|
|
18
|
+
* signer the base policy does not list makes it `attested-unverifiable-here`,
|
|
19
|
+
* not `unattested`: there is a signature, and nothing here can say whose key
|
|
20
|
+
* it is. An admin admits the signers by adding them to `.chant/trust.json`
|
|
21
|
+
* under `admitted`, naming the return (`chant workspace admit <id>`). That
|
|
22
|
+
* file is policy, read at base, and changing it is a protected write, so the
|
|
23
|
+
* admission is signed by the admin's own commit. From then on, the returned
|
|
24
|
+
* commits read as `attested`. An admitted key verifies only that return's
|
|
25
|
+
* commits and seals, never a commit made in the workspace's own repository.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { execFileSync } from "node:child_process";
|
|
29
|
+
import { createHash } from "node:crypto";
|
|
30
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
31
|
+
import { dirname, join } from "node:path";
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
import { fileHash, LockError } from "./lineage-lock";
|
|
34
|
+
import type { WorkspaceTree } from "./tree";
|
|
35
|
+
import { attestRawCommit, type CommitAttestor } from "./trust/attestor";
|
|
36
|
+
import { returnedPolicy, TRUST_CONFIG_PATH, type TrustPolicy } from "./trust/policy";
|
|
37
|
+
import type { RecordProvenance } from "./trust/provenance";
|
|
38
|
+
import { splitSignedCommit, sshSignatureIntact, sshSignatureKey } from "./trust/ssh-commit";
|
|
39
|
+
|
|
40
|
+
/** Where return records live, relative to the workspace root. */
|
|
41
|
+
export const RETURNS_DIR = ".chant/returns";
|
|
42
|
+
|
|
43
|
+
const Sha256 = z.string().regex(/^sha256:[0-9a-f]{64}$/);
|
|
44
|
+
const CommitId = z.string().regex(/^[0-9a-f]{40}([0-9a-f]{24})?$/);
|
|
45
|
+
const Base64 = z.string().regex(/^[A-Za-z0-9+/]*={0,2}$/);
|
|
46
|
+
|
|
47
|
+
const OriginSchema = z
|
|
48
|
+
.object({
|
|
49
|
+
/** The commit in the returned copy that last changed the file. */
|
|
50
|
+
commit: CommitId,
|
|
51
|
+
/** That commit object, raw, in base64: the signed payload and its signature. */
|
|
52
|
+
raw: Base64,
|
|
53
|
+
/** The raw tree objects from the commit's root tree down to the file's directory, in base64. */
|
|
54
|
+
trees: z.array(Base64).min(1),
|
|
55
|
+
})
|
|
56
|
+
.strict();
|
|
57
|
+
export type ReturnOrigin = z.infer<typeof OriginSchema>;
|
|
58
|
+
|
|
59
|
+
const ReturnSchema = z
|
|
60
|
+
.object({
|
|
61
|
+
schema: z.literal(1),
|
|
62
|
+
id: z.string().regex(/^ret-[0-9a-f]{12}$/),
|
|
63
|
+
/** The export the copy started from (`.chant/export.json`). */
|
|
64
|
+
export: z.object({ id: z.string().min(1), workspace: z.string().min(1), revision: CommitId.nullable() }).strict(),
|
|
65
|
+
/** The copy's HEAD, when it was a git repository of its own. */
|
|
66
|
+
head: CommitId.nullable(),
|
|
67
|
+
/** Paths written, relative to the workspace root, with the bytes' hash and, when it can be proved, the commit they come from. */
|
|
68
|
+
paths: z.record(z.string(), z.object({ sha256: Sha256, origin: OriginSchema.optional() }).strict()),
|
|
69
|
+
/** Paths removed. */
|
|
70
|
+
removed: z.array(z.string()),
|
|
71
|
+
/** Paths whose host-bound values the import switched back: their bytes are not the copy's, so they carry no origin. */
|
|
72
|
+
hostValues: z.array(z.string()),
|
|
73
|
+
/** The keys that signed the origin commits, for an admin to admit. `principal` is the committer's email, a suggestion only. */
|
|
74
|
+
signers: z.array(
|
|
75
|
+
z
|
|
76
|
+
.object({
|
|
77
|
+
key: z.string().min(1),
|
|
78
|
+
fingerprint: z.string(),
|
|
79
|
+
principal: z.string().min(1),
|
|
80
|
+
commits: z.array(CommitId),
|
|
81
|
+
})
|
|
82
|
+
.strict(),
|
|
83
|
+
),
|
|
84
|
+
})
|
|
85
|
+
.strict();
|
|
86
|
+
export type ReturnRecord = z.infer<typeof ReturnSchema>;
|
|
87
|
+
|
|
88
|
+
// ── Git objects ──────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
/** The id git gives an object: the hash of `<type> <length>\0<data>`, SHA-1 or SHA-256 by the id length in use. */
|
|
91
|
+
export function gitObjectId(type: "blob" | "tree" | "commit", data: Buffer, algorithm: "sha1" | "sha256"): string {
|
|
92
|
+
return createHash(algorithm).update(`${type} ${data.length}\0`).update(data).digest("hex");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The entries of a raw tree object: mode, name and id. */
|
|
96
|
+
export function parseTree(raw: Buffer, idBytes: number): { mode: string; name: string; id: string }[] {
|
|
97
|
+
const out: { mode: string; name: string; id: string }[] = [];
|
|
98
|
+
let i = 0;
|
|
99
|
+
while (i < raw.length) {
|
|
100
|
+
const sp = raw.indexOf(0x20, i);
|
|
101
|
+
const nul = raw.indexOf(0, sp);
|
|
102
|
+
if (sp < 0 || nul < 0 || nul + 1 + idBytes > raw.length) throw new Error("malformed tree object");
|
|
103
|
+
out.push({ mode: raw.subarray(i, sp).toString("latin1"), name: raw.subarray(sp + 1, nul).toString("utf-8"), id: raw.subarray(nul + 1, nul + 1 + idBytes).toString("hex") });
|
|
104
|
+
i = nul + 1 + idBytes;
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function gitBuf(cwd: string, args: string[]): Buffer {
|
|
110
|
+
return execFileSync("git", args, { cwd, maxBuffer: 256 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The origin of `path` (relative to the copy's root) in the copy's own
|
|
115
|
+
* repository at `dir`: the last commit that changed it, and the tree objects
|
|
116
|
+
* down to it. Undefined when the file at that commit is not `content`, such
|
|
117
|
+
* as a file with uncommitted changes.
|
|
118
|
+
*/
|
|
119
|
+
export function buildOrigin(dir: string, path: string, content: Buffer): ReturnOrigin | undefined {
|
|
120
|
+
let commit: string;
|
|
121
|
+
try {
|
|
122
|
+
commit = gitBuf(dir, ["log", "-1", "--format=%H", "HEAD", "--", path]).toString("utf-8").trim();
|
|
123
|
+
} catch {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
if (!commit) return undefined;
|
|
127
|
+
const raw = gitBuf(dir, ["cat-file", "commit", commit]);
|
|
128
|
+
const proof: ReturnOrigin = { commit, raw: raw.toString("base64"), trees: [] };
|
|
129
|
+
let tree = /^tree ([0-9a-f]+)$/m.exec(raw.toString("latin1"))?.[1];
|
|
130
|
+
const parts = path.split("/");
|
|
131
|
+
for (let i = 0; i < parts.length && tree; i++) {
|
|
132
|
+
const t = gitBuf(dir, ["cat-file", "tree", tree]);
|
|
133
|
+
proof.trees.push(t.toString("base64"));
|
|
134
|
+
tree = parseTree(t, tree.length / 2).find((e) => e.name === parts[i])?.id;
|
|
135
|
+
}
|
|
136
|
+
return verifyOrigin(proof, path, content).ok ? proof : undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Check that `origin`'s objects hash to their ids and lead from the commit to `content` at `path`. */
|
|
140
|
+
export function verifyOrigin(origin: ReturnOrigin, path: string, content: Buffer): { ok: true } | { ok: false; reason: string } {
|
|
141
|
+
const algorithm = origin.commit.length === 64 ? "sha256" : "sha1";
|
|
142
|
+
const raw = Buffer.from(origin.raw, "base64");
|
|
143
|
+
if (gitObjectId("commit", raw, algorithm) !== origin.commit) return { ok: false, reason: `the commit object does not hash to ${origin.commit.slice(0, 12)}` };
|
|
144
|
+
let id = /^tree ([0-9a-f]+)$/m.exec(raw.toString("latin1"))?.[1];
|
|
145
|
+
const parts = path.split("/");
|
|
146
|
+
if (origin.trees.length !== parts.length) return { ok: false, reason: `the proof has ${origin.trees.length} tree(s) for a path ${parts.length} deep` };
|
|
147
|
+
for (let i = 0; i < parts.length; i++) {
|
|
148
|
+
const t = Buffer.from(origin.trees[i], "base64");
|
|
149
|
+
if (!id || gitObjectId("tree", t, algorithm) !== id) return { ok: false, reason: `the tree for ${parts.slice(0, i).join("/") || "the root"} does not hash to its id` };
|
|
150
|
+
let entries;
|
|
151
|
+
try {
|
|
152
|
+
entries = parseTree(t, id.length / 2);
|
|
153
|
+
} catch {
|
|
154
|
+
return { ok: false, reason: "a tree object in the proof is malformed" };
|
|
155
|
+
}
|
|
156
|
+
id = entries.find((e) => e.name === parts[i])?.id;
|
|
157
|
+
}
|
|
158
|
+
if (!id || gitObjectId("blob", content, algorithm) !== id) return { ok: false, reason: `the commit holds other bytes at ${path}` };
|
|
159
|
+
return { ok: true };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Signers ──────────────────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
/** The committer's email in a raw commit object. */
|
|
165
|
+
function committerEmail(raw: Buffer): string | undefined {
|
|
166
|
+
return /^committer [^<]*<([^>]+)>/m.exec(raw.toString("utf-8"))?.[1];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function signatureHeader(origin: ReturnOrigin): string {
|
|
170
|
+
return origin.commit.length === 64 ? "gpgsig-sha256" : "gpgsig";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The keys that signed the origins, grouped by key, for an admin to admit. */
|
|
174
|
+
export function originSigners(origins: readonly ReturnOrigin[]): ReturnRecord["signers"] {
|
|
175
|
+
const byKey = new Map<string, ReturnRecord["signers"][number]>();
|
|
176
|
+
const seen = new Set<string>();
|
|
177
|
+
for (const o of origins) {
|
|
178
|
+
if (seen.has(o.commit)) continue;
|
|
179
|
+
seen.add(o.commit);
|
|
180
|
+
const raw = Buffer.from(o.raw, "base64");
|
|
181
|
+
const { payload, signature } = splitSignedCommit(raw, signatureHeader(o));
|
|
182
|
+
if (!signature) continue;
|
|
183
|
+
const key = sshSignatureKey(signature);
|
|
184
|
+
if (!key) continue;
|
|
185
|
+
const entry = byKey.get(key);
|
|
186
|
+
if (entry) {
|
|
187
|
+
entry.commits.push(o.commit);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const fingerprint = sshSignatureIntact(payload, signature, "git");
|
|
191
|
+
if (fingerprint === false) continue;
|
|
192
|
+
byKey.set(key, { key, fingerprint: fingerprint ?? "", principal: committerEmail(raw) ?? "unknown", commits: [o.commit] });
|
|
193
|
+
}
|
|
194
|
+
return [...byKey.values()].sort((a, b) => a.key.localeCompare(b.key));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ── Reading and writing ──────────────────────────────────────────────────────
|
|
198
|
+
|
|
199
|
+
export function parseReturn(text: string, label: string): ReturnRecord {
|
|
200
|
+
let raw: unknown;
|
|
201
|
+
try {
|
|
202
|
+
raw = JSON.parse(text);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
throw new LockError(`${label} is not JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
205
|
+
}
|
|
206
|
+
const parsed = ReturnSchema.safeParse(raw);
|
|
207
|
+
if (!parsed.success) throw new LockError(`${label} is not a return record: ${parsed.error.issues.map((i) => `${i.path.join(".") || "/"}: ${i.message}`).join("; ")}`);
|
|
208
|
+
return parsed.data;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function renderReturn(r: ReturnRecord): string {
|
|
212
|
+
const paths: ReturnRecord["paths"] = {};
|
|
213
|
+
for (const p of Object.keys(r.paths).sort()) paths[p] = r.paths[p];
|
|
214
|
+
return JSON.stringify(ReturnSchema.parse({ ...r, paths, removed: [...r.removed].sort(), hostValues: [...r.hostValues].sort() }), null, 2) + "\n";
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function writeReturn(root: string, r: ReturnRecord): string {
|
|
218
|
+
const rel = `${RETURNS_DIR}/${r.id}.json`;
|
|
219
|
+
mkdirSync(join(root, RETURNS_DIR), { recursive: true });
|
|
220
|
+
writeFileSync(join(root, rel), renderReturn(r));
|
|
221
|
+
return rel;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** The return records in `tree` (the workspace root's), sorted by id. Unreadable ones are skipped and named in `problems`. */
|
|
225
|
+
export function readReturns(tree: WorkspaceTree): { returns: ReturnRecord[]; problems: string[] } {
|
|
226
|
+
const returns: ReturnRecord[] = [];
|
|
227
|
+
const problems: string[] = [];
|
|
228
|
+
for (const e of (tree.list(RETURNS_DIR) ?? []).filter((x) => x.type === "file" && x.name.endsWith(".json")).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
229
|
+
const path = `${RETURNS_DIR}/${e.name}`;
|
|
230
|
+
try {
|
|
231
|
+
const r = parseReturn(tree.read(path), path);
|
|
232
|
+
if (`${r.id}.json` !== e.name) throw new LockError(`${path} holds return ${r.id}`);
|
|
233
|
+
returns.push(r);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
if (!(err instanceof LockError)) throw err;
|
|
236
|
+
problems.push(err.message);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return { returns, problems };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ── Provenance ───────────────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The provenance of a returned file: its origin commit judged by the
|
|
246
|
+
* attestors with the policy at base plus the signers admitted for the
|
|
247
|
+
* return. Undefined when the return holds no origin for the path, or the
|
|
248
|
+
* workspace's bytes are not the ones returned, so the commit that holds the
|
|
249
|
+
* file here is what counts.
|
|
250
|
+
*/
|
|
251
|
+
export function returnedProvenance(
|
|
252
|
+
policy: TrustPolicy,
|
|
253
|
+
attestors: readonly CommitAttestor[],
|
|
254
|
+
ret: ReturnRecord,
|
|
255
|
+
path: string,
|
|
256
|
+
content: Buffer,
|
|
257
|
+
host: RecordProvenance,
|
|
258
|
+
): RecordProvenance | undefined {
|
|
259
|
+
const entry = ret.paths[path];
|
|
260
|
+
if (!entry || entry.sha256 !== fileHash(content)) return undefined;
|
|
261
|
+
const returned = { id: ret.id, importedIn: host.commit };
|
|
262
|
+
if (!entry.origin) return undefined;
|
|
263
|
+
const proof = verifyOrigin(entry.origin, path, content);
|
|
264
|
+
if (!proof.ok) {
|
|
265
|
+
return { level: "unattested", commit: host.commit, reason: `returned in ${ret.id}, and its origin does not check: ${proof.reason}`, returned: { ...returned, commit: entry.origin.commit } };
|
|
266
|
+
}
|
|
267
|
+
const raw = Buffer.from(entry.origin.raw, "base64");
|
|
268
|
+
const judged = returnedPolicy(policy, ret.id);
|
|
269
|
+
const a = attestRawCommit({ repo: "", policy: judged }, raw, attestors);
|
|
270
|
+
const at = `returned in ${ret.id} from commit ${entry.origin.commit.slice(0, 12)}`;
|
|
271
|
+
const base = { commit: host.commit, attestor: a.attestor, returned: { ...returned, commit: entry.origin.commit } };
|
|
272
|
+
if (a.level === "attested") {
|
|
273
|
+
const admitted = (policy.admitted[ret.id] ?? []).some((s) => s.principal === a.principal) && !policy.signers.some((s) => s.principal === a.principal);
|
|
274
|
+
return { ...base, level: "attested", ...(a.principal ? { principal: a.principal } : {}), ...(a.key ? { key: a.key } : {}), reason: `${at}, ${a.reason}${admitted ? `, a signer admitted for ${ret.id} at base` : ""}` };
|
|
275
|
+
}
|
|
276
|
+
if (a.level === "unattested") {
|
|
277
|
+
const { payload, signature } = splitSignedCommit(raw, signatureHeader(entry.origin));
|
|
278
|
+
const intact = signature?.startsWith("-----BEGIN SSH SIGNATURE-----") ? sshSignatureIntact(payload, signature, "git") : false;
|
|
279
|
+
if (intact) {
|
|
280
|
+
return {
|
|
281
|
+
...base,
|
|
282
|
+
level: "attested-unverifiable-here",
|
|
283
|
+
key: intact,
|
|
284
|
+
reason: `${at}, signed with ${intact}, a key neither the signers nor an admission at base lists; it reads as attested once an admin admits the signer (chant workspace admit ${ret.id})`,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return { ...base, level: a.level, ...(a.key ? { key: a.key } : {}), reason: `${at}: ${a.reason}` };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ── Admission ────────────────────────────────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
export interface AdmitResult {
|
|
294
|
+
id: string;
|
|
295
|
+
/** Repository-relative path of the trust config. */
|
|
296
|
+
path: string;
|
|
297
|
+
/** The signers added. Empty when every one was already admitted. */
|
|
298
|
+
added: { principal: string; key: string }[];
|
|
299
|
+
written: boolean;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Add the signers of return `ret` to the `admitted` list of
|
|
304
|
+
* `.chant/trust.json` at the repository root `repo`, keeping everything else
|
|
305
|
+
* in it. The admission counts once an admin's signed commit merges it: the
|
|
306
|
+
* file is policy, read at base, and a protected write.
|
|
307
|
+
*/
|
|
308
|
+
export function admitReturn(repo: string, ret: ReturnRecord, opts: { note?: string; dryRun?: boolean } = {}): AdmitResult {
|
|
309
|
+
if (ret.signers.length === 0) throw new LockError(`return ${ret.id} names no signer: none of its origin commits carries an ssh signature`);
|
|
310
|
+
const abs = join(repo, TRUST_CONFIG_PATH);
|
|
311
|
+
let config: Record<string, unknown> = { schema: 1 };
|
|
312
|
+
if (existsSync(abs)) {
|
|
313
|
+
try {
|
|
314
|
+
config = JSON.parse(readFileSync(abs, "utf-8")) as Record<string, unknown>;
|
|
315
|
+
} catch (err) {
|
|
316
|
+
throw new LockError(`${TRUST_CONFIG_PATH} is not valid JSON, so the admission cannot be added to it: ${err instanceof Error ? err.message : String(err)}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const admitted = Array.isArray(config.admitted) ? (config.admitted as Array<{ return?: unknown; signers?: Array<{ key?: unknown }> }>) : [];
|
|
320
|
+
const have = new Set(admitted.filter((a) => a.return === ret.id).flatMap((a) => (a.signers ?? []).map((s) => s.key)));
|
|
321
|
+
const added = ret.signers.filter((s) => !have.has(s.key)).map((s) => ({ principal: s.principal, key: s.key }));
|
|
322
|
+
if (added.length > 0 && !opts.dryRun) {
|
|
323
|
+
config.admitted = [...admitted, { return: ret.id, signers: added, ...(opts.note ? { note: opts.note } : {}) }];
|
|
324
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
325
|
+
writeFileSync(abs, JSON.stringify(config, null, 2) + "\n");
|
|
326
|
+
}
|
|
327
|
+
return { id: ret.id, path: TRUST_CONFIG_PATH, added, written: added.length > 0 && !opts.dryRun };
|
|
328
|
+
}
|