@lannguyensi/harness 0.64.0 → 1.0.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/CHANGELOG.md +64 -0
- package/README.md +46 -42
- package/dist/cli/add/index.js +17 -21
- package/dist/cli/add/index.js.map +1 -1
- package/dist/cli/adopt/derive.d.ts +2 -2
- package/dist/cli/adopt/derive.js +2 -19
- package/dist/cli/adopt/derive.js.map +1 -1
- package/dist/cli/adopt/index.d.ts +1 -1
- package/dist/cli/adopt/index.js +1 -12
- package/dist/cli/adopt/index.js.map +1 -1
- package/dist/cli/apply/apply.d.ts +20 -35
- package/dist/cli/apply/apply.js +61 -136
- package/dist/cli/apply/apply.js.map +1 -1
- package/dist/cli/apply/generate-codex-config.js +10 -58
- package/dist/cli/apply/generate-codex-config.js.map +1 -1
- package/dist/cli/apply/generate-memory-index.js +1 -2
- package/dist/cli/apply/generate-memory-index.js.map +1 -1
- package/dist/cli/apply/generate-opencode-config.d.ts +2 -10
- package/dist/cli/apply/generate-opencode-config.js +74 -113
- package/dist/cli/apply/generate-opencode-config.js.map +1 -1
- package/dist/cli/apply/generate-settings.d.ts +11 -64
- package/dist/cli/apply/generate-settings.js +27 -132
- package/dist/cli/apply/generate-settings.js.map +1 -1
- package/dist/cli/apply/index.d.ts +1 -1
- package/dist/cli/apply/index.js +1 -1
- package/dist/cli/apply/index.js.map +1 -1
- package/dist/cli/apply/install-codex-config.d.ts +153 -1
- package/dist/cli/apply/install-codex-config.js +445 -70
- package/dist/cli/apply/install-codex-config.js.map +1 -1
- package/dist/cli/apply/next-steps.d.ts +7 -0
- package/dist/cli/apply/next-steps.js +13 -1
- package/dist/cli/apply/next-steps.js.map +1 -1
- package/dist/cli/bounded-stdin.d.ts +0 -23
- package/dist/cli/bounded-stdin.js +2 -49
- package/dist/cli/bounded-stdin.js.map +1 -1
- package/dist/cli/describe.d.ts +1 -1
- package/dist/cli/describe.js +0 -3
- package/dist/cli/describe.js.map +1 -1
- package/dist/cli/diff/engine.d.ts +0 -11
- package/dist/cli/diff/engine.js +1 -17
- package/dist/cli/diff/engine.js.map +1 -1
- package/dist/cli/diff/index.js +14 -25
- package/dist/cli/diff/index.js.map +1 -1
- package/dist/cli/doctor/claude-mcp.d.ts +4 -19
- package/dist/cli/doctor/claude-mcp.js +11 -22
- package/dist/cli/doctor/claude-mcp.js.map +1 -1
- package/dist/cli/doctor/codex.d.ts +12 -14
- package/dist/cli/doctor/codex.js +31 -144
- package/dist/cli/doctor/codex.js.map +1 -1
- package/dist/cli/doctor/format.js +23 -345
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/hook-liveness.d.ts +56 -0
- package/dist/cli/doctor/hook-liveness.js +455 -0
- package/dist/cli/doctor/hook-liveness.js.map +1 -0
- package/dist/cli/doctor/index.d.ts +13 -87
- package/dist/cli/doctor/index.js +57 -713
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/opencode.d.ts +2 -1
- package/dist/cli/doctor/opencode.js.map +1 -1
- package/dist/cli/doctor/types.d.ts +21 -387
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/drain-stdio.d.ts +31 -0
- package/dist/cli/drain-stdio.js +76 -0
- package/dist/cli/drain-stdio.js.map +1 -0
- package/dist/cli/export.d.ts +3 -1
- package/dist/cli/export.js +7 -16
- package/dist/cli/export.js.map +1 -1
- package/dist/cli/gate/codex-disable.d.ts +29 -0
- package/dist/cli/gate/codex-disable.js +195 -0
- package/dist/cli/gate/codex-disable.js.map +1 -0
- package/dist/cli/gate/codex-enable.d.ts +41 -0
- package/dist/cli/gate/codex-enable.js +127 -0
- package/dist/cli/gate/codex-enable.js.map +1 -0
- package/dist/cli/gate/codex-snapshot.d.ts +208 -0
- package/dist/cli/gate/codex-snapshot.js +402 -0
- package/dist/cli/gate/codex-snapshot.js.map +1 -0
- package/dist/cli/gate/disable.d.ts +9 -0
- package/dist/cli/gate/disable.js +263 -28
- package/dist/cli/gate/disable.js.map +1 -1
- package/dist/cli/gate/enable.d.ts +26 -6
- package/dist/cli/gate/enable.js +152 -80
- package/dist/cli/gate/enable.js.map +1 -1
- package/dist/cli/gate/link-chain.d.ts +53 -0
- package/dist/cli/gate/link-chain.js +122 -0
- package/dist/cli/gate/link-chain.js.map +1 -0
- package/dist/cli/gate/snapshot.d.ts +289 -12
- package/dist/cli/gate/snapshot.js +481 -22
- package/dist/cli/gate/snapshot.js.map +1 -1
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/index.js +9 -2131
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/composer.d.ts +3 -6
- package/dist/cli/init/composer.js +6 -370
- package/dist/cli/init/composer.js.map +1 -1
- package/dist/cli/init/dependencies.d.ts +1 -2
- package/dist/cli/init/dependencies.js +4 -80
- package/dist/cli/init/dependencies.js.map +1 -1
- package/dist/cli/init/detect.js +5 -4
- package/dist/cli/init/detect.js.map +1 -1
- package/dist/cli/init/interactive.d.ts +1 -23
- package/dist/cli/init/interactive.js +33 -247
- package/dist/cli/init/interactive.js.map +1 -1
- package/dist/cli/init/profiles.d.ts +2 -2
- package/dist/cli/init/profiles.js +51 -245
- package/dist/cli/init/profiles.js.map +1 -1
- package/dist/cli/init/templates.d.ts +2 -37
- package/dist/cli/init/templates.js +25 -1237
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/list.d.ts +1 -1
- package/dist/cli/list.js +1 -38
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/loader.d.ts +15 -1
- package/dist/cli/loader.js +56 -39
- package/dist/cli/loader.js.map +1 -1
- package/dist/cli/main.js +7 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/migrate-home/index.js +2 -2
- package/dist/cli/migrate-home/index.js.map +1 -1
- package/dist/cli/pack/add.js +1 -1
- package/dist/cli/pack/add.js.map +1 -1
- package/dist/cli/pack/hook-bootstrap.d.ts +5 -164
- package/dist/cli/pack/hook-bootstrap.js +15 -291
- package/dist/cli/pack/hook-bootstrap.js.map +1 -1
- package/dist/cli/pack/hook-branch-protection.d.ts +28 -21
- package/dist/cli/pack/hook-branch-protection.js +365 -340
- package/dist/cli/pack/hook-branch-protection.js.map +1 -1
- package/dist/cli/pack/index.d.ts +0 -1
- package/dist/cli/pack/index.js +0 -1
- package/dist/cli/pack/index.js.map +1 -1
- package/dist/cli/pack/list.js +1 -6
- package/dist/cli/pack/list.js.map +1 -1
- package/dist/cli/pack/mutate.d.ts +7 -9
- package/dist/cli/pack/mutate.js +6 -9
- package/dist/cli/pack/mutate.js.map +1 -1
- package/dist/cli/pack/reseed.d.ts +2 -2
- package/dist/cli/pack/reseed.js +16 -22
- package/dist/cli/pack/reseed.js.map +1 -1
- package/dist/cli/{delegate/register.d.ts → register-gate-group.d.ts} +1 -1
- package/dist/cli/register-gate-group.js +348 -0
- package/dist/cli/register-gate-group.js.map +1 -0
- package/dist/cli/register-inspect-group.d.ts +6 -0
- package/dist/cli/register-inspect-group.js +189 -0
- package/dist/cli/register-inspect-group.js.map +1 -0
- package/dist/cli/register-operator-lifecycle.d.ts +1 -1
- package/dist/cli/register-operator-lifecycle.js +3 -100
- package/dist/cli/register-operator-lifecycle.js.map +1 -1
- package/dist/cli/register-pack-group.d.ts +5 -0
- package/dist/cli/register-pack-group.js +134 -0
- package/dist/cli/register-pack-group.js.map +1 -0
- package/dist/cli/{register-audit-group.d.ts → register-setup-group.d.ts} +1 -1
- package/dist/cli/register-setup-group.js +495 -0
- package/dist/cli/register-setup-group.js.map +1 -0
- package/dist/cli/remove/index.d.ts +0 -14
- package/dist/cli/remove/index.js +2 -115
- package/dist/cli/remove/index.js.map +1 -1
- package/dist/cli/remove/mutate.d.ts +0 -2
- package/dist/cli/remove/mutate.js +1 -19
- package/dist/cli/remove/mutate.js.map +1 -1
- package/dist/cli/remove/register.js +2 -19
- package/dist/cli/remove/register.js.map +1 -1
- package/dist/cli/shell-quote.d.ts +7 -0
- package/dist/cli/shell-quote.js +17 -0
- package/dist/cli/shell-quote.js.map +1 -0
- package/dist/cli/uninstall/index.d.ts +4 -2
- package/dist/cli/uninstall/index.js +15 -7
- package/dist/cli/uninstall/index.js.map +1 -1
- package/dist/cli/uninstall/register.js +6 -4
- package/dist/cli/uninstall/register.js.map +1 -1
- package/dist/cli/uninstall/snapshot.d.ts +15 -0
- package/dist/cli/uninstall/snapshot.js +38 -0
- package/dist/cli/uninstall/snapshot.js.map +1 -1
- package/dist/cli/validate/checks.d.ts +0 -77
- package/dist/cli/validate/checks.js +3 -1049
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/cli/validate/index.js +19 -15
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/io/claude-mcp.d.ts +1 -1
- package/dist/io/claude-mcp.js +27 -14
- package/dist/io/claude-mcp.js.map +1 -1
- package/dist/io/harness-lock.js +2 -2
- package/dist/io/harness-lock.js.map +1 -1
- package/dist/io/lock.d.ts +0 -26
- package/dist/io/lock.js +10 -27
- package/dist/io/lock.js.map +1 -1
- package/dist/io/merge-settings.js +6 -4
- package/dist/io/merge-settings.js.map +1 -1
- package/dist/io/project-name.d.ts +22 -39
- package/dist/io/project-name.js +25 -42
- package/dist/io/project-name.js.map +1 -1
- package/dist/io/read-regular-file.d.ts +103 -40
- package/dist/io/read-regular-file.js +196 -35
- package/dist/io/read-regular-file.js.map +1 -1
- package/dist/io/restart-hints.js +3 -6
- package/dist/io/restart-hints.js.map +1 -1
- package/dist/io/version-compare.d.ts +1 -3
- package/dist/io/version-compare.js +1 -3
- package/dist/io/version-compare.js.map +1 -1
- package/dist/io/write-regular-file.d.ts +30 -0
- package/dist/io/write-regular-file.js +85 -0
- package/dist/io/write-regular-file.js.map +1 -0
- package/dist/overrides/index.d.ts +1 -0
- package/dist/overrides/index.js +1 -0
- package/dist/overrides/index.js.map +1 -1
- package/dist/overrides/merge-layers.d.ts +43 -0
- package/dist/overrides/merge-layers.js +76 -0
- package/dist/overrides/merge-layers.js.map +1 -0
- package/dist/overrides/merge.d.ts +16 -0
- package/dist/overrides/merge.js +21 -8
- package/dist/overrides/merge.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -69
- package/dist/policy-packs/builtin/branch-protection-runtime.js +12 -84
- package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection.d.ts +7 -30
- package/dist/policy-packs/builtin/branch-protection.js +56 -89
- package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
- package/dist/policy-packs/config-check.d.ts +7 -5
- package/dist/policy-packs/config-check.js +2 -2
- package/dist/policy-packs/config-check.js.map +1 -1
- package/dist/policy-packs/expand.d.ts +1 -3
- package/dist/policy-packs/expand.js +5 -42
- package/dist/policy-packs/expand.js.map +1 -1
- package/dist/policy-packs/index.d.ts +3 -3
- package/dist/policy-packs/index.js +2 -2
- package/dist/policy-packs/index.js.map +1 -1
- package/dist/policy-packs/registry.d.ts +9 -38
- package/dist/policy-packs/registry.js +5 -65
- package/dist/policy-packs/registry.js.map +1 -1
- package/dist/policy-packs/runtime.d.ts +0 -4
- package/dist/policy-packs/runtime.js +9 -22
- package/dist/policy-packs/runtime.js.map +1 -1
- package/dist/policy-packs/types.d.ts +0 -19
- package/dist/policy-packs/ux-compare.d.ts +1 -11
- package/dist/policy-packs/ux-compare.js +6 -42
- package/dist/policy-packs/ux-compare.js.map +1 -1
- package/dist/policy-packs/ux-drift-check.d.ts +5 -5
- package/dist/policy-packs/ux-drift-check.js +17 -22
- package/dist/policy-packs/ux-drift-check.js.map +1 -1
- package/dist/policy-packs/version-check.d.ts +5 -26
- package/dist/policy-packs/version-check.js +19 -74
- package/dist/policy-packs/version-check.js.map +1 -1
- package/dist/probes/memory.d.ts +1 -1
- package/dist/probes/memory.js +1 -1
- package/dist/probes/memory.js.map +1 -1
- package/dist/runtime/agent-facing.d.ts +9 -0
- package/dist/runtime/agent-facing.js +28 -14
- package/dist/runtime/agent-facing.js.map +1 -1
- package/dist/runtime/bounded-text.d.ts +15 -0
- package/dist/runtime/bounded-text.js +27 -0
- package/dist/runtime/bounded-text.js.map +1 -0
- package/dist/runtime/git-branch.d.ts +125 -0
- package/dist/runtime/git-branch.js +381 -0
- package/dist/runtime/git-branch.js.map +1 -0
- package/dist/runtime/hermetic-spawn-guard.d.ts +2 -2
- package/dist/runtime/hermetic-spawn-guard.js +24 -34
- package/dist/runtime/hermetic-spawn-guard.js.map +1 -1
- package/dist/runtime/home-dir.js +3 -2
- package/dist/runtime/home-dir.js.map +1 -1
- package/dist/runtime/tool-name-aliases.d.ts +0 -6
- package/dist/runtime/tool-name-aliases.js +5 -18
- package/dist/runtime/tool-name-aliases.js.map +1 -1
- package/dist/schema/grounding.d.ts +7 -54
- package/dist/schema/grounding.js +10 -12
- package/dist/schema/grounding.js.map +1 -1
- package/dist/schema/hooks.d.ts +39 -136
- package/dist/schema/hooks.js +3 -6
- package/dist/schema/hooks.js.map +1 -1
- package/dist/schema/index.d.ts +114 -3828
- package/dist/schema/index.js +41 -80
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/memory.d.ts +54 -131
- package/dist/schema/memory.js +2 -2
- package/dist/schema/memory.js.map +1 -1
- package/dist/schema/policy-packs.d.ts +3 -45
- package/dist/schema/policy-packs.js +7 -13
- package/dist/schema/policy-packs.js.map +1 -1
- package/dist/schema/policy-ux.d.ts +7 -0
- package/dist/schema/policy-ux.js +18 -0
- package/dist/schema/policy-ux.js.map +1 -0
- package/dist/schema/removed-keys.d.ts +185 -0
- package/dist/schema/removed-keys.js +531 -0
- package/dist/schema/removed-keys.js.map +1 -0
- package/dist/schema/tools.d.ts +30 -268
- package/dist/schema/tools.js +4 -4
- package/dist/schema/tools.js.map +1 -1
- package/package.json +5 -16
- package/dist/cli/approve/branch-protection.d.ts +0 -69
- package/dist/cli/approve/branch-protection.js +0 -144
- package/dist/cli/approve/branch-protection.js.map +0 -1
- package/dist/cli/approve/risk.d.ts +0 -112
- package/dist/cli/approve/risk.js +0 -197
- package/dist/cli/approve/risk.js.map +0 -1
- package/dist/cli/approve/stdin-report.d.ts +0 -57
- package/dist/cli/approve/stdin-report.js +0 -145
- package/dist/cli/approve/stdin-report.js.map +0 -1
- package/dist/cli/approve/understanding.d.ts +0 -410
- package/dist/cli/approve/understanding.js +0 -996
- package/dist/cli/approve/understanding.js.map +0 -1
- package/dist/cli/audit.d.ts +0 -80
- package/dist/cli/audit.js +0 -252
- package/dist/cli/audit.js.map +0 -1
- package/dist/cli/delegate/index.d.ts +0 -76
- package/dist/cli/delegate/index.js +0 -444
- package/dist/cli/delegate/index.js.map +0 -1
- package/dist/cli/delegate/register.js +0 -90
- package/dist/cli/delegate/register.js.map +0 -1
- package/dist/cli/doctor/auto-approve-mode.d.ts +0 -37
- package/dist/cli/doctor/auto-approve-mode.js +0 -80
- package/dist/cli/doctor/auto-approve-mode.js.map +0 -1
- package/dist/cli/doctor/bypass-without-auto-approve.d.ts +0 -38
- package/dist/cli/doctor/bypass-without-auto-approve.js +0 -95
- package/dist/cli/doctor/bypass-without-auto-approve.js.map +0 -1
- package/dist/cli/doctor/codex-config-drift.d.ts +0 -28
- package/dist/cli/doctor/codex-config-drift.js +0 -240
- package/dist/cli/doctor/codex-config-drift.js.map +0 -1
- package/dist/cli/doctor/expire-on-tool-match.d.ts +0 -15
- package/dist/cli/doctor/expire-on-tool-match.js +0 -58
- package/dist/cli/doctor/expire-on-tool-match.js.map +0 -1
- package/dist/cli/doctor/rogue-ledger.d.ts +0 -53
- package/dist/cli/doctor/rogue-ledger.js +0 -153
- package/dist/cli/doctor/rogue-ledger.js.map +0 -1
- package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +0 -83
- package/dist/cli/doctor/session-start-preflight-setup-version.js +0 -114
- package/dist/cli/doctor/session-start-preflight-setup-version.js.map +0 -1
- package/dist/cli/doctor/settings-drift.d.ts +0 -25
- package/dist/cli/doctor/settings-drift.js +0 -213
- package/dist/cli/doctor/settings-drift.js.map +0 -1
- package/dist/cli/doctor/toolchain-parity.d.ts +0 -63
- package/dist/cli/doctor/toolchain-parity.js +0 -154
- package/dist/cli/doctor/toolchain-parity.js.map +0 -1
- package/dist/cli/doctor/ug-auto-approvals.d.ts +0 -40
- package/dist/cli/doctor/ug-auto-approvals.js +0 -91
- package/dist/cli/doctor/ug-auto-approvals.js.map +0 -1
- package/dist/cli/doctor/ug-delegations.d.ts +0 -26
- package/dist/cli/doctor/ug-delegations.js +0 -121
- package/dist/cli/doctor/ug-delegations.js.map +0 -1
- package/dist/cli/doctor/ug-inflight.d.ts +0 -35
- package/dist/cli/doctor/ug-inflight.js +0 -57
- package/dist/cli/doctor/ug-inflight.js.map +0 -1
- package/dist/cli/doctor/understanding-mode-env.d.ts +0 -51
- package/dist/cli/doctor/understanding-mode-env.js +0 -98
- package/dist/cli/doctor/understanding-mode-env.js.map +0 -1
- package/dist/cli/dry-run.d.ts +0 -58
- package/dist/cli/dry-run.js +0 -283
- package/dist/cli/dry-run.js.map +0 -1
- package/dist/cli/enriched-event.d.ts +0 -35
- package/dist/cli/enriched-event.js +0 -60
- package/dist/cli/enriched-event.js.map +0 -1
- package/dist/cli/event-input.d.ts +0 -28
- package/dist/cli/event-input.js +0 -73
- package/dist/cli/event-input.js.map +0 -1
- package/dist/cli/explain-action.d.ts +0 -25
- package/dist/cli/explain-action.js +0 -57
- package/dist/cli/explain-action.js.map +0 -1
- package/dist/cli/explain-policy.d.ts +0 -147
- package/dist/cli/explain-policy.js +0 -248
- package/dist/cli/explain-policy.js.map +0 -1
- package/dist/cli/explain.d.ts +0 -31
- package/dist/cli/explain.js +0 -159
- package/dist/cli/explain.js.map +0 -1
- package/dist/cli/gc/index.d.ts +0 -63
- package/dist/cli/gc/index.js +0 -566
- package/dist/cli/gc/index.js.map +0 -1
- package/dist/cli/pack/approve-escape.d.ts +0 -19
- package/dist/cli/pack/approve-escape.js +0 -190
- package/dist/cli/pack/approve-escape.js.map +0 -1
- package/dist/cli/pack/auto-approve-path.d.ts +0 -146
- package/dist/cli/pack/auto-approve-path.js +0 -462
- package/dist/cli/pack/auto-approve-path.js.map +0 -1
- package/dist/cli/pack/hook-codex-post-tool-use.d.ts +0 -25
- package/dist/cli/pack/hook-codex-post-tool-use.js +0 -160
- package/dist/cli/pack/hook-codex-post-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +0 -48
- package/dist/cli/pack/hook-codex-pre-tool-use.js +0 -474
- package/dist/cli/pack/hook-codex-pre-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-codex-stop.d.ts +0 -35
- package/dist/cli/pack/hook-codex-stop.js +0 -329
- package/dist/cli/pack/hook-codex-stop.js.map +0 -1
- package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -24
- package/dist/cli/pack/hook-codex-user-prompt-submit.js +0 -93
- package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +0 -1
- package/dist/cli/pack/hook-post-merge-gate-record.d.ts +0 -37
- package/dist/cli/pack/hook-post-merge-gate-record.js +0 -190
- package/dist/cli/pack/hook-post-merge-gate-record.js.map +0 -1
- package/dist/cli/pack/hook-post-merge-gate.d.ts +0 -34
- package/dist/cli/pack/hook-post-merge-gate.js +0 -277
- package/dist/cli/pack/hook-post-merge-gate.js.map +0 -1
- package/dist/cli/pack/hook-post-tool-use.d.ts +0 -45
- package/dist/cli/pack/hook-post-tool-use.js +0 -137
- package/dist/cli/pack/hook-post-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-pre-tool-use.d.ts +0 -92
- package/dist/cli/pack/hook-pre-tool-use.js +0 -1328
- package/dist/cli/pack/hook-pre-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-runtime-reality.d.ts +0 -63
- package/dist/cli/pack/hook-runtime-reality.js +0 -210
- package/dist/cli/pack/hook-runtime-reality.js.map +0 -1
- package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +0 -32
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js +0 -438
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +0 -1
- package/dist/cli/pack/hook-solution-acceptance.d.ts +0 -157
- package/dist/cli/pack/hook-solution-acceptance.js +0 -530
- package/dist/cli/pack/hook-solution-acceptance.js.map +0 -1
- package/dist/cli/pack/hook-stay-in-scope.d.ts +0 -37
- package/dist/cli/pack/hook-stay-in-scope.js +0 -128
- package/dist/cli/pack/hook-stay-in-scope.js.map +0 -1
- package/dist/cli/pack/hook-subagent-start.d.ts +0 -23
- package/dist/cli/pack/hook-subagent-start.js +0 -88
- package/dist/cli/pack/hook-subagent-start.js.map +0 -1
- package/dist/cli/pack/hook-subagent-stop.d.ts +0 -19
- package/dist/cli/pack/hook-subagent-stop.js +0 -41
- package/dist/cli/pack/hook-subagent-stop.js.map +0 -1
- package/dist/cli/pack/hook-track-active-claim.d.ts +0 -27
- package/dist/cli/pack/hook-track-active-claim.js +0 -275
- package/dist/cli/pack/hook-track-active-claim.js.map +0 -1
- package/dist/cli/pack/transcript-report-scan.d.ts +0 -71
- package/dist/cli/pack/transcript-report-scan.js +0 -359
- package/dist/cli/pack/transcript-report-scan.js.map +0 -1
- package/dist/cli/pack/understanding-report-schema-hint.d.ts +0 -26
- package/dist/cli/pack/understanding-report-schema-hint.js +0 -120
- package/dist/cli/pack/understanding-report-schema-hint.js.map +0 -1
- package/dist/cli/pack/upgrade.d.ts +0 -32
- package/dist/cli/pack/upgrade.js +0 -273
- package/dist/cli/pack/upgrade.js.map +0 -1
- package/dist/cli/pause/index.d.ts +0 -113
- package/dist/cli/pause/index.js +0 -251
- package/dist/cli/pause/index.js.map +0 -1
- package/dist/cli/pause-check.d.ts +0 -22
- package/dist/cli/pause-check.js +0 -54
- package/dist/cli/pause-check.js.map +0 -1
- package/dist/cli/policy/intercept.d.ts +0 -233
- package/dist/cli/policy/intercept.js +0 -1022
- package/dist/cli/policy/intercept.js.map +0 -1
- package/dist/cli/policy/risk-envelope-enrichment.d.ts +0 -40
- package/dist/cli/policy/risk-envelope-enrichment.js +0 -110
- package/dist/cli/policy/risk-envelope-enrichment.js.map +0 -1
- package/dist/cli/record/index.d.ts +0 -81
- package/dist/cli/record/index.js +0 -348
- package/dist/cli/record/index.js.map +0 -1
- package/dist/cli/register-audit-group.js +0 -91
- package/dist/cli/register-audit-group.js.map +0 -1
- package/dist/cli/resolve-env.d.ts +0 -32
- package/dist/cli/resolve-env.js +0 -46
- package/dist/cli/resolve-env.js.map +0 -1
- package/dist/cli/session-export/index.d.ts +0 -46
- package/dist/cli/session-export/index.js +0 -169
- package/dist/cli/session-export/index.js.map +0 -1
- package/dist/cli/session-export/redact.d.ts +0 -22
- package/dist/cli/session-export/redact.js +0 -47
- package/dist/cli/session-export/redact.js.map +0 -1
- package/dist/cli/session-export/transcript.d.ts +0 -24
- package/dist/cli/session-export/transcript.js +0 -164
- package/dist/cli/session-export/transcript.js.map +0 -1
- package/dist/cli/session-start/branch-check.d.ts +0 -18
- package/dist/cli/session-start/branch-check.js +0 -140
- package/dist/cli/session-start/branch-check.js.map +0 -1
- package/dist/cli/session-start/index.d.ts +0 -121
- package/dist/cli/session-start/index.js +0 -591
- package/dist/cli/session-start/index.js.map +0 -1
- package/dist/cli/session-start/shared-options.d.ts +0 -103
- package/dist/cli/session-start/shared-options.js +0 -107
- package/dist/cli/session-start/shared-options.js.map +0 -1
- package/dist/cli/session-start/stale-base-check.d.ts +0 -46
- package/dist/cli/session-start/stale-base-check.js +0 -352
- package/dist/cli/session-start/stale-base-check.js.map +0 -1
- package/dist/cli/session-start/toolchain-parity.d.ts +0 -267
- package/dist/cli/session-start/toolchain-parity.js +0 -797
- package/dist/cli/session-start/toolchain-parity.js.map +0 -1
- package/dist/cli/smoke/assertions.d.ts +0 -46
- package/dist/cli/smoke/assertions.js +0 -170
- package/dist/cli/smoke/assertions.js.map +0 -1
- package/dist/cli/smoke/index.d.ts +0 -76
- package/dist/cli/smoke/index.js +0 -245
- package/dist/cli/smoke/index.js.map +0 -1
- package/dist/cli/smoke/runner.d.ts +0 -55
- package/dist/cli/smoke/runner.js +0 -134
- package/dist/cli/smoke/runner.js.map +0 -1
- package/dist/cli/smoke/stream-parser.d.ts +0 -65
- package/dist/cli/smoke/stream-parser.js +0 -115
- package/dist/cli/smoke/stream-parser.js.map +0 -1
- package/dist/cli/test-risk.d.ts +0 -27
- package/dist/cli/test-risk.js +0 -38
- package/dist/cli/test-risk.js.map +0 -1
- package/dist/io/display-path.d.ts +0 -11
- package/dist/io/display-path.js +0 -29
- package/dist/io/display-path.js.map +0 -1
- package/dist/io/duration.d.ts +0 -5
- package/dist/io/duration.js +0 -50
- package/dist/io/duration.js.map +0 -1
- package/dist/io/extract.d.ts +0 -79
- package/dist/io/extract.js +0 -226
- package/dist/io/extract.js.map +0 -1
- package/dist/io/ledger-record.d.ts +0 -83
- package/dist/io/ledger-record.js +0 -301
- package/dist/io/ledger-record.js.map +0 -1
- package/dist/io/read-json-dir-entries.d.ts +0 -36
- package/dist/io/read-json-dir-entries.js +0 -48
- package/dist/io/read-json-dir-entries.js.map +0 -1
- package/dist/io/safe-json-parse.d.ts +0 -5
- package/dist/io/safe-json-parse.js +0 -21
- package/dist/io/safe-json-parse.js.map +0 -1
- package/dist/policies/index.d.ts +0 -5
- package/dist/policies/index.js +0 -6
- package/dist/policies/index.js.map +0 -1
- package/dist/policies/ledger-client.d.ts +0 -113
- package/dist/policies/ledger-client.js +0 -500
- package/dist/policies/ledger-client.js.map +0 -1
- package/dist/policies/producers.d.ts +0 -12
- package/dist/policies/producers.js +0 -61
- package/dist/policies/producers.js.map +0 -1
- package/dist/policies/requires.d.ts +0 -75
- package/dist/policies/requires.js +0 -240
- package/dist/policies/requires.js.map +0 -1
- package/dist/policies/timestamp.d.ts +0 -14
- package/dist/policies/timestamp.js +0 -36
- package/dist/policies/timestamp.js.map +0 -1
- package/dist/policy-packs/builtin/permission-profiles.d.ts +0 -11
- package/dist/policy-packs/builtin/permission-profiles.js +0 -74
- package/dist/policy-packs/builtin/permission-profiles.js.map +0 -1
- package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +0 -286
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js +0 -397
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/post-merge-gate.d.ts +0 -56
- package/dist/policy-packs/builtin/post-merge-gate.js +0 -347
- package/dist/policy-packs/builtin/post-merge-gate.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +0 -50
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +0 -151
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +0 -323
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +0 -672
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance.d.ts +0 -45
- package/dist/policy-packs/builtin/solution-acceptance.js +0 -226
- package/dist/policy-packs/builtin/solution-acceptance.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.d.ts +0 -25
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js +0 -94
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +0 -35
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +0 -86
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +0 -210
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +0 -361
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +0 -304
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +0 -734
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.d.ts +0 -36
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js +0 -73
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +0 -19
- package/dist/policy-packs/builtin/understanding-before-execution/index.js +0 -83
- package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.d.ts +0 -135
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +0 -643
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.d.ts +0 -25
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.js +0 -56
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.d.ts +0 -20
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js +0 -106
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/markers.d.ts +0 -126
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js +0 -245
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +0 -29
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +0 -82
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +0 -71
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +0 -175
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +0 -625
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +0 -1076
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.d.ts +0 -128
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +0 -213
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +0 -129
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +0 -166
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.d.ts +0 -164
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js +0 -275
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +0 -10
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution.d.ts +0 -526
- package/dist/policy-packs/builtin/understanding-before-execution.js +0 -1078
- package/dist/policy-packs/builtin/understanding-before-execution.js.map +0 -1
- package/dist/policy-packs/permission-translator.d.ts +0 -9
- package/dist/policy-packs/permission-translator.js +0 -76
- package/dist/policy-packs/permission-translator.js.map +0 -1
- package/dist/runtime/action-envelope.d.ts +0 -64
- package/dist/runtime/action-envelope.js +0 -46
- package/dist/runtime/action-envelope.js.map +0 -1
- package/dist/runtime/approval-signing.d.ts +0 -111
- package/dist/runtime/approval-signing.js +0 -384
- package/dist/runtime/approval-signing.js.map +0 -1
- package/dist/runtime/bash-match-facts.d.ts +0 -60
- package/dist/runtime/bash-match-facts.js +0 -196
- package/dist/runtime/bash-match-facts.js.map +0 -1
- package/dist/runtime/bash-match-registry.d.ts +0 -112
- package/dist/runtime/bash-match-registry.js +0 -406
- package/dist/runtime/bash-match-registry.js.map +0 -1
- package/dist/runtime/bash-prefix-parse.d.ts +0 -31
- package/dist/runtime/bash-prefix-parse.js +0 -576
- package/dist/runtime/bash-prefix-parse.js.map +0 -1
- package/dist/runtime/command-normalize.d.ts +0 -658
- package/dist/runtime/command-normalize.js +0 -2410
- package/dist/runtime/command-normalize.js.map +0 -1
- package/dist/runtime/deletion-target-resolve.d.ts +0 -28
- package/dist/runtime/deletion-target-resolve.js +0 -1078
- package/dist/runtime/deletion-target-resolve.js.map +0 -1
- package/dist/runtime/destructive-shell-floor.d.ts +0 -19
- package/dist/runtime/destructive-shell-floor.js +0 -611
- package/dist/runtime/destructive-shell-floor.js.map +0 -1
- package/dist/runtime/environment-resolver.d.ts +0 -36
- package/dist/runtime/environment-resolver.js +0 -138
- package/dist/runtime/environment-resolver.js.map +0 -1
- package/dist/runtime/git-context.d.ts +0 -201
- package/dist/runtime/git-context.js +0 -422
- package/dist/runtime/git-context.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -12
- package/dist/runtime/index.js +0 -13
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/intercept.d.ts +0 -623
- package/dist/runtime/intercept.js +0 -1384
- package/dist/runtime/intercept.js.map +0 -1
- package/dist/runtime/kube-context.d.ts +0 -16
- package/dist/runtime/kube-context.js +0 -63
- package/dist/runtime/kube-context.js.map +0 -1
- package/dist/runtime/kubectl-target-parse.d.ts +0 -31
- package/dist/runtime/kubectl-target-parse.js +0 -249
- package/dist/runtime/kubectl-target-parse.js.map +0 -1
- package/dist/runtime/ledger-add.d.ts +0 -16
- package/dist/runtime/ledger-add.js +0 -150
- package/dist/runtime/ledger-add.js.map +0 -1
- package/dist/runtime/ledger-writer.d.ts +0 -27
- package/dist/runtime/ledger-writer.js +0 -46
- package/dist/runtime/ledger-writer.js.map +0 -1
- package/dist/runtime/pause-sentinel.d.ts +0 -60
- package/dist/runtime/pause-sentinel.js +0 -156
- package/dist/runtime/pause-sentinel.js.map +0 -1
- package/dist/runtime/pending-approval.d.ts +0 -23
- package/dist/runtime/pending-approval.js +0 -67
- package/dist/runtime/pending-approval.js.map +0 -1
- package/dist/runtime/read-only-bash.d.ts +0 -141
- package/dist/runtime/read-only-bash.js +0 -2204
- package/dist/runtime/read-only-bash.js.map +0 -1
- package/dist/runtime/recovery-git-commit.d.ts +0 -22
- package/dist/runtime/recovery-git-commit.js +0 -284
- package/dist/runtime/recovery-git-commit.js.map +0 -1
- package/dist/runtime/reject-malformed-session-id.d.ts +0 -8
- package/dist/runtime/reject-malformed-session-id.js +0 -16
- package/dist/runtime/reject-malformed-session-id.js.map +0 -1
- package/dist/runtime/risk-classifier.d.ts +0 -38
- package/dist/runtime/risk-classifier.js +0 -311
- package/dist/runtime/risk-classifier.js.map +0 -1
- package/dist/runtime/session-id.d.ts +0 -113
- package/dist/runtime/session-id.js +0 -193
- package/dist/runtime/session-id.js.map +0 -1
- package/dist/runtime/shell-word.d.ts +0 -62
- package/dist/runtime/shell-word.js +0 -410
- package/dist/runtime/shell-word.js.map +0 -1
- package/dist/runtime/task-providers/agent-tasks.d.ts +0 -105
- package/dist/runtime/task-providers/agent-tasks.js +0 -247
- package/dist/runtime/task-providers/agent-tasks.js.map +0 -1
- package/dist/runtime/when-eval.d.ts +0 -62
- package/dist/runtime/when-eval.js +0 -212
- package/dist/runtime/when-eval.js.map +0 -1
- package/dist/runtime/workflow-policies.d.ts +0 -207
- package/dist/runtime/workflow-policies.js +0 -596
- package/dist/runtime/workflow-policies.js.map +0 -1
- package/dist/schema/audit.d.ts +0 -71
- package/dist/schema/audit.js +0 -32
- package/dist/schema/audit.js.map +0 -1
- package/dist/schema/doctor.d.ts +0 -25
- package/dist/schema/doctor.js +0 -23
- package/dist/schema/doctor.js.map +0 -1
- package/dist/schema/environments.d.ts +0 -215
- package/dist/schema/environments.js +0 -101
- package/dist/schema/environments.js.map +0 -1
- package/dist/schema/extract.d.ts +0 -9
- package/dist/schema/extract.js +0 -86
- package/dist/schema/extract.js.map +0 -1
- package/dist/schema/permission-profiles.d.ts +0 -2292
- package/dist/schema/permission-profiles.js +0 -60
- package/dist/schema/permission-profiles.js.map +0 -1
- package/dist/schema/policies.d.ts +0 -974
- package/dist/schema/policies.js +0 -298
- package/dist/schema/policies.js.map +0 -1
- package/dist/schema/requires.d.ts +0 -131
- package/dist/schema/requires.js +0 -88
- package/dist/schema/requires.js.map +0 -1
- package/dist/schema/risk.d.ts +0 -144
- package/dist/schema/risk.js +0 -194
- package/dist/schema/risk.js.map +0 -1
- package/dist/schema/session-start-preflight.d.ts +0 -10
- package/dist/schema/session-start-preflight.js +0 -106
- package/dist/schema/session-start-preflight.js.map +0 -1
- package/dist/schema/stale-base-check.d.ts +0 -18
- package/dist/schema/stale-base-check.js +0 -37
- package/dist/schema/stale-base-check.js.map +0 -1
- package/dist/schema/toolchain-parity.d.ts +0 -21
- package/dist/schema/toolchain-parity.js +0 -48
- package/dist/schema/toolchain-parity.js.map +0 -1
- package/dist/schema/workflows.d.ts +0 -519
- package/dist/schema/workflows.js +0 -81
- package/dist/schema/workflows.js.map +0 -1
- package/scripts/runtime-reality-docker-probe.mjs +0 -71
|
@@ -1,734 +0,0 @@
|
|
|
1
|
-
// Signed DELEGATION markers for `claude -p` child sessions: slice 3 of
|
|
2
|
-
// docs/decisions/2026-08-27-ug-auto-mode-approval.md ("Delegation marker
|
|
3
|
-
// shape", "TTL, cwd, and subagents", "Audit and doctor").
|
|
4
|
-
//
|
|
5
|
-
// A delegation is a PRE-AUTHORIZATION, not an approval. It is key one of
|
|
6
|
-
// the ADR's two-key design: the parent, already approved, hands the child
|
|
7
|
-
// session a signed artifact that supplies the trusted signal and the
|
|
8
|
-
// parent linkage. Key two (the child's own Understanding Report) is
|
|
9
|
-
// checked elsewhere; nothing in this module ever opens a gate on its own.
|
|
10
|
-
//
|
|
11
|
-
// WHY ITS OWN DIRECTORY AND ITS OWN VERIFIER. The file lives at
|
|
12
|
-
// `<generatedDir>/.delegations/<child-sid>`, never in `.approvals/`:
|
|
13
|
-
// keeping pre-authorizations out of the approvals directory keeps every
|
|
14
|
-
// existing marker scan and the doctor `approvedBy`-prefix listing free of
|
|
15
|
-
// artifacts that never opened a gate. `checkApprovalMarker` cannot consume
|
|
16
|
-
// a delegation anyway: the signature is computed over the markerId
|
|
17
|
-
// `delegation-<child-sid>`, so a delegation copied onto `.approvals/<sid>`
|
|
18
|
-
// fails that reader's signature check exactly like a forgery, and an
|
|
19
|
-
// approval marker copied into `.delegations/` fails this module's check
|
|
20
|
-
// for the mirror-image reason. Both directions are pinned by
|
|
21
|
-
// tests/policy-packs/understanding-before-execution-delegation.test.ts.
|
|
22
|
-
//
|
|
23
|
-
// WHY EVERY BINDING TRAVELS INSIDE `approvedBy`. The signing primitive
|
|
24
|
-
// signs exactly the tuple (markerId, approvedAt, approvedBy,
|
|
25
|
-
// reportContentHash) (src/runtime/approval-signing.ts), plus the optional
|
|
26
|
-
// `claimTaskId` that keeps the old bytes when absent; adding any other
|
|
27
|
-
// signed field would change `canonicalPayload`, which under that module's
|
|
28
|
-
// strict no-migration precedent means a `SIGNING_ALG` bump and forced
|
|
29
|
-
// re-approval on every install. So the delegation packs parent, cwd, task
|
|
30
|
-
// and expiry into `approvedBy`, the one free-text field inside the signed
|
|
31
|
-
// tuple:
|
|
32
|
-
//
|
|
33
|
-
// delegated:<parent-sid>;cwd=<sha256|->;task=<id|->;expires=<iso>[;report=<sha256>]
|
|
34
|
-
//
|
|
35
|
-
// All of it is therefore tamper-evident with no schema change. The cwd is
|
|
36
|
-
// hashed rather than written literally so the file carries no machine
|
|
37
|
-
// path. `approvedAt` records ISSUE time only, never the expiry:
|
|
38
|
-
// `verifyMarkerSignature` rejects a marker with a missing/empty
|
|
39
|
-
// `approvedAt` before it computes any HMAC, so the field must be there,
|
|
40
|
-
// and the marker readers keep no `expiresAt` field for anything to
|
|
41
|
-
// enforce, which is exactly why the lifetime rides in the `expires`
|
|
42
|
-
// segment above and why this module ships its own verifier.
|
|
43
|
-
//
|
|
44
|
-
// FAIL CLOSED THROUGHOUT. Every refusal in `verifyDelegation` carries a
|
|
45
|
-
// distinct reason; no branch turns a missing, malformed, unparseable or
|
|
46
|
-
// unbound delegation into an `ok` result. `parseDelegationApprovedBy`
|
|
47
|
-
// never fills in a default for an absent segment: a delegation whose
|
|
48
|
-
// bindings cannot be read in full is not a delegation.
|
|
49
|
-
import * as fs from "node:fs";
|
|
50
|
-
import * as path from "node:path";
|
|
51
|
-
import { atomicWriteFile } from "../../../io/atomic-write.js";
|
|
52
|
-
import { probePathPresence, readRegularFileRejectingSymlink, } from "../../../io/read-regular-file.js";
|
|
53
|
-
import { safeJsonParse } from "../../../io/safe-json-parse.js";
|
|
54
|
-
import { sha256Hex, signMarker, signingKeyExists, signingKeyPathFor, verifyMarkerSignature, } from "../../../runtime/approval-signing.js";
|
|
55
|
-
import { rejectMalformedSessionId } from "../../../runtime/reject-malformed-session-id.js";
|
|
56
|
-
/** Directory holding delegation markers, a sibling of `.approvals/` under `generatedDir`. */
|
|
57
|
-
export const DELEGATION_MARKER_DIRNAME = ".delegations";
|
|
58
|
-
/**
|
|
59
|
-
* Directory holding the per-child ADOPTED-ENTRY ledgers (once-per-session
|
|
60
|
-
* transcript-capture bookkeeping written by the PreToolUse hook,
|
|
61
|
-
* `hook-pre-tool-use.ts`), a SIBLING of `.delegations/` itself rather than
|
|
62
|
-
* a subdirectory of it: `<generatedDir>/.delegation-adoptions/<sid>`.
|
|
63
|
-
*
|
|
64
|
-
* Defined here (not in `hook-pre-tool-use.ts`, the only writer) so that a
|
|
65
|
-
* reader that never writes a ledger, such as `harness gc`'s delegation
|
|
66
|
-
* sweep, can name the directory without importing a `cli/` module: this
|
|
67
|
-
* file already owns `DELEGATION_MARKER_DIRNAME`, the sibling constant an
|
|
68
|
-
* adoption-ledger reader also needs, and both dirnames traveling together
|
|
69
|
-
* keeps `.delegations/` and its ledger sibling from drifting apart.
|
|
70
|
-
*/
|
|
71
|
-
export const ADOPTION_LEDGER_DIRNAME = ".delegation-adoptions";
|
|
72
|
-
/**
|
|
73
|
-
* Directory holding the CONVENTIONAL launcher-report copies for the
|
|
74
|
-
* `--report` fallback shape, a SIBLING of `.delegations/` and
|
|
75
|
-
* `.delegation-adoptions/` (same reasoning: a reader that only needs the
|
|
76
|
-
* path convention, such as a future gc sweep, has no business importing
|
|
77
|
-
* the CLI module that writes into it). `harness delegate --report` copies
|
|
78
|
-
* the operator's file here, at `<childSessionId>.md`, and the child's own
|
|
79
|
-
* PreToolUse hook reads back from exactly this path (never the operator's
|
|
80
|
-
* original `--report` argument, which the hook has no way to learn): the
|
|
81
|
-
* conventional path is what lets both sides derive the SAME location from
|
|
82
|
-
* nothing but the child session id, closing the gap that used to leave a
|
|
83
|
-
* report-bound delegation issued and signature-verifiable but never
|
|
84
|
-
* actually checked against a file (agent-tasks 49d1ee41, follow-up to
|
|
85
|
-
* slice 3, agent-tasks 37ad0b05).
|
|
86
|
-
*/
|
|
87
|
-
export const DELEGATION_REPORT_DIRNAME = ".delegation-reports";
|
|
88
|
-
/** Prefix of the signed markerId, mirroring `task-<id>` for task markers. */
|
|
89
|
-
const DELEGATION_MARKER_ID_PREFIX = "delegation-";
|
|
90
|
-
/** The `approvedBy` segment carrying the parent linkage. Colon-separated, unlike the `key=value` segments after it. */
|
|
91
|
-
const DELEGATED_SEGMENT_PREFIX = "delegated:";
|
|
92
|
-
/** Literal written for a binding the delegation deliberately leaves open (`cwd=-`, `task=-`). */
|
|
93
|
-
const UNBOUND = "-";
|
|
94
|
-
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
95
|
-
// Control characters (including NUL and DEL) are rejected from the parent
|
|
96
|
-
// linkage in both directions: the writer refuses to encode one and the
|
|
97
|
-
// reader refuses to accept one it finds, mirroring `;`/`=`.
|
|
98
|
-
const CONTROL_CHARS = /[\x00-\x1f\x7f]/;
|
|
99
|
-
// Deliberately narrower than `Date.parse`, which accepts plenty of
|
|
100
|
-
// non-ISO input ("March 3 2026") and, worse, timezone-less strings whose
|
|
101
|
-
// meaning depends on the reader's local zone. An expiry must mean the
|
|
102
|
-
// same instant in the parent's process and in the child's.
|
|
103
|
-
const ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
104
|
-
/**
|
|
105
|
-
* The signed markerId for a child session: `delegation-<child-sid>`.
|
|
106
|
-
* Binding it into the signed payload is what stops a validly signed
|
|
107
|
-
* delegation from being copied onto another child id, or onto a session
|
|
108
|
-
* marker's id, and still verifying (`task-markers.ts` precedent).
|
|
109
|
-
*/
|
|
110
|
-
export function delegationMarkerIdFor(childSessionId) {
|
|
111
|
-
return `${DELEGATION_MARKER_ID_PREFIX}${childSessionId}`;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Filesystem path of a child session's delegation marker. Rejects a
|
|
115
|
-
* malformed session id the same way `approvalMarkerPathFor` does (the
|
|
116
|
-
* value lands in a `path.join` verbatim).
|
|
117
|
-
*/
|
|
118
|
-
export function delegationMarkerPathFor(generatedDir, childSessionId) {
|
|
119
|
-
rejectMalformedSessionId(childSessionId);
|
|
120
|
-
return path.join(generatedDir, DELEGATION_MARKER_DIRNAME, childSessionId);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Filesystem path of a child session's CONVENTIONAL launcher-report copy:
|
|
124
|
-
* `<generatedDir>/.delegation-reports/<childSessionId>.md`. Always `.md`,
|
|
125
|
-
* regardless of the extension the operator's original `--report` file
|
|
126
|
-
* carried: the point of the convention is that both `harness delegate`
|
|
127
|
-
* (the writer) and the child's PreToolUse hook (the reader) derive the
|
|
128
|
-
* SAME path from nothing but the child session id, so a preserved
|
|
129
|
-
* extension would only reintroduce a value the hook has no way to learn.
|
|
130
|
-
* Rejects a malformed session id the same way {@link delegationMarkerPathFor}
|
|
131
|
-
* does (the value lands in a `path.join` verbatim).
|
|
132
|
-
*/
|
|
133
|
-
export function delegationReportPathFor(generatedDir, childSessionId) {
|
|
134
|
-
rejectMalformedSessionId(childSessionId);
|
|
135
|
-
return path.join(generatedDir, DELEGATION_REPORT_DIRNAME, `${childSessionId}.md`);
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* sha256 hex of a filesystem path, canonicalized through `realpathSync`
|
|
139
|
-
* when the path exists and through `path.resolve` when it does not.
|
|
140
|
-
*
|
|
141
|
-
* The canonicalization is the point, not an optimization: the parent
|
|
142
|
-
* writing the delegation and the child reporting its cwd routinely spell
|
|
143
|
-
* the same directory differently (on macOS `os.tmpdir()` hands out
|
|
144
|
-
* `/var/folders/...` while the process reports `/private/var/folders/...`,
|
|
145
|
-
* because `/var` is a symlink), and an uncanonicalized comparison would
|
|
146
|
-
* refuse a perfectly legitimate delegation. Falling back to `resolve` for
|
|
147
|
-
* a non-existent path keeps the function total: a path that cannot be
|
|
148
|
-
* canonicalized still hashes deterministically, and a delegation bound to
|
|
149
|
-
* it simply will not match a cwd that resolves elsewhere.
|
|
150
|
-
*
|
|
151
|
-
* Named for its primary use; the fallback shape hashes the launcher-
|
|
152
|
-
* supplied report file's PATH with the same function, so that WHERE the
|
|
153
|
-
* parent put the report is part of what was signed.
|
|
154
|
-
*/
|
|
155
|
-
export function hashDelegationCwd(targetPath) {
|
|
156
|
-
let canonical;
|
|
157
|
-
try {
|
|
158
|
-
canonical = fs.realpathSync(targetPath);
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
canonical = path.resolve(targetPath);
|
|
162
|
-
}
|
|
163
|
-
return sha256Hex(canonical);
|
|
164
|
-
}
|
|
165
|
-
function rejectUnsafeSegmentValue(field, value) {
|
|
166
|
-
if (value.length === 0) {
|
|
167
|
-
throw new Error(`${field} is empty`);
|
|
168
|
-
}
|
|
169
|
-
if (value.includes(";") || value.includes("=")) {
|
|
170
|
-
throw new Error(`${field} contains a delegation-segment delimiter (";" or "="): ${JSON.stringify(value)}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function rejectNonSha256(field, value) {
|
|
174
|
-
if (!SHA256_HEX.test(value)) {
|
|
175
|
-
throw new Error(`${field} is not a sha256 hex digest: ${JSON.stringify(value)}`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
function rejectNonIsoInstant(field, value) {
|
|
179
|
-
if (!ISO_INSTANT.test(value) || !Number.isFinite(Date.parse(value))) {
|
|
180
|
-
throw new Error(`${field} is not an ISO-8601 instant: ${JSON.stringify(value)}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Build the `approvedBy` string a delegation signs:
|
|
185
|
-
* `delegated:<parent>;cwd=<sha256|->;task=<id|->;expires=<iso>` plus
|
|
186
|
-
* `;report=<sha256>` in the fallback shape.
|
|
187
|
-
*
|
|
188
|
-
* Throws on any input that would corrupt the encoding (an empty value, a
|
|
189
|
-
* value carrying a `;` or `=` delimiter or a control character, a
|
|
190
|
-
* malformed parent session id (`rejectMalformedSessionId`), a cwd/report
|
|
191
|
-
* hash that is not a sha256 digest, a non-ISO expiry, or the literal `-`
|
|
192
|
-
* as a task id, which would round-trip as "no task bound"). A silently
|
|
193
|
-
* mis-encoded delegation would be signed and then read back with
|
|
194
|
-
* different bindings than the caller intended, so this fails loudly at
|
|
195
|
-
* the only place that can still tell the difference.
|
|
196
|
-
*/
|
|
197
|
-
export function buildDelegationApprovedBy(fields) {
|
|
198
|
-
const { parentSessionId, cwdHash, taskId, expiresAt, reportPathHash } = fields;
|
|
199
|
-
// Same shape check the CHILD session id already gets in
|
|
200
|
-
// `delegationMarkerPathFor`: the parent id never reaches a `path.join`
|
|
201
|
-
// here, but it is still a session id, and a value carrying `/`, `\`, or
|
|
202
|
-
// `..` has no business inside a signed audit field either.
|
|
203
|
-
rejectMalformedSessionId(parentSessionId);
|
|
204
|
-
rejectUnsafeSegmentValue("parentSessionId", parentSessionId);
|
|
205
|
-
if (CONTROL_CHARS.test(parentSessionId)) {
|
|
206
|
-
throw new Error(`parentSessionId contains a control character: ${JSON.stringify(parentSessionId)}`);
|
|
207
|
-
}
|
|
208
|
-
if (cwdHash !== null)
|
|
209
|
-
rejectNonSha256("cwdHash", cwdHash);
|
|
210
|
-
if (taskId !== null) {
|
|
211
|
-
rejectUnsafeSegmentValue("taskId", taskId);
|
|
212
|
-
if (taskId === UNBOUND) {
|
|
213
|
-
throw new Error(`taskId is the reserved unbound literal ${JSON.stringify(UNBOUND)}`);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
rejectNonIsoInstant("expiresAt", expiresAt);
|
|
217
|
-
if (reportPathHash !== undefined)
|
|
218
|
-
rejectNonSha256("reportPathHash", reportPathHash);
|
|
219
|
-
const segments = [
|
|
220
|
-
`${DELEGATED_SEGMENT_PREFIX}${parentSessionId}`,
|
|
221
|
-
`cwd=${cwdHash ?? UNBOUND}`,
|
|
222
|
-
`task=${taskId ?? UNBOUND}`,
|
|
223
|
-
`expires=${expiresAt}`,
|
|
224
|
-
];
|
|
225
|
-
if (reportPathHash !== undefined) {
|
|
226
|
-
segments.push(`report=${reportPathHash}`);
|
|
227
|
-
}
|
|
228
|
-
return segments.join(";");
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Strict inverse of {@link buildDelegationApprovedBy}. All four of
|
|
232
|
-
* `delegated`, `cwd`, `task` and `expires` are required and `report` is
|
|
233
|
-
* optional; a missing, duplicated, unknown, empty or malformed segment is
|
|
234
|
-
* an error RESULT, never a default. Segment order is not enforced (the
|
|
235
|
-
* signature already pins the exact bytes), but every other deviation is
|
|
236
|
-
* refused: this string is the only place a delegation's bindings live, so
|
|
237
|
-
* "read it partially and assume the rest" is the one failure mode that
|
|
238
|
-
* would quietly widen a delegation past what the parent signed.
|
|
239
|
-
*/
|
|
240
|
-
export function parseDelegationApprovedBy(approvedBy) {
|
|
241
|
-
if (typeof approvedBy !== "string" || approvedBy.length === 0) {
|
|
242
|
-
return {
|
|
243
|
-
ok: false,
|
|
244
|
-
reason: `approvedBy is not a non-empty string (got ${typeof approvedBy})`,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
let parentSessionId;
|
|
248
|
-
let cwdRaw;
|
|
249
|
-
let taskRaw;
|
|
250
|
-
let expiresRaw;
|
|
251
|
-
let reportRaw;
|
|
252
|
-
for (const segment of approvedBy.split(";")) {
|
|
253
|
-
if (segment.startsWith(DELEGATED_SEGMENT_PREFIX)) {
|
|
254
|
-
if (parentSessionId !== undefined) {
|
|
255
|
-
return { ok: false, reason: `duplicate "delegated" segment` };
|
|
256
|
-
}
|
|
257
|
-
const value = segment.slice(DELEGATED_SEGMENT_PREFIX.length);
|
|
258
|
-
if (value.length === 0) {
|
|
259
|
-
return { ok: false, reason: `empty value for segment "delegated"` };
|
|
260
|
-
}
|
|
261
|
-
// Mirror of the writer's checks (`buildDelegationApprovedBy`): the
|
|
262
|
-
// reader must never accept a parent linkage the writer could not
|
|
263
|
-
// have produced. `;` cannot survive the `split(";")` above without
|
|
264
|
-
// becoming a second, unrecognized segment, but `=` and control
|
|
265
|
-
// characters can, so they are checked explicitly here.
|
|
266
|
-
if (value.includes("=") || CONTROL_CHARS.test(value)) {
|
|
267
|
-
return {
|
|
268
|
-
ok: false,
|
|
269
|
-
reason: `"delegated" value contains "=" or a control character: ${JSON.stringify(value)}`,
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
try {
|
|
273
|
-
rejectMalformedSessionId(value);
|
|
274
|
-
}
|
|
275
|
-
catch (err) {
|
|
276
|
-
return {
|
|
277
|
-
ok: false,
|
|
278
|
-
reason: `"delegated" value is not a well-formed session id: ${err instanceof Error ? err.message : String(err)}`,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
parentSessionId = value;
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const eq = segment.indexOf("=");
|
|
285
|
-
if (eq <= 0) {
|
|
286
|
-
return { ok: false, reason: `unrecognized delegation segment ${JSON.stringify(segment)}` };
|
|
287
|
-
}
|
|
288
|
-
const key = segment.slice(0, eq);
|
|
289
|
-
const value = segment.slice(eq + 1);
|
|
290
|
-
if (value.length === 0) {
|
|
291
|
-
return { ok: false, reason: `empty value for segment ${JSON.stringify(key)}` };
|
|
292
|
-
}
|
|
293
|
-
switch (key) {
|
|
294
|
-
case "cwd":
|
|
295
|
-
if (cwdRaw !== undefined)
|
|
296
|
-
return { ok: false, reason: `duplicate "cwd" segment` };
|
|
297
|
-
cwdRaw = value;
|
|
298
|
-
break;
|
|
299
|
-
case "task":
|
|
300
|
-
if (taskRaw !== undefined)
|
|
301
|
-
return { ok: false, reason: `duplicate "task" segment` };
|
|
302
|
-
taskRaw = value;
|
|
303
|
-
break;
|
|
304
|
-
case "expires":
|
|
305
|
-
if (expiresRaw !== undefined)
|
|
306
|
-
return { ok: false, reason: `duplicate "expires" segment` };
|
|
307
|
-
expiresRaw = value;
|
|
308
|
-
break;
|
|
309
|
-
case "report":
|
|
310
|
-
if (reportRaw !== undefined)
|
|
311
|
-
return { ok: false, reason: `duplicate "report" segment` };
|
|
312
|
-
reportRaw = value;
|
|
313
|
-
break;
|
|
314
|
-
default:
|
|
315
|
-
return { ok: false, reason: `unknown delegation segment key ${JSON.stringify(key)}` };
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
if (parentSessionId === undefined)
|
|
319
|
-
return { ok: false, reason: `missing "delegated" segment` };
|
|
320
|
-
if (cwdRaw === undefined)
|
|
321
|
-
return { ok: false, reason: `missing "cwd" segment` };
|
|
322
|
-
if (taskRaw === undefined)
|
|
323
|
-
return { ok: false, reason: `missing "task" segment` };
|
|
324
|
-
if (expiresRaw === undefined)
|
|
325
|
-
return { ok: false, reason: `missing "expires" segment` };
|
|
326
|
-
let cwdHash = null;
|
|
327
|
-
if (cwdRaw !== UNBOUND) {
|
|
328
|
-
if (!SHA256_HEX.test(cwdRaw)) {
|
|
329
|
-
return { ok: false, reason: `"cwd" is not a sha256 hex digest: ${JSON.stringify(cwdRaw)}` };
|
|
330
|
-
}
|
|
331
|
-
cwdHash = cwdRaw;
|
|
332
|
-
}
|
|
333
|
-
let taskId = null;
|
|
334
|
-
if (taskRaw !== UNBOUND) {
|
|
335
|
-
if (taskRaw.includes("=")) {
|
|
336
|
-
return { ok: false, reason: `"task" contains a segment delimiter: ${JSON.stringify(taskRaw)}` };
|
|
337
|
-
}
|
|
338
|
-
taskId = taskRaw;
|
|
339
|
-
}
|
|
340
|
-
if (!ISO_INSTANT.test(expiresRaw) || !Number.isFinite(Date.parse(expiresRaw))) {
|
|
341
|
-
return {
|
|
342
|
-
ok: false,
|
|
343
|
-
reason: `"expires" is not an ISO-8601 instant: ${JSON.stringify(expiresRaw)}`,
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
if (reportRaw !== undefined && !SHA256_HEX.test(reportRaw)) {
|
|
347
|
-
return { ok: false, reason: `"report" is not a sha256 hex digest: ${JSON.stringify(reportRaw)}` };
|
|
348
|
-
}
|
|
349
|
-
const value = {
|
|
350
|
-
parentSessionId,
|
|
351
|
-
cwdHash,
|
|
352
|
-
taskId,
|
|
353
|
-
expiresAt: expiresRaw,
|
|
354
|
-
...(reportRaw !== undefined ? { reportPathHash: reportRaw } : {}),
|
|
355
|
-
};
|
|
356
|
-
return { ok: true, value };
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Write a signed delegation marker through the shared `signMarker` path,
|
|
360
|
-
* under markerId `delegation-<child-sid>`, at
|
|
361
|
-
* `<generatedDir>/.delegations/<child-sid>`. Atomic and mode 0600, like
|
|
362
|
-
* every other marker write.
|
|
363
|
-
*
|
|
364
|
-
* NEVER CREATES THE SIGNING KEY. `signMarker` -> `getOrCreateSigningKey`
|
|
365
|
-
* treats a missing key as a case to REPAIR, generating one and signing
|
|
366
|
-
* with it; key creation is an operator-side act (`harness init`,
|
|
367
|
-
* `harness approve`), and a delegation minted on a machine that never had
|
|
368
|
-
* a key would be a marker signed by whoever asked for it. So this
|
|
369
|
-
* prechecks `signingKeyExists` and returns `signing-key-absent` without
|
|
370
|
-
* reaching the write path at all (ADR threat model (b) item 5, the same
|
|
371
|
-
* rule slice 1's auto path follows).
|
|
372
|
-
*
|
|
373
|
-
* Returns a result rather than throwing, for every failure mode: the
|
|
374
|
-
* callers are a CLI verb and, later, a hook, and both must fail closed
|
|
375
|
-
* with a diagnostic instead of unwinding.
|
|
376
|
-
*
|
|
377
|
-
* Deliberately does NOT refuse a delegation that binds neither cwd nor
|
|
378
|
-
* task. That refusal belongs to the issuing verb (ADR slice 3 acceptance
|
|
379
|
-
* criterion 1) and to `verifyDelegation`, which reports `no_binding`;
|
|
380
|
-
* keeping the writer able to produce one is what lets the test suite
|
|
381
|
-
* exercise that verifier branch against a genuinely signed artifact
|
|
382
|
-
* rather than a hand-rolled fake.
|
|
383
|
-
*/
|
|
384
|
-
export function writeDelegationMarker(opts) {
|
|
385
|
-
const reportPathHash = opts.reportPathHash;
|
|
386
|
-
const reportContentHash = opts.reportContentHash ?? null;
|
|
387
|
-
if ((reportPathHash === undefined) !== (reportContentHash === null)) {
|
|
388
|
-
// The fallback shape binds the launcher-supplied report by BOTH its
|
|
389
|
-
// path and its content. Half a binding is worse than none: a `report=`
|
|
390
|
-
// segment with no content hash, or a content hash with no `report=`
|
|
391
|
-
// segment, reads as "bound" to a human and enforces only one half.
|
|
392
|
-
return {
|
|
393
|
-
ok: false,
|
|
394
|
-
reason: "invalid-input",
|
|
395
|
-
detail: "the fallback shape requires reportPathHash AND reportContentHash together (one without the other would leave half the report binding unenforced)",
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
if (reportContentHash !== null) {
|
|
399
|
-
try {
|
|
400
|
-
rejectNonSha256("reportContentHash", reportContentHash);
|
|
401
|
-
}
|
|
402
|
-
catch (err) {
|
|
403
|
-
return {
|
|
404
|
-
ok: false,
|
|
405
|
-
reason: "invalid-input",
|
|
406
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
let filePath;
|
|
411
|
-
let approvedBy;
|
|
412
|
-
try {
|
|
413
|
-
filePath = delegationMarkerPathFor(opts.generatedDir, opts.childSessionId);
|
|
414
|
-
approvedBy = buildDelegationApprovedBy({
|
|
415
|
-
parentSessionId: opts.parentSessionId,
|
|
416
|
-
cwdHash: opts.cwdHash,
|
|
417
|
-
taskId: opts.taskId,
|
|
418
|
-
expiresAt: opts.expiresAt,
|
|
419
|
-
reportPathHash,
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
catch (err) {
|
|
423
|
-
return {
|
|
424
|
-
ok: false,
|
|
425
|
-
reason: "invalid-input",
|
|
426
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
if (!signingKeyExists(opts.generatedDir)) {
|
|
430
|
-
return {
|
|
431
|
-
ok: false,
|
|
432
|
-
reason: "signing-key-absent",
|
|
433
|
-
detail: `no operator signing key at ${signingKeyPathFor(opts.generatedDir)}; refusing to mint a delegation (key creation is an operator-side act, never a side effect of delegating)`,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
const approvedAt = (opts.now ?? new Date()).toISOString();
|
|
437
|
-
const markerId = delegationMarkerIdFor(opts.childSessionId);
|
|
438
|
-
const signed = signMarker(opts.generatedDir, markerId, {
|
|
439
|
-
approvedAt,
|
|
440
|
-
approvedBy,
|
|
441
|
-
reportContentHash,
|
|
442
|
-
});
|
|
443
|
-
try {
|
|
444
|
-
atomicWriteFile(filePath, `${JSON.stringify(signed, null, 2)}\n`, { mode: 0o600 });
|
|
445
|
-
}
|
|
446
|
-
catch (err) {
|
|
447
|
-
return {
|
|
448
|
-
ok: false,
|
|
449
|
-
reason: "write-failed",
|
|
450
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
return { ok: true, filePath, markerId, approvedAt, approvedBy };
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Gate-side: is there a valid, unexpired, matching delegation for this
|
|
457
|
-
* child session? Checks, in order (ADR slice 3 acceptance criterion 2):
|
|
458
|
-
*
|
|
459
|
-
* 1. the file is present and JSON-readable,
|
|
460
|
-
* 2. its signature verifies against markerId `delegation-<child-sid>`,
|
|
461
|
-
* 3. its `approvedBy` segments parse in full,
|
|
462
|
-
* 4. it binds at least one of cwd / task,
|
|
463
|
-
* 5. it has not expired,
|
|
464
|
-
* 6. the bound cwd hash-matches the caller's cwd,
|
|
465
|
-
* 7. the bound task equals the caller's task,
|
|
466
|
-
* 8. in the fallback shape, the launcher report EXISTS at the offered
|
|
467
|
-
* path, sits at the bound path, AND hashes to the bound content
|
|
468
|
-
* (in that order: existence before the path hash, so a missing
|
|
469
|
-
* file is always `report_missing`, never `report_path_mismatch`).
|
|
470
|
-
*
|
|
471
|
-
* Reads only `.delegations/`; an artifact in `.approvals/` is `missing`
|
|
472
|
-
* here, whatever it contains.
|
|
473
|
-
*
|
|
474
|
-
* NEVER CREATES THE SIGNING KEY, on the READ path either.
|
|
475
|
-
* `verifyMarkerSignature` obtains the key through
|
|
476
|
-
* `getOrCreateSigningKey`, which treats a missing key as a case to
|
|
477
|
-
* REPAIR and generates one; on a machine the operator never initialized
|
|
478
|
-
* that would make a mere gate-time read perform the operator-side act of
|
|
479
|
-
* minting the key. It cannot make a foreign-signed delegation verify, but
|
|
480
|
-
* it does leave a key behind that every LATER write path would then
|
|
481
|
-
* happily sign with, so the never-create rule applies here exactly as it
|
|
482
|
-
* does to `writeDelegationMarker` and to slice 1's auto path. An absent
|
|
483
|
-
* key is reported as `unreadable` (we could not check, not "we checked
|
|
484
|
-
* and it is a forgery"), the same class `verifyMarkerSignature`'s own
|
|
485
|
-
* `key-unavailable` lands in below.
|
|
486
|
-
*/
|
|
487
|
-
export function verifyDelegation(opts) {
|
|
488
|
-
const { generatedDir, childSessionId } = opts;
|
|
489
|
-
let filePath;
|
|
490
|
-
try {
|
|
491
|
-
filePath = delegationMarkerPathFor(generatedDir, childSessionId);
|
|
492
|
-
}
|
|
493
|
-
catch (err) {
|
|
494
|
-
// A session id that cannot name a file has no delegation, by
|
|
495
|
-
// construction. Fail closed here rather than throwing out of a hook.
|
|
496
|
-
return {
|
|
497
|
-
ok: false,
|
|
498
|
-
reason: "missing",
|
|
499
|
-
detail: `invalid childSessionId for delegation marker: ${err instanceof Error ? err.message : String(err)}`,
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
const delegationsDir = path.join(generatedDir, DELEGATION_MARKER_DIRNAME);
|
|
503
|
-
let delegationsDirStat;
|
|
504
|
-
try {
|
|
505
|
-
delegationsDirStat = fs.lstatSync(delegationsDir);
|
|
506
|
-
}
|
|
507
|
-
catch {
|
|
508
|
-
return { ok: false, reason: "missing", detail: `no delegation marker at ${filePath}` };
|
|
509
|
-
}
|
|
510
|
-
if (!delegationsDirStat.isDirectory()) {
|
|
511
|
-
return {
|
|
512
|
-
ok: false,
|
|
513
|
-
reason: "missing",
|
|
514
|
-
detail: `delegation marker containment refusal: ${delegationsDir} is not a plain directory`,
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
const read = readRegularFileRejectingSymlink(filePath);
|
|
518
|
-
if (read.kind === "missing") {
|
|
519
|
-
return { ok: false, reason: "missing", detail: `no delegation marker at ${filePath}` };
|
|
520
|
-
}
|
|
521
|
-
if (read.kind === "symlink") {
|
|
522
|
-
return {
|
|
523
|
-
ok: false,
|
|
524
|
-
reason: "unreadable",
|
|
525
|
-
detail: `delegation marker is a symlink, refusing for safety: ${filePath}`,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
if (read.kind === "not-regular") {
|
|
529
|
-
return {
|
|
530
|
-
ok: false,
|
|
531
|
-
reason: "unreadable",
|
|
532
|
-
detail: `delegation marker path is not a regular file: ${filePath}`,
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
if (read.kind === "unreadable") {
|
|
536
|
-
return {
|
|
537
|
-
ok: false,
|
|
538
|
-
reason: "unreadable",
|
|
539
|
-
detail: `delegation marker at ${filePath} exists but could not be read (I/O error); treating as no delegation since its signature cannot be verified`,
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
const parsed = safeJsonParse(read.content);
|
|
543
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
544
|
-
return {
|
|
545
|
-
ok: false,
|
|
546
|
-
reason: "forged",
|
|
547
|
-
detail: `forged/unsigned delegation rejected: body at ${filePath} is not a JSON object`,
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
const body = parsed;
|
|
551
|
-
// Key precheck BEFORE `verifyMarkerSignature`, which would otherwise
|
|
552
|
-
// mint the key it is supposed to require (see the doc comment above).
|
|
553
|
-
// Placed after the file read so a session with no delegation at all
|
|
554
|
-
// still reports `missing` rather than this stronger, misleading reason.
|
|
555
|
-
if (!signingKeyExists(generatedDir)) {
|
|
556
|
-
return {
|
|
557
|
-
ok: false,
|
|
558
|
-
reason: "unreadable",
|
|
559
|
-
detail: `signing key absent at ${signingKeyPathFor(generatedDir)}; the delegation at ${filePath} cannot be verified and no key is created to verify it (key creation is an operator-side act)`,
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
const markerId = delegationMarkerIdFor(childSessionId);
|
|
563
|
-
const verification = verifyMarkerSignature(generatedDir, markerId, body);
|
|
564
|
-
if (!verification.ok) {
|
|
565
|
-
if (verification.kind === "key-unavailable") {
|
|
566
|
-
// Fail-closed I/O problem, not evidence of tampering (the same
|
|
567
|
-
// distinction `checkApprovalMarker` draws).
|
|
568
|
-
return {
|
|
569
|
-
ok: false,
|
|
570
|
-
reason: "unreadable",
|
|
571
|
-
detail: `delegation at ${filePath} could not be verified: ${verification.reason}`,
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
return {
|
|
575
|
-
ok: false,
|
|
576
|
-
reason: "forged",
|
|
577
|
-
detail: `forged/unsigned delegation rejected: ${verification.reason} (${filePath})`,
|
|
578
|
-
};
|
|
579
|
-
}
|
|
580
|
-
const segments = parseDelegationApprovedBy(body["approvedBy"]);
|
|
581
|
-
if (!segments.ok) {
|
|
582
|
-
return {
|
|
583
|
-
ok: false,
|
|
584
|
-
reason: "unparseable",
|
|
585
|
-
detail: `delegation at ${filePath} has an unparseable approvedBy: ${segments.reason}`,
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
const { parentSessionId, cwdHash, taskId, expiresAt, reportPathHash } = segments.value;
|
|
589
|
-
if (cwdHash === null && taskId === null) {
|
|
590
|
-
return {
|
|
591
|
-
ok: false,
|
|
592
|
-
reason: "no_binding",
|
|
593
|
-
detail: `delegation at ${filePath} binds neither a cwd nor a task; refusing an unbound pre-authorization`,
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
const nowMs = (opts.now ?? new Date()).getTime();
|
|
597
|
-
const expiresMs = Date.parse(expiresAt);
|
|
598
|
-
// `nowMs` is caller-supplied (`opts.now`, a test-only override); an
|
|
599
|
-
// invalid Date's `.getTime()` is NaN, and NaN fails every `<=`
|
|
600
|
-
// comparison, which would otherwise fail this check OPEN (a clock that
|
|
601
|
-
// cannot report the time would silently pass every delegation as
|
|
602
|
-
// unexpired). Fail closed instead: an unusable clock is treated the same
|
|
603
|
-
// as an already-expired one.
|
|
604
|
-
if (!Number.isFinite(nowMs) || expiresMs <= nowMs) {
|
|
605
|
-
return {
|
|
606
|
-
ok: false,
|
|
607
|
-
reason: "expired",
|
|
608
|
-
detail: Number.isFinite(nowMs)
|
|
609
|
-
? `delegation at ${filePath} expired at ${expiresAt} (now ${new Date(nowMs).toISOString()})`
|
|
610
|
-
: `delegation at ${filePath} cannot be checked for expiry: the supplied clock is unusable (now getTime() => ${nowMs})`,
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
if (cwdHash !== null) {
|
|
614
|
-
if (opts.cwd === null) {
|
|
615
|
-
return {
|
|
616
|
-
ok: false,
|
|
617
|
-
reason: "cwd_mismatch",
|
|
618
|
-
detail: `delegation at ${filePath} is bound to a cwd but the caller supplied none`,
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
const actual = hashDelegationCwd(opts.cwd);
|
|
622
|
-
if (actual !== cwdHash) {
|
|
623
|
-
return {
|
|
624
|
-
ok: false,
|
|
625
|
-
reason: "cwd_mismatch",
|
|
626
|
-
detail: `delegation at ${filePath} is bound to a different cwd (bound ${cwdHash}, got ${actual} for ${opts.cwd})`,
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
if (taskId !== null) {
|
|
631
|
-
if (opts.taskId === null) {
|
|
632
|
-
return {
|
|
633
|
-
ok: false,
|
|
634
|
-
reason: "task_mismatch",
|
|
635
|
-
detail: `delegation at ${filePath} is bound to task ${taskId} but the caller supplied none`,
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
if (opts.taskId !== taskId) {
|
|
639
|
-
return {
|
|
640
|
-
ok: false,
|
|
641
|
-
reason: "task_mismatch",
|
|
642
|
-
detail: `delegation at ${filePath} is bound to task ${taskId}, not ${opts.taskId}`,
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
// Set only inside the `reportPathHash !== undefined` branch below, and
|
|
647
|
-
// only after the content hash has matched: the exact bytes returned to
|
|
648
|
-
// the caller in the ok shape's `reportContent`.
|
|
649
|
-
let reportContent;
|
|
650
|
-
if (reportPathHash !== undefined) {
|
|
651
|
-
if (opts.launcherReportPath === undefined) {
|
|
652
|
-
return {
|
|
653
|
-
ok: false,
|
|
654
|
-
reason: "report_path_mismatch",
|
|
655
|
-
detail: `delegation at ${filePath} binds a launcher-supplied report but no report path was offered`,
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
// Existence, BEFORE the path hash: `hashDelegationCwd` falls back to
|
|
659
|
-
// `path.resolve` for a path that does not exist, and under a
|
|
660
|
-
// symlinked temp root (macOS `os.tmpdir()`) that fallback can
|
|
661
|
-
// disagree with the write-time `realpathSync`, which would otherwise
|
|
662
|
-
// surface a plain "the file is gone" as `report_path_mismatch`
|
|
663
|
-
// instead of naming what actually happened. `probePathPresence`
|
|
664
|
-
// (shared home: `src/io/read-regular-file.ts`, same `lstatSync` as
|
|
665
|
-
// `readRegularFileRejectingSymlink` below) is a cheap stat-only probe,
|
|
666
|
-
// not the full read: it only asks "is anything there", so the ok path
|
|
667
|
-
// still reads the file's bytes exactly once, below, after the path
|
|
668
|
-
// hash and the content-hash presence have both already passed. A
|
|
669
|
-
// symlink or a directory here answers `present` and falls through to
|
|
670
|
-
// the path/content checks: a resolvable symlink is normally caught at
|
|
671
|
-
// the next step (`report_path_mismatch`); a dangling symlink or a
|
|
672
|
-
// directory reaches the full read and fails there instead
|
|
673
|
-
// (`report_content_mismatch`) once it cannot produce matching bytes.
|
|
674
|
-
// It is deliberately not treated as missing.
|
|
675
|
-
if (probePathPresence(opts.launcherReportPath).kind === "missing") {
|
|
676
|
-
return {
|
|
677
|
-
ok: false,
|
|
678
|
-
reason: "report_missing",
|
|
679
|
-
detail: `delegation at ${filePath} binds a launcher-supplied report but nothing could be stat'ed at ${opts.launcherReportPath} (absent, or not reachable: EACCES, ENOTDIR)`,
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
const actualPathHash = hashDelegationCwd(opts.launcherReportPath);
|
|
683
|
-
if (actualPathHash !== reportPathHash) {
|
|
684
|
-
return {
|
|
685
|
-
ok: false,
|
|
686
|
-
reason: "report_path_mismatch",
|
|
687
|
-
detail: `delegation at ${filePath} binds a report at a different path (bound ${reportPathHash}, got ${actualPathHash} for ${opts.launcherReportPath})`,
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
const boundContentHash = typeof body["reportContentHash"] === "string" ? body["reportContentHash"] : null;
|
|
691
|
-
if (boundContentHash === null) {
|
|
692
|
-
return {
|
|
693
|
-
ok: false,
|
|
694
|
-
reason: "report_content_mismatch",
|
|
695
|
-
detail: `delegation at ${filePath} carries a report path binding but no reportContentHash to check the file against`,
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
// The single full read of the launcher report on the ok path: done
|
|
699
|
-
// only now, after the path hash and the content-hash presence have
|
|
700
|
-
// both already passed, so the bytes hashed below are the bytes
|
|
701
|
-
// returned to the caller in `reportContent` (no second read, no
|
|
702
|
-
// second trust decision on a file the child does not control).
|
|
703
|
-
const reportRead = readRegularFileRejectingSymlink(opts.launcherReportPath);
|
|
704
|
-
if (reportRead.kind !== "ok") {
|
|
705
|
-
return {
|
|
706
|
-
ok: false,
|
|
707
|
-
reason: "report_content_mismatch",
|
|
708
|
-
detail: `launcher-supplied report at ${opts.launcherReportPath} could not be read (${reportRead.kind}); its content cannot be checked against the bound hash`,
|
|
709
|
-
};
|
|
710
|
-
}
|
|
711
|
-
const actualContentHash = sha256Hex(reportRead.content);
|
|
712
|
-
if (actualContentHash !== boundContentHash) {
|
|
713
|
-
return {
|
|
714
|
-
ok: false,
|
|
715
|
-
reason: "report_content_mismatch",
|
|
716
|
-
detail: `launcher-supplied report at ${opts.launcherReportPath} does not match the bound content hash (bound ${boundContentHash}, got ${actualContentHash})`,
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
// The exact bytes this call just hashed and matched against the
|
|
720
|
-
// bound hash: returned so the caller persists THESE bytes rather
|
|
721
|
-
// than opening the file a second time (a second read would be a
|
|
722
|
-
// second trust decision, and the very race this closes).
|
|
723
|
-
reportContent = reportRead.content;
|
|
724
|
-
}
|
|
725
|
-
return {
|
|
726
|
-
ok: true,
|
|
727
|
-
parentSessionId,
|
|
728
|
-
expiresAt,
|
|
729
|
-
boundCwdHash: cwdHash,
|
|
730
|
-
boundTaskId: taskId,
|
|
731
|
-
...(reportPathHash !== undefined ? { reportPathHash, reportContent: reportContent } : {}),
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
//# sourceMappingURL=delegation-markers.js.map
|