@intentius/chant 0.124.13 → 0.124.15
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/bin/chant +11 -0
- package/dist/agents/checks.js +326 -0
- package/dist/agents/discover.js +885 -0
- package/dist/agents/importer.js +17 -0
- package/dist/agents/index.js +12 -0
- package/dist/agents/types.js +19 -0
- package/dist/apply.js +151 -0
- package/dist/attrref.js +70 -0
- package/dist/audit/catalog.js +350 -0
- package/dist/audit/core.js +252 -0
- package/dist/audit/discover.js +633 -0
- package/dist/audit/fetch.js +666 -0
- package/dist/audit/lineage.js +91 -0
- package/dist/audit/nginx.js +366 -0
- package/dist/audit/prior-art.js +132 -0
- package/dist/audit/proof.js +321 -0
- package/dist/audit/report-html.js +194 -0
- package/dist/audit/report-model.js +198 -0
- package/dist/audit/report.js +102 -0
- package/dist/audit/rules-doc.js +144 -0
- package/dist/audit/secrets.js +405 -0
- package/dist/audit/terraform-state.js +140 -0
- package/dist/audit/wrangler.js +262 -0
- package/dist/behaviour-delta.js +401 -0
- package/dist/behaviour-engine.js +357 -0
- package/dist/behaviour-graph.js +83 -0
- package/dist/behaviour-http.js +188 -0
- package/dist/behaviour-kinds.js +172 -0
- package/dist/behaviour-overlay.js +50 -0
- package/dist/behaviour-predict.js +188 -0
- package/dist/behaviour-request.js +194 -0
- package/dist/behaviour.js +1325 -0
- package/dist/build-params.js +108 -0
- package/dist/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +669 -0
- package/dist/builder.js +44 -0
- package/dist/cdk/advise.js +30 -0
- package/dist/cdk/assembly.js +122 -0
- package/dist/cdk/graph.js +444 -0
- package/dist/cdk/tier-map.js +64 -0
- package/dist/cdk/types.js +24 -0
- package/dist/change-set.d.ts +24 -2
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +361 -0
- package/dist/child-project.js +21 -0
- package/dist/ci-jobs.d.ts +227 -0
- package/dist/ci-jobs.d.ts.map +1 -0
- package/dist/ci-jobs.js +448 -0
- package/dist/claimed-fields.js +135 -0
- package/dist/cli/build-options.js +70 -0
- package/dist/cli/build-params-cli.js +139 -0
- package/dist/cli/command-group.js +123 -0
- package/dist/cli/commands/audit-agents.js +326 -0
- package/dist/cli/commands/audit.js +571 -0
- package/dist/cli/commands/build.js +920 -0
- package/dist/cli/commands/carve-apply.js +153 -0
- package/dist/cli/commands/carve-bridge.js +201 -0
- package/dist/cli/commands/carve-emit.js +332 -0
- package/dist/cli/commands/carve-status.js +119 -0
- package/dist/cli/commands/carve.js +204 -0
- package/dist/cli/commands/check-lexicon-docs.js +79 -0
- package/dist/cli/commands/check-lexicon-examples.js +177 -0
- package/dist/cli/commands/check-lexicon-intrinsics.js +291 -0
- package/dist/cli/commands/check-lexicon-mcp.js +82 -0
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +104 -0
- package/dist/cli/commands/check-lexicon.js +766 -0
- package/dist/cli/commands/describe.js +85 -0
- package/dist/cli/commands/diff.js +175 -0
- package/dist/cli/commands/doctor.js +350 -0
- package/dist/cli/commands/import-agents.js +155 -0
- package/dist/cli/commands/import.js +670 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.js +194 -0
- package/dist/cli/commands/init-lexicon/templates/docs.js +100 -0
- package/dist/cli/commands/init-lexicon/templates/examples.js +29 -0
- package/dist/cli/commands/init-lexicon/templates/lint.js +34 -0
- package/dist/cli/commands/init-lexicon/templates/lsp.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/plugin.js +108 -0
- package/dist/cli/commands/init-lexicon/templates/project.js +240 -0
- package/dist/cli/commands/init-lexicon/templates/spec.js +56 -0
- package/dist/cli/commands/init-lexicon/templates/tests.js +66 -0
- package/dist/cli/commands/init-lexicon.js +172 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.js +145 -0
- package/dist/cli/commands/lexicon-surface-diff.js +145 -0
- package/dist/cli/commands/licenses.js +125 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +948 -0
- package/dist/cli/commands/list.js +63 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +423 -0
- package/dist/cli/commands/onboard.js +403 -0
- package/dist/cli/commands/pinned-upgrade.js +191 -0
- package/dist/cli/commands/update.js +194 -0
- package/dist/cli/commands/vendor.js +217 -0
- package/dist/cli/conflict-check.js +104 -0
- package/dist/cli/debug.js +8 -0
- package/dist/cli/format.js +104 -0
- package/dist/cli/handlers/build.js +267 -0
- package/dist/cli/handlers/carve-apply.js +30 -0
- package/dist/cli/handlers/carve-bridge.js +28 -0
- package/dist/cli/handlers/carve-emit.js +50 -0
- package/dist/cli/handlers/carve-status.js +26 -0
- package/dist/cli/handlers/carve.js +40 -0
- package/dist/cli/handlers/change-set.js +46 -0
- package/dist/cli/handlers/components.js +730 -0
- package/dist/cli/handlers/dev.js +113 -0
- package/dist/cli/handlers/emulator.js +233 -0
- package/dist/cli/handlers/explain.js +54 -0
- package/dist/cli/handlers/fan-out.js +422 -0
- package/dist/cli/handlers/gate-resume.js +275 -0
- package/dist/cli/handlers/generate.js +84 -0
- package/dist/cli/handlers/graph.js +969 -0
- package/dist/cli/handlers/init.js +102 -0
- package/dist/cli/handlers/lifecycle.js +1727 -0
- package/dist/cli/handlers/lint.js +62 -0
- package/dist/cli/handlers/migrate.js +48 -0
- package/dist/cli/handlers/misc.js +391 -0
- package/dist/cli/handlers/operator.js +1162 -0
- package/dist/cli/handlers/override-approve.js +102 -0
- package/dist/cli/handlers/pr.js +503 -0
- package/dist/cli/handlers/promote.js +342 -0
- package/dist/cli/handlers/run-generate.js +206 -0
- package/dist/cli/handlers/run-wave.js +66 -0
- package/dist/cli/handlers/run.js +1191 -0
- package/dist/cli/handlers/scenario.js +325 -0
- package/dist/cli/handlers/search.js +924 -0
- package/dist/cli/handlers/serve.js +32 -0
- package/dist/cli/handlers/vendor.js +154 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/is-entry-point.js +23 -0
- package/dist/cli/lsp/capabilities.js +28 -0
- package/dist/cli/lsp/diagnostics.js +34 -0
- package/dist/cli/lsp/server.js +329 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +2540 -0
- package/dist/cli/mcp/lifecycle-tools.js +80 -0
- package/dist/cli/mcp/op-tools.js +306 -0
- package/dist/cli/mcp/resource-handlers.js +258 -0
- package/dist/cli/mcp/resources/context.js +85 -0
- package/dist/cli/mcp/server.js +353 -0
- package/dist/cli/mcp/tools/build.js +111 -0
- package/dist/cli/mcp/tools/composites.js +95 -0
- package/dist/cli/mcp/tools/explain.js +166 -0
- package/dist/cli/mcp/tools/import.js +49 -0
- package/dist/cli/mcp/tools/lint.js +41 -0
- package/dist/cli/mcp/tools/scaffold.js +111 -0
- package/dist/cli/mcp/tools/search.js +112 -0
- package/dist/cli/mcp/types.js +1 -0
- package/dist/cli/mcp/workspace-plugins.js +91 -0
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.js +564 -0
- package/dist/cli/mcp-config.js +70 -0
- package/dist/cli/plugins.js +313 -0
- package/dist/cli/registry.js +23 -0
- package/dist/cli/reporters/stylish.js +329 -0
- package/dist/cli/version.js +15 -0
- package/dist/cli/watch.js +79 -0
- package/dist/codegen/bound-property-types.js +82 -0
- package/dist/codegen/coverage.js +119 -0
- package/dist/codegen/docs-file-markers.js +60 -0
- package/dist/codegen/docs-pages.js +115 -0
- package/dist/codegen/docs-rule-scanning.js +164 -0
- package/dist/codegen/docs-rules.js +76 -0
- package/dist/codegen/docs-sections.js +117 -0
- package/dist/codegen/docs-sidebar.js +65 -0
- package/dist/codegen/docs-types.js +4 -0
- package/dist/codegen/docs.js +356 -0
- package/dist/codegen/fetch.js +340 -0
- package/dist/codegen/generate-post-synth-barrel.js +63 -0
- package/dist/codegen/generate-registry.js +71 -0
- package/dist/codegen/generate-runtime-index.js +56 -0
- package/dist/codegen/generate-typescript.js +119 -0
- package/dist/codegen/generate.js +115 -0
- package/dist/codegen/json-patch.js +141 -0
- package/dist/codegen/json-schema-to-ts.js +344 -0
- package/dist/codegen/json-schema.js +246 -0
- package/dist/codegen/lexicon-regen.js +412 -0
- package/dist/codegen/naming.js +217 -0
- package/dist/codegen/okf-lexicon.js +245 -0
- package/dist/codegen/package.js +150 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.js +494 -0
- package/dist/codegen/registry.js +60 -0
- package/dist/codegen/rehype-base-url.mjs +68 -0
- package/dist/codegen/rolling-upgrade.js +217 -0
- package/dist/codegen/surface-snapshot.js +537 -0
- package/dist/codegen/testdata/postgres-tags.json +242 -0
- package/dist/codegen/topo-sort.js +36 -0
- package/dist/codegen/typecheck.js +115 -0
- package/dist/codegen/validate.js +200 -0
- package/dist/codegen/version-bump.js +35 -0
- package/dist/components/auto-release.js +143 -0
- package/dist/components/builders.js +47 -0
- package/dist/components/capability-plugin-loader.js +175 -0
- package/dist/components/capability-plugin-schema.js +46 -0
- package/dist/components/capability-plugin.js +99 -0
- package/dist/components/capability.js +60 -0
- package/dist/components/changed-files.js +72 -0
- package/dist/components/cli-support.js +427 -0
- package/dist/components/component.js +120 -0
- package/dist/components/component.schema.json +271 -0
- package/dist/components/config-defaults.js +130 -0
- package/dist/components/deploy-units.js +60 -0
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/discover.js +189 -0
- package/dist/components/driver-output.js +86 -0
- package/dist/components/driver.js +728 -0
- package/dist/components/fan-out-output.js +165 -0
- package/dist/components/fan-out-record.js +94 -0
- package/dist/components/fan-out-run.js +373 -0
- package/dist/components/fan-out-support.js +60 -0
- package/dist/components/fan-out.js +273 -0
- package/dist/components/gate-plan.js +41 -0
- package/dist/components/gated-wave-pipeline.js +46 -0
- package/dist/components/index.js +24 -0
- package/dist/components/layers.js +28 -0
- package/dist/components/manifest-persistence.js +108 -0
- package/dist/components/pilots/alb-ecs.pilot.js +59 -0
- package/dist/components/pilots/dynamodb.pilot.js +51 -0
- package/dist/components/pilots/jar-emr.pilot.js +65 -0
- package/dist/components/pilots/lambda.pilot.js +52 -0
- package/dist/components/pilots/neo4j-fanout.pilot.js +68 -0
- package/dist/components/pilots/project.js +12 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +135 -0
- package/dist/components/pr-run.js +363 -0
- package/dist/components/presets/ecs-fargate.js +72 -0
- package/dist/components/presets/index.js +28 -0
- package/dist/components/presets/lambda.js +34 -0
- package/dist/components/presets/single-host-compose.js +41 -0
- package/dist/components/promote.js +549 -0
- package/dist/components/registry.js +34 -0
- package/dist/components/run-progress.js +33 -0
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/driver.js +93 -0
- package/dist/components/sandbox/run.js +115 -0
- package/dist/components/starter-plugin.js +104 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.js +68 -0
- package/dist/components/verbs/__tests__/mock-process-runner.js +45 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.js +56 -0
- package/dist/components/verbs/bom-writer.js +287 -0
- package/dist/components/verbs/build-archive.js +188 -0
- package/dist/components/verbs/build.js +142 -0
- package/dist/components/verbs/cloud-executor.js +110 -0
- package/dist/components/verbs/component-bom.js +125 -0
- package/dist/components/verbs/ensure-secret.js +50 -0
- package/dist/components/verbs/index.js +61 -0
- package/dist/components/verbs/license-policy.js +75 -0
- package/dist/components/verbs/lockfile-sbom-generator.js +191 -0
- package/dist/components/verbs/process-runner.js +78 -0
- package/dist/components/verbs/r2-sync.js +93 -0
- package/dist/components/verbs/reproducibility.js +62 -0
- package/dist/components/verbs/run-agent.js +577 -0
- package/dist/components/verbs/sbom-generator.js +119 -0
- package/dist/components/verbs/sbom.js +97 -0
- package/dist/components/verbs/shell.js +32 -0
- package/dist/components/verbs/sign.js +221 -0
- package/dist/components/verbs/stub.js +28 -0
- package/dist/components/verbs/tool-sbom-generator.js +154 -0
- package/dist/components/verbs/verify.js +112 -0
- package/dist/components/verbs/vex.js +131 -0
- package/dist/components/verbs/vuln-gate.js +152 -0
- package/dist/components/verbs/vuln-scan.js +288 -0
- package/dist/components/verbs/wait-verify.js +106 -0
- package/dist/components/verbs/wrangler.js +179 -0
- package/dist/components/wave-plan.js +102 -0
- package/dist/composite.d.ts +10 -2
- package/dist/composite.d.ts.map +1 -1
- package/dist/composite.js +313 -0
- package/dist/config-import.d.ts.map +1 -1
- package/dist/config-import.js +22 -0
- package/dist/config-sandbox.js +122 -0
- package/dist/config-static.js +206 -0
- package/dist/config.js +605 -0
- package/dist/content-digest.js +23 -0
- package/dist/declarable.js +114 -0
- package/dist/deep-observation.js +437 -0
- package/dist/detectLexicon.js +54 -0
- package/dist/discovery/cache.js +70 -0
- package/dist/discovery/collect.d.ts +2 -1
- package/dist/discovery/collect.d.ts.map +1 -1
- package/dist/discovery/collect.js +223 -0
- package/dist/discovery/cycles.js +95 -0
- package/dist/discovery/entity-wire-codec.js +391 -0
- package/dist/discovery/entity-wire.js +42 -0
- package/dist/discovery/files.js +121 -0
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +4073 -0
- package/dist/discovery/fold-rank.js +292 -0
- package/dist/discovery/graph.js +115 -0
- package/dist/discovery/host-composite.d.ts +35 -0
- package/dist/discovery/host-composite.d.ts.map +1 -0
- package/dist/discovery/host-composite.js +93 -0
- package/dist/discovery/import.d.ts.map +1 -1
- package/dist/discovery/import.js +65 -0
- package/dist/discovery/index.d.ts +9 -0
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +333 -0
- package/dist/discovery/param-deps.js +487 -0
- package/dist/discovery/resolve.js +39 -0
- package/dist/discovery/sandbox/bundle.js +214 -0
- package/dist/discovery/sandbox/child-errors.js +26 -0
- package/dist/discovery/sandbox/config-run.js +100 -0
- package/dist/discovery/sandbox/config-wire.js +183 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.js +333 -0
- package/dist/discovery/sandbox/fork.js +229 -0
- package/dist/discovery/sandbox/policy-run.js +142 -0
- package/dist/discovery/sandbox/policy-wire.js +152 -0
- package/dist/discovery/sandbox/run.js +77 -0
- package/dist/discovery/specifier-resolve.js +320 -0
- package/dist/discovery/walk.js +284 -0
- package/dist/effect-receipt.js +340 -0
- package/dist/env.js +55 -0
- package/dist/errors.js +62 -0
- package/dist/fold/fold.js +1434 -0
- package/dist/fold/foldable-helpers.js +229 -0
- package/dist/fold/subset.js +696 -0
- package/dist/fold-provenance.js +414 -0
- package/dist/gate-decision.d.ts +20 -9
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +313 -0
- package/dist/gate-resume-run.js +154 -0
- package/dist/gated-waves.js +165 -0
- package/dist/governance.js +43 -0
- package/dist/graph-declared.js +45 -0
- package/dist/graph-detail.js +207 -0
- package/dist/graph-dot.js +54 -0
- package/dist/graph-effective.js +107 -0
- package/dist/graph-ir.js +623 -0
- package/dist/graph-layout.js +184 -0
- package/dist/graph-lens.js +105 -0
- package/dist/graph-mermaid.js +83 -0
- package/dist/graph-ops.js +39 -0
- package/dist/graph-refs.js +156 -0
- package/dist/held-elsewhere.js +87 -0
- package/dist/identity.js +251 -0
- package/dist/import/base-parser.js +34 -0
- package/dist/import/embedded.js +255 -0
- package/dist/import/generator.js +1 -0
- package/dist/import/ir-utils.js +85 -0
- package/dist/import/parser-options.js +45 -0
- package/dist/import/parser.js +1 -0
- package/dist/index.js +118 -0
- package/dist/intrinsic-interpolation.js +73 -0
- package/dist/intrinsic.js +31 -0
- package/dist/join-key.js +35 -0
- package/dist/kubectl-context.js +150 -0
- package/dist/lexicon-config.js +58 -0
- package/dist/lexicon-integrity.js +47 -0
- package/dist/lexicon-manifest.js +70 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +241 -0
- package/dist/lexicon-output.js +218 -0
- package/dist/lexicon-plugin-helpers.js +104 -0
- package/dist/lexicon-schema.js +136 -0
- package/dist/lexicon.js +130 -0
- package/dist/lifecycle/affected.js +224 -0
- package/dist/lifecycle/assert-live.js +110 -0
- package/dist/lifecycle/build-ledger-store.js +160 -0
- package/dist/lifecycle/build-ledger.js +155 -0
- package/dist/lifecycle/change-set.js +356 -0
- package/dist/lifecycle/converge-ledger.js +161 -0
- package/dist/lifecycle/deep-diff.js +233 -0
- package/dist/lifecycle/deep-observe.js +147 -0
- package/dist/lifecycle/digest.js +143 -0
- package/dist/lifecycle/disruption.js +135 -0
- package/dist/lifecycle/gate-applied.js +113 -0
- package/dist/lifecycle/gate-audit.d.ts +69 -2
- package/dist/lifecycle/gate-audit.d.ts.map +1 -1
- package/dist/lifecycle/gate-audit.js +415 -0
- package/dist/lifecycle/gate-ledger-select.js +89 -0
- package/dist/lifecycle/gate-ledger.d.ts +24 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +201 -0
- package/dist/lifecycle/gate-origin.js +117 -0
- package/dist/lifecycle/gate-pending.js +58 -0
- package/dist/lifecycle/git.js +1182 -0
- package/dist/lifecycle/identity.js +58 -0
- package/dist/lifecycle/index.js +26 -0
- package/dist/lifecycle/lease.js +283 -0
- package/dist/lifecycle/ledger-port.js +1 -0
- package/dist/lifecycle/legacy-digest.js +91 -0
- package/dist/lifecycle/live-diff.js +274 -0
- package/dist/lifecycle/local-note.js +15 -0
- package/dist/lifecycle/member-ledger.js +122 -0
- package/dist/lifecycle/observation-baseline.js +155 -0
- package/dist/lifecycle/observe.js +375 -0
- package/dist/lifecycle/oras-referrer-lookup.js +82 -0
- package/dist/lifecycle/override-ledger.js +54 -0
- package/dist/lifecycle/plan-digest.js +110 -0
- package/dist/lifecycle/plan-ledger.js +129 -0
- package/dist/lifecycle/receipt-plan.js +192 -0
- package/dist/lifecycle/release-ledger.js +155 -0
- package/dist/lifecycle/release-read.js +64 -0
- package/dist/lifecycle/replay.js +193 -0
- package/dist/lifecycle/rollback.js +102 -0
- package/dist/lifecycle/run-ledger.js +183 -0
- package/dist/lifecycle/scenario-eval.js +204 -0
- package/dist/lifecycle/scenario.js +214 -0
- package/dist/lifecycle/snapshot.js +239 -0
- package/dist/lifecycle/status.js +447 -0
- package/dist/lifecycle/symptoms.js +117 -0
- package/dist/lifecycle/teardown.js +255 -0
- package/dist/lifecycle/types.js +1 -0
- package/dist/lifecycle/unobserved-gate.js +33 -0
- package/dist/lifecycle/wave-plans.js +68 -0
- package/dist/lifecycle/work-item-id.js +36 -0
- package/dist/lifecycle/work-lease.js +393 -0
- package/dist/lint/component-checks.js +87 -0
- package/dist/lint/config.js +483 -0
- package/dist/lint/declarative.js +122 -0
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +138 -0
- package/dist/lint/engine.js +246 -0
- package/dist/lint/knowledge-checks.js +64 -0
- package/dist/lint/named-checks.js +22 -0
- package/dist/lint/output-checks.js +87 -0
- package/dist/lint/output-docs.js +163 -0
- package/dist/lint/parser.js +33 -0
- package/dist/lint/pipeline-change-gate.js +70 -0
- package/dist/lint/policy-import.d.ts +1 -1
- package/dist/lint/policy-import.d.ts.map +1 -1
- package/dist/lint/policy-import.js +62 -0
- package/dist/lint/policy-sandbox.js +86 -0
- package/dist/lint/policy.js +122 -0
- package/dist/lint/post-synth.js +87 -0
- package/dist/lint/presets/relaxed.json +26 -0
- package/dist/lint/presets/strict.json +24 -24
- package/dist/lint/receipt-checks.js +83 -0
- package/dist/lint/rule-loader.d.ts.map +1 -1
- package/dist/lint/rule-loader.js +89 -0
- package/dist/lint/rule-registry.js +86 -0
- package/dist/lint/rule.js +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.js +25 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.js +21 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.js +24 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.js +17 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.js +18 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.js +20 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.js +16 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.js +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.js +16 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.js +69 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.js +84 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.js +103 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.js +70 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.js +109 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.js +49 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.js +64 -0
- package/dist/lint/rules/comp/index.js +33 -0
- package/dist/lint/rules/comp/support.js +129 -0
- package/dist/lint/rules/composite-scope.js +51 -0
- package/dist/lint/rules/cor017-composite-name-match.js +93 -0
- package/dist/lint/rules/cor018-composite-prefer-lexicon-type.js +136 -0
- package/dist/lint/rules/cor021-env-literal-name.js +100 -0
- package/dist/lint/rules/cor022-receipt-leaf.js +118 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.js +199 -0
- package/dist/lint/rules/declarable-naming-convention.js +62 -0
- package/dist/lint/rules/evl001-non-literal-expression.js +66 -0
- package/dist/lint/rules/evl002-control-flow-resource.js +69 -0
- package/dist/lint/rules/evl003-dynamic-property-access.js +44 -0
- package/dist/lint/rules/evl004-spread-non-const.js +94 -0
- package/dist/lint/rules/evl005-resource-block-body.js +41 -0
- package/dist/lint/rules/evl007-invalid-siblings.js +105 -0
- package/dist/lint/rules/evl009-composite-no-constant.js +158 -0
- package/dist/lint/rules/evl010-composite-no-transform.js +59 -0
- package/dist/lint/rules/evl011-symbolic-in-template.js +106 -0
- package/dist/lint/rules/export-required.js +115 -0
- package/dist/lint/rules/file-declarable-limit.js +88 -0
- package/dist/lint/rules/flat-declarations.js +62 -0
- package/dist/lint/rules/index.js +90 -0
- package/dist/lint/rules/no-cyclic-declarable-ref.js +138 -0
- package/dist/lint/rules/no-redundant-type-import.js +76 -0
- package/dist/lint/rules/no-redundant-value-cast.js +41 -0
- package/dist/lint/rules/no-string-ref.js +59 -0
- package/dist/lint/rules/no-unused-declarable-import.js +75 -0
- package/dist/lint/rules/no-unused-declarable.js +142 -0
- package/dist/lint/rules/op/index.js +28 -0
- package/dist/lint/rules/op/ops012-activity-contract.js +54 -0
- package/dist/lint/rules/op/ops013-step-output-ref.js +88 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.js +114 -0
- package/dist/lint/rules/op/ops015-gate-approval.js +45 -0
- package/dist/lint/rules/op/support.js +11 -0
- package/dist/lint/rules/op/sys010-key-over-plain-http.js +100 -0
- package/dist/lint/rules/property-kind.js +56 -0
- package/dist/lint/rules/single-concern-file.js +71 -0
- package/dist/lint/rules/sys001-no-literal-key.js +60 -0
- package/dist/lint/selectors.js +168 -0
- package/dist/lint/suppressions.js +129 -0
- package/dist/lint/typescript.js +17 -0
- package/dist/live-endpoint.js +113 -0
- package/dist/live-read-session.js +76 -0
- package/dist/lsp/lexicon-providers.js +163 -0
- package/dist/lsp/types.js +5 -0
- package/dist/managed-fields.js +293 -0
- package/dist/mcp/types.js +4 -0
- package/dist/notify-verify.js +0 -1
- package/dist/notify.js +0 -1
- package/dist/notify.schema.json +72 -0
- package/dist/observation.js +266 -0
- package/dist/okf-read.js +134 -0
- package/dist/okf.js +275 -0
- package/dist/op/__fixtures__/decide-stub-backend.js +125 -0
- package/dist/op/activities/activity-contracts.d.ts +1 -1
- package/dist/op/activities/activity-contracts.js +313 -0
- package/dist/op/activities/apply.js +582 -0
- package/dist/op/activities/build.js +18 -0
- package/dist/op/activities/change-coverage.js +40 -0
- package/dist/op/activities/change-set.d.ts +8 -3
- package/dist/op/activities/change-set.d.ts.map +1 -1
- package/dist/op/activities/change-set.js +67 -0
- package/dist/op/activities/converge.js +492 -0
- package/dist/op/activities/decide.js +211 -0
- package/dist/op/activities/env-teardown.js +110 -0
- package/dist/op/activities/factory.js +591 -0
- package/dist/op/activities/forge-pull-request.js +82 -0
- package/dist/op/activities/gh-host.js +78 -0
- package/dist/op/activities/guard-validate.js +165 -0
- package/dist/op/activities/http-check.js +40 -0
- package/dist/op/activities/index.js +59 -0
- package/dist/op/activities/lexicon-upgrade.js +629 -0
- package/dist/op/activities/lifecycle.js +109 -0
- package/dist/op/activities/pipeline-audit.js +147 -0
- package/dist/op/activities/policy.js +26 -0
- package/dist/op/activities/predict-behaviour.js +341 -0
- package/dist/op/activities/propose-upgrade.js +165 -0
- package/dist/op/activities/reconcile.d.ts +28 -16
- package/dist/op/activities/reconcile.d.ts.map +1 -1
- package/dist/op/activities/reconcile.js +1011 -0
- package/dist/op/activities/shell.js +118 -0
- package/dist/op/activities/source-release.js +97 -0
- package/dist/op/activities/source-rollback.js +165 -0
- package/dist/op/activities/teardown.js +17 -0
- package/dist/op/activities/util.js +6 -0
- package/dist/op/activities/wait.js +51 -0
- package/dist/op/activities/work-evidence.js +35 -0
- package/dist/op/activities/workflow-audit.js +133 -0
- package/dist/op/activity-contract-registry.js +106 -0
- package/dist/op/activity-contract.js +232 -0
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/activity-profiles.js +129 -0
- package/dist/op/activity-registry.js +105 -0
- package/dist/op/activity-runtime.js +28 -0
- package/dist/op/builders.d.ts +1 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +801 -0
- package/dist/op/change-signal.js +118 -0
- package/dist/op/composites/apply-op.js +151 -0
- package/dist/op/composites/behaviour-op.js +65 -0
- package/dist/op/composites/converge-op.js +141 -0
- package/dist/op/composites/index.js +19 -0
- package/dist/op/composites/lexicon-upgrade-op.js +107 -0
- package/dist/op/composites/pipeline-audit-op.js +50 -0
- package/dist/op/composites/reconcile-op.js +84 -0
- package/dist/op/composites/watch-op.js +69 -0
- package/dist/op/composites/workflow-audit-op.js +57 -0
- package/dist/op/converge-rule.js +205 -0
- package/dist/op/cron.js +146 -0
- package/dist/op/decide-backend.js +181 -0
- package/dist/op/decide-config.js +68 -0
- package/dist/op/decide-read-inputs.js +141 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +213 -0
- package/dist/op/duration.js +21 -0
- package/dist/op/emulator-freshness.js +80 -0
- package/dist/op/emulator-lifecycle.js +269 -0
- package/dist/op/factory.js +83 -0
- package/dist/op/gate-approval.js +172 -0
- package/dist/op/gate-name.js +86 -0
- package/dist/op/gate-plan-context.js +167 -0
- package/dist/op/gate-point-run.js +67 -0
- package/dist/op/gate-point.js +111 -0
- package/dist/op/gate-resume-plan.js +155 -0
- package/dist/op/gate-resume.js +31 -0
- package/dist/op/gate-review.js +290 -0
- package/dist/op/gate-run-locator.js +85 -0
- package/dist/op/gate-summary.js +100 -0
- package/dist/op/gate-wait.js +56 -0
- package/dist/op/gate.js +449 -0
- package/dist/op/generate-pipeline.js +124 -0
- package/dist/op/index.js +51 -0
- package/dist/op/lifecycle-receipt-store.js +45 -0
- package/dist/op/local-executor.js +1164 -0
- package/dist/op/local-output.js +140 -0
- package/dist/op/op-ir.js +317 -0
- package/dist/op/op-verb-class.js +131 -0
- package/dist/op/op-waves-notify.js +136 -0
- package/dist/op/op-waves-run.d.ts +1 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +1657 -0
- package/dist/op/op-waves.js +409 -0
- package/dist/op/operator.js +743 -0
- package/dist/op/receipt-store.js +94 -0
- package/dist/op/resource.js +23 -0
- package/dist/op/run-context.js +28 -0
- package/dist/op/run-live.js +256 -0
- package/dist/op/runtime.js +21 -0
- package/dist/op/runtimes/local.js +195 -0
- package/dist/op/source-archive.js +131 -0
- package/dist/op/step-output-ref.js +397 -0
- package/dist/op/steward-beside.js +169 -0
- package/dist/op/steward-points.js +138 -0
- package/dist/op/steward-turn.js +59 -0
- package/dist/op/steward.js +317 -0
- package/dist/op/types.js +25 -0
- package/dist/op/work-lease-decl.js +81 -0
- package/dist/op/work-lease-run.js +393 -0
- package/dist/override-gate.js +284 -0
- package/dist/owner-chain.js +74 -0
- package/dist/ownership.js +92 -0
- package/dist/params.js +61 -0
- package/dist/plan-summary.js +711 -0
- package/dist/point-decision.js +211 -0
- package/dist/pr-forge.js +810 -0
- package/dist/pr-loop.js +203 -0
- package/dist/project-codegen.js +191 -0
- package/dist/project-root.js +74 -0
- package/dist/project-validation.js +50 -0
- package/dist/provenance.js +157 -0
- package/dist/pseudo-parameter.js +40 -0
- package/dist/reconcile.js +450 -0
- package/dist/resource-attributes.js +33 -0
- package/dist/runtime-adapter.js +77 -0
- package/dist/runtime.js +66 -0
- package/dist/secret-materialization.js +153 -0
- package/dist/secret-provenance.js +250 -0
- package/dist/serializer-walker.js +112 -0
- package/dist/serializer.js +1 -0
- package/dist/sort.js +45 -0
- package/dist/stack-output.js +115 -0
- package/dist/telemetry-attribution.js +149 -0
- package/dist/terraform/__fixtures__/build-graph.js +63 -0
- package/dist/terraform/adopt-state.js +40 -0
- package/dist/terraform/aws-resources.js +384 -0
- package/dist/terraform/bridge.js +204 -0
- package/dist/terraform/carve-provider.js +155 -0
- package/dist/terraform/carve.js +138 -0
- package/dist/terraform/data-source-shape.js +57 -0
- package/dist/terraform/emit-source.js +36 -0
- package/dist/terraform/excise.js +123 -0
- package/dist/terraform/graduate.js +128 -0
- package/dist/terraform/graph.js +435 -0
- package/dist/terraform/hcl2json.js +60 -0
- package/dist/terraform/manifest.js +149 -0
- package/dist/terraform/parse.js +81 -0
- package/dist/terraform/providers/aws.js +146 -0
- package/dist/terraform/providers/gcp.js +294 -0
- package/dist/terraform/providers/index.js +17 -0
- package/dist/terraform/providers/kubernetes.js +253 -0
- package/dist/terraform/score.js +151 -0
- package/dist/terraform/state.js +67 -0
- package/dist/terraform/tier-map.js +74 -0
- package/dist/terraform/types.js +13 -0
- package/dist/terraform/unified-diff.js +132 -0
- package/dist/testing.js +295 -0
- package/dist/toml-emit.js +153 -0
- package/dist/toml-parse.js +355 -0
- package/dist/toml-utils.js +60 -0
- package/dist/toml.js +428 -0
- package/dist/ts-loader.d.ts +46 -0
- package/dist/ts-loader.d.ts.map +1 -0
- package/dist/ts-loader.js +103 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +61 -0
- package/dist/validation.js +20 -0
- package/dist/vendor/js-yaml-load.js +1662 -0
- package/dist/workspace/__fixtures__/contract-repo.d.ts +7 -0
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.js +119 -0
- package/dist/workspace/__fixtures__/decide-workspace.js +112 -0
- package/dist/workspace/__fixtures__/sessions.d.ts +1 -1
- package/dist/workspace/__fixtures__/sessions.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/sessions.js +91 -0
- package/dist/workspace/__fixtures__/two-member-workspace.js +34 -0
- package/dist/workspace/agent-cli.js +99 -0
- package/dist/workspace/agent.schema.json +390 -0
- package/dist/workspace/answers-ledger.js +89 -0
- package/dist/workspace/box-cli.js +142 -0
- package/dist/workspace/box-factory-write.js +196 -0
- package/dist/workspace/box-factory-write.schema.json +342 -0
- package/dist/workspace/box-factory.js +88 -0
- package/dist/workspace/box-intent.js +126 -0
- package/dist/workspace/box-isolation.js +169 -0
- package/dist/workspace/box-listing-write.schema.json +204 -0
- package/dist/workspace/box-listing.js +298 -0
- package/dist/workspace/box-publish.js +352 -0
- package/dist/workspace/box-publish.schema.json +498 -0
- package/dist/workspace/box-services.js +39 -0
- package/dist/workspace/broker-protocol.js +359 -0
- package/dist/workspace/broker-protocol.schema.json +228 -0
- package/dist/workspace/change-set.schema.json +462 -0
- package/dist/workspace/changes-cli.js +56 -0
- package/dist/workspace/changes.js +446 -0
- package/dist/workspace/changes.schema.json +642 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.js +198 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.js +155 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.js +214 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.js +180 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.js +99 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.js +847 -0
- package/dist/workspace/chant-migrations.js +113 -0
- package/dist/workspace/check.schema.json +433 -0
- package/dist/workspace/checks/box-isolation.js +62 -0
- package/dist/workspace/checks/boxes.js +491 -0
- package/dist/workspace/checks/diagrams.js +104 -0
- package/dist/workspace/checks/generated.js +419 -0
- package/dist/workspace/checks/ledgers.js +212 -0
- package/dist/workspace/checks/links.js +191 -0
- package/dist/workspace/checks/live.js +100 -0
- package/dist/workspace/checks/pipelines.js +188 -0
- package/dist/workspace/checks/records.js +169 -0
- package/dist/workspace/checks.js +426 -0
- package/dist/workspace/ci-green-cli.js +125 -0
- package/dist/workspace/ci-green-forge.js +83 -0
- package/dist/workspace/ci-green-workflow.d.ts +3 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +202 -0
- package/dist/workspace/ci-green.js +325 -0
- package/dist/workspace/ci-last-green.schema.json +158 -0
- package/dist/workspace/class-data.d.ts +84 -0
- package/dist/workspace/class-data.d.ts.map +1 -0
- package/dist/workspace/class-data.js +238 -0
- package/dist/workspace/compose-graph.js +235 -0
- package/dist/workspace/compose-reports.js +146 -0
- package/dist/workspace/composites.js +264 -0
- package/dist/workspace/composites.schema.json +617 -0
- package/dist/workspace/conformance/__fixture__/app/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/app/src/server.mjs +29 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.kind.mjs +54 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.schema.json +512 -0
- package/dist/workspace/conformance/__fixture__/decisions/fix-001-how-the-app-is-deployed.md +40 -0
- package/dist/workspace/conformance/__fixture__/delivery/chant.config.ts +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/lexicon/index.ts +26 -0
- package/dist/workspace/conformance/__fixture__/delivery/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.component.ts +14 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.ts +4 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.js +205 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/dist/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/dist/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/dist/workspace/conformance/broker.js +736 -0
- package/dist/workspace/conformance/index.js +673 -0
- package/dist/workspace/conformance/vitest.js +108 -0
- package/dist/workspace/conformance/writer.js +1080 -0
- package/dist/workspace/decide.js +879 -0
- package/dist/workspace/decision-points.schema.json +135 -135
- package/dist/workspace/declaration-write-cli.js +74 -0
- package/dist/workspace/declaration-write.js +238 -0
- package/dist/workspace/declaration.js +938 -0
- package/dist/workspace/declaration.schema.json +1413 -1413
- package/dist/workspace/declared-kinds.js +106 -0
- package/dist/workspace/environments.js +164 -0
- package/dist/workspace/evidence.schema.json +279 -0
- package/dist/workspace/export-cli.js +185 -0
- package/dist/workspace/export.js +499 -0
- package/dist/workspace/factory-rules.js +175 -0
- package/dist/workspace/generated-files.js +92 -0
- package/dist/workspace/glob.js +45 -0
- package/dist/workspace/graph-cache.js +352 -0
- package/dist/workspace/graph-cli.js +348 -0
- package/dist/workspace/graph.schema.json +1338 -0
- package/dist/workspace/identity-gate-rule.js +75 -0
- package/dist/workspace/identity.js +126 -0
- package/dist/workspace/import.js +283 -0
- package/dist/workspace/init.js +620 -0
- package/dist/workspace/intent-cli.js +263 -0
- package/dist/workspace/intent-joins.js +201 -0
- package/dist/workspace/intent-record.js +352 -0
- package/dist/workspace/intent-record.schema.json +864 -0
- package/dist/workspace/intent.js +1582 -0
- package/dist/workspace/intent.schema.json +2420 -0
- package/dist/workspace/json-edit.js +221 -0
- package/dist/workspace/jsonc.js +235 -0
- package/dist/workspace/kind-readers.js +103 -0
- package/dist/workspace/kinds.d.ts +3 -7
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/kinds.js +553 -0
- package/dist/workspace/lexicon-symbols.js +112 -0
- package/dist/workspace/lineage-adopt-cli.js +102 -0
- package/dist/workspace/lineage-adopt.js +360 -0
- package/dist/workspace/lineage-check.js +282 -0
- package/dist/workspace/lineage-cli.js +121 -0
- package/dist/workspace/lineage-hash-index.js +284 -0
- package/dist/workspace/lineage-init.js +507 -0
- package/dist/workspace/lineage-lock.js +387 -0
- package/dist/workspace/lineage-merge.js +45 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.js +329 -0
- package/dist/workspace/lineage-provenance.js +36 -0
- package/dist/workspace/lineage-update.js +138 -0
- package/dist/workspace/lineage-upgrade-cli.js +131 -0
- package/dist/workspace/lineage-upgrade.js +889 -0
- package/dist/workspace/lineage-vendor.js +171 -0
- package/dist/workspace/lineage-version.js +128 -0
- package/dist/workspace/lineage-versions.js +275 -0
- package/dist/workspace/links.js +330 -0
- package/dist/workspace/ls-generated.js +95 -0
- package/dist/workspace/ls.js +277 -0
- package/dist/workspace/ls.schema.json +333 -0
- package/dist/workspace/member-commands.js +508 -0
- package/dist/workspace/member-handles.js +216 -0
- package/dist/workspace/member-pipeline.js +258 -0
- package/dist/workspace/member-run.js +117 -0
- package/dist/workspace/member-write.schema.json +193 -0
- package/dist/workspace/nested-graph.js +156 -0
- package/dist/workspace/nesting.js +38 -0
- package/dist/workspace/patch.js +301 -0
- package/dist/workspace/patch.schema.json +321 -0
- package/dist/workspace/pin-cli.js +55 -0
- package/dist/workspace/pin-integrity.js +100 -0
- package/dist/workspace/plan-summary.schema.json +155 -0
- package/dist/workspace/point-answer.schema.json +129 -129
- package/dist/workspace/points-cli.js +291 -0
- package/dist/workspace/points-write.schema.json +660 -0
- package/dist/workspace/points.js +521 -0
- package/dist/workspace/points.schema.json +916 -0
- package/dist/workspace/pr-report.schema.json +108 -0
- package/dist/workspace/principal-classes.d.ts +4 -11
- package/dist/workspace/principal-classes.d.ts.map +1 -1
- package/dist/workspace/principal-classes.js +162 -0
- package/dist/workspace/reason-codes.js +326 -0
- package/dist/workspace/record-assets.js +151 -0
- package/dist/workspace/record-decided.js +105 -0
- package/dist/workspace/record-sessions.js +96 -0
- package/dist/workspace/record-source.js +114 -0
- package/dist/workspace/records-amend.schema.json +284 -0
- package/dist/workspace/records-checkout.js +76 -0
- package/dist/workspace/records-cli.js +707 -0
- package/dist/workspace/records-close.js +116 -0
- package/dist/workspace/records-close.schema.json +278 -0
- package/dist/workspace/records-new.schema.json +202 -0
- package/dist/workspace/records-review.schema.json +367 -0
- package/dist/workspace/records-since.js +317 -0
- package/dist/workspace/records-since.schema.json +218 -0
- package/dist/workspace/records-write.js +1229 -0
- package/dist/workspace/records.js +1345 -0
- package/dist/workspace/records.schema.json +604 -0
- package/dist/workspace/reference-kinds/app/package.json +10 -0
- package/dist/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/dist/workspace/returns.js +303 -0
- package/dist/workspace/root-refusal.js +75 -0
- package/dist/workspace/run-statement.schema.json +622 -0
- package/dist/workspace/runs-cli.js +584 -0
- package/dist/workspace/runs-write.schema.json +994 -0
- package/dist/workspace/runs.js +708 -0
- package/dist/workspace/runs.schema.json +1257 -0
- package/dist/workspace/runtimes.js +76 -0
- package/dist/workspace/session-kinds.js +83 -0
- package/dist/workspace/signers.schema.json +206 -0
- package/dist/workspace/source-block.js +125 -0
- package/dist/workspace/squash.js +177 -0
- package/dist/workspace/status-gates.js +162 -0
- package/dist/workspace/status-stewards.js +330 -0
- package/dist/workspace/status.js +514 -0
- package/dist/workspace/status.schema.json +998 -0
- package/dist/workspace/steward-index.js +191 -0
- package/dist/workspace/symbols.js +188 -0
- package/dist/workspace/template-manifest.js +227 -0
- package/dist/workspace/template-pins.js +115 -0
- package/dist/workspace/trailer-joins.js +65 -0
- package/dist/workspace/trailers.js +111 -0
- package/dist/workspace/tree.js +136 -0
- package/dist/workspace/trust/attestor.js +63 -0
- package/dist/workspace/trust/dsse.js +108 -0
- package/dist/workspace/trust/evidence-cli.js +175 -0
- package/dist/workspace/trust/evidence.js +161 -0
- package/dist/workspace/trust/gate-seal.js +226 -0
- package/dist/workspace/trust/policy.js +190 -0
- package/dist/workspace/trust/provenance.js +180 -0
- package/dist/workspace/trust/rotation.js +298 -0
- package/dist/workspace/trust/run-commits.js +101 -0
- package/dist/workspace/trust/run-statement.js +182 -0
- package/dist/workspace/trust/seal.js +272 -0
- package/dist/workspace/trust/signers-cli.js +152 -0
- package/dist/workspace/trust/ssh-commit.js +178 -0
- package/dist/workspace/trust/test-repo.js +118 -0
- package/dist/workspace/trust/trust-files.js +193 -0
- package/dist/workspace/trust/verify-cli.js +63 -0
- package/dist/workspace/trust/verify.js +192 -0
- package/dist/workspace/which-chant.js +141 -0
- package/dist/workspace/wip-cli.js +95 -0
- package/dist/workspace/wip-write.schema.json +504 -0
- package/dist/workspace/wip.js +631 -0
- package/dist/workspace/wip.schema.json +334 -0
- package/dist/workspace/work-cli.js +448 -0
- package/dist/workspace/work-evidence.js +122 -0
- package/dist/workspace/work-evidence.schema.json +222 -0
- package/dist/workspace/work-history.schema.json +421 -0
- package/dist/workspace/work-lease.schema.json +246 -0
- package/dist/workspace/work-size.js +77 -0
- package/dist/workspace/work.js +283 -0
- package/dist/workspace/workspace-kinds.schema.json +259 -259
- package/dist/workspace/workspace-principals.schema.json +53 -53
- package/dist/workspace/write-lock-cli.js +105 -0
- package/dist/workspace/write-lock.js +424 -0
- package/dist/workspace/write-lock.schema.json +172 -0
- package/dist/workspace/write-scope.js +484 -0
- package/dist/yaml.js +459 -0
- package/package.json +2 -2
- package/src/build.ts +8 -0
- package/src/change-set.test.ts +48 -0
- package/src/change-set.ts +52 -2
- package/src/ci-jobs.test.ts +49 -0
- package/src/ci-jobs.ts +515 -0
- package/src/cli/commands/check-lexicon-plugin.ts +2 -0
- package/src/cli/commands/lint.ts +3 -0
- package/src/cli/commands/migrate.ts +2 -0
- package/src/cli/compiled-cli.e2e.test.ts +165 -0
- package/src/cli/main.ts +121 -27
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -0
- package/src/components/discover.ts +2 -0
- package/src/components/pr-pipeline.ts +3 -2
- package/src/components/sandbox/driver.ts +3 -1
- package/src/composite.ts +15 -3
- package/src/config-import.ts +3 -0
- package/src/discovery/collect.ts +15 -1
- package/src/discovery/fold-build-parity.test.ts +71 -0
- package/src/discovery/fold-import.ts +25 -127
- package/src/discovery/fold-project-provenance.test.ts +21 -4
- package/src/discovery/host-composite.ts +101 -0
- package/src/discovery/import.ts +2 -0
- package/src/discovery/index.ts +11 -1
- package/src/discovery/sandbox/driver.ts +3 -1
- package/src/gate-decision-bundle.test.ts +5 -4
- package/src/gate-decision-identity.test.ts +59 -6
- package/src/gate-decision.ts +81 -21
- package/src/lexicon-module.ts +3 -0
- package/src/lifecycle/gate-audit.test.ts +55 -1
- package/src/lifecycle/gate-audit.ts +116 -3
- package/src/lifecycle/gate-ledger.test.ts +20 -1
- package/src/lifecycle/gate-ledger.ts +33 -1
- package/src/lint/config.ts +1 -1
- package/src/lint/discover.ts +28 -8
- package/src/lint/policy-import.ts +4 -1
- package/src/lint/rule-loader.ts +2 -0
- package/src/op/activities/activity-contracts.ts +1 -1
- package/src/op/activities/change-set.ts +11 -3
- package/src/op/activities/lexicon-upgrade.test.ts +2 -0
- package/src/op/activities/reconcile.test.ts +62 -2
- package/src/op/activities/reconcile.ts +46 -22
- package/src/op/builders.ts +1 -1
- package/src/op/discover.ts +3 -0
- package/src/op/op-waves-run.ts +4 -3
- package/src/op/op-waves.test.ts +2 -0
- package/src/op/work-lease-run.test.ts +12 -4
- package/src/ts-loader.test.ts +23 -0
- package/src/ts-loader.ts +122 -0
- package/src/workspace/__fixtures__/contract-repo.ts +17 -1
- package/src/workspace/__fixtures__/sessions.ts +3 -3
- package/src/workspace/change-set.schema.json +5 -3
- package/src/workspace/chant-migrations/chud-lexicon-exit.ts +1 -1
- package/src/workspace/ci-green-workflow.test.ts +4 -4
- package/src/workspace/ci-green-workflow.ts +5 -2
- package/src/workspace/class-data.test.ts +64 -0
- package/src/workspace/class-data.ts +236 -0
- package/src/workspace/declaration.ts +1 -1
- package/src/workspace/kinds.ts +7 -36
- package/src/workspace/lineage-migrations.ts +2 -0
- package/src/workspace/points.ts +1 -1
- package/src/workspace/principal-classes.ts +12 -95
- package/src/workspace/records-formats.test.ts +7 -2
- package/src/workspace/records-sessions-write.test.ts +3 -3
- package/src/workspace/status-contract.e2e.test.ts +37 -0
- package/src/workspace/status-contract.test.ts +23 -21
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust policy, always read from the base revision (#2524 D5, Threat model;
|
|
3
|
+
* ws-001, ws-002).
|
|
4
|
+
*
|
|
5
|
+
* A check reads who may sign, and who holds which role, from the target
|
|
6
|
+
* branch tip or `--base <rev>`, never from the change under review. A change
|
|
7
|
+
* can edit its own copy of these files, and those edits have no effect until
|
|
8
|
+
* they are merged: the change is still judged by the policy at base. Editing
|
|
9
|
+
* the policy is itself a protected write (see ./verify.ts).
|
|
10
|
+
*
|
|
11
|
+
* Two files, both optional:
|
|
12
|
+
*
|
|
13
|
+
* - `.chant/allowed_signers` holds the signers, in ssh-keygen's
|
|
14
|
+
* allowed_signers format, so `git log --show-signature` can use the same
|
|
15
|
+
* file. `trust.json` may name another path.
|
|
16
|
+
* - `.chant/trust.json` holds the override for the signers path, the role
|
|
17
|
+
* grants and the adopted commit ranges. Role grants move into
|
|
18
|
+
* `chant.workspace.json` once the declaration exists (#2534).
|
|
19
|
+
*
|
|
20
|
+
* Attestation is opt-in (#2525 rule 6). Without a signers file at base,
|
|
21
|
+
* nothing is verified and every record is `unattested`.
|
|
22
|
+
*/
|
|
23
|
+
import { posix } from "node:path";
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
import { DEFAULT_SIGNERS_PATH, TRUST_CONFIG_PATH, parseAllowedSigners } from "./trust-files.js";
|
|
26
|
+
export { DEFAULT_SIGNERS_PATH, TRUST_CONFIG_PATH, parseAllowedSigners, renderAllowedSigners, } from "./trust-files.js";
|
|
27
|
+
// ── trust.json ───────────────────────────────────────────────────────────────
|
|
28
|
+
const fullCommit = z.string().regex(/^[0-9a-f]{40}([0-9a-f]{24})?$/, "a full commit id");
|
|
29
|
+
/** A repository-relative path: no `..`, not absolute, `/` separators. */
|
|
30
|
+
const repoPath = z
|
|
31
|
+
.string()
|
|
32
|
+
.min(1)
|
|
33
|
+
.refine((p) => !p.startsWith("/") && !p.includes("\\") && posix.normalize(p) === p && !p.split("/").includes(".."), {
|
|
34
|
+
message: "a path inside the repository, with / separators and no ..",
|
|
35
|
+
});
|
|
36
|
+
export const trustConfigSchema = z
|
|
37
|
+
.object({
|
|
38
|
+
schema: z.literal(1),
|
|
39
|
+
/** Where the signers file is, instead of `.chant/allowed_signers`. */
|
|
40
|
+
signers: repoPath.optional(),
|
|
41
|
+
/**
|
|
42
|
+
* Role name to the principals holding it. Until #2534 these live here;
|
|
43
|
+
* then they move into the declaration.
|
|
44
|
+
*/
|
|
45
|
+
roles: z.record(z.string().regex(/^[a-z][a-z0-9-]*$/), z.array(z.string().min(1))).optional(),
|
|
46
|
+
/**
|
|
47
|
+
* Commit ranges admitted without signatures (#2524 D5, adoption). Each is
|
|
48
|
+
* exact: `to` and, when given, `from` are full commit ids, and the range is
|
|
49
|
+
* the commits `from..to`.
|
|
50
|
+
*/
|
|
51
|
+
adopted: z.array(z.object({ from: fullCommit.optional(), to: fullCommit, note: z.string().optional() }).strict()).optional(),
|
|
52
|
+
/**
|
|
53
|
+
* Keys that sign runner evidence (#2553). Each belongs to a service or a CI
|
|
54
|
+
* identity, never to a person: a key or principal the signers file lists
|
|
55
|
+
* is refused here.
|
|
56
|
+
*/
|
|
57
|
+
runners: z
|
|
58
|
+
.array(z
|
|
59
|
+
.object({
|
|
60
|
+
principal: z.string().min(1),
|
|
61
|
+
class: z.enum(["runner", "service"]),
|
|
62
|
+
key: z.string().regex(/^ssh-ed25519 [A-Za-z0-9+/]+={0,2}$/, "an ssh-ed25519 public key, with no comment"),
|
|
63
|
+
})
|
|
64
|
+
.strict())
|
|
65
|
+
.optional(),
|
|
66
|
+
/**
|
|
67
|
+
* Signers admitted for the work one return brought back (#2552, D10,
|
|
68
|
+
* ws-004). Each entry names the return by its id (the file
|
|
69
|
+
* `.chant/returns/<id>.json` the import wrote) and the keys it admits.
|
|
70
|
+
* An admitted key verifies only the returned commits and seals of that
|
|
71
|
+
* return, never a commit made in this repository.
|
|
72
|
+
*/
|
|
73
|
+
admitted: z
|
|
74
|
+
.array(z
|
|
75
|
+
.object({
|
|
76
|
+
return: z.string().regex(/^ret-[0-9a-f]{12}$/, "a return id, ret-<12 hex>"),
|
|
77
|
+
signers: z
|
|
78
|
+
.array(z
|
|
79
|
+
.object({
|
|
80
|
+
principal: z.string().min(1),
|
|
81
|
+
key: z.string().regex(/^(ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp(256|384|521)|sk-ssh-ed25519@openssh\.com|sk-ecdsa-sha2-nistp256@openssh\.com) [A-Za-z0-9+/]+={0,2}$/, "an ssh public key, with no comment"),
|
|
82
|
+
})
|
|
83
|
+
.strict())
|
|
84
|
+
.min(1),
|
|
85
|
+
note: z.string().optional(),
|
|
86
|
+
})
|
|
87
|
+
.strict())
|
|
88
|
+
.optional(),
|
|
89
|
+
})
|
|
90
|
+
.strict();
|
|
91
|
+
/** The role whose holders may change the policy. Without any grant of it, every signer may. */
|
|
92
|
+
export const ADMIN_ROLE = "admin";
|
|
93
|
+
/** Paths whose change is a protected write under `policy`: the config, the signers file and its rotation file (#2553). */
|
|
94
|
+
export function protectedPaths(policy) {
|
|
95
|
+
const s = policy.signersPath;
|
|
96
|
+
return [...new Set([TRUST_CONFIG_PATH, s, posix.join(posix.dirname(s), `${posix.basename(s)}.rotation.json`)])].sort();
|
|
97
|
+
}
|
|
98
|
+
/** Principals allowed to change the policy: the admins when any are granted, otherwise every signer. */
|
|
99
|
+
export function policyWriters(policy) {
|
|
100
|
+
const admins = policy.roles[ADMIN_ROLE];
|
|
101
|
+
if (admins && admins.length > 0)
|
|
102
|
+
return new Set(admins);
|
|
103
|
+
return new Set(policy.signers.map((s) => s.principal));
|
|
104
|
+
}
|
|
105
|
+
/** A policy with nothing in it: attestation off. */
|
|
106
|
+
export function emptyPolicy(base, problems = []) {
|
|
107
|
+
return { base, signersPath: DEFAULT_SIGNERS_PATH, active: false, signers: [], excluded: [], roles: {}, adopted: [], runners: [], excludedRunners: [], admitted: {}, problems };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Read the policy through `source`, which must read the base revision.
|
|
111
|
+
* Never throws: a policy that cannot be read yields an inactive policy with
|
|
112
|
+
* its problems listed, so nothing is attested (fail closed).
|
|
113
|
+
*/
|
|
114
|
+
export function readTrustPolicy(source, base) {
|
|
115
|
+
let config = { schema: 1 };
|
|
116
|
+
const configText = readOptional(source, TRUST_CONFIG_PATH);
|
|
117
|
+
if (configText !== undefined) {
|
|
118
|
+
let raw;
|
|
119
|
+
try {
|
|
120
|
+
raw = JSON.parse(configText);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
return emptyPolicy(base, [`${TRUST_CONFIG_PATH} is not JSON: ${err instanceof Error ? err.message : String(err)}`]);
|
|
124
|
+
}
|
|
125
|
+
const parsed = trustConfigSchema.safeParse(raw);
|
|
126
|
+
if (!parsed.success) {
|
|
127
|
+
const detail = parsed.error.issues.map((i) => `${i.path.join(".") || "/"}: ${i.message}`).join("; ");
|
|
128
|
+
return emptyPolicy(base, [`${TRUST_CONFIG_PATH} is invalid: ${detail}`]);
|
|
129
|
+
}
|
|
130
|
+
config = parsed.data;
|
|
131
|
+
}
|
|
132
|
+
const signersPath = config.signers ?? DEFAULT_SIGNERS_PATH;
|
|
133
|
+
const text = readOptional(source, signersPath);
|
|
134
|
+
const set = text === undefined ? { signers: [], excluded: [] } : parseAllowedSigners(text);
|
|
135
|
+
// A runner key is a machine's, never a person's (#2553).
|
|
136
|
+
const humanKeys = new Set(set.signers.map((s) => s.key));
|
|
137
|
+
const humanNames = new Set(set.signers.map((s) => s.principal));
|
|
138
|
+
const runners = [];
|
|
139
|
+
const excludedRunners = [];
|
|
140
|
+
const all = config.runners ?? [];
|
|
141
|
+
for (const r of all) {
|
|
142
|
+
if (humanKeys.has(r.key) || humanNames.has(r.principal)) {
|
|
143
|
+
excludedRunners.push({ principal: r.principal, reason: `${signersPath} lists this ${humanKeys.has(r.key) ? "key" : "principal"}; runner keys belong to a service or CI identity, never to a signer` });
|
|
144
|
+
}
|
|
145
|
+
else if (all.filter((o) => o.key === r.key || o.principal === r.principal).length > 1) {
|
|
146
|
+
// One key under two names, or one name with two entries, would leave it unclear who signed.
|
|
147
|
+
excludedRunners.push({ principal: r.principal, reason: "another runner entry has the same key or principal; each runner is one principal with one key" });
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
runners.push(r);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
base,
|
|
155
|
+
signersPath,
|
|
156
|
+
active: text !== undefined,
|
|
157
|
+
signers: set.signers,
|
|
158
|
+
excluded: set.excluded,
|
|
159
|
+
roles: config.roles ?? {},
|
|
160
|
+
adopted: config.adopted ?? [],
|
|
161
|
+
runners,
|
|
162
|
+
excludedRunners,
|
|
163
|
+
admitted: admittedOf(config),
|
|
164
|
+
problems: [],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** The admitted signers, by return id. Two entries for one return add up. */
|
|
168
|
+
function admittedOf(config) {
|
|
169
|
+
const out = {};
|
|
170
|
+
for (const a of config.admitted ?? []) {
|
|
171
|
+
out[a.return] = [...(out[a.return] ?? []), ...a.signers.map((s) => ({ principal: s.principal, key: s.key, line: 0 }))];
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The policy for work that came back in return `id` (#2552): the signers at
|
|
177
|
+
* base plus the ones admitted for that return, marked with the return so a
|
|
178
|
+
* seal by an unknown signer reads as unverifiable.
|
|
179
|
+
*/
|
|
180
|
+
export function returnedPolicy(policy, id) {
|
|
181
|
+
return { ...policy, signers: [...policy.signers, ...(policy.admitted[id] ?? [])], returnedFrom: id };
|
|
182
|
+
}
|
|
183
|
+
/** A file's text through `source`, or undefined when it is not there. */
|
|
184
|
+
export function readOptional(source, path) {
|
|
185
|
+
const dir = posix.dirname(path);
|
|
186
|
+
const names = source.list(dir);
|
|
187
|
+
if (!names || !names.includes(posix.basename(path)))
|
|
188
|
+
return undefined;
|
|
189
|
+
return source.read(path);
|
|
190
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provenance level of each record (#2524 D5, Threat model).
|
|
3
|
+
*
|
|
4
|
+
* A record's content comes from the last commit that changed its file. That
|
|
5
|
+
* commit is asked of each attestor, with the policy read at base. A file with
|
|
6
|
+
* uncommitted changes is `unattested`: its bytes are in no commit, so nothing
|
|
7
|
+
* vouches for them.
|
|
8
|
+
*
|
|
9
|
+
* On a developer machine this detects; it does not enforce (ws-002). An agent
|
|
10
|
+
* running as the developer can use an unlocked signing agent or skip the check.
|
|
11
|
+
* Enforcement is CI running the same check against base.
|
|
12
|
+
*/
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
14
|
+
import { gitRevisionSource } from "../record-source.js";
|
|
15
|
+
import { attestCommit } from "./attestor.js";
|
|
16
|
+
import { emptyPolicy, readTrustPolicy } from "./policy.js";
|
|
17
|
+
import { SignerPositions, signerHistory } from "./rotation.js";
|
|
18
|
+
function git(repo, args) {
|
|
19
|
+
return execFileSync("git", args, { cwd: repo, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 256 * 1024 * 1024 });
|
|
20
|
+
}
|
|
21
|
+
function tryCommit(repo, rev) {
|
|
22
|
+
try {
|
|
23
|
+
return git(repo, ["rev-parse", "--verify", "--quiet", `${rev}^{commit}`]).trim() || undefined;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The base revision: `--base <rev>` when given, otherwise the target branch
|
|
31
|
+
* tip, taken as `origin/HEAD`, then a local `main`, then `master`. Never
|
|
32
|
+
* `HEAD`, which is the change under review.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveBase(repo, explicit) {
|
|
35
|
+
if (explicit !== undefined) {
|
|
36
|
+
const c = explicit.startsWith("-") ? undefined : tryCommit(repo, explicit);
|
|
37
|
+
return c ? { commit: c, from: "flag" } : { commit: null, from: null, problem: `--base ${explicit} names no commit in this repository` };
|
|
38
|
+
}
|
|
39
|
+
for (const [rev, from] of [
|
|
40
|
+
["refs/remotes/origin/HEAD", "origin/HEAD"],
|
|
41
|
+
["refs/heads/main", "main"],
|
|
42
|
+
["refs/heads/master", "master"],
|
|
43
|
+
]) {
|
|
44
|
+
const c = tryCommit(repo, rev);
|
|
45
|
+
if (c)
|
|
46
|
+
return { commit: c, from };
|
|
47
|
+
}
|
|
48
|
+
return { commit: null, from: null, problem: "no base revision: pass --base <rev> (there is no origin/HEAD, main or master)" };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The policy at `base`, or an inactive one when there is no base. With a
|
|
52
|
+
* signers file, its history is verified too (#2553): every version must be
|
|
53
|
+
* signed by a threshold of the one before, or nothing verifies.
|
|
54
|
+
*/
|
|
55
|
+
export function policyAtBase(repo, base) {
|
|
56
|
+
if (!base.commit)
|
|
57
|
+
return emptyPolicy(null, base.problem ? [base.problem] : []);
|
|
58
|
+
const policy = readTrustPolicy(gitRevisionSource(repo, base.commit), base.commit);
|
|
59
|
+
if (!policy.active || policy.problems.length > 0)
|
|
60
|
+
return policy;
|
|
61
|
+
const history = signerHistory(repo, base.commit, policy.signersPath);
|
|
62
|
+
if (history.broken) {
|
|
63
|
+
const at = history.broken.commit ? ` at ${history.broken.commit.slice(0, 8)}` : "";
|
|
64
|
+
return { ...policy, problems: [`the signer history of ${policy.signersPath} is broken${at}: ${history.broken.reason}`] };
|
|
65
|
+
}
|
|
66
|
+
const positions = new SignerPositions(repo, base.commit, history);
|
|
67
|
+
return { ...policy, signersAt: (commit) => positions.versionFor(commit) };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The last commit reachable from `rev` that changed each path. Merges are
|
|
71
|
+
* diffed against all their parents (`-c`), so a merge that changes a file
|
|
72
|
+
* beyond what either side brought is the commit that file comes from, and a
|
|
73
|
+
* merge that only takes one side's version is passed through to that side.
|
|
74
|
+
*/
|
|
75
|
+
export function lastCommits(repo, rev, paths) {
|
|
76
|
+
const out = new Map();
|
|
77
|
+
if (paths.length === 0)
|
|
78
|
+
return out;
|
|
79
|
+
const log = git(repo, ["--literal-pathspecs", "log", "-c", "--name-only", "--no-renames", "--format=%x00%H", rev, "--", ...paths]);
|
|
80
|
+
const wanted = new Set(paths);
|
|
81
|
+
let commit = "";
|
|
82
|
+
for (const line of log.split("\n")) {
|
|
83
|
+
if (line.startsWith("\0"))
|
|
84
|
+
commit = line.slice(1).trim();
|
|
85
|
+
else if (line && wanted.has(line) && !out.has(line))
|
|
86
|
+
out.set(line, commit);
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
/** Paths with staged, unstaged or untracked changes in the working tree. */
|
|
91
|
+
export function dirtyPaths(repo, paths) {
|
|
92
|
+
if (paths.length === 0)
|
|
93
|
+
return new Set();
|
|
94
|
+
const status = git(repo, ["--literal-pathspecs", "status", "--porcelain=v1", "-z", "--untracked-files=all", "--", ...paths]);
|
|
95
|
+
const dirty = new Set();
|
|
96
|
+
const parts = status.split("\0");
|
|
97
|
+
for (let i = 0; i < parts.length; i++) {
|
|
98
|
+
const p = parts[i];
|
|
99
|
+
if (p.length < 4)
|
|
100
|
+
continue;
|
|
101
|
+
dirty.add(p.slice(3));
|
|
102
|
+
if (p[0] === "R" || p[0] === "C")
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
return dirty;
|
|
106
|
+
}
|
|
107
|
+
function isAncestor(repo, a, b) {
|
|
108
|
+
try {
|
|
109
|
+
execFileSync("git", ["merge-base", "--is-ancestor", a, b], { cwd: repo, stdio: "ignore" });
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Whether `commit` lies in a range the policy adopts (`from..to`, exact). */
|
|
117
|
+
export function isAdopted(repo, policy, commit) {
|
|
118
|
+
return policy.adopted.some((r) => isAncestor(repo, commit, r.to) && (r.from === undefined || !isAncestor(repo, commit, r.from)));
|
|
119
|
+
}
|
|
120
|
+
/** A commit's provenance level under `policy`. */
|
|
121
|
+
export function commitProvenance(repo, policy, commit, attestors) {
|
|
122
|
+
// Judge the commit by the signer set in effect where it entered the base's history (#2553).
|
|
123
|
+
let judged = policy;
|
|
124
|
+
if (policy.signersAt) {
|
|
125
|
+
const v = policy.signersAt(commit);
|
|
126
|
+
judged = { ...policy, signers: v?.signers ?? [] };
|
|
127
|
+
if (!v || v.version === 0) {
|
|
128
|
+
const none = "no signer set was in effect where this commit entered the base's history";
|
|
129
|
+
if (isAdopted(repo, policy, commit))
|
|
130
|
+
return { level: "adopted", commit, reason: `in a commit range the policy at base adopts; ${none}` };
|
|
131
|
+
return { level: "unattested", commit, reason: none };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const a = attestCommit({ repo, policy: judged }, commit, attestors);
|
|
135
|
+
if (a.level === "unattested" && isAdopted(repo, policy, commit)) {
|
|
136
|
+
return { level: "adopted", commit, attestor: a.attestor, reason: `in a commit range the policy at base adopts; ${a.reason}` };
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
level: a.level,
|
|
140
|
+
commit,
|
|
141
|
+
attestor: a.attestor,
|
|
142
|
+
...(a.principal ? { principal: a.principal } : {}),
|
|
143
|
+
...(a.key ? { key: a.key } : {}),
|
|
144
|
+
reason: a.reason,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The provenance of each path. With attestation off (no signers file at
|
|
149
|
+
* base) nothing is checked and every path is `unattested`.
|
|
150
|
+
*/
|
|
151
|
+
export function recordProvenance(q) {
|
|
152
|
+
const out = new Map();
|
|
153
|
+
const all = (reason) => {
|
|
154
|
+
for (const p of q.paths)
|
|
155
|
+
out.set(p, { level: "unattested", commit: null, reason });
|
|
156
|
+
return out;
|
|
157
|
+
};
|
|
158
|
+
if (!q.repo)
|
|
159
|
+
return all("not in a git repository");
|
|
160
|
+
if (q.policy.problems.length > 0)
|
|
161
|
+
return all(q.policy.problems.join("; "));
|
|
162
|
+
if (!q.policy.active)
|
|
163
|
+
return all(`no signers file (${q.policy.signersPath}) at base ${q.policy.base?.slice(0, 8)}; attestation is off`);
|
|
164
|
+
const dirty = q.at === null ? dirtyPaths(q.repo, q.paths) : new Set();
|
|
165
|
+
const commits = lastCommits(q.repo, q.at ?? "HEAD", q.paths.filter((p) => !dirty.has(p)));
|
|
166
|
+
for (const p of q.paths) {
|
|
167
|
+
if (dirty.has(p)) {
|
|
168
|
+
out.set(p, { level: "unattested", commit: null, reason: "the working tree has uncommitted changes to this file" });
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const c = commits.get(p);
|
|
172
|
+
if (!c) {
|
|
173
|
+
out.set(p, { level: "unattested", commit: null, reason: "no commit holds this file" });
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const host = commitProvenance(q.repo, q.policy, c, q.attestors);
|
|
177
|
+
out.set(p, q.revisit?.(p, host) ?? host);
|
|
178
|
+
}
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signer rotation, verified from history (#2553, #2524 D5, ws-001).
|
|
3
|
+
*
|
|
4
|
+
* A signer set is the signers file plus a threshold. A new set is valid only
|
|
5
|
+
* when a threshold of the previous set signed it, as in TUF's root rotation.
|
|
6
|
+
* The signatures live beside the signers file, in `<signers>.rotation.json`:
|
|
7
|
+
*
|
|
8
|
+
* ```json
|
|
9
|
+
* { "schema": 1, "version": 2, "previous": "sha256:…", "threshold": 1,
|
|
10
|
+
* "signatures": [{ "principal": "alice@example.com", "signature": "-----BEGIN SSH SIGNATURE-----…" }] }
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Each signature is `ssh-keygen -Y sign -n chant-signers` over the statement
|
|
14
|
+
* {@link rotationStatement} returns: the new version, the digest of the
|
|
15
|
+
* previous signers file, the digest of the new one and the new threshold. The
|
|
16
|
+
* version number and the previous digest together stop an old, once-valid set
|
|
17
|
+
* from being replayed, and the namespace stops a commit signature from
|
|
18
|
+
* standing in for a rotation signature.
|
|
19
|
+
*
|
|
20
|
+
* ## Revocation by position
|
|
21
|
+
*
|
|
22
|
+
* Dates prove nothing: whoever makes a commit sets its date. So a commit is
|
|
23
|
+
* judged by where it sits in the base's history. Walking the base's
|
|
24
|
+
* first-parent line from the oldest commit, each commit that changes the
|
|
25
|
+
* signer set starts a version, and each version must be signed by a threshold
|
|
26
|
+
* of the one before. A commit already in the base's history is judged by the
|
|
27
|
+
* version in effect just before the first-parent commit that brought it in. A
|
|
28
|
+
* key removed at version N therefore still vouches for what was merged before
|
|
29
|
+
* N, and for nothing merged after, however the later commit is dated. A commit
|
|
30
|
+
* not yet in the base's history is judged by the latest version.
|
|
31
|
+
*/
|
|
32
|
+
import { createHash } from "node:crypto";
|
|
33
|
+
import { execFileSync } from "node:child_process";
|
|
34
|
+
import { posix } from "node:path";
|
|
35
|
+
import { z } from "zod";
|
|
36
|
+
import { canonicalJson } from "../../effect-receipt.js";
|
|
37
|
+
import { sshFingerprint } from "./dsse.js";
|
|
38
|
+
import { parseAllowedSigners } from "./policy.js";
|
|
39
|
+
import { verifySshSignature } from "./ssh-commit.js";
|
|
40
|
+
/** Why a signer set is not a valid next version (#2553). Each is in `reason-codes.ts` and in `signers.schema.json`. */
|
|
41
|
+
export const ROTATION_REFUSAL_CODES = [
|
|
42
|
+
"signers-removed",
|
|
43
|
+
"rotation-unparseable",
|
|
44
|
+
"rotation-invalid",
|
|
45
|
+
"rotation-first-version",
|
|
46
|
+
"rotation-missing",
|
|
47
|
+
"rotation-version-skew",
|
|
48
|
+
"rotation-previous-mismatch",
|
|
49
|
+
"rotation-threshold-unsatisfiable",
|
|
50
|
+
"rotation-threshold-not-met",
|
|
51
|
+
];
|
|
52
|
+
/** The ssh-keygen namespace rotation signatures are made in. Never `git`. */
|
|
53
|
+
export const ROTATION_NAMESPACE = "chant-signers";
|
|
54
|
+
/** The rotation file for a signers file. */
|
|
55
|
+
export function rotationPath(signersPath) {
|
|
56
|
+
return posix.join(posix.dirname(signersPath), `${posix.basename(signersPath)}.rotation.json`);
|
|
57
|
+
}
|
|
58
|
+
/** `sha256:<hex>` of a signers file's bytes, line endings normalised. */
|
|
59
|
+
export function signersDigest(text) {
|
|
60
|
+
return `sha256:${createHash("sha256").update(text.replace(/\r\n?/g, "\n"), "utf8").digest("hex")}`;
|
|
61
|
+
}
|
|
62
|
+
export const rotationFileSchema = z
|
|
63
|
+
.object({
|
|
64
|
+
schema: z.literal(1),
|
|
65
|
+
version: z.number().int().min(1),
|
|
66
|
+
previous: z.string().regex(/^sha256:[0-9a-f]{64}$/).nullable(),
|
|
67
|
+
threshold: z.number().int().min(1),
|
|
68
|
+
signatures: z.array(z.object({ principal: z.string().min(1), signature: z.string().min(1) }).strict()),
|
|
69
|
+
})
|
|
70
|
+
.strict();
|
|
71
|
+
/** The bytes each rotation signature covers. */
|
|
72
|
+
export function rotationStatement(r, signers) {
|
|
73
|
+
return Buffer.from(canonicalJson({ type: "chant-signer-set", version: r.version, previous: r.previous, signers, threshold: r.threshold }), "utf8");
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check `next` against the version before it. Returns the new version, or
|
|
77
|
+
* the reason it is not valid. `prev` undefined means there was no signer set,
|
|
78
|
+
* so `next` is a first version and needs no signatures.
|
|
79
|
+
*/
|
|
80
|
+
export function nextVersion(prev, next, commit) {
|
|
81
|
+
if (next.signers === undefined)
|
|
82
|
+
return { code: "signers-removed", reason: "the signers file was removed" };
|
|
83
|
+
const digest = signersDigest(next.signers);
|
|
84
|
+
let rotation;
|
|
85
|
+
if (next.rotation !== undefined) {
|
|
86
|
+
let raw;
|
|
87
|
+
try {
|
|
88
|
+
raw = JSON.parse(next.rotation);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return { code: "rotation-unparseable", reason: `the rotation file is not JSON: ${err instanceof Error ? err.message : String(err)}` };
|
|
92
|
+
}
|
|
93
|
+
const parsed = rotationFileSchema.safeParse(raw);
|
|
94
|
+
if (!parsed.success)
|
|
95
|
+
return { code: "rotation-invalid", reason: `the rotation file is invalid: ${parsed.error.issues.map((i) => `${i.path.join(".") || "/"}: ${i.message}`).join("; ")}` };
|
|
96
|
+
rotation = parsed.data;
|
|
97
|
+
}
|
|
98
|
+
const set = parseAllowedSigners(next.signers);
|
|
99
|
+
const threshold = rotation?.threshold ?? 1;
|
|
100
|
+
// A threshold no future rotation could meet would freeze the set for good.
|
|
101
|
+
const holders = distinctHolders(set.signers);
|
|
102
|
+
if (threshold > holders) {
|
|
103
|
+
return {
|
|
104
|
+
code: "rotation-threshold-unsatisfiable",
|
|
105
|
+
reason: `the threshold is ${threshold}, and the set has ${holders} distinct signer${holders === 1 ? "" : "s"} to meet it`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (!prev) {
|
|
109
|
+
if (rotation && (rotation.version !== 1 || rotation.previous !== null)) {
|
|
110
|
+
return { code: "rotation-first-version", reason: `a first signer set must be version 1 with no previous digest, not version ${rotation.version}` };
|
|
111
|
+
}
|
|
112
|
+
return { version: 1, commit, digest, threshold, signers: set.signers, excluded: set.excluded, signedBy: [] };
|
|
113
|
+
}
|
|
114
|
+
if (digest === prev.digest && threshold === prev.threshold)
|
|
115
|
+
return prev;
|
|
116
|
+
if (!rotation)
|
|
117
|
+
return { code: "rotation-missing", reason: `the signer set changed from version ${prev.version} with no rotation file signed by the set before it` };
|
|
118
|
+
if (rotation.version !== prev.version + 1)
|
|
119
|
+
return { code: "rotation-version-skew", reason: `the rotation says version ${rotation.version}; the next version is ${prev.version + 1}` };
|
|
120
|
+
if (rotation.previous !== prev.digest)
|
|
121
|
+
return { code: "rotation-previous-mismatch", reason: `the rotation names previous ${rotation.previous}, but version ${prev.version} is ${prev.digest}` };
|
|
122
|
+
const statement = rotationStatement(rotation, digest);
|
|
123
|
+
// Each signature counts once per key and once per principal: one key listed
|
|
124
|
+
// under two names is one signer, and so is one person with two keys.
|
|
125
|
+
const keys = new Set();
|
|
126
|
+
const signedBy = [];
|
|
127
|
+
for (const s of rotation.signatures) {
|
|
128
|
+
if (signedBy.includes(s.principal))
|
|
129
|
+
continue;
|
|
130
|
+
const mine = prev.signers.filter((x) => x.principal === s.principal);
|
|
131
|
+
const r = verifySshSignature(mine, statement, s.signature, ROTATION_NAMESPACE);
|
|
132
|
+
if (!r.ok)
|
|
133
|
+
continue;
|
|
134
|
+
const key = r.key ?? (mine.length === 1 ? sshFingerprint(mine[0].key) : `principal:${r.principal}`);
|
|
135
|
+
if (keys.has(key))
|
|
136
|
+
continue;
|
|
137
|
+
keys.add(key);
|
|
138
|
+
signedBy.push(r.principal);
|
|
139
|
+
}
|
|
140
|
+
if (keys.size < prev.threshold) {
|
|
141
|
+
return {
|
|
142
|
+
code: "rotation-threshold-not-met",
|
|
143
|
+
reason: `version ${rotation.version} is signed by ${keys.size} of the ${prev.threshold} signers of version ${prev.version} it needs${signedBy.length ? ` (${signedBy.join(", ")})` : ""}`,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { version: rotation.version, commit, digest, threshold, signers: set.signers, excluded: set.excluded, signedBy };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* How many signers could each give a counted signature: principals and keys
|
|
150
|
+
* are both distinct, so this is the size of a largest matching between them.
|
|
151
|
+
*/
|
|
152
|
+
export function distinctHolders(signers) {
|
|
153
|
+
const keysOf = new Map();
|
|
154
|
+
for (const s of signers) {
|
|
155
|
+
const set = keysOf.get(s.principal) ?? new Set();
|
|
156
|
+
set.add(s.key);
|
|
157
|
+
keysOf.set(s.principal, set);
|
|
158
|
+
}
|
|
159
|
+
const owner = new Map();
|
|
160
|
+
const tryAssign = (p, seen) => {
|
|
161
|
+
for (const k of keysOf.get(p) ?? []) {
|
|
162
|
+
if (seen.has(k))
|
|
163
|
+
continue;
|
|
164
|
+
seen.add(k);
|
|
165
|
+
const o = owner.get(k);
|
|
166
|
+
if (o === undefined || tryAssign(o, seen)) {
|
|
167
|
+
owner.set(k, p);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
};
|
|
173
|
+
let n = 0;
|
|
174
|
+
for (const p of keysOf.keys())
|
|
175
|
+
if (tryAssign(p, new Set()))
|
|
176
|
+
n++;
|
|
177
|
+
return n;
|
|
178
|
+
}
|
|
179
|
+
function git(repo, args) {
|
|
180
|
+
return execFileSync("git", args, { cwd: repo, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 256 * 1024 * 1024 });
|
|
181
|
+
}
|
|
182
|
+
/** A file's text at `commit`, or undefined when it is not there. */
|
|
183
|
+
export function fileAt(repo, commit, path) {
|
|
184
|
+
try {
|
|
185
|
+
return git(repo, ["cat-file", "blob", `${commit}:${path}`]);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Walk the signer set's history along the first-parent line of `base`,
|
|
193
|
+
* oldest first. A removal ends the chain; a later signers file starts a new
|
|
194
|
+
* one, which only the protected-write check in CI could have admitted.
|
|
195
|
+
*/
|
|
196
|
+
export function signerHistory(repo, base, signersPath) {
|
|
197
|
+
const paths = [signersPath, rotationPath(signersPath)];
|
|
198
|
+
const commits = git(repo, ["--literal-pathspecs", "log", "--first-parent", "--reverse", "--format=%H", base, "--", ...paths])
|
|
199
|
+
.split("\n")
|
|
200
|
+
.filter(Boolean);
|
|
201
|
+
const versions = [];
|
|
202
|
+
let prev;
|
|
203
|
+
for (const commit of commits) {
|
|
204
|
+
const files = { signers: fileAt(repo, commit, paths[0]), rotation: fileAt(repo, commit, paths[1]) };
|
|
205
|
+
if (files.signers === undefined) {
|
|
206
|
+
// Earlier versions still judge what was merged under them; from here on, nothing verifies.
|
|
207
|
+
if (prev)
|
|
208
|
+
versions.push({ version: 0, commit, digest: "", threshold: 0, signers: [], excluded: [], signedBy: [] });
|
|
209
|
+
prev = undefined;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const next = nextVersion(prev, files, commit);
|
|
213
|
+
if ("code" in next)
|
|
214
|
+
return { versions, broken: { commit, code: next.code, reason: next.reason } };
|
|
215
|
+
if (next !== prev)
|
|
216
|
+
versions.push(next);
|
|
217
|
+
prev = next;
|
|
218
|
+
}
|
|
219
|
+
return { versions };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Finds the signer set in effect for a commit, by its position in the base's
|
|
223
|
+
* history. Built once per base; the first-parent line is read once and
|
|
224
|
+
* each lookup is a binary search.
|
|
225
|
+
*/
|
|
226
|
+
export class SignerPositions {
|
|
227
|
+
constructor(repo, base, history) {
|
|
228
|
+
this.repo = repo;
|
|
229
|
+
this.base = base;
|
|
230
|
+
this.history = history;
|
|
231
|
+
this.index = new Map();
|
|
232
|
+
this.memo = new Map();
|
|
233
|
+
}
|
|
234
|
+
isAncestor(a, b) {
|
|
235
|
+
try {
|
|
236
|
+
execFileSync("git", ["merge-base", "--is-ancestor", a, b], { cwd: this.repo, stdio: "ignore" });
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/** The base's first-parent line, newest first. */
|
|
244
|
+
firstParents() {
|
|
245
|
+
if (!this.line) {
|
|
246
|
+
this.line = git(this.repo, ["rev-list", "--first-parent", this.base]).split("\n").filter(Boolean);
|
|
247
|
+
this.line.forEach((c, i) => this.index.set(c, i));
|
|
248
|
+
}
|
|
249
|
+
return this.line;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* The version that judges `commit`, or null when no signer set was in
|
|
253
|
+
* effect there (before the first one, or the chain is broken).
|
|
254
|
+
*/
|
|
255
|
+
versionFor(commit) {
|
|
256
|
+
const hit = this.memo.get(commit);
|
|
257
|
+
if (hit !== undefined)
|
|
258
|
+
return hit;
|
|
259
|
+
const answer = this.lookup(commit);
|
|
260
|
+
this.memo.set(commit, answer);
|
|
261
|
+
return answer;
|
|
262
|
+
}
|
|
263
|
+
lookup(commit) {
|
|
264
|
+
if (this.history.broken)
|
|
265
|
+
return null;
|
|
266
|
+
const latest = this.history.versions.at(-1) ?? null;
|
|
267
|
+
if (!this.isAncestor(commit, this.base))
|
|
268
|
+
return latest;
|
|
269
|
+
const line = this.firstParents();
|
|
270
|
+
// The oldest first-parent commit that contains `commit` is where it came in.
|
|
271
|
+
let lo = 0;
|
|
272
|
+
let hi = line.length - 1;
|
|
273
|
+
let at = 0;
|
|
274
|
+
while (lo <= hi) {
|
|
275
|
+
const mid = (lo + hi) >> 1;
|
|
276
|
+
if (this.isAncestor(commit, line[mid])) {
|
|
277
|
+
at = mid;
|
|
278
|
+
lo = mid + 1;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
hi = mid - 1;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// The newest version made strictly before that commit.
|
|
285
|
+
let best = null;
|
|
286
|
+
let bestIndex = Infinity;
|
|
287
|
+
for (const v of this.history.versions) {
|
|
288
|
+
const i = v.commit ? this.index.get(v.commit) : undefined;
|
|
289
|
+
if (i === undefined || i <= at)
|
|
290
|
+
continue;
|
|
291
|
+
if (i < bestIndex) {
|
|
292
|
+
best = v;
|
|
293
|
+
bestIndex = i;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return best;
|
|
297
|
+
}
|
|
298
|
+
}
|