approval-md 0.0.1 → 0.2.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/LICENSE +176 -0
- package/NOTICE +5 -0
- package/README.md +940 -4
- package/SPEC.md +476 -34
- package/cli.js +29 -3
- package/dist/src/adapters/agentmail.d.ts +426 -0
- package/dist/src/adapters/agentmail.js +1200 -0
- package/dist/src/adapters/agentmail.js.map +1 -0
- package/dist/src/adapters/conformance.d.ts +149 -0
- package/dist/src/adapters/conformance.js +461 -0
- package/dist/src/adapters/conformance.js.map +1 -0
- package/dist/src/adapters/contract.d.ts +628 -0
- package/dist/src/adapters/contract.js +1035 -0
- package/dist/src/adapters/contract.js.map +1 -0
- package/dist/src/adapters/email.d.ts +324 -0
- package/dist/src/adapters/email.js +749 -0
- package/dist/src/adapters/email.js.map +1 -0
- package/dist/src/adapters/env-passphrase.d.ts +93 -0
- package/dist/src/adapters/env-passphrase.js +132 -0
- package/dist/src/adapters/env-passphrase.js.map +1 -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 +77 -0
- package/dist/src/adapters/registry.js.map +1 -0
- package/dist/src/adapters/smtp.d.ts +213 -0
- package/dist/src/adapters/smtp.js +499 -0
- package/dist/src/adapters/smtp.js.map +1 -0
- package/dist/src/adapters/vault-provider.d.ts +114 -0
- package/dist/src/adapters/vault-provider.js +161 -0
- package/dist/src/adapters/vault-provider.js.map +1 -0
- 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/batch.js +121 -0
- package/dist/src/channels/batch.js.map +1 -0
- package/dist/src/channels/cli.d.ts +193 -0
- package/dist/src/channels/cli.js +468 -0
- package/dist/src/channels/cli.js.map +1 -0
- package/dist/src/channels/conformance.d.ts +92 -0
- package/dist/src/channels/conformance.js +445 -0
- package/dist/src/channels/conformance.js.map +1 -0
- package/dist/src/channels/contract.d.ts +623 -0
- package/dist/src/channels/contract.js +494 -0
- package/dist/src/channels/contract.js.map +1 -0
- package/dist/src/channels/payload-view.d.ts +35 -0
- package/dist/src/channels/payload-view.js +43 -0
- package/dist/src/channels/payload-view.js.map +1 -0
- package/dist/src/channels/render-queue.d.ts +149 -0
- package/dist/src/channels/render-queue.js +564 -0
- package/dist/src/channels/render-queue.js.map +1 -0
- package/dist/src/channels/tagging.d.ts +196 -0
- package/dist/src/channels/tagging.js +723 -0
- package/dist/src/channels/tagging.js.map +1 -0
- package/dist/src/channels/telegram.d.ts +1832 -0
- package/dist/src/channels/telegram.js +3190 -0
- package/dist/src/channels/telegram.js.map +1 -0
- package/dist/src/channels/web.d.ts +341 -0
- package/dist/src/channels/web.js +903 -0
- package/dist/src/channels/web.js.map +1 -0
- package/dist/src/cli/adapter.d.ts +90 -0
- package/dist/src/cli/adapter.js +288 -0
- package/dist/src/cli/adapter.js.map +1 -0
- package/dist/src/cli/amend.d.ts +59 -0
- package/dist/src/cli/amend.js +2171 -0
- package/dist/src/cli/amend.js.map +1 -0
- package/dist/src/cli/args.d.ts +43 -0
- package/dist/src/cli/args.js +86 -0
- package/dist/src/cli/args.js.map +1 -0
- package/dist/src/cli/attest.d.ts +41 -0
- package/dist/src/cli/attest.js +307 -0
- package/dist/src/cli/attest.js.map +1 -0
- package/dist/src/cli/audit-card.d.ts +62 -0
- package/dist/src/cli/audit-card.js +201 -0
- package/dist/src/cli/audit-card.js.map +1 -0
- package/dist/src/cli/audit.d.ts +59 -0
- package/dist/src/cli/audit.js +460 -0
- package/dist/src/cli/audit.js.map +1 -0
- package/dist/src/cli/channel-telegram.d.ts +806 -0
- package/dist/src/cli/channel-telegram.js +2063 -0
- package/dist/src/cli/channel-telegram.js.map +1 -0
- package/dist/src/cli/channel-web.d.ts +131 -0
- package/dist/src/cli/channel-web.js +357 -0
- package/dist/src/cli/channel-web.js.map +1 -0
- package/dist/src/cli/channel.d.ts +71 -0
- package/dist/src/cli/channel.js +438 -0
- package/dist/src/cli/channel.js.map +1 -0
- package/dist/src/cli/checkpoint-tap.d.ts +169 -0
- package/dist/src/cli/checkpoint-tap.js +238 -0
- package/dist/src/cli/checkpoint-tap.js.map +1 -0
- package/dist/src/cli/codex.d.ts +2 -0
- package/dist/src/cli/codex.js +172 -0
- package/dist/src/cli/codex.js.map +1 -0
- package/dist/src/cli/coverage.d.ts +61 -0
- package/dist/src/cli/coverage.js +343 -0
- package/dist/src/cli/coverage.js.map +1 -0
- package/dist/src/cli/daemon.d.ts +120 -0
- package/dist/src/cli/daemon.js +631 -0
- package/dist/src/cli/daemon.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +129 -0
- package/dist/src/cli/doctor.js +2762 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/env.d.ts +65 -0
- package/dist/src/cli/env.js +302 -0
- package/dist/src/cli/env.js.map +1 -0
- package/dist/src/cli/execute.d.ts +202 -0
- package/dist/src/cli/execute.js +1682 -0
- package/dist/src/cli/execute.js.map +1 -0
- package/dist/src/cli/exit-codes.d.ts +73 -0
- package/dist/src/cli/exit-codes.js +82 -0
- package/dist/src/cli/exit-codes.js.map +1 -0
- package/dist/src/cli/feedback.d.ts +60 -0
- package/dist/src/cli/feedback.js +205 -0
- package/dist/src/cli/feedback.js.map +1 -0
- package/dist/src/cli/gate-window.d.ts +40 -0
- package/dist/src/cli/gate-window.js +294 -0
- package/dist/src/cli/gate-window.js.map +1 -0
- package/dist/src/cli/gate.d.ts +68 -0
- package/dist/src/cli/gate.js +557 -0
- package/dist/src/cli/gate.js.map +1 -0
- package/dist/src/cli/git-scope.d.ts +190 -0
- package/dist/src/cli/git-scope.js +295 -0
- package/dist/src/cli/git-scope.js.map +1 -0
- package/dist/src/cli/gloss-attach.d.ts +85 -0
- package/dist/src/cli/gloss-attach.js +107 -0
- package/dist/src/cli/gloss-attach.js.map +1 -0
- package/dist/src/cli/gloss-codex-child.d.ts +9 -0
- package/dist/src/cli/gloss-codex-child.js +149 -0
- package/dist/src/cli/gloss-codex-child.js.map +1 -0
- package/dist/src/cli/gloss-codex.d.ts +24 -0
- package/dist/src/cli/gloss-codex.js +255 -0
- package/dist/src/cli/gloss-codex.js.map +1 -0
- package/dist/src/cli/gloss-options.d.ts +42 -0
- package/dist/src/cli/gloss-options.js +79 -0
- package/dist/src/cli/gloss-options.js.map +1 -0
- package/dist/src/cli/gloss.d.ts +265 -0
- package/dist/src/cli/gloss.js +362 -0
- package/dist/src/cli/gloss.js.map +1 -0
- package/dist/src/cli/help.d.ts +103 -0
- package/dist/src/cli/help.js +2339 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/hook-codex.d.ts +78 -0
- package/dist/src/cli/hook-codex.js +167 -0
- package/dist/src/cli/hook-codex.js.map +1 -0
- package/dist/src/cli/hook.d.ts +331 -0
- package/dist/src/cli/hook.js +2849 -0
- package/dist/src/cli/hook.js.map +1 -0
- package/dist/src/cli/import.d.ts +35 -0
- package/dist/src/cli/import.js +175 -0
- package/dist/src/cli/import.js.map +1 -0
- package/dist/src/cli/init.d.ts +84 -0
- package/dist/src/cli/init.js +336 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/instructions.d.ts +23 -0
- package/dist/src/cli/instructions.js +262 -0
- package/dist/src/cli/instructions.js.map +1 -0
- package/dist/src/cli/journal.d.ts +41 -0
- package/dist/src/cli/journal.js +238 -0
- package/dist/src/cli/journal.js.map +1 -0
- package/dist/src/cli/log-advance.d.ts +287 -0
- package/dist/src/cli/log-advance.js +840 -0
- package/dist/src/cli/log-advance.js.map +1 -0
- package/dist/src/cli/log-anchor.d.ts +176 -0
- package/dist/src/cli/log-anchor.js +387 -0
- package/dist/src/cli/log-anchor.js.map +1 -0
- package/dist/src/cli/log-checkpoint.d.ts +22 -0
- package/dist/src/cli/log-checkpoint.js +128 -0
- package/dist/src/cli/log-checkpoint.js.map +1 -0
- package/dist/src/cli/log-sync.d.ts +243 -0
- package/dist/src/cli/log-sync.js +849 -0
- package/dist/src/cli/log-sync.js.map +1 -0
- package/dist/src/cli/log-verbs.d.ts +16 -0
- package/dist/src/cli/log-verbs.js +360 -0
- package/dist/src/cli/log-verbs.js.map +1 -0
- package/dist/src/cli/long-help.d.ts +70 -0
- package/dist/src/cli/long-help.js +148 -0
- package/dist/src/cli/long-help.js.map +1 -0
- package/dist/src/cli/main.d.ts +77 -0
- package/dist/src/cli/main.js +1206 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/mcp.d.ts +52 -0
- package/dist/src/cli/mcp.js +306 -0
- package/dist/src/cli/mcp.js.map +1 -0
- package/dist/src/cli/paths.d.ts +56 -0
- package/dist/src/cli/paths.js +79 -0
- package/dist/src/cli/paths.js.map +1 -0
- package/dist/src/cli/payload.d.ts +58 -0
- package/dist/src/cli/payload.js +253 -0
- package/dist/src/cli/payload.js.map +1 -0
- package/dist/src/cli/policy.d.ts +43 -0
- package/dist/src/cli/policy.js +229 -0
- package/dist/src/cli/policy.js.map +1 -0
- package/dist/src/cli/preflight.d.ts +363 -0
- package/dist/src/cli/preflight.js +1175 -0
- package/dist/src/cli/preflight.js.map +1 -0
- package/dist/src/cli/progress.d.ts +78 -0
- package/dist/src/cli/progress.js +112 -0
- package/dist/src/cli/progress.js.map +1 -0
- package/dist/src/cli/prompt.d.ts +209 -0
- package/dist/src/cli/prompt.js +312 -0
- package/dist/src/cli/prompt.js.map +1 -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/records.js +66 -0
- package/dist/src/cli/records.js.map +1 -0
- package/dist/src/cli/render.d.ts +22 -0
- package/dist/src/cli/render.js +132 -0
- package/dist/src/cli/render.js.map +1 -0
- package/dist/src/cli/sandbox.d.ts +51 -0
- package/dist/src/cli/sandbox.js +150 -0
- package/dist/src/cli/sandbox.js.map +1 -0
- package/dist/src/cli/scaffold.d.ts +79 -0
- package/dist/src/cli/scaffold.js +137 -0
- package/dist/src/cli/scaffold.js.map +1 -0
- package/dist/src/cli/setup-adapter.d.ts +137 -0
- package/dist/src/cli/setup-adapter.js +509 -0
- package/dist/src/cli/setup-adapter.js.map +1 -0
- package/dist/src/cli/setup-channel.d.ts +117 -0
- package/dist/src/cli/setup-channel.js +635 -0
- package/dist/src/cli/setup-channel.js.map +1 -0
- package/dist/src/cli/setup-checkpoint.d.ts +57 -0
- package/dist/src/cli/setup-checkpoint.js +196 -0
- package/dist/src/cli/setup-checkpoint.js.map +1 -0
- package/dist/src/cli/setup-common.d.ts +275 -0
- package/dist/src/cli/setup-common.js +376 -0
- package/dist/src/cli/setup-common.js.map +1 -0
- package/dist/src/cli/setup-flow.d.ts +287 -0
- package/dist/src/cli/setup-flow.js +476 -0
- package/dist/src/cli/setup-flow.js.map +1 -0
- package/dist/src/cli/setup-service.d.ts +96 -0
- package/dist/src/cli/setup-service.js +308 -0
- package/dist/src/cli/setup-service.js.map +1 -0
- package/dist/src/cli/setup.d.ts +202 -0
- package/dist/src/cli/setup.js +473 -0
- package/dist/src/cli/setup.js.map +1 -0
- package/dist/src/cli/style.d.ts +320 -0
- package/dist/src/cli/style.js +469 -0
- package/dist/src/cli/style.js.map +1 -0
- package/dist/src/cli/token.d.ts +39 -0
- package/dist/src/cli/token.js +274 -0
- package/dist/src/cli/token.js.map +1 -0
- package/dist/src/cli/up.d.ts +155 -0
- package/dist/src/cli/up.js +849 -0
- package/dist/src/cli/up.js.map +1 -0
- package/dist/src/cli/usage.d.ts +37 -0
- package/dist/src/cli/usage.js +91 -0
- package/dist/src/cli/usage.js.map +1 -0
- package/dist/src/cli/values.d.ts +40 -0
- package/dist/src/cli/values.js +189 -0
- package/dist/src/cli/values.js.map +1 -0
- package/dist/src/cli/vault.d.ts +59 -0
- package/dist/src/cli/vault.js +362 -0
- package/dist/src/cli/vault.js.map +1 -0
- package/dist/src/cli/verb-registry.d.ts +76 -0
- package/dist/src/cli/verb-registry.js +2341 -0
- package/dist/src/cli/verb-registry.js.map +1 -0
- package/dist/src/cli/wordmark.d.ts +31 -0
- package/dist/src/cli/wordmark.js +52 -0
- package/dist/src/cli/wordmark.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/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-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 +170 -0
- package/dist/src/core/advance-cycle.js +200 -0
- package/dist/src/core/advance-cycle.js.map +1 -0
- package/dist/src/core/agents-md.d.ts +276 -0
- package/dist/src/core/agents-md.js +747 -0
- package/dist/src/core/agents-md.js.map +1 -0
- 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 +420 -0
- package/dist/src/core/attest.js +589 -0
- package/dist/src/core/attest.js.map +1 -0
- package/dist/src/core/audit.d.ts +492 -0
- package/dist/src/core/audit.js +882 -0
- package/dist/src/core/audit.js.map +1 -0
- package/dist/src/core/budgets.d.ts +238 -0
- package/dist/src/core/budgets.js +449 -0
- package/dist/src/core/budgets.js.map +1 -0
- package/dist/src/core/checkpoint.d.ts +500 -0
- package/dist/src/core/checkpoint.js +738 -0
- package/dist/src/core/checkpoint.js.map +1 -0
- package/dist/src/core/child-env.d.ts +88 -0
- package/dist/src/core/child-env.js +86 -0
- package/dist/src/core/child-env.js.map +1 -0
- package/dist/src/core/clock.d.ts +52 -0
- package/dist/src/core/clock.js +43 -0
- package/dist/src/core/clock.js.map +1 -0
- package/dist/src/core/command-class.d.ts +543 -0
- package/dist/src/core/command-class.js +2356 -0
- package/dist/src/core/command-class.js.map +1 -0
- package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
- package/dist/src/core/coverage-sources/adapter.js +71 -0
- package/dist/src/core/coverage-sources/adapter.js.map +1 -0
- package/dist/src/core/coverage-sources/gh.d.ts +48 -0
- package/dist/src/core/coverage-sources/gh.js +136 -0
- package/dist/src/core/coverage-sources/gh.js.map +1 -0
- package/dist/src/core/coverage-sources/git.d.ts +101 -0
- package/dist/src/core/coverage-sources/git.js +269 -0
- package/dist/src/core/coverage-sources/git.js.map +1 -0
- package/dist/src/core/coverage.d.ts +217 -0
- package/dist/src/core/coverage.js +337 -0
- package/dist/src/core/coverage.js.map +1 -0
- package/dist/src/core/credential-spec.d.ts +72 -0
- package/dist/src/core/credential-spec.js +23 -0
- package/dist/src/core/credential-spec.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +331 -0
- package/dist/src/core/dark-session.js +714 -0
- package/dist/src/core/dark-session.js.map +1 -0
- package/dist/src/core/decision-refusal.d.ts +185 -0
- package/dist/src/core/decision-refusal.js +265 -0
- package/dist/src/core/decision-refusal.js.map +1 -0
- package/dist/src/core/env-file.d.ts +450 -0
- package/dist/src/core/env-file.js +837 -0
- package/dist/src/core/env-file.js.map +1 -0
- package/dist/src/core/execute.d.ts +858 -0
- package/dist/src/core/execute.js +1271 -0
- package/dist/src/core/execute.js.map +1 -0
- package/dist/src/core/frontmatter.d.ts +78 -0
- package/dist/src/core/frontmatter.js +100 -0
- package/dist/src/core/frontmatter.js.map +1 -0
- package/dist/src/core/gate-window.d.ts +312 -0
- package/dist/src/core/gate-window.js +506 -0
- package/dist/src/core/gate-window.js.map +1 -0
- package/dist/src/core/gate.d.ts +1364 -0
- package/dist/src/core/gate.js +3002 -0
- package/dist/src/core/gate.js.map +1 -0
- package/dist/src/core/git-run.d.ts +73 -0
- package/dist/src/core/git-run.js +93 -0
- package/dist/src/core/git-run.js.map +1 -0
- package/dist/src/core/harness-version.d.ts +157 -0
- package/dist/src/core/harness-version.js +211 -0
- package/dist/src/core/harness-version.js.map +1 -0
- package/dist/src/core/harness-wait.d.ts +55 -0
- package/dist/src/core/harness-wait.js +58 -0
- package/dist/src/core/harness-wait.js.map +1 -0
- package/dist/src/core/head-retry.d.ts +107 -0
- package/dist/src/core/head-retry.js +121 -0
- package/dist/src/core/head-retry.js.map +1 -0
- package/dist/src/core/instance.d.ts +253 -0
- package/dist/src/core/instance.js +319 -0
- package/dist/src/core/instance.js.map +1 -0
- package/dist/src/core/intake-limits.d.ts +247 -0
- package/dist/src/core/intake-limits.js +350 -0
- package/dist/src/core/intake-limits.js.map +1 -0
- package/dist/src/core/jcs.d.ts +52 -0
- package/dist/src/core/jcs.js +132 -0
- package/dist/src/core/jcs.js.map +1 -0
- package/dist/src/core/journal.d.ts +144 -0
- package/dist/src/core/journal.js +200 -0
- package/dist/src/core/journal.js.map +1 -0
- package/dist/src/core/live-draw.d.ts +436 -0
- package/dist/src/core/live-draw.js +703 -0
- package/dist/src/core/live-draw.js.map +1 -0
- package/dist/src/core/log-reconcile.d.ts +89 -0
- package/dist/src/core/log-reconcile.js +136 -0
- package/dist/src/core/log-reconcile.js.map +1 -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 +278 -0
- package/dist/src/core/log.js +546 -0
- package/dist/src/core/log.js.map +1 -0
- package/dist/src/core/loop.d.ts +274 -0
- package/dist/src/core/loop.js +487 -0
- package/dist/src/core/loop.js.map +1 -0
- package/dist/src/core/md-fence.d.ts +41 -0
- package/dist/src/core/md-fence.js +74 -0
- package/dist/src/core/md-fence.js.map +1 -0
- package/dist/src/core/money.d.ts +147 -0
- package/dist/src/core/money.js +195 -0
- package/dist/src/core/money.js.map +1 -0
- package/dist/src/core/payload-census.d.ts +74 -0
- package/dist/src/core/payload-census.js +146 -0
- package/dist/src/core/payload-census.js.map +1 -0
- package/dist/src/core/payload-store.d.ts +175 -0
- package/dist/src/core/payload-store.js +340 -0
- package/dist/src/core/payload-store.js.map +1 -0
- package/dist/src/core/payload.d.ts +71 -0
- package/dist/src/core/payload.js +80 -0
- package/dist/src/core/payload.js.map +1 -0
- package/dist/src/core/policy-diff.d.ts +292 -0
- package/dist/src/core/policy-diff.js +588 -0
- package/dist/src/core/policy-diff.js.map +1 -0
- package/dist/src/core/policy-expectations.d.ts +199 -0
- package/dist/src/core/policy-expectations.js +394 -0
- package/dist/src/core/policy-expectations.js.map +1 -0
- package/dist/src/core/policy-explain.d.ts +150 -0
- package/dist/src/core/policy-explain.js +258 -0
- package/dist/src/core/policy-explain.js.map +1 -0
- package/dist/src/core/policy-load.d.ts +527 -0
- package/dist/src/core/policy-load.js +536 -0
- package/dist/src/core/policy-load.js.map +1 -0
- package/dist/src/core/policy-match.d.ts +281 -0
- package/dist/src/core/policy-match.js +478 -0
- package/dist/src/core/policy-match.js.map +1 -0
- package/dist/src/core/policy-proposal.d.ts +265 -0
- package/dist/src/core/policy-proposal.js +458 -0
- package/dist/src/core/policy-proposal.js.map +1 -0
- package/dist/src/core/prompt-layout.d.ts +221 -0
- package/dist/src/core/prompt-layout.js +422 -0
- package/dist/src/core/prompt-layout.js.map +1 -0
- package/dist/src/core/protected-path-guard.d.ts +453 -0
- package/dist/src/core/protected-path-guard.js +1566 -0
- package/dist/src/core/protected-path-guard.js.map +1 -0
- package/dist/src/core/registration.d.ts +25 -0
- package/dist/src/core/registration.js +39 -0
- package/dist/src/core/registration.js.map +1 -0
- package/dist/src/core/reindex.d.ts +99 -0
- package/dist/src/core/reindex.js +336 -0
- package/dist/src/core/reindex.js.map +1 -0
- package/dist/src/core/sampler.d.ts +313 -0
- package/dist/src/core/sampler.js +388 -0
- package/dist/src/core/sampler.js.map +1 -0
- package/dist/src/core/sandbox.d.ts +290 -0
- package/dist/src/core/sandbox.js +424 -0
- package/dist/src/core/sandbox.js.map +1 -0
- package/dist/src/core/seal.d.ts +165 -0
- package/dist/src/core/seal.js +290 -0
- package/dist/src/core/seal.js.map +1 -0
- package/dist/src/core/state.d.ts +505 -0
- package/dist/src/core/state.js +1009 -0
- package/dist/src/core/state.js.map +1 -0
- package/dist/src/core/task-file.d.ts +185 -0
- package/dist/src/core/task-file.js +464 -0
- package/dist/src/core/task-file.js.map +1 -0
- package/dist/src/core/telegram-config.d.ts +93 -0
- package/dist/src/core/telegram-config.js +114 -0
- package/dist/src/core/telegram-config.js.map +1 -0
- package/dist/src/core/token.d.ts +409 -0
- package/dist/src/core/token.js +561 -0
- package/dist/src/core/token.js.map +1 -0
- package/dist/src/core/validate.d.ts +138 -0
- package/dist/src/core/validate.js +0 -0
- package/dist/src/core/validate.js.map +1 -0
- package/dist/src/core/values.d.ts +137 -0
- package/dist/src/core/values.js +153 -0
- package/dist/src/core/values.js.map +1 -0
- package/dist/src/core/vault.d.ts +291 -0
- package/dist/src/core/vault.js +612 -0
- package/dist/src/core/vault.js.map +1 -0
- package/dist/src/core/verified-snapshot.d.ts +204 -0
- package/dist/src/core/verified-snapshot.js +506 -0
- package/dist/src/core/verified-snapshot.js.map +1 -0
- package/dist/src/core/verify.d.ts +336 -0
- package/dist/src/core/verify.js +549 -0
- package/dist/src/core/verify.js.map +1 -0
- package/dist/src/core/version.d.ts +8 -0
- package/dist/src/core/version.js +9 -0
- package/dist/src/core/version.js.map +1 -0
- package/dist/src/core/wysiwys.d.ts +370 -0
- package/dist/src/core/wysiwys.js +728 -0
- package/dist/src/core/wysiwys.js.map +1 -0
- package/dist/src/daemon/advance-child.d.ts +39 -0
- package/dist/src/daemon/advance-child.js +78 -0
- package/dist/src/daemon/advance-child.js.map +1 -0
- package/dist/src/daemon/advance.d.ts +466 -0
- package/dist/src/daemon/advance.js +849 -0
- package/dist/src/daemon/advance.js.map +1 -0
- package/dist/src/daemon/audit.d.ts +87 -0
- package/dist/src/daemon/audit.js +90 -0
- package/dist/src/daemon/audit.js.map +1 -0
- package/dist/src/daemon/daemon.d.ts +1180 -0
- package/dist/src/daemon/daemon.js +1988 -0
- package/dist/src/daemon/daemon.js.map +1 -0
- package/dist/src/daemon/dark-session.d.ts +64 -0
- package/dist/src/daemon/dark-session.js +119 -0
- package/dist/src/daemon/dark-session.js.map +1 -0
- package/dist/src/daemon/draw-child.d.ts +36 -0
- package/dist/src/daemon/draw-child.js +132 -0
- package/dist/src/daemon/draw-child.js.map +1 -0
- package/dist/src/daemon/draw.d.ts +154 -0
- package/dist/src/daemon/draw.js +458 -0
- package/dist/src/daemon/draw.js.map +1 -0
- package/dist/src/daemon/git-evidence.d.ts +173 -0
- package/dist/src/daemon/git-evidence.js +345 -0
- package/dist/src/daemon/git-evidence.js.map +1 -0
- package/dist/src/daemon/projection.d.ts +180 -0
- package/dist/src/daemon/projection.js +233 -0
- package/dist/src/daemon/projection.js.map +1 -0
- package/dist/src/daemon/prune.d.ts +207 -0
- package/dist/src/daemon/prune.js +376 -0
- package/dist/src/daemon/prune.js.map +1 -0
- package/dist/src/mcp/http.d.ts +113 -0
- package/dist/src/mcp/http.js +343 -0
- package/dist/src/mcp/http.js.map +1 -0
- package/dist/src/mcp/server.d.ts +265 -0
- package/dist/src/mcp/server.js +602 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/docs/adapter-api.md +106 -0
- package/docs/cli-reference.md +5716 -0
- package/docs/codex-enforced-session.md +30 -0
- package/package.json +53 -4
- package/schema/.gitkeep +0 -0
- package/schema/LICENSE +117 -0
- package/schema/codex-instance.schema.json +82 -0
- package/schema/envelope.schema.json +137 -0
- package/schema/event.schema.json +1811 -0
- 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/envelope/invalid/action-missing-idempotency-key.json +15 -0
- package/schema/fixtures/envelope/invalid/action-unknown-class-format.json +14 -0
- package/schema/fixtures/envelope/invalid/confidence-out-of-range.json +11 -0
- package/schema/fixtures/envelope/invalid/est-cost-bare-number.json +14 -0
- package/schema/fixtures/envelope/invalid/est-cost-noncanonical-string.json +14 -0
- package/schema/fixtures/envelope/invalid/malformed-assignee.json +10 -0
- package/schema/fixtures/envelope/invalid/malformed-created-by.json +7 -0
- package/schema/fixtures/envelope/invalid/malformed-max-latency.json +11 -0
- package/schema/fixtures/envelope/invalid/malformed-payload-hash.json +14 -0
- package/schema/fixtures/envelope/invalid/max-cost-bare-number.json +11 -0
- package/schema/fixtures/envelope/invalid/missing-origin.json +3 -0
- package/schema/fixtures/envelope/invalid/negative-est-cost.json +14 -0
- package/schema/fixtures/envelope/invalid/unknown-state.json +7 -0
- package/schema/fixtures/envelope/invalid/unknown-top-level-field.json +8 -0
- package/schema/fixtures/envelope/valid/action-payload-hash.json +17 -0
- package/schema/fixtures/envelope/valid/actions-without-budget.json +18 -0
- package/schema/fixtures/envelope/valid/canonical.json +25 -0
- package/schema/fixtures/envelope/valid/minimal.json +7 -0
- package/schema/fixtures/envelope/valid/multi-action-executed.json +30 -0
- package/schema/fixtures/envelope/valid/record-write-stage.json +22 -0
- package/schema/fixtures/event/invalid/approval-granted-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/approval-granted-empty-batch-delivery-id.json +17 -0
- package/schema/fixtures/event/invalid/approval-granted-fifth-reaction.json +16 -0
- package/schema/fixtures/event/invalid/approval-granted-missing-actor.json +14 -0
- package/schema/fixtures/event/invalid/approval-requested-missing-action-key.json +14 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-agent-policy-drift.json +15 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-missing-reason.json +15 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-system-actor.json +15 -0
- package/schema/fixtures/event/invalid/audit-decision-refused-human-actor.json +17 -0
- package/schema/fixtures/event/invalid/audit-decision-refused-missing-code.json +16 -0
- package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +16 -0
- package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +15 -0
- package/schema/fixtures/event/invalid/bad-actor-prefix.json +15 -0
- package/schema/fixtures/event/invalid/est-cost-bare-number.json +17 -0
- package/schema/fixtures/event/invalid/execution-completed-fabricated-exit-code.json +16 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-empty-id.json +18 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-extra-field.json +19 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-id-not-string.json +18 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-missing-adapter.json +17 -0
- package/schema/fixtures/event/invalid/execution-failed-open-reported-by.json +16 -0
- package/schema/fixtures/event/invalid/execution-indeterminate-open-reason.json +14 -0
- package/schema/fixtures/event/invalid/execution-reconciled-agent-actor.json +17 -0
- package/schema/fixtures/event/invalid/execution-started-negative-env-stripped.json +16 -0
- package/schema/fixtures/event/invalid/gate-bypassed-missing-opened-seq.json +15 -0
- package/schema/fixtures/event/invalid/gate-closed-non-integer-opened-seq.json +13 -0
- package/schema/fixtures/event/invalid/gate-opened-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-missing-organ-path.json +13 -0
- package/schema/fixtures/event/invalid/harness-unknown-kind.json +18 -0
- package/schema/fixtures/event/invalid/harness-version-multiline.json +16 -0
- package/schema/fixtures/event/invalid/log-checkpoint-agent-actor.json +17 -0
- package/schema/fixtures/event/invalid/log-checkpoint-missing-signature.json +16 -0
- package/schema/fixtures/event/invalid/log-checkpoint-short-signed-hash.json +17 -0
- package/schema/fixtures/event/invalid/log-checkpoint-unknown-signature-alg.json +17 -0
- package/schema/fixtures/event/invalid/malformed-ts.json +15 -0
- package/schema/fixtures/event/invalid/missing-alg.json +14 -0
- package/schema/fixtures/event/invalid/missing-hash.json +14 -0
- package/schema/fixtures/event/invalid/non-integer-seq.json +15 -0
- package/schema/fixtures/event/invalid/payload-pruned-human-actor.json +14 -0
- package/schema/fixtures/event/invalid/payload-pruned-missing-hash.json +14 -0
- package/schema/fixtures/event/invalid/policy-declined-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/policy-proposed-missing-diff.json +19 -0
- package/schema/fixtures/event/invalid/policy-proposed-system-actor.json +26 -0
- package/schema/fixtures/event/invalid/short-hash.json +15 -0
- package/schema/fixtures/event/invalid/unknown-alg.json +15 -0
- package/schema/fixtures/event/invalid/unknown-event-type.json +15 -0
- package/schema/fixtures/event/invalid/unknown-top-level-field.json +16 -0
- package/schema/fixtures/event/valid/approval-expired.json +15 -0
- package/schema/fixtures/event/valid/approval-granted-batch.json +19 -0
- package/schema/fixtures/event/valid/approval-granted-reaction.json +16 -0
- package/schema/fixtures/event/valid/approval-granted.json +15 -0
- package/schema/fixtures/event/valid/approval-rejected.json +15 -0
- package/schema/fixtures/event/valid/approval-requested.json +19 -0
- package/schema/fixtures/event/valid/approval-revoked.json +15 -0
- package/schema/fixtures/event/valid/approval-withdrawn-policy-drift.json +17 -0
- package/schema/fixtures/event/valid/approval-withdrawn.json +16 -0
- package/schema/fixtures/event/valid/audit-decision-refused.json +20 -0
- package/schema/fixtures/event/valid/audit-reviewed-reaction.json +17 -0
- package/schema/fixtures/event/valid/audit-reviewed.json +15 -0
- package/schema/fixtures/event/valid/audit-sampled.json +14 -0
- package/schema/fixtures/event/valid/budget-exceeded.json +21 -0
- package/schema/fixtures/event/valid/envelope-drift.json +16 -0
- package/schema/fixtures/event/valid/execution-completed-harness-report.json +16 -0
- package/schema/fixtures/event/valid/execution-completed-provider-ref.json +18 -0
- package/schema/fixtures/event/valid/execution-completed.json +15 -0
- package/schema/fixtures/event/valid/execution-failed-harness-report.json +16 -0
- package/schema/fixtures/event/valid/execution-failed.json +15 -0
- package/schema/fixtures/event/valid/execution-indeterminate.json +15 -0
- package/schema/fixtures/event/valid/execution-reconciled.json +17 -0
- package/schema/fixtures/event/valid/execution-started-env-stripped.json +17 -0
- package/schema/fixtures/event/valid/execution-started.json +14 -0
- package/schema/fixtures/event/valid/gate-bypassed-harness-version.json +18 -0
- package/schema/fixtures/event/valid/gate-bypassed.json +19 -0
- package/schema/fixtures/event/valid/gate-closed.json +14 -0
- package/schema/fixtures/event/valid/gate-opened.json +16 -0
- package/schema/fixtures/event/valid/gate-organ-attested.json +14 -0
- package/schema/fixtures/event/valid/genesis-null-prev.json +14 -0
- package/schema/fixtures/event/valid/log-checkpoint.json +17 -0
- package/schema/fixtures/event/valid/payload-pruned-orphan.json +13 -0
- package/schema/fixtures/event/valid/payload-pruned.json +17 -0
- package/schema/fixtures/event/valid/policy-declined.json +16 -0
- package/schema/fixtures/event/valid/policy-proposed.json +35 -0
- package/schema/fixtures/event/valid/policy-updated.json +14 -0
- package/schema/fixtures/event/valid/reconciliation-required.json +18 -0
- package/schema/fixtures/event/valid/reconciliation-satisfied.json +17 -0
- package/schema/fixtures/event/valid/route-accepted.json +15 -0
- package/schema/fixtures/event/valid/route-proposed.json +16 -0
- package/schema/fixtures/event/valid/spec-example.json +15 -0
- package/schema/fixtures/event/valid/task-registered-harness-version.json +23 -0
- package/schema/fixtures/event/valid/task-registered.json +14 -0
- package/schema/fixtures/hash/known-answer-pre-121.json +74 -0
- package/schema/fixtures/hash/known-answer.json +74 -0
- package/schema/fixtures/policy/invalid/bad-approval-ttl.json +7 -0
- package/schema/fixtures/policy/invalid/bad-web-port.json +4 -0
- package/schema/fixtures/policy/invalid/checkpoint-key-not-base64.json +6 -0
- package/schema/fixtures/policy/invalid/class-rule-missing-autonomy.json +9 -0
- package/schema/fixtures/policy/invalid/empty-class-key.json +6 -0
- package/schema/fixtures/policy/invalid/live-rate-on-human-only.json +7 -0
- package/schema/fixtures/policy/invalid/malformed-class-key.json +6 -0
- package/schema/fixtures/policy/invalid/missing-version.json +8 -0
- package/schema/fixtures/policy/invalid/negative-limit.json +9 -0
- package/schema/fixtures/policy/invalid/non-numeric-limit.json +9 -0
- package/schema/fixtures/policy/invalid/non-positive-max-pending.json +9 -0
- package/schema/fixtures/policy/invalid/on-expiry-grant.json +8 -0
- package/schema/fixtures/policy/invalid/payload-retention-bare-number.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-compound.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-fractional.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-zero.json +4 -0
- package/schema/fixtures/policy/invalid/protected-paths-escape.json +4 -0
- package/schema/fixtures/policy/invalid/protected-paths-glob.json +4 -0
- package/schema/fixtures/policy/invalid/retro-rate-on-human-only.json +7 -0
- package/schema/fixtures/policy/invalid/retro-rate-on-manual.json +7 -0
- package/schema/fixtures/policy/invalid/retro-rate-zero.json +7 -0
- package/schema/fixtures/policy/invalid/sample-rate-too-high.json +5 -0
- package/schema/fixtures/policy/invalid/sampling-secret-env-empty.json +7 -0
- package/schema/fixtures/policy/invalid/sampling-secret-env-not-string.json +6 -0
- package/schema/fixtures/policy/invalid/skew-tolerance-compound.json +6 -0
- package/schema/fixtures/policy/invalid/unknown-autonomy.json +7 -0
- package/schema/fixtures/policy/invalid/unknown-class-rule-key.json +6 -0
- package/schema/fixtures/policy/invalid/unknown-top-level-key.json +7 -0
- package/schema/fixtures/policy/invalid/vault-passphrase-env-empty.json +6 -0
- package/schema/fixtures/policy/invalid/vault-passphrase-literal.json +6 -0
- package/schema/fixtures/policy/invalid/version-not-string.json +4 -0
- package/schema/fixtures/policy/valid/canonical.json +47 -0
- package/schema/fixtures/policy/valid/checkpoint-keys.json +18 -0
- package/schema/fixtures/policy/valid/class-approvers-limits.json +25 -0
- package/schema/fixtures/policy/valid/class-retro-rate.json +17 -0
- package/schema/fixtures/policy/valid/global-budgets.json +19 -0
- package/schema/fixtures/policy/valid/human-only.json +9 -0
- package/schema/fixtures/policy/valid/minimal.json +6 -0
- package/schema/fixtures/policy/valid/protected-paths.json +10 -0
- package/schema/fixtures/policy/valid/record-namespace.json +13 -0
- package/schema/fixtures/policy/valid/request-volume-limits.json +26 -0
- package/schema/fixtures/policy/valid/retention-and-sampling-secret.json +16 -0
- package/schema/fixtures/policy/valid/skew-tolerance.json +15 -0
- package/schema/fixtures/policy/valid/vault-passphrase-env.json +14 -0
- package/schema/fixtures/policy/valid/wildcards.json +15 -0
- package/schema/fixtures/policy-md/invalid/alias-bomb.md +15 -0
- package/schema/fixtures/policy-md/invalid/no-fence.md +7 -0
- package/schema/fixtures/policy-md/invalid/protected-route-not-a-subclass.md +16 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-autonomy.md +16 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-read-proof.md +17 -0
- package/schema/fixtures/policy-md/invalid/two-fences.md +19 -0
- package/schema/fixtures/policy-md/invalid/unclosed-fence.md +11 -0
- package/schema/fixtures/policy-md/invalid/wrong-info-string.md +11 -0
- package/schema/fixtures/policy-md/invalid/yaml-syntax-error.md +13 -0
- package/schema/fixtures/policy-md/precedence/both/APPROVAL.md +7 -0
- package/schema/fixtures/policy-md/precedence/both/APPROVALS.md +7 -0
- package/schema/fixtures/policy-md/precedence/fallback-only/APPROVALS.md +7 -0
- package/schema/fixtures/policy-md/valid/canonical.md +50 -0
- package/schema/fixtures/policy-md/valid/daemon-read-proof.md +18 -0
- package/schema/fixtures/policy-md/valid/minimal.md +3 -0
- package/schema/fixtures/policy-md/valid/prose-lookalikes.md +54 -0
- package/schema/fixtures/policy-md/valid/routed-protected-paths.md +49 -0
- package/schema/fixtures/policy-md/valid/with-values.md +79 -0
- package/schema/fixtures/sample-record/invalid/bad-date-time.json +4 -0
- package/schema/fixtures/sample-record/invalid/missing-required-field.json +3 -0
- package/schema/fixtures/sample-record/invalid/unknown-top-level-field.json +5 -0
- package/schema/fixtures/sample-record/invalid/wrong-type.json +4 -0
- package/schema/fixtures/sample-record/valid/minimal.json +4 -0
- package/schema/fixtures/sample-record/valid/with-note.json +5 -0
- package/schema/fixtures/values/invalid/class-shaped.json +9 -0
- package/schema/fixtures/values/invalid/duplicate-entry.json +4 -0
- package/schema/fixtures/values/invalid/non-string-item.json +4 -0
- package/schema/fixtures/values/invalid/over-cap.json +26 -0
- package/schema/fixtures/values/invalid/unknown-key.json +5 -0
- package/schema/fixtures/values/invalid/version-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +7 -0
- package/schema/fixtures/values/valid/full.json +20 -0
- package/schema/fixtures/values/valid/minimal.json +1 -0
- package/schema/fixtures/values-md/invalid/schema-invalid.md +62 -0
- package/schema/fixtures/values-md/invalid/two-blocks.md +69 -0
- package/schema/fixtures/values-md/invalid/unterminated.md +61 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +63 -0
- package/schema/fixtures/values-md/valid/absent.md +50 -0
- package/schema/fixtures/values-md/valid/with-values.md +79 -0
- package/schema/policy.schema.json +501 -0
- package/schema/sample-record.schema.json +26 -0
- package/schema/values.schema.json +55 -0
- package/templates/codex/README.md +9 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which gate instance this process is talking about (APRV-178).
|
|
3
|
+
*
|
|
4
|
+
* Everything else in this runtime is directory-scoped already: the policy is
|
|
5
|
+
* the `APPROVAL.md` beside the working directory, the log is that directory's
|
|
6
|
+
* `.approval/log/events.jsonl`, the vault and `.approval/env` sit next to it.
|
|
7
|
+
* Two checkouts on one machine are two gates, and nothing they hold is shared.
|
|
8
|
+
*
|
|
9
|
+
* The OS keystore was the exception, and it cost a live incident: the item
|
|
10
|
+
* names were three fixed strings, so a demo instance provisioned in another
|
|
11
|
+
* directory stored its bot token over the production instance's item and then
|
|
12
|
+
* read the production token back. Both gates then long-polled ONE bot, the
|
|
13
|
+
* `getUpdates` offsets fought, and a human's approval tap was consumed by the
|
|
14
|
+
* listener that had not asked for it. A keystore is machine-global; the names
|
|
15
|
+
* put into it have to carry the scoping the filesystem gave everything else.
|
|
16
|
+
*
|
|
17
|
+
* ## What the identity is
|
|
18
|
+
*
|
|
19
|
+
* The absolute path of the instance's `.approval` directory, hashed. Not the
|
|
20
|
+
* repository root (a gate may be configured with `--log` somewhere else), not
|
|
21
|
+
* a random id written into a file (a file the operator can copy is an identity
|
|
22
|
+
* that travels, which is the bug), and not the log path itself (a `--log` that
|
|
23
|
+
* names the same instance's log by a different but equivalent spelling should
|
|
24
|
+
* not mint a second identity, and `envFilePathFor` already normalises the two
|
|
25
|
+
* spellings this runtime supports).
|
|
26
|
+
*
|
|
27
|
+
* Symlinks are deliberately NOT resolved. `realpathSync` would touch the
|
|
28
|
+
* filesystem, so the identity of an instance would depend on whether its
|
|
29
|
+
* directory currently exists — and `approval setup` must be able to name the
|
|
30
|
+
* item it is about to create before anything is on disk. Two paths that reach
|
|
31
|
+
* one directory by different routes are therefore two identities; that is the
|
|
32
|
+
* safe direction of the error (two names, no sharing) rather than the unsafe
|
|
33
|
+
* one.
|
|
34
|
+
*
|
|
35
|
+
* ## What the names look like
|
|
36
|
+
*
|
|
37
|
+
* ```
|
|
38
|
+
* approval-tg-token-3f2a9c11
|
|
39
|
+
* approval-vault-passphrase-3f2a9c11
|
|
40
|
+
* approval-sampling-secret-3f2a9c11
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Eight hex digits: long enough that two instances on one machine will not
|
|
44
|
+
* collide by accident, short enough that an operator reading
|
|
45
|
+
* `keychain:approval-tg-token-3f2a9c11` in `.approval/env` and the same suffix
|
|
46
|
+
* in `approval doctor` can compare them at a glance. The suffix is not a
|
|
47
|
+
* secret and is not derived from one — it is a hash of a directory path, which
|
|
48
|
+
* `.approval/env` already carries in the open.
|
|
49
|
+
*/
|
|
50
|
+
import { type ResolvedVariable } from "./env-file.js";
|
|
51
|
+
import type { PolicyLoadResult } from "./policy-load.js";
|
|
52
|
+
/**
|
|
53
|
+
* The unscoped item names this project used before APRV-178.
|
|
54
|
+
*
|
|
55
|
+
* Kept, and kept named, for two reasons: an instance provisioned before the
|
|
56
|
+
* change still has its token under one of them, and the migration path is to
|
|
57
|
+
* READ them as a fallback and say so out loud, never to silently adopt them.
|
|
58
|
+
*/
|
|
59
|
+
export declare const LEGACY_SERVICE_TELEGRAM_TOKEN = "approval-tg-token";
|
|
60
|
+
export declare const LEGACY_SERVICE_VAULT_PASSPHRASE = "approval-vault-passphrase";
|
|
61
|
+
export declare const LEGACY_SERVICE_SAMPLING_SECRET = "approval-sampling-secret";
|
|
62
|
+
/** Every unscoped name, for the "is this the legacy one?" test. */
|
|
63
|
+
export declare const LEGACY_SERVICES: readonly string[];
|
|
64
|
+
/** How many hex digits of the digest a scoped name carries. */
|
|
65
|
+
export declare const INSTANCE_ID_LENGTH = 8;
|
|
66
|
+
/**
|
|
67
|
+
* The `.approval` directory this log path belongs to, absolute as given.
|
|
68
|
+
*
|
|
69
|
+
* `envFilePathFor` already answers "which instance is this log in", by walking
|
|
70
|
+
* up out of `log/` when it is there; the env file's own directory IS the
|
|
71
|
+
* instance home, so this is that answer with the filename removed rather than
|
|
72
|
+
* a second rule that could disagree with it.
|
|
73
|
+
*/
|
|
74
|
+
export declare function instanceHomeFor(logPath: string): string;
|
|
75
|
+
/** The instance's short identity: {@link INSTANCE_ID_LENGTH} hex digits. */
|
|
76
|
+
export declare function instanceIdFor(logPath: string): string;
|
|
77
|
+
/** The keystore item name `base` takes in the instance owning `logPath`. */
|
|
78
|
+
export declare function scopedService(base: string, logPath: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* How a service name relates to the instance owning `logPath`.
|
|
81
|
+
*
|
|
82
|
+
* Answered from the NAME alone, with no keystore lookup: `approval doctor`
|
|
83
|
+
* reports on this and a diagnostic may not pop a keychain-unlock prompt (see
|
|
84
|
+
* `cli/doctor.ts`'s `NON_RESOLVING_RUNNER`). The name is enough, because the
|
|
85
|
+
* name is what decides which item a lookup would find.
|
|
86
|
+
*
|
|
87
|
+
* - `mine` — the scoped name this instance writes.
|
|
88
|
+
* - `legacy` — one of the unscoped pre-APRV-178 names, which every instance on
|
|
89
|
+
* the machine resolves to the same item.
|
|
90
|
+
* - `other-instance` — a scoped name whose suffix is some other instance's.
|
|
91
|
+
* - `unknown` — a name this runtime never wrote; the operator chose it, and
|
|
92
|
+
* nothing here can say whose it is.
|
|
93
|
+
*/
|
|
94
|
+
export type ServiceScope = "mine" | "legacy" | "other-instance" | "unknown";
|
|
95
|
+
export declare function scopeOfService(service: string, logPath: string): ServiceScope;
|
|
96
|
+
/**
|
|
97
|
+
* The variable `approval env`'s export block uses to say what it exported.
|
|
98
|
+
*
|
|
99
|
+
* ## The bug this exists to close
|
|
100
|
+
*
|
|
101
|
+
* The bleed rule below reads no values, on purpose: it runs inside `approval
|
|
102
|
+
* doctor` and `approval up`, neither of which may pop a keystore-unlock dialog
|
|
103
|
+
* to produce a diagnostic (`NON_RESOLVING_RUNNER`). So it saw "this variable is
|
|
104
|
+
* exported, and the file has a line for it" and reported that the value in use
|
|
105
|
+
* was not the one the instance configured. It could not know that. The
|
|
106
|
+
* documented start ritual is
|
|
107
|
+
*
|
|
108
|
+
* ```sh
|
|
109
|
+
* eval "$(approval env)"
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* which exports THIS instance's own values from THIS instance's own file, and
|
|
113
|
+
* leaves behind exactly the state the rule was calling an incident: exported,
|
|
114
|
+
* with a file line naming a source. Observed on 2026-09-06 in the primary,
|
|
115
|
+
* where `unset APPROVAL_SAMPLING_SECRET && eval "$(approval env)" && approval
|
|
116
|
+
* up` printed the finding for the variable the eval had just resolved from the
|
|
117
|
+
* gate's own keychain item. A check that asserts a fact it never tested is
|
|
118
|
+
* worse than no check: it teaches the operator to skip the line.
|
|
119
|
+
*
|
|
120
|
+
* ## What is exported, and why it is value-free
|
|
121
|
+
*
|
|
122
|
+
* ```
|
|
123
|
+
* APPROVAL_ENV_PROVENANCE=1:3f2a9c11:<64 hex>:APPROVAL_TG_TOKEN,APPROVAL_TG_CHAT
|
|
124
|
+
* │ │ │ └ the NAMES it exported from the file
|
|
125
|
+
* │ │ └ sha256 of the env file bytes it read
|
|
126
|
+
* │ └ the instance whose file that was
|
|
127
|
+
* └ the format version
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* Four colon-separated fields; the names are shell variable names, which cannot
|
|
131
|
+
* contain a colon or a comma, so the shape needs no escaping. Every field is a
|
|
132
|
+
* NAME, an id or a digest: the same three kinds of thing `.approval/env` already
|
|
133
|
+
* carries in the open, and none of them is a value. The rule stays as value-free
|
|
134
|
+
* after this change as it was before it, which is the point — a check that had
|
|
135
|
+
* to read the secret to decide whether to complain about the secret would be a
|
|
136
|
+
* worse trade than the false positive.
|
|
137
|
+
*
|
|
138
|
+
* ## What it does NOT weaken
|
|
139
|
+
*
|
|
140
|
+
* Invariant 7 (no verb loads `.approval/env` implicitly) is untouched: this
|
|
141
|
+
* variable reaches a shell only when a human evaluates `approval env`'s output,
|
|
142
|
+
* exactly like every other line in that block, and no verb gains the ability to
|
|
143
|
+
* read the file for its values. And it cannot launder a foreign export, because
|
|
144
|
+
* `approval env` lists only the names it resolved FROM THE FILE. A value that
|
|
145
|
+
* was already in the environment is re-exported by that block for fidelity, and
|
|
146
|
+
* deliberately left out of this list, so a bled variable stays reported however
|
|
147
|
+
* many times the ritual is run over it.
|
|
148
|
+
*
|
|
149
|
+
* Trusting the variable is safe in the only direction that matters. Anything
|
|
150
|
+
* able to set it in this process's environment could already set the credential
|
|
151
|
+
* variables themselves, so it buys an attacker nothing; and being wrong here
|
|
152
|
+
* silences a WARNING rather than opening a gate. The reverse default — believing
|
|
153
|
+
* the exported value is foreign — is the bug being fixed.
|
|
154
|
+
*/
|
|
155
|
+
export declare const ENV_PROVENANCE_VAR = "APPROVAL_ENV_PROVENANCE";
|
|
156
|
+
/** The only format version this build writes, and the only one it reads. */
|
|
157
|
+
export declare const ENV_PROVENANCE_VERSION = "1";
|
|
158
|
+
/** What one `approval env` export block claims about itself. */
|
|
159
|
+
export interface EnvProvenance {
|
|
160
|
+
/** The instance whose env file it resolved from. */
|
|
161
|
+
instanceId: string;
|
|
162
|
+
/** `envFileDigest` of the bytes it resolved from (`core/env-file.ts`). */
|
|
163
|
+
digest: string;
|
|
164
|
+
/** The names it exported FROM that file. Never the ones it passed through. */
|
|
165
|
+
names: ReadonlySet<string>;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The value for {@link ENV_PROVENANCE_VAR}, for an export block that resolved
|
|
169
|
+
* `names` out of the file `digest` identifies.
|
|
170
|
+
*/
|
|
171
|
+
export declare function formatEnvProvenance(logPath: string, digest: string, names: readonly string[]): string;
|
|
172
|
+
/**
|
|
173
|
+
* Read the claim back, or `null` for anything this build does not recognise.
|
|
174
|
+
*
|
|
175
|
+
* Strict on every field, and `null` rather than a partial answer: a malformed
|
|
176
|
+
* claim is an unverified one, an unverified one earns no credit, and no credit
|
|
177
|
+
* means the finding is still reported. That is the fail-closed direction (the
|
|
178
|
+
* check stays loud) for a value whose whole job is to make the check quieter.
|
|
179
|
+
*/
|
|
180
|
+
export declare function parseEnvProvenance(raw: string | undefined): EnvProvenance | null;
|
|
181
|
+
/**
|
|
182
|
+
* One way this instance's credentials can belong to somebody else.
|
|
183
|
+
*
|
|
184
|
+
* - `foreign-instance` — `.approval/env` names a keystore item whose scope
|
|
185
|
+
* suffix is another instance's. Two gates then hold one credential, which is
|
|
186
|
+
* the incident: one bot, two long pollers, and a human's tap consumed by the
|
|
187
|
+
* listener that did not ask the question. This is WRONG, not a state.
|
|
188
|
+
* - `legacy-shared` — the file names one of the unscoped pre-APRV-178 items.
|
|
189
|
+
* Correct on a machine with one gate and a trap on a machine with two, so it
|
|
190
|
+
* is reported and not failed: it is what every existing installation looks
|
|
191
|
+
* like, and the repair is one re-run of `approval setup channel telegram`.
|
|
192
|
+
* - `ambient-bleed` — the value was exported before this process started, the
|
|
193
|
+
* file names a source of its own, and the export is NOT one this instance's
|
|
194
|
+
* `approval env` made (see {@link ENV_PROVENANCE_VAR}). The shell wins on
|
|
195
|
+
* purpose (invariant 7); what was missing is anyone saying so. This is the
|
|
196
|
+
* half of the incident that survived fixing the file: the operator's rc
|
|
197
|
+
* exported the production token, so every fresh terminal kept using the
|
|
198
|
+
* production bot.
|
|
199
|
+
*/
|
|
200
|
+
export type InstanceFindingKind = "foreign-instance" | "legacy-shared" | "ambient-bleed";
|
|
201
|
+
export interface InstanceFinding {
|
|
202
|
+
kind: InstanceFindingKind;
|
|
203
|
+
/** The environment variable the finding is about. */
|
|
204
|
+
variable: string;
|
|
205
|
+
/** The item name, for the two name-shaped findings. */
|
|
206
|
+
service?: string;
|
|
207
|
+
/** One sentence, and never a value. */
|
|
208
|
+
detail: string;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* What is wrong with WHOSE credentials this instance is using (APRV-178).
|
|
212
|
+
*
|
|
213
|
+
* Answered from names alone. No keystore is consulted ({@link
|
|
214
|
+
* NON_RESOLVING_RUNNER}), so this may be called from `approval doctor` and from
|
|
215
|
+
* `approval up`'s start-up without either of them blocking on an unlock dialog.
|
|
216
|
+
* No value is read, compared or printed on any path: the inputs are a service
|
|
217
|
+
* name, a scheme, a variable name, and (since APRV-278) an instance id, a file
|
|
218
|
+
* digest and a list of variable names out of {@link ENV_PROVENANCE_VAR} — all of
|
|
219
|
+
* which `.approval/env` and `approval env --check` carry in the open. The
|
|
220
|
+
* exported VALUES this reports on are still never read, compared or printed.
|
|
221
|
+
*
|
|
222
|
+
* A file this runtime cannot read at all produces no findings rather than a
|
|
223
|
+
* guess; `approval env --check` and doctor's `environment` row are what report
|
|
224
|
+
* an unreadable or wrong-moded file, and saying it twice in different words is
|
|
225
|
+
* how two commands come to disagree.
|
|
226
|
+
*/
|
|
227
|
+
export declare function instanceFindings(logPath: string, load: PolicyLoadResult, ambientEnv?: NodeJS.ProcessEnv): InstanceFinding[];
|
|
228
|
+
/**
|
|
229
|
+
* What the rule may consult beyond the names (APRV-278).
|
|
230
|
+
*
|
|
231
|
+
* Both fields are optional and an absent one only ever makes the report LOUDER:
|
|
232
|
+
* a caller that supplies neither gets the pre-APRV-278 behaviour, where every
|
|
233
|
+
* exported variable with a file line is reported.
|
|
234
|
+
*/
|
|
235
|
+
export interface FindingsContext {
|
|
236
|
+
/** The environment the report is about. Read for {@link ENV_PROVENANCE_VAR}. */
|
|
237
|
+
ambientEnv?: NodeJS.ProcessEnv;
|
|
238
|
+
/** `envFileDigest` of this instance's env file as it now reads. */
|
|
239
|
+
envFileDigest?: string;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The exported names this instance's OWN current `approval env` vouches for
|
|
243
|
+
* (APRV-278).
|
|
244
|
+
*
|
|
245
|
+
* Empty unless {@link ENV_PROVENANCE_VAR} parses, names this instance, and
|
|
246
|
+
* matches the env file as it now reads. `approval env --check` and the finding
|
|
247
|
+
* rule below both answer "is this export the documented ritual's?" from this one
|
|
248
|
+
* function, because two spellings of that question are two chances for `approval
|
|
249
|
+
* env --check` and `approval up` to say different things about one shell.
|
|
250
|
+
*/
|
|
251
|
+
export declare function ownEnvExports(logPath: string, context?: FindingsContext): ReadonlySet<string>;
|
|
252
|
+
/** The name-only rules, over an already-resolved variable set. */
|
|
253
|
+
export declare function findingsFor(logPath: string, variables: readonly ResolvedVariable[], context?: FindingsContext): InstanceFinding[];
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which gate instance this process is talking about (APRV-178).
|
|
3
|
+
*
|
|
4
|
+
* Everything else in this runtime is directory-scoped already: the policy is
|
|
5
|
+
* the `APPROVAL.md` beside the working directory, the log is that directory's
|
|
6
|
+
* `.approval/log/events.jsonl`, the vault and `.approval/env` sit next to it.
|
|
7
|
+
* Two checkouts on one machine are two gates, and nothing they hold is shared.
|
|
8
|
+
*
|
|
9
|
+
* The OS keystore was the exception, and it cost a live incident: the item
|
|
10
|
+
* names were three fixed strings, so a demo instance provisioned in another
|
|
11
|
+
* directory stored its bot token over the production instance's item and then
|
|
12
|
+
* read the production token back. Both gates then long-polled ONE bot, the
|
|
13
|
+
* `getUpdates` offsets fought, and a human's approval tap was consumed by the
|
|
14
|
+
* listener that had not asked for it. A keystore is machine-global; the names
|
|
15
|
+
* put into it have to carry the scoping the filesystem gave everything else.
|
|
16
|
+
*
|
|
17
|
+
* ## What the identity is
|
|
18
|
+
*
|
|
19
|
+
* The absolute path of the instance's `.approval` directory, hashed. Not the
|
|
20
|
+
* repository root (a gate may be configured with `--log` somewhere else), not
|
|
21
|
+
* a random id written into a file (a file the operator can copy is an identity
|
|
22
|
+
* that travels, which is the bug), and not the log path itself (a `--log` that
|
|
23
|
+
* names the same instance's log by a different but equivalent spelling should
|
|
24
|
+
* not mint a second identity, and `envFilePathFor` already normalises the two
|
|
25
|
+
* spellings this runtime supports).
|
|
26
|
+
*
|
|
27
|
+
* Symlinks are deliberately NOT resolved. `realpathSync` would touch the
|
|
28
|
+
* filesystem, so the identity of an instance would depend on whether its
|
|
29
|
+
* directory currently exists — and `approval setup` must be able to name the
|
|
30
|
+
* item it is about to create before anything is on disk. Two paths that reach
|
|
31
|
+
* one directory by different routes are therefore two identities; that is the
|
|
32
|
+
* safe direction of the error (two names, no sharing) rather than the unsafe
|
|
33
|
+
* one.
|
|
34
|
+
*
|
|
35
|
+
* ## What the names look like
|
|
36
|
+
*
|
|
37
|
+
* ```
|
|
38
|
+
* approval-tg-token-3f2a9c11
|
|
39
|
+
* approval-vault-passphrase-3f2a9c11
|
|
40
|
+
* approval-sampling-secret-3f2a9c11
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Eight hex digits: long enough that two instances on one machine will not
|
|
44
|
+
* collide by accident, short enough that an operator reading
|
|
45
|
+
* `keychain:approval-tg-token-3f2a9c11` in `.approval/env` and the same suffix
|
|
46
|
+
* in `approval doctor` can compare them at a glance. The suffix is not a
|
|
47
|
+
* secret and is not derived from one — it is a hash of a directory path, which
|
|
48
|
+
* `.approval/env` already carries in the open.
|
|
49
|
+
*/
|
|
50
|
+
import { createHash } from "node:crypto";
|
|
51
|
+
import { dirname } from "node:path";
|
|
52
|
+
import { NON_RESOLVING_RUNNER, envFilePathFor, resolveEnvironment, } from "./env-file.js";
|
|
53
|
+
/**
|
|
54
|
+
* The unscoped item names this project used before APRV-178.
|
|
55
|
+
*
|
|
56
|
+
* Kept, and kept named, for two reasons: an instance provisioned before the
|
|
57
|
+
* change still has its token under one of them, and the migration path is to
|
|
58
|
+
* READ them as a fallback and say so out loud, never to silently adopt them.
|
|
59
|
+
*/
|
|
60
|
+
export const LEGACY_SERVICE_TELEGRAM_TOKEN = "approval-tg-token";
|
|
61
|
+
export const LEGACY_SERVICE_VAULT_PASSPHRASE = "approval-vault-passphrase";
|
|
62
|
+
export const LEGACY_SERVICE_SAMPLING_SECRET = "approval-sampling-secret";
|
|
63
|
+
/** Every unscoped name, for the "is this the legacy one?" test. */
|
|
64
|
+
export const LEGACY_SERVICES = [
|
|
65
|
+
LEGACY_SERVICE_TELEGRAM_TOKEN,
|
|
66
|
+
LEGACY_SERVICE_VAULT_PASSPHRASE,
|
|
67
|
+
LEGACY_SERVICE_SAMPLING_SECRET,
|
|
68
|
+
];
|
|
69
|
+
/** How many hex digits of the digest a scoped name carries. */
|
|
70
|
+
export const INSTANCE_ID_LENGTH = 8;
|
|
71
|
+
/** A scoped name is a legacy base plus exactly that many hex digits. */
|
|
72
|
+
const SCOPED_SUFFIX = new RegExp(`^-[0-9a-f]{${String(INSTANCE_ID_LENGTH)}}$`, "u");
|
|
73
|
+
/**
|
|
74
|
+
* The `.approval` directory this log path belongs to, absolute as given.
|
|
75
|
+
*
|
|
76
|
+
* `envFilePathFor` already answers "which instance is this log in", by walking
|
|
77
|
+
* up out of `log/` when it is there; the env file's own directory IS the
|
|
78
|
+
* instance home, so this is that answer with the filename removed rather than
|
|
79
|
+
* a second rule that could disagree with it.
|
|
80
|
+
*/
|
|
81
|
+
export function instanceHomeFor(logPath) {
|
|
82
|
+
return dirname(envFilePathFor(logPath));
|
|
83
|
+
}
|
|
84
|
+
/** The instance's short identity: {@link INSTANCE_ID_LENGTH} hex digits. */
|
|
85
|
+
export function instanceIdFor(logPath) {
|
|
86
|
+
return createHash("sha256")
|
|
87
|
+
.update(instanceHomeFor(logPath), "utf8")
|
|
88
|
+
.digest("hex")
|
|
89
|
+
.slice(0, INSTANCE_ID_LENGTH);
|
|
90
|
+
}
|
|
91
|
+
/** The keystore item name `base` takes in the instance owning `logPath`. */
|
|
92
|
+
export function scopedService(base, logPath) {
|
|
93
|
+
return `${base}-${instanceIdFor(logPath)}`;
|
|
94
|
+
}
|
|
95
|
+
export function scopeOfService(service, logPath) {
|
|
96
|
+
for (const base of LEGACY_SERVICES) {
|
|
97
|
+
if (service === base)
|
|
98
|
+
return "legacy";
|
|
99
|
+
if (service.startsWith(base)) {
|
|
100
|
+
const suffix = service.slice(base.length);
|
|
101
|
+
if (!SCOPED_SUFFIX.test(suffix))
|
|
102
|
+
continue;
|
|
103
|
+
return suffix === `-${instanceIdFor(logPath)}` ? "mine" : "other-instance";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return "unknown";
|
|
107
|
+
}
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Export provenance (APRV-278)
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
/**
|
|
112
|
+
* The variable `approval env`'s export block uses to say what it exported.
|
|
113
|
+
*
|
|
114
|
+
* ## The bug this exists to close
|
|
115
|
+
*
|
|
116
|
+
* The bleed rule below reads no values, on purpose: it runs inside `approval
|
|
117
|
+
* doctor` and `approval up`, neither of which may pop a keystore-unlock dialog
|
|
118
|
+
* to produce a diagnostic (`NON_RESOLVING_RUNNER`). So it saw "this variable is
|
|
119
|
+
* exported, and the file has a line for it" and reported that the value in use
|
|
120
|
+
* was not the one the instance configured. It could not know that. The
|
|
121
|
+
* documented start ritual is
|
|
122
|
+
*
|
|
123
|
+
* ```sh
|
|
124
|
+
* eval "$(approval env)"
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* which exports THIS instance's own values from THIS instance's own file, and
|
|
128
|
+
* leaves behind exactly the state the rule was calling an incident: exported,
|
|
129
|
+
* with a file line naming a source. Observed on 2026-09-06 in the primary,
|
|
130
|
+
* where `unset APPROVAL_SAMPLING_SECRET && eval "$(approval env)" && approval
|
|
131
|
+
* up` printed the finding for the variable the eval had just resolved from the
|
|
132
|
+
* gate's own keychain item. A check that asserts a fact it never tested is
|
|
133
|
+
* worse than no check: it teaches the operator to skip the line.
|
|
134
|
+
*
|
|
135
|
+
* ## What is exported, and why it is value-free
|
|
136
|
+
*
|
|
137
|
+
* ```
|
|
138
|
+
* APPROVAL_ENV_PROVENANCE=1:3f2a9c11:<64 hex>:APPROVAL_TG_TOKEN,APPROVAL_TG_CHAT
|
|
139
|
+
* │ │ │ └ the NAMES it exported from the file
|
|
140
|
+
* │ │ └ sha256 of the env file bytes it read
|
|
141
|
+
* │ └ the instance whose file that was
|
|
142
|
+
* └ the format version
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* Four colon-separated fields; the names are shell variable names, which cannot
|
|
146
|
+
* contain a colon or a comma, so the shape needs no escaping. Every field is a
|
|
147
|
+
* NAME, an id or a digest: the same three kinds of thing `.approval/env` already
|
|
148
|
+
* carries in the open, and none of them is a value. The rule stays as value-free
|
|
149
|
+
* after this change as it was before it, which is the point — a check that had
|
|
150
|
+
* to read the secret to decide whether to complain about the secret would be a
|
|
151
|
+
* worse trade than the false positive.
|
|
152
|
+
*
|
|
153
|
+
* ## What it does NOT weaken
|
|
154
|
+
*
|
|
155
|
+
* Invariant 7 (no verb loads `.approval/env` implicitly) is untouched: this
|
|
156
|
+
* variable reaches a shell only when a human evaluates `approval env`'s output,
|
|
157
|
+
* exactly like every other line in that block, and no verb gains the ability to
|
|
158
|
+
* read the file for its values. And it cannot launder a foreign export, because
|
|
159
|
+
* `approval env` lists only the names it resolved FROM THE FILE. A value that
|
|
160
|
+
* was already in the environment is re-exported by that block for fidelity, and
|
|
161
|
+
* deliberately left out of this list, so a bled variable stays reported however
|
|
162
|
+
* many times the ritual is run over it.
|
|
163
|
+
*
|
|
164
|
+
* Trusting the variable is safe in the only direction that matters. Anything
|
|
165
|
+
* able to set it in this process's environment could already set the credential
|
|
166
|
+
* variables themselves, so it buys an attacker nothing; and being wrong here
|
|
167
|
+
* silences a WARNING rather than opening a gate. The reverse default — believing
|
|
168
|
+
* the exported value is foreign — is the bug being fixed.
|
|
169
|
+
*/
|
|
170
|
+
export const ENV_PROVENANCE_VAR = "APPROVAL_ENV_PROVENANCE";
|
|
171
|
+
/** The only format version this build writes, and the only one it reads. */
|
|
172
|
+
export const ENV_PROVENANCE_VERSION = "1";
|
|
173
|
+
const PROVENANCE_INSTANCE_ID = new RegExp(`^[0-9a-f]{${String(INSTANCE_ID_LENGTH)}}$`, "u");
|
|
174
|
+
const PROVENANCE_DIGEST = /^[0-9a-f]{64}$/u;
|
|
175
|
+
const PROVENANCE_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
176
|
+
/**
|
|
177
|
+
* The value for {@link ENV_PROVENANCE_VAR}, for an export block that resolved
|
|
178
|
+
* `names` out of the file `digest` identifies.
|
|
179
|
+
*/
|
|
180
|
+
export function formatEnvProvenance(logPath, digest, names) {
|
|
181
|
+
return [ENV_PROVENANCE_VERSION, instanceIdFor(logPath), digest, [...names].join(",")].join(":");
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Read the claim back, or `null` for anything this build does not recognise.
|
|
185
|
+
*
|
|
186
|
+
* Strict on every field, and `null` rather than a partial answer: a malformed
|
|
187
|
+
* claim is an unverified one, an unverified one earns no credit, and no credit
|
|
188
|
+
* means the finding is still reported. That is the fail-closed direction (the
|
|
189
|
+
* check stays loud) for a value whose whole job is to make the check quieter.
|
|
190
|
+
*/
|
|
191
|
+
export function parseEnvProvenance(raw) {
|
|
192
|
+
if (raw === undefined)
|
|
193
|
+
return null;
|
|
194
|
+
const fields = raw.split(":");
|
|
195
|
+
if (fields.length !== 4)
|
|
196
|
+
return null;
|
|
197
|
+
const [version, instanceId, digest, joined] = fields;
|
|
198
|
+
if (version !== ENV_PROVENANCE_VERSION)
|
|
199
|
+
return null;
|
|
200
|
+
if (!PROVENANCE_INSTANCE_ID.test(instanceId))
|
|
201
|
+
return null;
|
|
202
|
+
if (!PROVENANCE_DIGEST.test(digest))
|
|
203
|
+
return null;
|
|
204
|
+
const names = joined.length === 0 ? [] : joined.split(",");
|
|
205
|
+
if (names.some((name) => !PROVENANCE_NAME.test(name)))
|
|
206
|
+
return null;
|
|
207
|
+
return { instanceId, digest, names: new Set(names) };
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* What is wrong with WHOSE credentials this instance is using (APRV-178).
|
|
211
|
+
*
|
|
212
|
+
* Answered from names alone. No keystore is consulted ({@link
|
|
213
|
+
* NON_RESOLVING_RUNNER}), so this may be called from `approval doctor` and from
|
|
214
|
+
* `approval up`'s start-up without either of them blocking on an unlock dialog.
|
|
215
|
+
* No value is read, compared or printed on any path: the inputs are a service
|
|
216
|
+
* name, a scheme, a variable name, and (since APRV-278) an instance id, a file
|
|
217
|
+
* digest and a list of variable names out of {@link ENV_PROVENANCE_VAR} — all of
|
|
218
|
+
* which `.approval/env` and `approval env --check` carry in the open. The
|
|
219
|
+
* exported VALUES this reports on are still never read, compared or printed.
|
|
220
|
+
*
|
|
221
|
+
* A file this runtime cannot read at all produces no findings rather than a
|
|
222
|
+
* guess; `approval env --check` and doctor's `environment` row are what report
|
|
223
|
+
* an unreadable or wrong-moded file, and saying it twice in different words is
|
|
224
|
+
* how two commands come to disagree.
|
|
225
|
+
*/
|
|
226
|
+
export function instanceFindings(logPath, load, ambientEnv = process.env) {
|
|
227
|
+
const resolved = resolveEnvironment(load, envFilePathFor(logPath), NON_RESOLVING_RUNNER, ambientEnv);
|
|
228
|
+
return resolved.ok
|
|
229
|
+
? findingsFor(logPath, resolved.variables, {
|
|
230
|
+
ambientEnv,
|
|
231
|
+
// The digest of the file THIS call read, which is what the provenance
|
|
232
|
+
// claim is checked against: an env file edited since the operator's
|
|
233
|
+
// `eval` earns no credit for the export it no longer describes.
|
|
234
|
+
envFileDigest: resolved.digest,
|
|
235
|
+
})
|
|
236
|
+
: [];
|
|
237
|
+
}
|
|
238
|
+
function provenanceView(logPath, context) {
|
|
239
|
+
const claim = parseEnvProvenance(context.ambientEnv?.[ENV_PROVENANCE_VAR]);
|
|
240
|
+
if (claim === null) {
|
|
241
|
+
return { claimsThisInstance: false, claimsThisFile: false, names: new Set() };
|
|
242
|
+
}
|
|
243
|
+
const claimsThisInstance = claim.instanceId === instanceIdFor(logPath);
|
|
244
|
+
return {
|
|
245
|
+
claimsThisInstance,
|
|
246
|
+
// An unknown digest is not a match: the rule may only vouch for what it has
|
|
247
|
+
// verified, and "the caller did not tell me" is not verification.
|
|
248
|
+
claimsThisFile: claimsThisInstance &&
|
|
249
|
+
context.envFileDigest !== undefined &&
|
|
250
|
+
claim.digest === context.envFileDigest,
|
|
251
|
+
names: claim.names,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The exported names this instance's OWN current `approval env` vouches for
|
|
256
|
+
* (APRV-278).
|
|
257
|
+
*
|
|
258
|
+
* Empty unless {@link ENV_PROVENANCE_VAR} parses, names this instance, and
|
|
259
|
+
* matches the env file as it now reads. `approval env --check` and the finding
|
|
260
|
+
* rule below both answer "is this export the documented ritual's?" from this one
|
|
261
|
+
* function, because two spellings of that question are two chances for `approval
|
|
262
|
+
* env --check` and `approval up` to say different things about one shell.
|
|
263
|
+
*/
|
|
264
|
+
export function ownEnvExports(logPath, context = {}) {
|
|
265
|
+
const view = provenanceView(logPath, context);
|
|
266
|
+
return view.claimsThisFile ? view.names : new Set();
|
|
267
|
+
}
|
|
268
|
+
/** The name-only rules, over an already-resolved variable set. */
|
|
269
|
+
export function findingsFor(logPath, variables, context = {}) {
|
|
270
|
+
const home = instanceHomeFor(logPath);
|
|
271
|
+
const { claimsThisInstance, claimsThisFile, names } = provenanceView(logPath, context);
|
|
272
|
+
const findings = [];
|
|
273
|
+
for (const variable of variables) {
|
|
274
|
+
const source = variable.fileSource;
|
|
275
|
+
if (source === undefined)
|
|
276
|
+
continue;
|
|
277
|
+
if (variable.status === "set-in-environment") {
|
|
278
|
+
const claimed = names.has(variable.name);
|
|
279
|
+
// The documented ritual: this instance's own `approval env`, run against
|
|
280
|
+
// the file as it now reads, exported this name out of it. The exported
|
|
281
|
+
// value IS the one the file configures, so there is nothing to report.
|
|
282
|
+
if (claimsThisFile && claimed)
|
|
283
|
+
continue;
|
|
284
|
+
findings.push({
|
|
285
|
+
kind: "ambient-bleed",
|
|
286
|
+
variable: variable.name,
|
|
287
|
+
detail: claimsThisInstance && claimed
|
|
288
|
+
? // This instance's own export, but of some other version of the
|
|
289
|
+
// file. Which version is not knowable from here, so the finding
|
|
290
|
+
// says only that, and does not claim the value is a stranger's.
|
|
291
|
+
`${variable.name} was exported by an \`approval env\` run this process cannot match to ${home}'s env file as it now reads, so line ${String(source.line)} as it now reads was not consulted`
|
|
292
|
+
: `${variable.name} was exported before this process started and is not this instance's own \`approval env\` export; line ${String(source.line)} of ${home}'s env file was not consulted`,
|
|
293
|
+
});
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const service = source.service;
|
|
297
|
+
if (service === undefined)
|
|
298
|
+
continue;
|
|
299
|
+
const scope = scopeOfService(service, logPath);
|
|
300
|
+
if (scope === "other-instance") {
|
|
301
|
+
findings.push({
|
|
302
|
+
kind: "foreign-instance",
|
|
303
|
+
variable: variable.name,
|
|
304
|
+
service,
|
|
305
|
+
detail: `${variable.name} names ${service}, whose scope suffix is not this instance's (${instanceIdFor(logPath)}, ${home}): two gates on this machine are pointed at one credential`,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
else if (scope === "legacy") {
|
|
309
|
+
findings.push({
|
|
310
|
+
kind: "legacy-shared",
|
|
311
|
+
variable: variable.name,
|
|
312
|
+
service,
|
|
313
|
+
detail: `${variable.name} names ${service}, the unscoped item name every gate on this machine resolves to the same value`,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return findings;
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../../../src/core/instance.ts"],"names":[],"mappings":"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"}
|