approval-md 0.1.0 → 0.3.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/README.md +629 -559
- package/SPEC.md +99 -24
- package/dist/src/adapters/agentmail.d.ts +426 -0
- package/dist/src/adapters/agentmail.js +2 -2
- package/dist/src/adapters/conformance.d.ts +149 -0
- package/dist/src/adapters/contract.d.ts +628 -0
- package/dist/src/adapters/contract.js +110 -16
- package/dist/src/adapters/contract.js.map +1 -1
- package/dist/src/adapters/email.d.ts +324 -0
- package/dist/src/adapters/env-passphrase.d.ts +93 -0
- package/dist/src/adapters/public.d.ts +11 -0
- package/dist/src/adapters/public.js +11 -0
- package/dist/src/adapters/public.js.map +1 -0
- package/dist/src/adapters/registry.d.ts +59 -0
- package/dist/src/adapters/registry.js +2 -1
- package/dist/src/adapters/registry.js.map +1 -1
- package/dist/src/adapters/smtp.d.ts +213 -0
- package/dist/src/adapters/vault-provider.d.ts +114 -0
- package/dist/src/adapters/vault-provider.js +3 -3
- package/dist/src/adapters/zzz.d.ts +66 -0
- package/dist/src/adapters/zzz.js +299 -0
- package/dist/src/adapters/zzz.js.map +1 -0
- package/dist/src/channels/batch.d.ts +109 -0
- package/dist/src/channels/cli.d.ts +193 -0
- package/dist/src/channels/conformance.d.ts +92 -0
- package/dist/src/channels/contract.d.ts +656 -0
- package/dist/src/channels/contract.js +200 -7
- package/dist/src/channels/contract.js.map +1 -1
- package/dist/src/channels/payload-view.d.ts +35 -0
- package/dist/src/channels/render-queue.d.ts +149 -0
- package/dist/src/channels/tagging.d.ts +196 -0
- package/dist/src/channels/telegram.d.ts +1944 -0
- package/dist/src/channels/telegram.js +218 -23
- package/dist/src/channels/telegram.js.map +1 -1
- package/dist/src/channels/web.d.ts +350 -0
- package/dist/src/channels/web.js +17 -0
- package/dist/src/channels/web.js.map +1 -1
- package/dist/src/cli/adapter.d.ts +90 -0
- package/dist/src/cli/adapter.js +25 -15
- package/dist/src/cli/adapter.js.map +1 -1
- package/dist/src/cli/amend.d.ts +59 -0
- package/dist/src/cli/amend.js +214 -30
- package/dist/src/cli/amend.js.map +1 -1
- package/dist/src/cli/args.d.ts +43 -0
- package/dist/src/cli/attest.d.ts +50 -0
- package/dist/src/cli/attest.js +134 -7
- package/dist/src/cli/attest.js.map +1 -1
- package/dist/src/cli/audit-card.d.ts +62 -0
- package/dist/src/cli/audit.d.ts +59 -0
- package/dist/src/cli/channel-telegram.d.ts +879 -0
- package/dist/src/cli/channel-telegram.js +311 -13
- package/dist/src/cli/channel-telegram.js.map +1 -1
- package/dist/src/cli/channel-web.d.ts +131 -0
- package/dist/src/cli/channel.d.ts +80 -0
- package/dist/src/cli/channel.js +9 -0
- package/dist/src/cli/channel.js.map +1 -1
- package/dist/src/cli/checkpoint-tap.d.ts +169 -0
- package/dist/src/cli/codex-bridge.d.ts +819 -0
- package/dist/src/cli/codex-bridge.js +1607 -0
- package/dist/src/cli/codex-bridge.js.map +1 -0
- package/dist/src/cli/codex.d.ts +2 -0
- package/dist/src/cli/codex.js +469 -0
- package/dist/src/cli/codex.js.map +1 -0
- package/dist/src/cli/coverage.d.ts +61 -0
- package/dist/src/cli/daemon.d.ts +120 -0
- package/dist/src/cli/daemon.js +4 -1
- package/dist/src/cli/daemon.js.map +1 -1
- package/dist/src/cli/doctor.d.ts +129 -0
- package/dist/src/cli/doctor.js +586 -17
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/env.d.ts +65 -0
- package/dist/src/cli/execute.d.ts +202 -0
- package/dist/src/cli/execute.js +25 -2
- package/dist/src/cli/execute.js.map +1 -1
- package/dist/src/cli/exit-codes.d.ts +73 -0
- package/dist/src/cli/feedback.d.ts +60 -0
- package/dist/src/cli/gate-window.d.ts +40 -0
- package/dist/src/cli/gate.d.ts +68 -0
- package/dist/src/cli/git-scope.d.ts +190 -0
- package/dist/src/cli/gloss-attach.d.ts +85 -0
- package/dist/src/cli/gloss-codex-child.d.ts +9 -0
- package/dist/src/cli/gloss-codex.d.ts +24 -0
- package/dist/src/cli/gloss-options.d.ts +42 -0
- package/dist/src/cli/gloss.d.ts +265 -0
- package/dist/src/cli/help.d.ts +107 -0
- package/dist/src/cli/help.js +320 -93
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook-codex.d.ts +126 -0
- package/dist/src/cli/hook-codex.js +226 -0
- package/dist/src/cli/hook-codex.js.map +1 -0
- package/dist/src/cli/hook.d.ts +787 -0
- package/dist/src/cli/hook.js +1235 -181
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/import.d.ts +35 -0
- package/dist/src/cli/import.js +1 -1
- package/dist/src/cli/import.js.map +1 -1
- package/dist/src/cli/init.d.ts +84 -0
- package/dist/src/cli/init.js +2 -2
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/instructions.d.ts +23 -0
- package/dist/src/cli/journal.d.ts +41 -0
- package/dist/src/cli/log-advance.d.ts +287 -0
- package/dist/src/cli/log-advance.js +102 -11
- package/dist/src/cli/log-advance.js.map +1 -1
- package/dist/src/cli/log-anchor.d.ts +176 -0
- package/dist/src/cli/log-checkpoint.d.ts +22 -0
- package/dist/src/cli/log-sync.d.ts +243 -0
- package/dist/src/cli/log-verbs.d.ts +16 -0
- package/dist/src/cli/log-verbs.js +7 -1
- package/dist/src/cli/log-verbs.js.map +1 -1
- package/dist/src/cli/long-help.d.ts +70 -0
- package/dist/src/cli/main.d.ts +77 -0
- package/dist/src/cli/main.js +159 -7
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/mcp.d.ts +52 -0
- package/dist/src/cli/paths.d.ts +56 -0
- package/dist/src/cli/payload.d.ts +58 -0
- package/dist/src/cli/policy-apply.d.ts +195 -0
- package/dist/src/cli/policy-apply.js +573 -0
- package/dist/src/cli/policy-apply.js.map +1 -0
- package/dist/src/cli/policy.d.ts +43 -0
- package/dist/src/cli/policy.js +14 -1
- package/dist/src/cli/policy.js.map +1 -1
- package/dist/src/cli/preflight.d.ts +501 -0
- package/dist/src/cli/preflight.js +689 -45
- package/dist/src/cli/preflight.js.map +1 -1
- package/dist/src/cli/progress.d.ts +78 -0
- package/dist/src/cli/prompt.d.ts +209 -0
- package/dist/src/cli/quickstart.d.ts +46 -0
- package/dist/src/cli/quickstart.js +297 -0
- package/dist/src/cli/quickstart.js.map +1 -0
- package/dist/src/cli/records.d.ts +34 -0
- package/dist/src/cli/render.d.ts +22 -0
- package/dist/src/cli/sandbox.d.ts +51 -0
- package/dist/src/cli/sandbox.js +17 -1
- package/dist/src/cli/sandbox.js.map +1 -1
- package/dist/src/cli/scaffold.d.ts +79 -0
- package/dist/src/cli/scaffold.js +1 -1
- package/dist/src/cli/setup-adapter.d.ts +137 -0
- package/dist/src/cli/setup-adapter.js +38 -4
- package/dist/src/cli/setup-adapter.js.map +1 -1
- package/dist/src/cli/setup-channel.d.ts +126 -0
- package/dist/src/cli/setup-channel.js +28 -1
- package/dist/src/cli/setup-channel.js.map +1 -1
- package/dist/src/cli/setup-checkpoint.d.ts +57 -0
- package/dist/src/cli/setup-common.d.ts +277 -0
- package/dist/src/cli/setup-common.js +3 -2
- package/dist/src/cli/setup-common.js.map +1 -1
- package/dist/src/cli/setup-flow.d.ts +287 -0
- package/dist/src/cli/setup-service.d.ts +96 -0
- package/dist/src/cli/setup.d.ts +204 -0
- package/dist/src/cli/setup.js +94 -2
- package/dist/src/cli/setup.js.map +1 -1
- package/dist/src/cli/style.d.ts +320 -0
- package/dist/src/cli/token.d.ts +39 -0
- package/dist/src/cli/up.d.ts +155 -0
- package/dist/src/cli/up.js +119 -53
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/usage.d.ts +37 -0
- package/dist/src/cli/values.d.ts +40 -0
- package/dist/src/cli/values.js +3 -4
- package/dist/src/cli/values.js.map +1 -1
- package/dist/src/cli/vault.d.ts +59 -0
- package/dist/src/cli/vault.js +2 -2
- package/dist/src/cli/vault.js.map +1 -1
- package/dist/src/cli/verb-registry.d.ts +76 -0
- package/dist/src/cli/verb-registry.js +344 -11
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +31 -0
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/codex/broker.d.ts +229 -0
- package/dist/src/codex/broker.js +548 -0
- package/dist/src/codex/broker.js.map +1 -0
- package/dist/src/codex/doctor.d.ts +13 -0
- package/dist/src/codex/doctor.js +41 -0
- package/dist/src/codex/doctor.js.map +1 -0
- package/dist/src/codex/manifest.d.ts +49 -0
- package/dist/src/codex/manifest.js +103 -0
- package/dist/src/codex/manifest.js.map +1 -0
- package/dist/src/codex/runner.d.ts +178 -0
- package/dist/src/codex/runner.js +231 -0
- package/dist/src/codex/runner.js.map +1 -0
- package/dist/src/codex/serve.d.ts +56 -0
- package/dist/src/codex/serve.js +98 -0
- package/dist/src/codex/serve.js.map +1 -0
- package/dist/src/codex/templates.d.ts +41 -0
- package/dist/src/codex/templates.js +319 -0
- package/dist/src/codex/templates.js.map +1 -0
- package/dist/src/codex/trust.d.ts +19 -0
- package/dist/src/codex/trust.js +183 -0
- package/dist/src/codex/trust.js.map +1 -0
- package/dist/src/codex/workspace-commit.d.ts +219 -0
- package/dist/src/codex/workspace-commit.js +549 -0
- package/dist/src/codex/workspace-commit.js.map +1 -0
- package/dist/src/codex/workspace-plan.d.ts +131 -0
- package/dist/src/codex/workspace-plan.js +561 -0
- package/dist/src/codex/workspace-plan.js.map +1 -0
- package/dist/src/core/actor.d.ts +2 -0
- package/dist/src/core/actor.js +5 -0
- package/dist/src/core/actor.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +221 -0
- package/dist/src/core/advance-cycle.js +66 -2
- package/dist/src/core/advance-cycle.js.map +1 -1
- package/dist/src/core/agents-md.d.ts +278 -0
- package/dist/src/core/agents-md.js +33 -31
- package/dist/src/core/agents-md.js.map +1 -1
- package/dist/src/core/apply-patch.d.ts +49 -0
- package/dist/src/core/apply-patch.js +266 -0
- package/dist/src/core/apply-patch.js.map +1 -0
- package/dist/src/core/attest.d.ts +635 -0
- package/dist/src/core/attest.js +326 -4
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +510 -0
- package/dist/src/core/audit.js +13 -0
- package/dist/src/core/audit.js.map +1 -1
- package/dist/src/core/budgets.d.ts +238 -0
- package/dist/src/core/channel-owner.d.ts +213 -0
- package/dist/src/core/channel-owner.js +358 -0
- package/dist/src/core/channel-owner.js.map +1 -0
- package/dist/src/core/checkpoint.d.ts +500 -0
- package/dist/src/core/child-env.d.ts +88 -0
- package/dist/src/core/clock.d.ts +52 -0
- package/dist/src/core/command-class.d.ts +697 -0
- package/dist/src/core/command-class.js +713 -25
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/commit-guard.d.ts +272 -0
- package/dist/src/core/commit-guard.js +424 -0
- package/dist/src/core/commit-guard.js.map +1 -0
- package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
- package/dist/src/core/coverage-sources/gh.d.ts +48 -0
- package/dist/src/core/coverage-sources/git.d.ts +101 -0
- package/dist/src/core/coverage.d.ts +217 -0
- package/dist/src/core/credential-spec.d.ts +72 -0
- package/dist/src/core/daemon-actor.d.ts +45 -0
- package/dist/src/core/daemon-actor.js +54 -0
- package/dist/src/core/daemon-actor.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +432 -0
- package/dist/src/core/dark-session.js +266 -82
- package/dist/src/core/dark-session.js.map +1 -1
- package/dist/src/core/decision-refusal.d.ts +206 -0
- package/dist/src/core/decision-refusal.js +24 -2
- package/dist/src/core/decision-refusal.js.map +1 -1
- package/dist/src/core/env-file.d.ts +455 -0
- package/dist/src/core/env-file.js +60 -1
- package/dist/src/core/env-file.js.map +1 -1
- package/dist/src/core/execute.d.ts +871 -0
- package/dist/src/core/execute.js +59 -8
- package/dist/src/core/execute.js.map +1 -1
- package/dist/src/core/frontmatter.d.ts +78 -0
- package/dist/src/core/gate-window.d.ts +312 -0
- package/dist/src/core/gate.d.ts +1449 -0
- package/dist/src/core/gate.js +149 -14
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/gesture-refusal.d.ts +166 -0
- package/dist/src/core/gesture-refusal.js +188 -0
- package/dist/src/core/gesture-refusal.js.map +1 -0
- package/dist/src/core/git-run.d.ts +73 -0
- package/dist/src/core/harness-version.d.ts +157 -0
- package/dist/src/core/harness-version.js +4 -1
- package/dist/src/core/harness-version.js.map +1 -1
- package/dist/src/core/harness-wait.d.ts +55 -0
- package/dist/src/core/head-retry.d.ts +107 -0
- package/dist/src/core/instance.d.ts +310 -0
- package/dist/src/core/instance.js +113 -0
- package/dist/src/core/instance.js.map +1 -1
- package/dist/src/core/intake-limits.d.ts +247 -0
- package/dist/src/core/jcs.d.ts +52 -0
- package/dist/src/core/journal.d.ts +144 -0
- package/dist/src/core/live-draw.d.ts +436 -0
- package/dist/src/core/log-reconcile.d.ts +89 -0
- package/dist/src/core/log-subscribe.d.ts +36 -0
- package/dist/src/core/log-subscribe.js +162 -0
- package/dist/src/core/log-subscribe.js.map +1 -0
- package/dist/src/core/log.d.ts +316 -0
- package/dist/src/core/log.js.map +1 -1
- package/dist/src/core/loop.d.ts +274 -0
- package/dist/src/core/loop.js +11 -0
- package/dist/src/core/loop.js.map +1 -1
- package/dist/src/core/md-fence.d.ts +41 -0
- package/dist/src/core/money.d.ts +147 -0
- package/dist/src/core/payload-census.d.ts +74 -0
- package/dist/src/core/payload-store.d.ts +175 -0
- package/dist/src/core/payload.d.ts +71 -0
- package/dist/src/core/policy-diff.d.ts +292 -0
- package/dist/src/core/policy-diff.js +27 -4
- package/dist/src/core/policy-diff.js.map +1 -1
- package/dist/src/core/policy-expectations.d.ts +199 -0
- package/dist/src/core/policy-explain.d.ts +160 -0
- package/dist/src/core/policy-explain.js +63 -3
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +567 -0
- package/dist/src/core/policy-load.js +36 -6
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +324 -0
- package/dist/src/core/policy-match.js +72 -9
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +317 -0
- package/dist/src/core/policy-proposal.js +102 -2
- package/dist/src/core/policy-proposal.js.map +1 -1
- package/dist/src/core/prompt-layout.d.ts +221 -0
- package/dist/src/core/protected-path-guard.d.ts +566 -0
- package/dist/src/core/protected-path-guard.js +848 -55
- package/dist/src/core/protected-path-guard.js.map +1 -1
- package/dist/src/core/question-preempted.d.ts +141 -0
- package/dist/src/core/question-preempted.js +152 -0
- package/dist/src/core/question-preempted.js.map +1 -0
- package/dist/src/core/read-scope.d.ts +172 -0
- package/dist/src/core/read-scope.js +252 -0
- package/dist/src/core/read-scope.js.map +1 -0
- package/dist/src/core/registration.d.ts +25 -0
- package/dist/src/core/reindex.d.ts +99 -0
- package/dist/src/core/sampler.d.ts +313 -0
- package/dist/src/core/sandbox.d.ts +371 -0
- package/dist/src/core/sandbox.js +190 -1
- package/dist/src/core/sandbox.js.map +1 -1
- package/dist/src/core/seal.d.ts +165 -0
- package/dist/src/core/sender-identity.d.ts +476 -0
- package/dist/src/core/sender-identity.js +572 -0
- package/dist/src/core/sender-identity.js.map +1 -0
- package/dist/src/core/shlex.d.ts +102 -0
- package/dist/src/core/shlex.js +159 -0
- package/dist/src/core/shlex.js.map +1 -0
- package/dist/src/core/state.d.ts +505 -0
- package/dist/src/core/task-file.d.ts +185 -0
- package/dist/src/core/telegram-config.d.ts +93 -0
- package/dist/src/core/token.d.ts +409 -0
- package/dist/src/core/token.js +21 -38
- package/dist/src/core/token.js.map +1 -1
- package/dist/src/core/validate.d.ts +138 -0
- package/dist/src/core/values.d.ts +147 -0
- package/dist/src/core/values.js +36 -1
- package/dist/src/core/values.js.map +1 -1
- package/dist/src/core/vault.d.ts +291 -0
- package/dist/src/core/verified-snapshot.d.ts +204 -0
- package/dist/src/core/verify.d.ts +336 -0
- package/dist/src/core/version.d.ts +8 -0
- package/dist/src/core/wysiwys.d.ts +370 -0
- package/dist/src/daemon/advance-child.d.ts +39 -0
- package/dist/src/daemon/advance.d.ts +476 -0
- package/dist/src/daemon/advance.js +25 -4
- package/dist/src/daemon/advance.js.map +1 -1
- package/dist/src/daemon/audit.d.ts +87 -0
- package/dist/src/daemon/daemon.d.ts +1180 -0
- package/dist/src/daemon/daemon.js +9 -0
- package/dist/src/daemon/daemon.js.map +1 -1
- package/dist/src/daemon/dark-session.d.ts +64 -0
- package/dist/src/daemon/draw-child.d.ts +36 -0
- package/dist/src/daemon/draw.d.ts +154 -0
- package/dist/src/daemon/git-evidence.d.ts +173 -0
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/daemon/projection.d.ts +180 -0
- package/dist/src/daemon/prune.d.ts +207 -0
- package/dist/src/mcp/http.d.ts +113 -0
- package/dist/src/mcp/server.d.ts +265 -0
- package/dist/src/mcp/server.js +17 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/docs/adapter-api.md +106 -0
- package/docs/cli-reference.md +1316 -63
- package/docs/codex-enforced-session.md +103 -0
- package/docs/codex-workspace-broker.md +118 -0
- package/package.json +14 -2
- package/schema/codex-instance.schema.json +82 -0
- package/schema/event.schema.json +539 -9
- package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
- package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-false.json +20 -0
- package/schema/fixtures/event/invalid/approval-granted-sender-hashed-raw-id.json +20 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-human-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-no-actor-no-sender.json +15 -0
- package/schema/fixtures/event/invalid/audit-gesture-refused-unknown-gesture.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-no-question-id.json +16 -0
- package/schema/fixtures/event/invalid/audit-question-preempted-unknown-source.json +15 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-path-signed-off-missing-path.json +13 -0
- package/schema/fixtures/event/valid/approval-granted-sender-hashed.json +20 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-review-note.json +21 -0
- package/schema/fixtures/event/valid/audit-gesture-refused-sender-key-unavailable.json +19 -0
- package/schema/fixtures/event/valid/audit-gesture-refused.json +19 -0
- package/schema/fixtures/event/valid/audit-question-preempted-no-verdict.json +16 -0
- package/schema/fixtures/event/valid/audit-question-preempted.json +20 -0
- package/schema/fixtures/event/valid/gate-path-signed-off.json +14 -0
- package/schema/fixtures/event/valid/harness-kind-claude-code.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-codex.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-cursor.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-grok.json +23 -0
- package/schema/fixtures/event/valid/harness-kind-muse.json +23 -0
- package/schema/fixtures/policy/invalid/senders-half-keyed.json +20 -0
- package/schema/fixtures/policy/valid/canonical.json +1 -1
- package/schema/fixtures/policy/valid/senders-keyed.json +24 -0
- package/schema/fixtures/policy-md/valid/canonical.md +1 -1
- package/schema/fixtures/policy-md/valid/with-values.md +5 -7
- package/schema/fixtures/values/invalid/class-shaped.json +1 -1
- package/schema/fixtures/values/invalid/duplicate-entry.json +1 -1
- package/schema/fixtures/values/invalid/non-string-item.json +1 -1
- package/schema/fixtures/values/invalid/over-cap.json +1 -1
- package/schema/fixtures/values/invalid/unknown-key.json +1 -1
- package/schema/fixtures/values/invalid/version-float.json +1 -0
- package/schema/fixtures/values/invalid/version-integer.json +1 -0
- package/schema/fixtures/values/invalid/version-wrong-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +2 -3
- package/schema/fixtures/values/valid/full.json +5 -7
- package/schema/fixtures/values/valid/minimal.json +1 -1
- package/schema/fixtures/values-md/invalid/schema-invalid.md +5 -3
- package/schema/fixtures/values-md/invalid/two-blocks.md +3 -3
- package/schema/fixtures/values-md/invalid/unterminated.md +2 -2
- package/schema/fixtures/values-md/invalid/version-1.md +69 -0
- package/schema/fixtures/values-md/invalid/version-unquoted.md +64 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +2 -2
- package/schema/fixtures/values-md/valid/absent.md +1 -1
- package/schema/fixtures/values-md/valid/with-values.md +5 -7
- package/schema/policy.schema.json +75 -3
- package/schema/values.schema.json +7 -11
- package/templates/codex/README.md +9 -0
- package/schema/fixtures/values/invalid/version-string.json +0 -1
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unit of judgment: one commit (APRV-375).
|
|
3
|
+
*
|
|
4
|
+
* ## What a grant binds
|
|
5
|
+
*
|
|
6
|
+
* A `policy.edit` grant binds ONE edit: a before-state, an after-state, and a
|
|
7
|
+
* human who was shown them. The protected-path guard of
|
|
8
|
+
* `core/protected-path-guard.ts` decides whether a change is made of such
|
|
9
|
+
* material, and everything it answers is relative to the pair of blobs the
|
|
10
|
+
* caller hands it. So the caller's choice of pair is the whole question, and
|
|
11
|
+
* until this module the CI guard chose the pull request's COMBINED diff: base
|
|
12
|
+
* tree against head tree, every commit's work replayed as one change.
|
|
13
|
+
*
|
|
14
|
+
* That pairing has no grant. PR #427 is the worked example (APRV-357's
|
|
15
|
+
* reproduction, PR #452): three lane commits, each granted, plus two merges of
|
|
16
|
+
* `origin/main` made while four other lanes were editing `SPEC.md`. Replayed as
|
|
17
|
+
* one change it failed `uncovered-hunk` with fourteen uncovered lines, twenty
|
|
18
|
+
* nine records naming the path and twenty seven covering part of it, because a
|
|
19
|
+
* grant binds a before-state that the combined base no longer carries once an
|
|
20
|
+
* earlier commit in the range has moved those bytes. Replayed per commit all
|
|
21
|
+
* three pass, in well under a second each.
|
|
22
|
+
*
|
|
23
|
+
* `approval doctor`'s dark-session arm A reached the same conclusion from the
|
|
24
|
+
* other side (APRV-369): it used to replay a whole window as one change and
|
|
25
|
+
* failed a change CI had passed, at every session start. It now replays per
|
|
26
|
+
* commit. This module is where the two meet, so the agreement is by
|
|
27
|
+
* construction rather than by two code paths kept in step.
|
|
28
|
+
*
|
|
29
|
+
* ## The security argument
|
|
30
|
+
*
|
|
31
|
+
* Judging per commit asks a SMALLER question than judging the combined diff, so
|
|
32
|
+
* it owes an argument that nothing escapes. It is this:
|
|
33
|
+
*
|
|
34
|
+
* 1. Every byte that differs between the base tree and the head tree was
|
|
35
|
+
* written by some commit in `base..head`. Two-dot range semantics is what
|
|
36
|
+
* makes that true: a commit reachable from base is excluded, and a commit
|
|
37
|
+
* reachable from base changed nothing about the difference between the two
|
|
38
|
+
* trees that its own history did not already carry.
|
|
39
|
+
* 2. A non-merge commit's whole contribution is its diff against its parent,
|
|
40
|
+
* which is exactly what this module hands the guard.
|
|
41
|
+
* 3. A merge commit contributes only what it resolved: the bytes its result
|
|
42
|
+
* carries that no parent carried. That is git's DENSE combined diff
|
|
43
|
+
* (`--cc`), and a merge with a non-empty one on a guarded path is judged
|
|
44
|
+
* against its first parent here. A merge whose result on a path is some
|
|
45
|
+
* parent's bytes verbatim invented nothing and is listed as skipped.
|
|
46
|
+
*
|
|
47
|
+
* Together: every changed byte is inside some judged unit, and each unit is
|
|
48
|
+
* judged against the before-state a grant for it would have bound. The guard
|
|
49
|
+
* stops asking about the combined diff because the combined diff is a change
|
|
50
|
+
* nobody ever made and nobody could have approved.
|
|
51
|
+
*
|
|
52
|
+
* ## One thing is NOT per commit: whole-file evidence
|
|
53
|
+
*
|
|
54
|
+
* A grant binds a hunk, so it is evidence about one commit. A sign-off
|
|
55
|
+
* (APRV-338), an organ attestation (APRV-272) and the policy attestation say a
|
|
56
|
+
* human read the file AS IT NOW STANDS, so they are evidence about the bytes
|
|
57
|
+
* the range INSTALLS: every commit is offered the digests at the RANGE HEAD.
|
|
58
|
+
* {@link digestsAt} carries the reasoning, and it matters because matching them
|
|
59
|
+
* per commit would have repealed the escape hatch for every edit before the
|
|
60
|
+
* last one.
|
|
61
|
+
*
|
|
62
|
+
* ## What this does NOT do
|
|
63
|
+
*
|
|
64
|
+
* It does not re-judge work the branch absorbed by merging `origin/main`. Those
|
|
65
|
+
* commits are main's, they passed their own pull requests, and two-dot
|
|
66
|
+
* `base..head` excludes them by construction: CI computes base as `git
|
|
67
|
+
* merge-base origin/main HEAD`, so a branch that merged main has every absorbed
|
|
68
|
+
* commit reachable from base. Nothing is skipped by a rule about authorship or
|
|
69
|
+
* about who pushed what; the range is simply the commits this pull request is
|
|
70
|
+
* proposing to add.
|
|
71
|
+
*
|
|
72
|
+
* It also does not relax the exact-replay byte budget of
|
|
73
|
+
* `core/protected-path-guard.ts`. Per commit that budget is not reached in any
|
|
74
|
+
* case observed, which is why APRV-357 closes as superseded rather than fixed.
|
|
75
|
+
*/
|
|
76
|
+
import { createHash } from "node:crypto";
|
|
77
|
+
import { evaluateProtectedPaths, isGuardedPath } from "./protected-path-guard.js";
|
|
78
|
+
/** SHA-256 of a UTF-8 string, hex. */
|
|
79
|
+
function sha256Hex(text) {
|
|
80
|
+
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
81
|
+
}
|
|
82
|
+
/** Is this commit a merge? */
|
|
83
|
+
export function isMerge(commit) {
|
|
84
|
+
return commit.parents.length > 1;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The revision a commit is judged AGAINST: its first parent.
|
|
88
|
+
*
|
|
89
|
+
* First parent and not the merge base of the parents, for a merge, because the
|
|
90
|
+
* first parent is the state the branch was in before the merge and the merge's
|
|
91
|
+
* own contribution is measured from there. `null` for a root commit, which has
|
|
92
|
+
* no before-state at all and whose every path is an add.
|
|
93
|
+
*/
|
|
94
|
+
export function baseRevOf(commit) {
|
|
95
|
+
return commit.parents.length === 0 ? null : `${commit.sha}^1`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Record and field separators inside `git log --pretty`.
|
|
99
|
+
*
|
|
100
|
+
* ASCII 30 and 31, for the reason `core/dark-session.ts` states where it uses
|
|
101
|
+
* the same pair: git quotes any path containing a control character, so a
|
|
102
|
+
* filename engineered to carry one arrives escaped and cannot forge a commit
|
|
103
|
+
* boundary in output the guard parses.
|
|
104
|
+
*/
|
|
105
|
+
const RS = "";
|
|
106
|
+
const FS = "";
|
|
107
|
+
function datesOf(author, committer) {
|
|
108
|
+
const a = author === undefined || author.length === 0 ? null : author;
|
|
109
|
+
const c = committer === undefined || committer.length === 0 ? null : committer;
|
|
110
|
+
return { author: a, committer: c ?? a };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The commits of `base..head`, oldest first, each with the paths it is judged
|
|
114
|
+
* for.
|
|
115
|
+
*
|
|
116
|
+
* `judged` narrows the per-path work a MERGE costs: git's dense combined diff
|
|
117
|
+
* has to be asked for one path at a time (see below), and asking it about every
|
|
118
|
+
* file a large merge touched would be a git invocation per file for no verdict.
|
|
119
|
+
* A non-merge commit's path list is not narrowed at all, so the guard still
|
|
120
|
+
* reports exempt paths and still sees everything it might protect.
|
|
121
|
+
*
|
|
122
|
+
* The two-step merge question is not an optimization, it is correctness.
|
|
123
|
+
* `git log -c --name-only` lists the files "modified from all parents", which
|
|
124
|
+
* OVER-reports: at PR #427's merge `e66ba9e` it lists `SPEC.md`, whose result
|
|
125
|
+
* differs from both parents as a blob while every hunk of it came verbatim from
|
|
126
|
+
* one side. The dense (`--cc`) rendering is the one that drops hunks a parent
|
|
127
|
+
* already carried, and a path whose dense rendering is empty invented nothing.
|
|
128
|
+
* So each candidate is re-asked with a per-path `--cc` patch, and passing the
|
|
129
|
+
* path as a pathspec rather than parsing it out of a `diff --cc` header keeps
|
|
130
|
+
* quoted and unusual filenames out of the parser entirely.
|
|
131
|
+
*/
|
|
132
|
+
export function listCommits(read, base, head, judged) {
|
|
133
|
+
const log = read([
|
|
134
|
+
"log",
|
|
135
|
+
"--reverse",
|
|
136
|
+
`--pretty=format:${RS}%H${FS}%P${FS}%aI${FS}%cI`,
|
|
137
|
+
"--name-only",
|
|
138
|
+
`${base}..${head}`,
|
|
139
|
+
]);
|
|
140
|
+
if (log === null) {
|
|
141
|
+
return { ok: false, message: `\`git log ${base}..${head}\` failed` };
|
|
142
|
+
}
|
|
143
|
+
const commits = [];
|
|
144
|
+
for (const chunk of log.split(RS)) {
|
|
145
|
+
const lines = chunk.split("\n").filter((line) => line.length > 0);
|
|
146
|
+
const header = lines.shift();
|
|
147
|
+
if (header === undefined)
|
|
148
|
+
continue;
|
|
149
|
+
const [sha, parents, authored, committed] = header.split(FS);
|
|
150
|
+
if (sha === undefined || sha.length === 0)
|
|
151
|
+
continue;
|
|
152
|
+
const parentList = (parents ?? "")
|
|
153
|
+
.split(" ")
|
|
154
|
+
.map((part) => part.trim())
|
|
155
|
+
.filter((part) => part.length > 0);
|
|
156
|
+
const commit = {
|
|
157
|
+
sha,
|
|
158
|
+
parents: parentList,
|
|
159
|
+
ts: datesOf(authored, committed),
|
|
160
|
+
// `--name-only` reports nothing for a merge; the dense pass below fills it.
|
|
161
|
+
changedPaths: parentList.length > 1 ? denseCombinedPaths(read, sha, judged) : lines,
|
|
162
|
+
};
|
|
163
|
+
commits.push(commit);
|
|
164
|
+
}
|
|
165
|
+
return { ok: true, commits };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The guarded paths a merge commit's result carries that no parent carried:
|
|
169
|
+
* the merge's own work, which is what an evil merge is made of.
|
|
170
|
+
*
|
|
171
|
+
* EXPORTED because arm A of `core/dark-session.ts` asks the same question of a
|
|
172
|
+
* merge it finds on main (APRV-374), and two implementations of "what did this
|
|
173
|
+
* merge invent" would be two things to keep in step — the disagreement APRV-369
|
|
174
|
+
* was filed about. The observer there lists a window rather than a range, so it
|
|
175
|
+
* cannot reuse {@link listCommits}; it reuses this.
|
|
176
|
+
*
|
|
177
|
+
* The two-step shape is the correctness (see {@link listCommits}): `-c
|
|
178
|
+
* --name-only` gives candidates and over-reports, and the per-path `--cc` patch
|
|
179
|
+
* is the discriminator, empty for every merge whose every hunk came from a
|
|
180
|
+
* parent verbatim.
|
|
181
|
+
*/
|
|
182
|
+
export function denseCombinedPaths(read, sha, judged) {
|
|
183
|
+
const listed = read(["log", "-1", "-c", "--name-only", "--pretty=format:", sha]);
|
|
184
|
+
if (listed === null)
|
|
185
|
+
return [];
|
|
186
|
+
const dense = [];
|
|
187
|
+
for (const line of listed.split("\n")) {
|
|
188
|
+
const path = line.trim();
|
|
189
|
+
if (path.length === 0 || !judged(path))
|
|
190
|
+
continue;
|
|
191
|
+
const patch = read(["log", "-1", "--cc", "--pretty=format:", sha, "--", path]);
|
|
192
|
+
if (patch !== null && patch.trim().length > 0)
|
|
193
|
+
dense.push(path);
|
|
194
|
+
}
|
|
195
|
+
return dense;
|
|
196
|
+
}
|
|
197
|
+
export function commitGuardInputParts(read, commit) {
|
|
198
|
+
const parents = commit.parents;
|
|
199
|
+
const baseRev = parents !== undefined && parents.length === 0 ? null : `${commit.sha}^1`;
|
|
200
|
+
const blobCache = new Map();
|
|
201
|
+
const digestCache = new Map();
|
|
202
|
+
const inTree = (rev, path) => {
|
|
203
|
+
const listed = read(["ls-tree", "--name-only", rev, "--", path]);
|
|
204
|
+
return listed !== null && listed.trim().length > 0;
|
|
205
|
+
};
|
|
206
|
+
const show = (rev, path) => read(["show", `${rev}:${path}`]);
|
|
207
|
+
return {
|
|
208
|
+
blobsFor: (path) => {
|
|
209
|
+
const cached = blobCache.get(path);
|
|
210
|
+
if (cached !== undefined)
|
|
211
|
+
return cached;
|
|
212
|
+
const baseHas = baseRev !== null && inTree(baseRev, path);
|
|
213
|
+
const headHas = inTree(commit.sha, path);
|
|
214
|
+
const baseText = baseHas && baseRev !== null ? show(baseRev, path) : null;
|
|
215
|
+
const headText = headHas ? show(commit.sha, path) : null;
|
|
216
|
+
// A blob git cannot show, or one with a NUL byte in it, answers null and
|
|
217
|
+
// the guard fails the path `change-unreadable` rather than falling back
|
|
218
|
+
// to the path-level rule. The fallback is the hole (APRV-202).
|
|
219
|
+
const unreadable = (baseHas && baseText === null) ||
|
|
220
|
+
(headHas && headText === null) ||
|
|
221
|
+
(baseText !== null && baseText.includes("")) ||
|
|
222
|
+
(headText !== null && headText.includes(""));
|
|
223
|
+
const value = unreadable ? null : { base: baseText, head: headText };
|
|
224
|
+
blobCache.set(path, value);
|
|
225
|
+
return value;
|
|
226
|
+
},
|
|
227
|
+
sha256At: (path) => {
|
|
228
|
+
const cached = digestCache.get(path);
|
|
229
|
+
if (cached !== undefined)
|
|
230
|
+
return cached;
|
|
231
|
+
const blob = show(commit.sha, path);
|
|
232
|
+
const value = blob === null ? null : sha256Hex(blob);
|
|
233
|
+
digestCache.set(path, value);
|
|
234
|
+
return value;
|
|
235
|
+
},
|
|
236
|
+
changeTsFor: () => commit.ts,
|
|
237
|
+
window: {
|
|
238
|
+
base: baseRev === null ? "(root)" : `${commit.sha.slice(0, 12)}^1`,
|
|
239
|
+
head: commit.sha.slice(0, 12),
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* SHA-256 of any path's bytes AT ONE REVISION, cached.
|
|
245
|
+
*
|
|
246
|
+
* ## Why whole-file evidence is matched at the range head and not per commit
|
|
247
|
+
*
|
|
248
|
+
* The two kinds of evidence answer different questions, so they are anchored to
|
|
249
|
+
* different things:
|
|
250
|
+
*
|
|
251
|
+
* - A GRANT binds a hunk — a before-state, an after-state, a human who was
|
|
252
|
+
* shown them — so it is evidence about ONE COMMIT and is matched per commit,
|
|
253
|
+
* which is what APRV-375 is about.
|
|
254
|
+
* - A SIGN-OFF (`gate.path.signed_off`, APRV-338), an ORGAN attestation
|
|
255
|
+
* (`gate.organ.attested`, APRV-272) and the POLICY attestation
|
|
256
|
+
* (`policy.updated`) are whole-file records: a human read the file AS IT NOW
|
|
257
|
+
* STANDS and ratified those exact bytes. What they are about is the bytes the
|
|
258
|
+
* pull request INSTALLS, which is the blob at the range head.
|
|
259
|
+
*
|
|
260
|
+
* Matching them per commit would have quietly repealed the escape hatch. A
|
|
261
|
+
* two-commit branch whose first commit has no grant could no longer be rescued
|
|
262
|
+
* by a sign-off at head, because the intermediate blob is not the ratified one;
|
|
263
|
+
* a policy amendment split over two commits would fail on the first. So every
|
|
264
|
+
* commit in a range is offered the digests at the range head, whatever its own
|
|
265
|
+
* blob hashes to. The ordering APRV-338 asked for is untouched: the evaluator
|
|
266
|
+
* reaches the sign-off only after every grant search has failed, so hunk
|
|
267
|
+
* evidence still leads the reasons wherever it exists.
|
|
268
|
+
*/
|
|
269
|
+
export function digestsAt(read, rev) {
|
|
270
|
+
const cache = new Map();
|
|
271
|
+
return (path) => {
|
|
272
|
+
const cached = cache.get(path);
|
|
273
|
+
if (cached !== undefined)
|
|
274
|
+
return cached;
|
|
275
|
+
const blob = read(["show", `${rev}:${path}`]);
|
|
276
|
+
const value = blob === null ? null : sha256Hex(blob);
|
|
277
|
+
cache.set(path, value);
|
|
278
|
+
return value;
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Judge every commit of `base..head` on its own records, and report the
|
|
283
|
+
* conjunction.
|
|
284
|
+
*
|
|
285
|
+
* `evaluateProtectedPaths` is unchanged and is what decides each commit: this
|
|
286
|
+
* function chooses the unit and nothing else. A commit that changed no guarded
|
|
287
|
+
* path costs one evaluator call that finds nothing, and a clean merge costs no
|
|
288
|
+
* evaluator call at all.
|
|
289
|
+
*/
|
|
290
|
+
export function judgeCommits(options) {
|
|
291
|
+
const { read, base, head, shared } = options;
|
|
292
|
+
const empty = {
|
|
293
|
+
ok: false,
|
|
294
|
+
commits: [],
|
|
295
|
+
findings: [],
|
|
296
|
+
exempt: [],
|
|
297
|
+
window: shared.window,
|
|
298
|
+
};
|
|
299
|
+
const listed = listCommits(read, base, head, (path) => isJudgedPath(path, shared));
|
|
300
|
+
if (!listed.ok)
|
|
301
|
+
return { ...empty, unavailable: listed.message };
|
|
302
|
+
// Whole-file evidence is about the bytes this pull request INSTALLS, so it is
|
|
303
|
+
// matched at the RANGE head for every commit in the range. See {@link digestsAt}.
|
|
304
|
+
const atRangeHead = digestsAt(read, head);
|
|
305
|
+
const policySha256AtHead = atRangeHead(shared.policyPath);
|
|
306
|
+
const commits = [];
|
|
307
|
+
const findings = [];
|
|
308
|
+
const exempt = new Set();
|
|
309
|
+
for (const commit of listed.commits) {
|
|
310
|
+
const merge = isMerge(commit);
|
|
311
|
+
const baseRev = baseRevOf(commit);
|
|
312
|
+
if (commit.changedPaths.length === 0) {
|
|
313
|
+
commits.push({
|
|
314
|
+
sha: commit.sha,
|
|
315
|
+
base: baseRev,
|
|
316
|
+
merge,
|
|
317
|
+
judged: false,
|
|
318
|
+
skipped: merge ? "clean-merge" : "no-guarded-path",
|
|
319
|
+
ok: true,
|
|
320
|
+
findings: [],
|
|
321
|
+
exempt: [],
|
|
322
|
+
covered: [],
|
|
323
|
+
});
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const parts = commitGuardInputParts(read, commit);
|
|
327
|
+
const report = evaluateProtectedPaths({
|
|
328
|
+
...shared,
|
|
329
|
+
policySha256AtHead,
|
|
330
|
+
changedPaths: [...commit.changedPaths].sort(),
|
|
331
|
+
blobsFor: parts.blobsFor,
|
|
332
|
+
organSha256AtHead: atRangeHead,
|
|
333
|
+
pathSha256AtHead: atRangeHead,
|
|
334
|
+
changeTsFor: parts.changeTsFor,
|
|
335
|
+
window: { ...shared.window, base: parts.window.base, head: parts.window.head },
|
|
336
|
+
});
|
|
337
|
+
for (const path of report.exempt)
|
|
338
|
+
exempt.add(path);
|
|
339
|
+
for (const finding of report.findings)
|
|
340
|
+
findings.push({ ...finding, commit: commit.sha });
|
|
341
|
+
const covered = [];
|
|
342
|
+
for (const finding of report.findings) {
|
|
343
|
+
if (!finding.ok)
|
|
344
|
+
continue;
|
|
345
|
+
for (const seq of finding.coveredBy ?? (finding.seq === undefined ? [] : [finding.seq])) {
|
|
346
|
+
if (!covered.includes(seq))
|
|
347
|
+
covered.push(seq);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const nothingToJudge = report.findings.length === 0 && report.exempt.length === 0;
|
|
351
|
+
commits.push({
|
|
352
|
+
sha: commit.sha,
|
|
353
|
+
base: baseRev,
|
|
354
|
+
merge,
|
|
355
|
+
judged: !nothingToJudge,
|
|
356
|
+
skipped: nothingToJudge ? (merge ? "clean-merge" : "no-guarded-path") : null,
|
|
357
|
+
ok: report.ok,
|
|
358
|
+
findings: report.findings,
|
|
359
|
+
exempt: report.exempt,
|
|
360
|
+
covered,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
ok: commits.every((commit) => commit.ok),
|
|
365
|
+
commits,
|
|
366
|
+
findings,
|
|
367
|
+
exempt: [...exempt],
|
|
368
|
+
window: shared.window,
|
|
369
|
+
unavailable: null,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Would the guard have an opinion about this path?
|
|
374
|
+
*
|
|
375
|
+
* Only used to keep the merge pass cheap, so it is deliberately the PERMISSIVE
|
|
376
|
+
* side of the question: the policy's widening entries plus the built-in set,
|
|
377
|
+
* which is what `isGuardedPath` asks. A path this answers `true` for still has
|
|
378
|
+
* to earn its verdict from the evaluator.
|
|
379
|
+
*/
|
|
380
|
+
function isJudgedPath(path, shared) {
|
|
381
|
+
return isGuardedPath(path, shared.policyProtectedPaths);
|
|
382
|
+
}
|
|
383
|
+
/** The report as the lines CI prints. Pure. */
|
|
384
|
+
export function renderCommitGuardReport(report) {
|
|
385
|
+
const lines = [];
|
|
386
|
+
const judged = report.commits.filter((commit) => commit.judged);
|
|
387
|
+
lines.push(`protected-path guard: ${report.window.base}..${report.window.head}, judged one commit at a time (${String(report.commits.length)} commit(s) in the range, ${String(judged.length)} with a protected change)`);
|
|
388
|
+
if (report.unavailable !== null) {
|
|
389
|
+
lines.push(` the guard could not look: ${report.unavailable}`);
|
|
390
|
+
return `${lines.join("\n")}\n`;
|
|
391
|
+
}
|
|
392
|
+
if (report.exempt.length > 0) {
|
|
393
|
+
lines.push(` exempt (the daemon's own append surface, evidence rather than a protected write): ${report.exempt.join(", ")}`);
|
|
394
|
+
}
|
|
395
|
+
if (report.commits.length === 0) {
|
|
396
|
+
lines.push(" no commits in the range");
|
|
397
|
+
return `${lines.join("\n")}\n`;
|
|
398
|
+
}
|
|
399
|
+
for (const commit of report.commits) {
|
|
400
|
+
const sha = commit.sha.slice(0, 12);
|
|
401
|
+
const against = commit.base === null ? "a root commit" : `base ${sha}^1`;
|
|
402
|
+
if (!commit.judged) {
|
|
403
|
+
const why = commit.skipped === "clean-merge"
|
|
404
|
+
? "merge, and its result on every guarded path is one parent's bytes verbatim"
|
|
405
|
+
: "no protected path changed";
|
|
406
|
+
lines.push(` SKIP ${sha} (${against}): ${why}`);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
const covered = commit.covered.length === 0
|
|
410
|
+
? ""
|
|
411
|
+
: `, covered by seq ${commit.covered.slice(0, 8).join(", ")}${commit.covered.length > 8 ? ", …" : ""}`;
|
|
412
|
+
lines.push(` ${commit.ok ? "PASS" : "FAIL"} ${sha} (${against})${commit.merge ? ", merge resolution" : ""}${covered}`);
|
|
413
|
+
for (const finding of commit.findings) {
|
|
414
|
+
lines.push(finding.ok
|
|
415
|
+
? ` PASS ${finding.path} [${finding.evidence}]`
|
|
416
|
+
: ` FAIL ${finding.path} [${finding.code}]`);
|
|
417
|
+
lines.push(` ${finding.detail}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
if (judged.length === 0)
|
|
421
|
+
lines.push(" no protected paths changed");
|
|
422
|
+
return `${lines.join("\n")}\n`;
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=commit-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-guard.js","sourceRoot":"","sources":["../../../src/core/commit-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAUzC,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAElF,sCAAsC;AACtC,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjE,CAAC;AAgCD,8BAA8B;AAC9B,MAAM,UAAU,OAAO,CAAC,MAAoB;IAC1C,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,MAAoB;IAC5C,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,EAAE,GAAG,GAAG,CAAC;AACf,MAAM,EAAE,GAAG,GAAG,CAAC;AAEf,SAAS,OAAO,CAAC,MAA0B,EAAE,SAA6B;IACxE,MAAM,CAAC,GAAG,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,MAAM,CAAC,GAAG,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,WAAW,CACzB,IAAe,EACf,IAAY,EACZ,IAAY,EACZ,MAAiC;IAEjC,MAAM,GAAG,GAAG,IAAI,CAAC;QACf,KAAK;QACL,WAAW;QACX,mBAAmB,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;QAChD,aAAa;QACb,GAAG,IAAI,KAAK,IAAI,EAAE;KACnB,CAAC,CAAC;IACH,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,IAAI,KAAK,IAAI,WAAW,EAAE,CAAC;IACvE,CAAC;IAED,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,MAAM,KAAK,SAAS;YAAE,SAAS;QACnC,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7D,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACpD,MAAM,UAAU,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;aAC/B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrC,MAAM,MAAM,GAAiB;YAC3B,GAAG;YACH,OAAO,EAAE,UAAU;YACnB,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC;YAChC,4EAA4E;YAC5E,YAAY,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;SACpF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAe,EACf,GAAW,EACX,MAAiC;IAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC;IACjF,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,SAAS;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/E,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AA0BD,MAAM,UAAU,qBAAqB,CACnC,IAAe,EACf,MAA0E;IAE1E,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,MAAM,OAAO,GACX,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAC3E,MAAM,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;IACxD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;IAErD,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,IAAY,EAAW,EAAE;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACjE,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACrD,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,IAAY,EAAiB,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;IAE5F,OAAO;QACL,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;YACjB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,MAAM,CAAC;YACxC,MAAM,OAAO,GAAG,OAAO,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1E,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACzD,yEAAyE;YACzE,wEAAwE;YACxE,+DAA+D;YAC/D,MAAM,UAAU,GACd,CAAC,OAAO,IAAI,QAAQ,KAAK,IAAI,CAAC;gBAC9B,CAAC,OAAO,IAAI,QAAQ,KAAK,IAAI,CAAC;gBAC9B,CAAC,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAC7C,CAAC,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAChD,MAAM,KAAK,GAAuB,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YACzF,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC3B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;YACjB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,MAAM,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACpC,MAAM,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACrD,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE;QAC5B,MAAM,EAAE;YACN,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI;YAClE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SAC9B;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,SAAS,CAAC,IAAe,EAAE,GAAW;IACpD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC/C,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC;AAmDD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAK5B;IACC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,KAAK,GAAG;QACZ,EAAE,EAAE,KAAK;QACT,OAAO,EAAE,EAAqB;QAC9B,QAAQ,EAAE,EAAqB;QAC/B,MAAM,EAAE,EAAc;QACtB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;IACF,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CACpD,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAC3B,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAEjE,8EAA8E;IAC9E,kFAAkF;IAClF,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC;gBACX,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,IAAI,EAAE,OAAO;gBACb,KAAK;gBACL,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB;gBAClD,EAAE,EAAE,IAAI;gBACR,QAAQ,EAAE,EAAE;gBACZ,MAAM,EAAE,EAAE;gBACV,OAAO,EAAE,EAAE;aACZ,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,MAAM,GAAgB,sBAAsB,CAAC;YACjD,GAAG,MAAM;YACT,kBAAkB;YAClB,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE;YAC7C,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,iBAAiB,EAAE,WAAW;YAC9B,gBAAgB,EAAE,WAAW;YAC7B,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,MAAM,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;SAC/E,CAAC,CAAC;QACH,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;QACzF,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,EAAE;gBAAE,SAAS;YAC1B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACxF,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QACD,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;QAClF,OAAO,CAAC,IAAI,CAAC;YACX,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,IAAI,EAAE,OAAO;YACb,KAAK;YACL,MAAM,EAAE,CAAC,cAAc;YACvB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI;YAC5E,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,OAAO;QACP,QAAQ;QACR,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,MAAwB;IAC1D,OAAO,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC;AAC1D,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,uBAAuB,CAAC,MAAyB;IAC/D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CACR,yBAAyB,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,kCAAkC,MAAM,CACxG,MAAM,CAAC,OAAO,CAAC,MAAM,CACtB,4BAA4B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,2BAA2B,CAC9E,CAAC;IACF,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,+BAA+B,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QAChE,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CACR,uFAAuF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClH,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACxC,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC;QACzE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,GAAG,GACP,MAAM,CAAC,OAAO,KAAK,aAAa;gBAC9B,CAAC,CAAC,4EAA4E;gBAC9E,CAAC,CAAC,2BAA2B,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,OAAO,MAAM,GAAG,EAAE,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GACX,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YACzB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,oBAAoB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GACvD,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EACtC,EAAE,CAAC;QACT,KAAK,CAAC,IAAI,CACR,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAC5G,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CACR,OAAO,CAAC,EAAE;gBACR,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,GAAG;gBAClD,CAAC,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,GAAG,CACjD,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACpE,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adapter coverage source (APRV-245).
|
|
3
|
+
*
|
|
4
|
+
* The other two sources read a repository. This one asks the PROVIDER what it
|
|
5
|
+
* recorded: AgentMail knows which messages an inbox actually sent, and that
|
|
6
|
+
* record is written by neither the agent nor this runtime. An adapter that
|
|
7
|
+
* implements the optional `observe` (see `adapters/contract.ts`) publishes that
|
|
8
|
+
* knowledge, and an adapter that does not is reported as offering none rather
|
|
9
|
+
* than as having seen nothing.
|
|
10
|
+
*
|
|
11
|
+
* ## What this source guarantees about the call
|
|
12
|
+
*
|
|
13
|
+
* - **Read-only, and outside any grant window.** `observe` is never handed a
|
|
14
|
+
* token, never called from inside `executeThroughAdapter`, and is documented
|
|
15
|
+
* in the contract as a read. A coverage report that could send would be a
|
|
16
|
+
* report nobody dares run.
|
|
17
|
+
* - **The caller redacts.** An adapter's answer can quote whatever its far side
|
|
18
|
+
* said, so every `detail` goes through {@link redactSecrets} against the
|
|
19
|
+
* secrets the caller knows before it is returned. The adapter scrubs its own
|
|
20
|
+
* strings too; this is the second pass, on the principle that redaction is
|
|
21
|
+
* cheap and a leak is not (SPEC.md §11.1 invariant 3).
|
|
22
|
+
* - **A throw is a source failure, not a crash.** An adapter whose far side is
|
|
23
|
+
* down makes its own source unavailable and leaves every other source's
|
|
24
|
+
* answer intact.
|
|
25
|
+
*/
|
|
26
|
+
import { type Adapter, type CredentialProvider } from "../../adapters/contract.js";
|
|
27
|
+
import type { ObservationWindow } from "../coverage.js";
|
|
28
|
+
import type { SourceObservation } from "./git.js";
|
|
29
|
+
export interface AdapterSourceOptions {
|
|
30
|
+
/** Values to scrub out of every returned detail. */
|
|
31
|
+
secrets?: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Ask one adapter what its provider recorded in `window`.
|
|
35
|
+
*
|
|
36
|
+
* An adapter with no `observe` is `available: false` with a reason that names
|
|
37
|
+
* the gap honestly: this adapter offers no observation, so the runtime cannot
|
|
38
|
+
* say whether effects of its class happened outside the gate.
|
|
39
|
+
*/
|
|
40
|
+
export declare function observeAdapter(adapter: Adapter, window: ObservationWindow, credentials: CredentialProvider, options?: AdapterSourceOptions): Promise<SourceObservation>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GitHub coverage source (APRV-245).
|
|
3
|
+
*
|
|
4
|
+
* A pull request is an effect with a witness this project does not write:
|
|
5
|
+
* GitHub recorded who opened it and when, and GitHub recorded the merge that
|
|
6
|
+
* moved the trunk. `gh pr list --json` reads both back, and neither number can
|
|
7
|
+
* be edited by an agent editing its own log.
|
|
8
|
+
*
|
|
9
|
+
* ## Absent is reported, never inferred
|
|
10
|
+
*
|
|
11
|
+
* `gh` is optional and unauthenticated checkouts are ordinary, so an absent or
|
|
12
|
+
* refusing `gh` produces `available: false` with the reason and NO effects. That
|
|
13
|
+
* distinction is the whole reliability of the report: "gh saw no pull requests"
|
|
14
|
+
* and "gh could not be asked" are different facts, and collapsing them into an
|
|
15
|
+
* empty list would let a broken CLI read as a clean bill of health.
|
|
16
|
+
*
|
|
17
|
+
* ## The class mapping
|
|
18
|
+
*
|
|
19
|
+
* - opening a pull request is `vcs.pr.open`, the class `core/command-class.ts`
|
|
20
|
+
* gives `gh pr create`;
|
|
21
|
+
* - merging one is `vcs.push.main`, the class it gives `gh pr merge`, because
|
|
22
|
+
* what a merge does is move the trunk.
|
|
23
|
+
*
|
|
24
|
+
* A pull request that was opened and merged inside the window produces TWO
|
|
25
|
+
* effects, because they are two decisions a policy answers separately and each
|
|
26
|
+
* needs its own evidence.
|
|
27
|
+
*
|
|
28
|
+
* Nothing here reads the clock: the window comes from the caller and every
|
|
29
|
+
* timestamp is GitHub's own.
|
|
30
|
+
*/
|
|
31
|
+
import { type SourceObservation } from "./git.js";
|
|
32
|
+
/** How many pull requests one run asks for. `gh` caps at 1000; this is plenty. */
|
|
33
|
+
export declare const GH_PR_LIMIT = 100;
|
|
34
|
+
export interface GhSourceOptions {
|
|
35
|
+
/** Inclusive lower bound of the window, RFC 3339. */
|
|
36
|
+
since: string;
|
|
37
|
+
/** Inclusive upper bound, RFC 3339. */
|
|
38
|
+
until: string;
|
|
39
|
+
/** Override {@link GH_PR_LIMIT}. */
|
|
40
|
+
limit?: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* What GitHub witnessed in the window.
|
|
44
|
+
*
|
|
45
|
+
* Never throws. `gh` that is not installed, not authenticated, or pointed at a
|
|
46
|
+
* directory with no remote all come back as `available: false`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function observeGh(root: string, options: GhSourceOptions): SourceObservation;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The git coverage source (APRV-245).
|
|
3
|
+
*
|
|
4
|
+
* Git history is the cheapest witness this project has that it does not write:
|
|
5
|
+
* a commit, a merge into the trunk and a tag are all effects an agent produced,
|
|
6
|
+
* all recorded by a tool with no idea approval.md exists, and all readable back
|
|
7
|
+
* long after the session that made them is gone.
|
|
8
|
+
*
|
|
9
|
+
* **Never the working tree.** Every fact here comes from `git log`, `git show`
|
|
10
|
+
* and `git for-each-ref` over committed objects. An uncommitted edit is not an
|
|
11
|
+
* effect yet — it is a file a person can still delete — and reading the tree
|
|
12
|
+
* would make the report depend on whatever happened to be lying around when it
|
|
13
|
+
* ran, which is the opposite of the determinism a witness needs.
|
|
14
|
+
*
|
|
15
|
+
* ## The class mapping
|
|
16
|
+
*
|
|
17
|
+
* The classes are SPEC.md §7's own, spelled as `core/command-class.ts` spells
|
|
18
|
+
* them, because a source that invented a class would produce effects no record
|
|
19
|
+
* could ever match:
|
|
20
|
+
*
|
|
21
|
+
* - a commit REACHABLE FROM `origin/main` is `vcs.push.main`. What the class
|
|
22
|
+
* names is the trunk moving, and a commit on the trunk moved it however it
|
|
23
|
+
* got there (a merge, a fast-forward, a direct push);
|
|
24
|
+
* - a commit the trunk does not reach but SOME remote-tracking ref does
|
|
25
|
+
* (`refs/remotes/*`) is `vcs.push.branch`, which is the class the classifier
|
|
26
|
+
* gives `git push origin <branch>`: the commit left the machine, and the
|
|
27
|
+
* action a task declares for that is the push, never the commit;
|
|
28
|
+
* - any other commit in the range is `vcs.commit.branch`, which is the class the
|
|
29
|
+
* classifier gives a bare `git commit`: it exists only here;
|
|
30
|
+
* - a tag is `release.publish`, which is the class the classifier gives
|
|
31
|
+
* `git tag`;
|
|
32
|
+
* - a protected path a commit changed is `policy.edit`, reported as its own
|
|
33
|
+
* effect carrying the `path`, so `core/coverage.ts` can put the
|
|
34
|
+
* protected-path guard's byte-level verdict against it rather than the
|
|
35
|
+
* class-and-window rule.
|
|
36
|
+
*
|
|
37
|
+
* A merge commit is a `vcs.push.main` like any other trunk commit and says so in
|
|
38
|
+
* its detail line; it is not given a class of its own, because the policy has
|
|
39
|
+
* none for it and an effect nobody can declare is an effect nothing can cover.
|
|
40
|
+
*
|
|
41
|
+
* Nothing here reads the clock: every timestamp is git's author date for the
|
|
42
|
+
* object being reported.
|
|
43
|
+
*/
|
|
44
|
+
import { type ProtectedPathEntry } from "../command-class.js";
|
|
45
|
+
import type { ObservedEffect } from "../coverage.js";
|
|
46
|
+
/** The result of asking one source what it saw. */
|
|
47
|
+
export interface SourceObservation {
|
|
48
|
+
name: string;
|
|
49
|
+
available: boolean;
|
|
50
|
+
/** Why it is unavailable, or what qualifies an available answer. */
|
|
51
|
+
reason?: string;
|
|
52
|
+
effects: ObservedEffect[];
|
|
53
|
+
}
|
|
54
|
+
/** The default trunk ref. Overridable so a fork with another name still reports. */
|
|
55
|
+
export declare const DEFAULT_TRUNK_REF = "origin/main";
|
|
56
|
+
/**
|
|
57
|
+
* How many commits one run will describe.
|
|
58
|
+
*
|
|
59
|
+
* A bound rather than a stream, because each commit costs one `git show` for
|
|
60
|
+
* its changed paths and an unbounded range would turn a reporting verb into a
|
|
61
|
+
* repository walk. A truncated run says so in the source's `reason`, so the
|
|
62
|
+
* number is never quietly wrong.
|
|
63
|
+
*/
|
|
64
|
+
export declare const MAX_COMMITS = 200;
|
|
65
|
+
export interface GitSourceOptions {
|
|
66
|
+
/** Exclusive lower bound of the commit range. */
|
|
67
|
+
base: string;
|
|
68
|
+
/** Inclusive upper bound. */
|
|
69
|
+
head: string;
|
|
70
|
+
/** The ref that decides `vcs.push.main`. Defaults to {@link DEFAULT_TRUNK_REF}. */
|
|
71
|
+
trunk?: string;
|
|
72
|
+
/** `policy.protected_paths` from the policy, widening the built-in set. */
|
|
73
|
+
policyProtectedPaths?: readonly ProtectedPathEntry[];
|
|
74
|
+
/** Override {@link MAX_COMMITS}. */
|
|
75
|
+
maxCommits?: number;
|
|
76
|
+
}
|
|
77
|
+
/** The first non-empty line of whatever a failed command printed. */
|
|
78
|
+
export declare function firstLine(text: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* What git witnessed between `base` and `head`.
|
|
81
|
+
*
|
|
82
|
+
* Never throws: a directory that is not a repository, a ref that does not
|
|
83
|
+
* resolve and an absent git all come back as `available: false` with the reason
|
|
84
|
+
* git printed. A reporting verb that crashed on a checkout without a remote
|
|
85
|
+
* would be a verb people stop running.
|
|
86
|
+
*/
|
|
87
|
+
export declare function observeGit(root: string, options: GitSourceOptions): SourceObservation;
|
|
88
|
+
/**
|
|
89
|
+
* The default commit range: `merge-base <trunk> HEAD`, falling back to `HEAD~20`.
|
|
90
|
+
*
|
|
91
|
+
* The fallback is announced rather than silent. A checkout with no `origin/main`
|
|
92
|
+
* (a fresh clone of a fork, a fixture repository, a detached CI checkout) has no
|
|
93
|
+
* merge base to take, and a range of "the last twenty commits" is a guess; a
|
|
94
|
+
* reader has to be able to see that the answer they are looking at came from a
|
|
95
|
+
* guess and not from the trunk.
|
|
96
|
+
*/
|
|
97
|
+
export declare function defaultRange(root: string, trunk?: string): {
|
|
98
|
+
base: string;
|
|
99
|
+
head: string;
|
|
100
|
+
note?: string;
|
|
101
|
+
};
|