open-multi-agent-kit 0.90.8 → 0.91.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 +41 -0
- package/README.md +21 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +4 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/doctor-provider-cli.d.ts +33 -0
- package/dist/commands/doctor-provider-cli.d.ts.map +1 -0
- package/dist/commands/doctor-provider-cli.js +215 -0
- package/dist/commands/doctor-provider-cli.js.map +1 -0
- package/dist/commands/doctor-provider-transport.d.ts +35 -0
- package/dist/commands/doctor-provider-transport.d.ts.map +1 -0
- package/dist/commands/doctor-provider-transport.js +185 -0
- package/dist/commands/doctor-provider-transport.js.map +1 -0
- package/dist/commands/doctor-provider.d.ts +121 -7
- package/dist/commands/doctor-provider.d.ts.map +1 -1
- package/dist/commands/doctor-provider.js +1295 -102
- package/dist/commands/doctor-provider.js.map +1 -1
- package/dist/commands/session-doctor-cli.d.ts +43 -0
- package/dist/commands/session-doctor-cli.d.ts.map +1 -0
- package/dist/commands/session-doctor-cli.js +494 -0
- package/dist/commands/session-doctor-cli.js.map +1 -0
- package/dist/commands/verify-ci.d.ts +21 -0
- package/dist/commands/verify-ci.d.ts.map +1 -0
- package/dist/commands/verify-ci.js +66 -0
- package/dist/commands/verify-ci.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +3 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +140 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1179 -95
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agent-tool-settings.d.ts +35 -0
- package/dist/core/agent-tool-settings.d.ts.map +1 -0
- package/dist/core/agent-tool-settings.js +155 -0
- package/dist/core/agent-tool-settings.js.map +1 -0
- package/dist/core/atomic-session-file.d.ts +14 -0
- package/dist/core/atomic-session-file.d.ts.map +1 -0
- package/dist/core/atomic-session-file.js +104 -0
- package/dist/core/atomic-session-file.js.map +1 -0
- package/dist/core/command-safety.d.ts.map +1 -1
- package/dist/core/command-safety.js +0 -8
- package/dist/core/command-safety.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +6 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +12 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/hysteresis.d.ts +27 -0
- package/dist/core/compaction/hysteresis.d.ts.map +1 -0
- package/dist/core/compaction/hysteresis.js +84 -0
- package/dist/core/compaction/hysteresis.js.map +1 -0
- package/dist/core/compaction/index.d.ts +2 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +2 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/transaction.d.ts +172 -0
- package/dist/core/compaction/transaction.d.ts.map +1 -0
- package/dist/core/compaction/transaction.js +824 -0
- package/dist/core/compaction/transaction.js.map +1 -0
- package/dist/core/context-budget-governor-v2.d.ts +2 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +2 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-reserved-tokens.d.ts +110 -0
- package/dist/core/context-budget-reserved-tokens.d.ts.map +1 -0
- package/dist/core/context-budget-reserved-tokens.js +188 -0
- package/dist/core/context-budget-reserved-tokens.js.map +1 -0
- package/dist/core/context-budget-v2-cache-invalidation.d.ts +133 -0
- package/dist/core/context-budget-v2-cache-invalidation.d.ts.map +1 -0
- package/dist/core/context-budget-v2-cache-invalidation.js +452 -0
- package/dist/core/context-budget-v2-cache-invalidation.js.map +1 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +6 -0
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-cache-provider.d.ts +4 -0
- package/dist/core/context-budget-v2-cache-provider.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-provider.js +19 -0
- package/dist/core/context-budget-v2-cache-provider.js.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-plan-cache-keys.js +1 -0
- package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +1 -0
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +4 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/durable-file-directory.d.ts +4 -0
- package/dist/core/durable-file-directory.d.ts.map +1 -0
- package/dist/core/durable-file-directory.js +76 -0
- package/dist/core/durable-file-directory.js.map +1 -0
- package/dist/core/durable-file-identity.d.ts +26 -0
- package/dist/core/durable-file-identity.d.ts.map +1 -0
- package/dist/core/durable-file-identity.js +118 -0
- package/dist/core/durable-file-identity.js.map +1 -0
- package/dist/core/durable-file-io.d.ts +29 -0
- package/dist/core/durable-file-io.d.ts.map +1 -0
- package/dist/core/durable-file-io.js +179 -0
- package/dist/core/durable-file-io.js.map +1 -0
- package/dist/core/durable-file-lock-cleanup.d.ts +12 -0
- package/dist/core/durable-file-lock-cleanup.d.ts.map +1 -0
- package/dist/core/durable-file-lock-cleanup.js +39 -0
- package/dist/core/durable-file-lock-cleanup.js.map +1 -0
- package/dist/core/durable-file-lock-owner.d.ts +18 -0
- package/dist/core/durable-file-lock-owner.d.ts.map +1 -0
- package/dist/core/durable-file-lock-owner.js +78 -0
- package/dist/core/durable-file-lock-owner.js.map +1 -0
- package/dist/core/durable-file-lock-storage.d.ts +35 -0
- package/dist/core/durable-file-lock-storage.d.ts.map +1 -0
- package/dist/core/durable-file-lock-storage.js +263 -0
- package/dist/core/durable-file-lock-storage.js.map +1 -0
- package/dist/core/durable-file-mode.d.ts +8 -0
- package/dist/core/durable-file-mode.d.ts.map +1 -0
- package/dist/core/durable-file-mode.js +41 -0
- package/dist/core/durable-file-mode.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +12 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +46 -37
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +7 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +12 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +7 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/metrics-sampler.d.ts +20 -0
- package/dist/core/metrics-sampler.d.ts.map +1 -1
- package/dist/core/metrics-sampler.js +52 -0
- package/dist/core/metrics-sampler.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +4 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +16 -7
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-resilience.d.ts +51 -0
- package/dist/core/provider-resilience.d.ts.map +1 -0
- package/dist/core/provider-resilience.js +86 -0
- package/dist/core/provider-resilience.js.map +1 -0
- package/dist/core/redaction.d.ts +8 -0
- package/dist/core/redaction.d.ts.map +1 -0
- package/dist/core/redaction.js +31 -0
- package/dist/core/redaction.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +36 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/run-journal-store.d.ts +53 -0
- package/dist/core/run-journal-store.d.ts.map +1 -0
- package/dist/core/run-journal-store.js +278 -0
- package/dist/core/run-journal-store.js.map +1 -0
- package/dist/core/run-journal.d.ts +172 -0
- package/dist/core/run-journal.d.ts.map +1 -0
- package/dist/core/run-journal.js +1045 -0
- package/dist/core/run-journal.js.map +1 -0
- package/dist/core/sdk.d.ts +7 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +94 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-doctor-plan.d.ts +128 -0
- package/dist/core/session-doctor-plan.d.ts.map +1 -0
- package/dist/core/session-doctor-plan.js +833 -0
- package/dist/core/session-doctor-plan.js.map +1 -0
- package/dist/core/session-file-compaction.d.ts +6 -0
- package/dist/core/session-file-compaction.d.ts.map +1 -0
- package/dist/core/session-file-compaction.js +169 -0
- package/dist/core/session-file-compaction.js.map +1 -0
- package/dist/core/session-file-head.d.ts +10 -0
- package/dist/core/session-file-head.d.ts.map +1 -0
- package/dist/core/session-file-head.js +78 -0
- package/dist/core/session-file-head.js.map +1 -0
- package/dist/core/session-file-persistence.d.ts +30 -0
- package/dist/core/session-file-persistence.d.ts.map +1 -0
- package/dist/core/session-file-persistence.js +106 -0
- package/dist/core/session-file-persistence.js.map +1 -0
- package/dist/core/session-integrity.d.ts +43 -0
- package/dist/core/session-integrity.d.ts.map +1 -0
- package/dist/core/session-integrity.js +420 -0
- package/dist/core/session-integrity.js.map +1 -0
- package/dist/core/session-manager.d.ts +24 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +242 -125
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-owner-lease.d.ts +22 -0
- package/dist/core/session-owner-lease.d.ts.map +1 -0
- package/dist/core/session-owner-lease.js +176 -0
- package/dist/core/session-owner-lease.js.map +1 -0
- package/dist/core/session-path-policy.d.ts +132 -0
- package/dist/core/session-path-policy.d.ts.map +1 -0
- package/dist/core/session-path-policy.js +780 -0
- package/dist/core/session-path-policy.js.map +1 -0
- package/dist/core/session-repair-plan.d.ts +49 -0
- package/dist/core/session-repair-plan.d.ts.map +1 -0
- package/dist/core/session-repair-plan.js +202 -0
- package/dist/core/session-repair-plan.js.map +1 -0
- package/dist/core/session-termination.d.ts +106 -0
- package/dist/core/session-termination.d.ts.map +1 -0
- package/dist/core/session-termination.js +445 -0
- package/dist/core/session-termination.js.map +1 -0
- package/dist/core/settings-manager.d.ts +52 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +54 -5
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +47 -0
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/omp-pure-seams.d.ts +41 -0
- package/dist/core/tools/omp-pure-seams.d.ts.map +1 -0
- package/dist/core/tools/omp-pure-seams.js +142 -0
- package/dist/core/tools/omp-pure-seams.js.map +1 -0
- package/dist/core/tools/omp-seam-runtime.d.ts +100 -0
- package/dist/core/tools/omp-seam-runtime.d.ts.map +1 -0
- package/dist/core/tools/omp-seam-runtime.js +40 -0
- package/dist/core/tools/omp-seam-runtime.js.map +1 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +34 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/verified-bash-adapter.d.ts +36 -0
- package/dist/core/verified-bash-adapter.d.ts.map +1 -0
- package/dist/core/verified-bash-adapter.js +90 -0
- package/dist/core/verified-bash-adapter.js.map +1 -0
- package/dist/guardrails/command-redaction.d.ts +32 -0
- package/dist/guardrails/command-redaction.d.ts.map +1 -0
- package/dist/guardrails/command-redaction.js +776 -0
- package/dist/guardrails/command-redaction.js.map +1 -0
- package/dist/guardrails/evidence-attestation.d.ts +31 -0
- package/dist/guardrails/evidence-attestation.d.ts.map +1 -0
- package/dist/guardrails/evidence-attestation.js +178 -0
- package/dist/guardrails/evidence-attestation.js.map +1 -0
- package/dist/guardrails/evidence-receipt-store.d.ts +33 -0
- package/dist/guardrails/evidence-receipt-store.d.ts.map +1 -0
- package/dist/guardrails/evidence-receipt-store.js +446 -0
- package/dist/guardrails/evidence-receipt-store.js.map +1 -0
- package/dist/guardrails/evidence-receipt.d.ts +58 -0
- package/dist/guardrails/evidence-receipt.d.ts.map +1 -0
- package/dist/guardrails/evidence-receipt.js +389 -0
- package/dist/guardrails/evidence-receipt.js.map +1 -0
- package/dist/guardrails/evidence-system.d.ts +39 -15
- package/dist/guardrails/evidence-system.d.ts.map +1 -1
- package/dist/guardrails/evidence-system.js +255 -97
- package/dist/guardrails/evidence-system.js.map +1 -1
- package/dist/guardrails/replay-ledger-io.d.ts +6 -0
- package/dist/guardrails/replay-ledger-io.d.ts.map +1 -0
- package/dist/guardrails/replay-ledger-io.js +42 -0
- package/dist/guardrails/replay-ledger-io.js.map +1 -0
- package/dist/guardrails/replay-ledger-lock-owner.d.ts +32 -0
- package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -0
- package/dist/guardrails/replay-ledger-lock-owner.js +138 -0
- package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -0
- package/dist/guardrails/replay-ledger-lock.d.ts +24 -0
- package/dist/guardrails/replay-ledger-lock.d.ts.map +1 -0
- package/dist/guardrails/replay-ledger-lock.js +135 -0
- package/dist/guardrails/replay-ledger-lock.js.map +1 -0
- package/dist/guardrails/replay-ledger-mutation-gate.d.ts +24 -0
- package/dist/guardrails/replay-ledger-mutation-gate.d.ts.map +1 -0
- package/dist/guardrails/replay-ledger-mutation-gate.js +205 -0
- package/dist/guardrails/replay-ledger-mutation-gate.js.map +1 -0
- package/dist/guardrails/replay-ledger-quarantine.d.ts +2 -0
- package/dist/guardrails/replay-ledger-quarantine.d.ts.map +1 -0
- package/dist/guardrails/replay-ledger-quarantine.js +19 -0
- package/dist/guardrails/replay-ledger-quarantine.js.map +1 -0
- package/dist/guardrails/replay-ledger-store.d.ts +32 -0
- package/dist/guardrails/replay-ledger-store.d.ts.map +1 -0
- package/dist/guardrails/replay-ledger-store.js +211 -0
- package/dist/guardrails/replay-ledger-store.js.map +1 -0
- package/dist/guardrails/shell-command-name-glob.d.ts +3 -0
- package/dist/guardrails/shell-command-name-glob.d.ts.map +1 -0
- package/dist/guardrails/shell-command-name-glob.js +233 -0
- package/dist/guardrails/shell-command-name-glob.js.map +1 -0
- package/dist/guardrails/shell-command-option.d.ts +7 -0
- package/dist/guardrails/shell-command-option.d.ts.map +1 -0
- package/dist/guardrails/shell-command-option.js +24 -0
- package/dist/guardrails/shell-command-option.js.map +1 -0
- package/dist/guardrails/shell-command-tokenizer.d.ts +29 -0
- package/dist/guardrails/shell-command-tokenizer.d.ts.map +1 -0
- package/dist/guardrails/shell-command-tokenizer.js +145 -0
- package/dist/guardrails/shell-command-tokenizer.js.map +1 -0
- package/dist/guardrails/shell-command-wrapper.d.ts +18 -0
- package/dist/guardrails/shell-command-wrapper.d.ts.map +1 -0
- package/dist/guardrails/shell-command-wrapper.js +42 -0
- package/dist/guardrails/shell-command-wrapper.js.map +1 -0
- package/dist/guardrails/verified-executor.d.ts +65 -0
- package/dist/guardrails/verified-executor.d.ts.map +1 -0
- package/dist/guardrails/verified-executor.js +171 -0
- package/dist/guardrails/verified-executor.js.map +1 -0
- package/dist/guardrails/workspace-fingerprint.d.ts +23 -0
- package/dist/guardrails/workspace-fingerprint.d.ts.map +1 -0
- package/dist/guardrails/workspace-fingerprint.js +634 -0
- package/dist/guardrails/workspace-fingerprint.js.map +1 -0
- package/dist/index.d.ts +15 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +11 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +59 -9
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/omk-aurora-dark.json +80 -0
- package/dist/modes/interactive/theme/omk-aurora-light.json +80 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +5 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +43 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -5
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +3 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/types/evidence.d.ts +211 -1
- package/dist/types/evidence.d.ts.map +1 -1
- package/dist/types/evidence.js.map +1 -1
- package/dist/verify-ci.d.ts +3 -0
- package/dist/verify-ci.d.ts.map +1 -0
- package/dist/verify-ci.js +30 -0
- package/dist/verify-ci.js.map +1 -0
- package/docs/adaptorch-preview.md +1 -1
- package/docs/compaction.md +38 -4
- package/docs/extensions.md +2 -0
- package/docs/provider-resilience.md +87 -0
- package/docs/sdk.md +238 -1
- package/docs/settings.md +80 -2
- package/docs/themes.md +2 -0
- package/docs/usage.md +38 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +5 -5
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +4 -4
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +22 -13
- package/package.json +6 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-redaction.js","sourceRoot":"","sources":["../../src/guardrails/command-redaction.ts"],"names":[],"mappings":"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","sourcesContent":["// allow: SIZE_OK - command-string secret policy: single source of truth for credential\n// detection, placeholder tokenization, and the internal HMAC key boundary (ALG-003 §7.7).\nimport type {\n\tCommandHmacBinding,\n\tCommandRedactionPlaceholder,\n\tCommandRedactionPlaceholderType,\n\tCommandRedactionSummary,\n\tEvidenceCommandDescriptor,\n\tSha256Hex,\n} from \"../types/evidence.ts\";\nimport {\n\ttype NormalizedStaticShell,\n\tStaticShellSyntaxError,\n\tnormalizeStaticShell as tokenizeStaticShell,\n} from \"./shell-command-tokenizer.ts\";\n\n/** Identifies the tokenization rules that produced a persisted redacted command. */\nexport const EVIDENCE_COMMAND_REDACTION_POLICY_ID = \"omk-command-redaction-v1\" as const;\n\n/** Upper bound for the total number of placeholders in one redacted command. */\nexport const MAX_COMMAND_REDACTION_PLACEHOLDERS = 256;\n\nconst REDACTED = \"[REDACTED]\";\nconst KEY_ID_HEX = /^[0-9a-f]{16}$/;\nconst NONCE_HEX = /^[0-9a-f]{32}$/;\nconst MAC_HEX = /^[0-9a-f]{64}$/;\n\nconst PLACEHOLDER_TYPES: readonly CommandRedactionPlaceholderType[] = Object.freeze([\n\t\"api-key-header\",\n\t\"authorization-header\",\n\t\"basic-auth\",\n\t\"bearer-token\",\n\t\"cli-option-inline\",\n\t\"cli-option-value\",\n\t\"cookie-header\",\n\t\"env-assignment\",\n\t\"known-token\",\n\t\"url-credential\",\n\t\"url-query\",\n]);\nconst PLACEHOLDER_TYPE_SET: ReadonlySet<string> = new Set(PLACEHOLDER_TYPES);\n\n/** All command redaction failures are static-message errors that never echo command data. */\nexport class CommandRedactionError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CommandRedactionError\";\n\t}\n}\n\n// ============================================================================\n// Structural command-shape validation (paranoid, own-enumerable-data only)\n// ============================================================================\n\nfunction exactObject(\n\tvalue: unknown,\n\tlabel: string,\n\trequiredKeys: readonly string[],\n\toptionalKeys: readonly string[] = [],\n): Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\tthrow new CommandRedactionError(`${label} must be an object`);\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst descriptors = Object.getOwnPropertyDescriptors(record);\n\tconst actual = Object.entries(descriptors)\n\t\t.filter(([, descriptor]) => descriptor.enumerable)\n\t\t.map(([key]) => key)\n\t\t.sort();\n\tconst allowed = new Set([...requiredKeys, ...optionalKeys]);\n\tconst isOwnEnumerableDataProperty = (key: string): boolean => {\n\t\tconst descriptor = descriptors[key];\n\t\treturn descriptor !== undefined && descriptor.enumerable === true && \"value\" in descriptor;\n\t};\n\tif (\n\t\tactual.some((key) => !allowed.has(key)) ||\n\t\trequiredKeys.some((key) => !isOwnEnumerableDataProperty(key)) ||\n\t\toptionalKeys.some((key) => key in record && !isOwnEnumerableDataProperty(key))\n\t) {\n\t\tthrow new CommandRedactionError(`${label} has an invalid key set`);\n\t}\n\tconst snapshot: Record<string, unknown> = {};\n\tfor (const key of actual) {\n\t\tconst descriptor = descriptors[key];\n\t\tif (descriptor === undefined || !(\"value\" in descriptor)) {\n\t\t\tthrow new CommandRedactionError(`${label} has an invalid key set`);\n\t\t}\n\t\tsnapshot[key] = descriptor.value;\n\t}\n\treturn snapshot;\n}\n\nfunction exactArray(value: unknown, label: string): unknown[] {\n\tif (!Array.isArray(value)) throw new CommandRedactionError(`${label} must be an array`);\n\tconst descriptors = Object.getOwnPropertyDescriptors(value);\n\tconst lengthDescriptor = descriptors.length as PropertyDescriptor | undefined;\n\tif (lengthDescriptor === undefined || !(\"value\" in lengthDescriptor)) {\n\t\tthrow new CommandRedactionError(`${label} has invalid index properties`);\n\t}\n\tconst rawLength = lengthDescriptor.value;\n\tif (!Number.isSafeInteger(rawLength) || (rawLength as number) < 0) {\n\t\tthrow new CommandRedactionError(`${label} has invalid index properties`);\n\t}\n\tconst length = rawLength as number;\n\tconst snapshot: unknown[] = [];\n\tfor (let index = 0; index < length; index++) {\n\t\tconst descriptor = descriptors[String(index)];\n\t\tif (descriptor === undefined || descriptor.enumerable !== true || !(\"value\" in descriptor)) {\n\t\t\tthrow new CommandRedactionError(`${label} must use own enumerable data index properties`);\n\t\t}\n\t\tsnapshot.push(descriptor.value);\n\t}\n\tconst enumerableKeys = Object.entries(descriptors)\n\t\t.filter(([, descriptor]) => descriptor.enumerable)\n\t\t.map(([key]) => key);\n\tif (enumerableKeys.length !== length || enumerableKeys.some((key, index) => key !== String(index))) {\n\t\tthrow new CommandRedactionError(`${label} must use own enumerable data index properties`);\n\t}\n\treturn snapshot;\n}\n\nfunction ownEnumerableDataProperty(record: Record<string, unknown>, label: string, key: string): unknown {\n\tconst descriptor = Object.getOwnPropertyDescriptor(record, key);\n\tif (descriptor === undefined || descriptor.enumerable !== true || !(\"value\" in descriptor)) {\n\t\tthrow new CommandRedactionError(`${label} has an invalid key set`);\n\t}\n\treturn descriptor.value;\n}\n\nfunction nonEmptyString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\" || value.length === 0 || value.includes(\"\\0\")) {\n\t\tthrow new CommandRedactionError(`${label} must be a non-empty string without NUL bytes`);\n\t}\n\treturn value;\n}\n\nfunction stringWithoutNul(value: unknown, label: string): string {\n\tif (typeof value !== \"string\" || value.includes(\"\\0\")) {\n\t\tthrow new CommandRedactionError(`${label} must be a string without NUL bytes`);\n\t}\n\treturn value;\n}\n\nfunction positiveBoundedInteger(value: unknown, label: string, max: number): number {\n\tif (!Number.isSafeInteger(value) || (value as number) <= 0 || (value as number) > max) {\n\t\tthrow new CommandRedactionError(`${label} must be a positive integer within the placeholder bound`);\n\t}\n\treturn value as number;\n}\n\n/** Structure-only parse of a command descriptor; performs no credential policy checks. */\nexport function parseEvidenceCommandShape(value: unknown): EvidenceCommandDescriptor {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\tthrow new CommandRedactionError(\"receipt core command must be an object\");\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tconst kind = ownEnumerableDataProperty(candidate, \"command descriptor\", \"kind\");\n\tif (kind === \"argv\") {\n\t\tconst raw = exactObject(value, \"argv command descriptor\", [\"kind\", \"executable\", \"argv\"]);\n\t\tconst rawArgv = exactArray(raw.argv, \"argv command descriptor argv\");\n\t\tif (!rawArgv.every((argument) => typeof argument === \"string\")) {\n\t\t\tthrow new CommandRedactionError(\"argv command descriptor argv must be a string array\");\n\t\t}\n\t\tconst executable = nonEmptyString(raw.executable, \"argv command executable\");\n\t\tconst argv = rawArgv.map((argument, index) => stringWithoutNul(argument, `argv[${index}]`));\n\t\treturn Object.freeze({ kind: \"argv\", executable, argv: Object.freeze(argv) });\n\t}\n\tif (kind === \"shell\") {\n\t\tconst raw = exactObject(value, \"shell command descriptor\", [\"kind\", \"shell\", \"script\"]);\n\t\treturn Object.freeze({\n\t\t\tkind: \"shell\",\n\t\t\tshell: nonEmptyString(raw.shell, \"shell command identity\"),\n\t\t\tscript: nonEmptyString(raw.script, \"shell command script\"),\n\t\t});\n\t}\n\tthrow new CommandRedactionError(\"receipt command kind must be argv or shell\");\n}\n\n// ============================================================================\n// Placeholder recognition\n// ============================================================================\n\nfunction unquote(value: string): string {\n\tif (\n\t\tvalue.length >= 2 &&\n\t\t((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\")))\n\t) {\n\t\treturn value.slice(1, -1);\n\t}\n\treturn value;\n}\n\nfunction shellCredentialValue(value: string): string {\n\tconst candidate = value.trim();\n\tif (\n\t\tcandidate.length >= 2 &&\n\t\t((candidate.startsWith('\"') && candidate.endsWith('\"')) || (candidate.startsWith(\"'\") && candidate.endsWith(\"'\")))\n\t) {\n\t\treturn candidate.slice(1, -1);\n\t}\n\tif (candidate.endsWith('\"') || candidate.endsWith(\"'\")) return candidate.slice(0, -1);\n\treturn candidate;\n}\n\nfunction isCredentialPlaceholder(value: string): boolean {\n\tconst candidate = unquote(shellCredentialValue(value));\n\treturn (\n\t\t/^\\[(?:REDACTED|MASKED)\\]$/i.test(candidate) ||\n\t\t/^<(?:redacted|masked)>$/i.test(candidate) ||\n\t\t/^\\$[A-Za-z_][A-Za-z0-9_]*$/.test(candidate) ||\n\t\t/^\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}$/.test(candidate)\n\t);\n}\n\nfunction isAuthorizationPlaceholder(value: string): boolean {\n\tconst candidate = shellCredentialValue(value);\n\tconst scheme = /^(?:bearer|basic)\\s+(.+)$/i.exec(candidate);\n\treturn isCredentialPlaceholder(scheme?.[1] ?? candidate);\n}\n\nfunction isBasicAuthPlaceholder(value: string): boolean {\n\tconst candidate = shellCredentialValue(value);\n\tif (isCredentialPlaceholder(candidate)) return true;\n\tconst separator = candidate.indexOf(\":\");\n\treturn separator >= 0 && isCredentialPlaceholder(candidate.slice(separator + 1));\n}\n\n// ============================================================================\n// Header credential scanning (shared by detection and tokenization)\n// ============================================================================\n\ntype HeaderValueBoundary = \"argument\" | \"shell\";\n\ninterface HeaderCredentialRule {\n\treadonly type: \"api-key-header\" | \"authorization-header\" | \"cookie-header\";\n\treadonly preserveScheme: boolean;\n}\n\nfunction headerCredentialRule(name: string): HeaderCredentialRule | undefined {\n\tconst normalized = name.toLowerCase().replaceAll(\"_\", \"-\");\n\tif (normalized === \"authorization\" || normalized === \"proxy-authorization\") {\n\t\treturn { type: \"authorization-header\", preserveScheme: true };\n\t}\n\tif (normalized === \"cookie\" || normalized === \"set-cookie\") {\n\t\treturn { type: \"cookie-header\", preserveScheme: false };\n\t}\n\tif (\n\t\t/^(?:x-)?(?:[a-z0-9]+-)*(?:api-key|api-token|auth-token|access-token|security-token|bearer-token|private-key|token)$/.test(\n\t\t\tnormalized,\n\t\t) ||\n\t\t/^x-(?:[a-z0-9]+-)+key$/.test(normalized)\n\t) {\n\t\treturn { type: \"api-key-header\", preserveScheme: false };\n\t}\n\treturn undefined;\n}\n\ninterface RedactionSpan {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly type: CommandRedactionPlaceholderType;\n\treadonly exactArgumentEnd?: boolean;\n}\n\nfunction isHeaderTokenBoundary(character: string): boolean {\n\treturn /[\\s,;|()\"'`]/.test(character);\n}\n\nfunction isHeaderTokenStart(text: string, index: number): boolean {\n\tif (index === 0 || isHeaderTokenBoundary(text[index - 1])) return true;\n\tconst shortOptionStart = index - 2;\n\tif (\n\t\tshortOptionStart >= 0 &&\n\t\ttext.slice(shortOptionStart, index) === \"-H\" &&\n\t\t(shortOptionStart === 0 || isHeaderTokenBoundary(text[shortOptionStart - 1]))\n\t) {\n\t\treturn true;\n\t}\n\tconst longOptionStart = index - 9;\n\treturn (\n\t\tlongOptionStart >= 0 &&\n\t\ttext.slice(longOptionStart, index) === \"--header=\" &&\n\t\t(longOptionStart === 0 || isHeaderTokenBoundary(text[longOptionStart - 1]))\n\t);\n}\n\ninterface HeaderValueAtom {\n\treadonly value: string;\n\treadonly start: number;\n\treadonly end: number;\n\treadonly scanEnd: number;\n}\n\nfunction staticShellError(): never {\n\tthrow new CommandRedactionError(\"shell command is dynamic or malformed; failing closed\");\n}\n\nfunction normalizeStaticShell(text: string): NormalizedStaticShell {\n\ttry {\n\t\treturn tokenizeStaticShell(text);\n\t} catch (error) {\n\t\tif (error instanceof StaticShellSyntaxError) staticShellError();\n\t\tthrow error;\n\t}\n}\n\nfunction readCompleteHeaderValue(text: string, start: number): HeaderValueAtom | undefined {\n\tlet valueStart = start;\n\twhile (valueStart < text.length && /\\s/.test(text[valueStart])) valueStart++;\n\treturn valueStart === text.length\n\t\t? undefined\n\t\t: { value: text.slice(valueStart), start: valueStart, end: text.length, scanEnd: text.length };\n}\n\n/**\n * Walk every credential-bearing header occurrence. Returns whether any literal\n * (non-placeholder) credential exists; optionally collects replacement spans.\n */\nfunction scanHeaderCredentials(text: string, spans?: RedactionSpan[]): boolean {\n\tlet found = false;\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (!isHeaderTokenStart(text, index)) continue;\n\t\tconst name = /^[A-Za-z][A-Za-z0-9_-]*/.exec(text.slice(index))?.[0];\n\t\tif (name === undefined) continue;\n\t\tconst rule = headerCredentialRule(name);\n\t\tif (rule === undefined) continue;\n\t\tlet separatorIndex = index + name.length;\n\t\twhile (separatorIndex < text.length && /\\s/.test(text[separatorIndex])) separatorIndex++;\n\t\tif (text[separatorIndex] !== \":\" && text[separatorIndex] !== \"=\") continue;\n\t\tif (text[separatorIndex] === \"=\" && name.includes(\"_\")) continue;\n\t\tconst credential = readCompleteHeaderValue(text, separatorIndex + 1);\n\t\tif (credential === undefined) {\n\t\t\tfound = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconst placeholder = rule.preserveScheme\n\t\t\t? isAuthorizationPlaceholder(credential.value)\n\t\t\t: isCredentialPlaceholder(credential.value);\n\t\tif (!placeholder) {\n\t\t\tfound = true;\n\t\t\tconst scheme = rule.preserveScheme ? /^(?:bearer|basic)\\s+/i.exec(credential.value) : null;\n\t\t\tconst redactStart = credential.start + (scheme?.[0].length ?? 0);\n\t\t\tif (redactStart < credential.end) spans?.push({ start: redactStart, end: credential.end, type: rule.type });\n\t\t}\n\t\tindex = Math.max(index, credential.scanEnd - 1);\n\t}\n\treturn found;\n}\n\n// ============================================================================\n// Pattern scanning (shared by detection and tokenization)\n// ============================================================================\n\nconst SECRET_NAME = `(?:token|secret|password|passwd|api[-_]?key|private[-_]?key)`;\nconst SECRET_OPTION_NAME = `(?:[A-Za-z0-9]+[-_])*${SECRET_NAME}(?:[-_][A-Za-z0-9]+)*`;\nconst envAssignmentPattern = () =>\n\tnew RegExp(\n\t\tString.raw`(?:^|[\\s;\"'\\x60])(?:export\\s+)?(?:[A-Za-z0-9_]*${SECRET_NAME}[A-Za-z0-9_]*)\\s*[:=]\\s*([^\\s;]+)`,\n\t\t\"dgi\",\n\t);\nconst cliOptionPattern = () =>\n\tnew RegExp(String.raw`--(?:${SECRET_OPTION_NAME}|authorization|cookie)(=|\\s+)([^\\s;]+)`, \"dgi\");\nconst basicAuthPattern = () =>\n\t/(?:^|[\\s;&|()\"'`])(?:(?:-[uU])(?:=|\\s+)?|--(?:proxy-)?user(?:=|\\s+))(\"[^\"\\r\\n;&|()]*\"|'[^'\\r\\n;&|()]*'|[^\\s;&|()]+)/dg;\nconst urlCredentialPattern = () => /\\b[a-z][a-z0-9+.-]*:\\/\\/[^/\\s:@]+:([^/\\s@]+)@/dgi;\nconst bareBearerPattern = () => /\\bbearer\\s+([A-Za-z0-9._~+/-]{12,})/dgi;\nconst knownTokenPattern = () =>\n\t/\\b(?:sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9_-]{16,}|github_pat_[A-Za-z0-9_]{20,}|npm_[A-Za-z0-9_-]{16,}|AIza[A-Za-z0-9_-]{35})\\b/dg;\n\ninterface PatternScan {\n\treadonly pattern: RegExp;\n\treadonly valueGroup: number;\n\treadonly placeholder?: (value: string) => boolean;\n\treadonly shellWord?: boolean;\n\treadonly shellStopCharacters?: string;\n\treadonly exactArgumentEnd?: boolean;\n\treadonly type: (match: RegExpMatchArray) => CommandRedactionPlaceholderType;\n}\n\nfunction scanPattern(\n\ttext: string,\n\tscan: PatternScan,\n\tspans?: RedactionSpan[],\n\tboundary: HeaderValueBoundary = \"shell\",\n\tshellWords?: NormalizedStaticShell[\"words\"],\n): boolean {\n\tlet found = false;\n\tfor (const match of text.matchAll(scan.pattern)) {\n\t\tconst value = match[scan.valueGroup];\n\t\tif (value === undefined || scan.placeholder?.(value)) continue;\n\t\tfound = true;\n\t\tif (spans === undefined) continue;\n\t\tconst indices = match.indices?.[scan.valueGroup];\n\t\tif (indices === undefined) continue;\n\t\tconst [start, rawEnd] = indices;\n\t\tlet end = rawEnd;\n\t\tif (scan.shellWord && boundary === \"shell\") {\n\t\t\tconst word = shellWords?.find((candidate) => start >= candidate.start && start < candidate.end);\n\t\t\tif (word !== undefined) {\n\t\t\t\tend = word.end;\n\t\t\t\tif (scan.shellStopCharacters !== undefined) {\n\t\t\t\t\tfor (let cursor = start; cursor < end; cursor++) {\n\t\t\t\t\t\tif (scan.shellStopCharacters.includes(text[cursor])) {\n\t\t\t\t\t\t\tend = cursor;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstaticShellError();\n\t\t\t}\n\t\t} else if (scan.exactArgumentEnd && scan.shellStopCharacters !== undefined) {\n\t\t\tend = start;\n\t\t\twhile (end < text.length && !scan.shellStopCharacters.includes(text[end])) end++;\n\t\t}\n\t\tspans.push({ start, end, type: scan.type(match), exactArgumentEnd: scan.exactArgumentEnd });\n\t}\n\treturn found;\n}\n\nconst ENV_SCAN: PatternScan = {\n\tpattern: envAssignmentPattern(),\n\tvalueGroup: 1,\n\tplaceholder: isCredentialPlaceholder,\n\tshellWord: true,\n\ttype: () => \"env-assignment\",\n};\nconst CLI_SCAN: PatternScan = {\n\tpattern: cliOptionPattern(),\n\tvalueGroup: 2,\n\tplaceholder: isCredentialPlaceholder,\n\tshellWord: true,\n\ttype: (match) => (match[1] === \"=\" ? \"cli-option-inline\" : \"cli-option-value\"),\n};\nconst BASIC_SCAN: PatternScan = {\n\tpattern: basicAuthPattern(),\n\tvalueGroup: 1,\n\tplaceholder: isBasicAuthPlaceholder,\n\tshellWord: true,\n\ttype: () => \"basic-auth\",\n};\nconst URL_SCAN: PatternScan = {\n\tpattern: urlCredentialPattern(),\n\tvalueGroup: 1,\n\tplaceholder: isCredentialPlaceholder,\n\ttype: () => \"url-credential\",\n};\nconst BEARER_SCAN: PatternScan = {\n\tpattern: bareBearerPattern(),\n\tvalueGroup: 1,\n\ttype: () => \"bearer-token\",\n};\nconst KNOWN_TOKEN_SCAN: PatternScan = {\n\tpattern: knownTokenPattern(),\n\tvalueGroup: 0,\n\ttype: () => \"known-token\",\n};\n\nfunction withFreshPattern(scan: PatternScan): PatternScan {\n\treturn { ...scan, pattern: new RegExp(scan.pattern.source, scan.pattern.flags) };\n}\n\nconst QUERY_SECRET_NAME = new RegExp(`^[A-Za-z0-9_.~-]*${SECRET_NAME}[A-Za-z0-9_.~-]*$`, \"i\");\n\ninterface QueryPair {\n\treadonly name: string;\n\treadonly rawName: string;\n\treadonly nameStart: number;\n\treadonly valueStart: number;\n\treadonly valueEnd: number;\n}\n\nfunction queryPairs(text: string): QueryPair[] {\n\tconst pairs: QueryPair[] = [];\n\tfor (let index = 0; index < text.length; index++) {\n\t\tif (text[index] !== \"?\" && text[index] !== \"&\") continue;\n\t\tconst nameStart = index + 1;\n\t\tlet separator = nameStart;\n\t\twhile (separator < text.length && !\"=&#\".includes(text[separator])) separator++;\n\t\tif (text[separator] !== \"=\") continue;\n\t\tconst rawName = text.slice(nameStart, separator);\n\t\tif (/%(?![0-9a-f]{2})/i.test(rawName)) staticShellError();\n\t\tlet name: string;\n\t\ttry {\n\t\t\tname = decodeURIComponent(rawName);\n\t\t} catch {\n\t\t\tstaticShellError();\n\t\t}\n\t\tif (/%[0-9a-f]{2}|%/i.test(name)) staticShellError();\n\t\tlet valueEnd = separator + 1;\n\t\twhile (valueEnd < text.length && text[valueEnd] !== \"&\" && text[valueEnd] !== \"#\") valueEnd++;\n\t\tpairs.push({ name, rawName, nameStart, valueStart: separator + 1, valueEnd });\n\t}\n\treturn pairs;\n}\n\nfunction scanUrlQueryCredentials(text: string, spans?: RedactionSpan[]): boolean {\n\tlet found = false;\n\tfor (const pair of queryPairs(text)) {\n\t\tif (!QUERY_SECRET_NAME.test(pair.name)) continue;\n\t\tconst value = text.slice(pair.valueStart, pair.valueEnd);\n\t\tif (!isCredentialPlaceholder(value)) {\n\t\t\tfound = true;\n\t\t\tif (pair.valueStart < pair.valueEnd) {\n\t\t\t\tspans?.push({ start: pair.valueStart, end: pair.valueEnd, type: \"url-query\", exactArgumentEnd: true });\n\t\t\t}\n\t\t}\n\t}\n\treturn found;\n}\n\nfunction scanStaticShellHeaders(shell: NormalizedStaticShell, spans?: RedactionSpan[]): boolean {\n\tlet found = false;\n\tfor (const word of shell.words) {\n\t\tconst local: RedactionSpan[] | undefined = spans === undefined ? undefined : [];\n\t\tif (scanHeaderCredentials(shell.text.slice(word.start, word.end), local)) found = true;\n\t\tfor (const span of local ?? [])\n\t\t\tspans?.push({ ...span, start: span.start + word.start, end: span.end + word.start });\n\t}\n\treturn found;\n}\n\nfunction scanStaticShellQueries(shell: NormalizedStaticShell, spans?: RedactionSpan[]): boolean {\n\tlet found = false;\n\tfor (const word of shell.words) {\n\t\tconst local: RedactionSpan[] | undefined = spans === undefined ? undefined : [];\n\t\tif (scanUrlQueryCredentials(shell.text.slice(word.start, word.end), local)) found = true;\n\t\tfor (const span of local ?? [])\n\t\t\tspans?.push({ ...span, start: span.start + word.start, end: span.end + word.start });\n\t}\n\treturn found;\n}\n\nfunction mapStaticShellSpans(shell: NormalizedStaticShell, spans: readonly RedactionSpan[]): RedactionSpan[] {\n\treturn spans.map((span) => {\n\t\tconst first = shell.sources[span.start];\n\t\tconst last = shell.sources[span.end - 1];\n\t\tif (first === undefined || last === undefined) staticShellError();\n\t\tconst end = last.quoteStart !== undefined && last.quoteStart < first.start ? last.contentEnd : last.end;\n\t\treturn { ...span, start: first.start, end };\n\t});\n}\n\ninterface CredentialValueRange {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly atomStart: number;\n\treadonly atomEnd: number;\n}\n\nfunction credentialAtom(start: number, value: string, basic = false, authorization = false): CredentialValueRange {\n\tlet atomOffset = 0;\n\tif (authorization) atomOffset = /^(?:bearer|basic)\\s+/i.exec(value)?.[0].length ?? 0;\n\tif (basic && !authorization) atomOffset = Math.max(0, value.indexOf(\":\") + 1);\n\treturn { start, end: start + value.length, atomStart: start + atomOffset, atomEnd: start + value.length };\n}\n\nfunction headerCredentialRange(word: string, offset: number): CredentialValueRange | undefined {\n\tconst start = word.startsWith(\"-H\") ? 2 : word.startsWith(\"--header=\") ? 9 : 0;\n\tconst name = /^[A-Za-z][A-Za-z0-9_-]*/.exec(word.slice(start))?.[0];\n\tif (name === undefined) return undefined;\n\tconst rule = headerCredentialRule(name);\n\tif (rule === undefined) return undefined;\n\tlet separator = start + name.length;\n\twhile (/\\s/.test(word[separator] ?? \"\")) separator++;\n\tif (word[separator] !== \":\" && word[separator] !== \"=\") return undefined;\n\tlet valueStart = separator + 1;\n\twhile (/\\s/.test(word[valueStart] ?? \"\")) valueStart++;\n\treturn credentialAtom(offset + valueStart, word.slice(valueStart), false, rule.preserveScheme);\n}\n\nfunction credentialRanges(shell: NormalizedStaticShell): CredentialValueRange[] {\n\tconst ranges: CredentialValueRange[] = [];\n\tfor (let index = 0; index < shell.words.length; index++) {\n\t\tconst word = shell.words[index];\n\t\tconst text = shell.text.slice(word.start, word.end);\n\t\tconst previousWord = shell.words[index - 1];\n\t\tconst previous = previousWord === undefined ? undefined : shell.text.slice(previousWord.start, previousWord.end);\n\t\tif (previous !== undefined && (CREDENTIAL_OPTION_PAIR.test(previous) || BASIC_AUTH_OPTION_PAIR.test(previous))) {\n\t\t\tranges.push(credentialAtom(word.start, text, BASIC_AUTH_OPTION_PAIR.test(previous)));\n\t\t}\n\t\tconst assignment = new RegExp(`^[A-Za-z0-9_]*${SECRET_NAME}[A-Za-z0-9_]*\\\\s*[:=]\\\\s*`, \"i\").exec(text);\n\t\tif (assignment !== null)\n\t\t\tranges.push(credentialAtom(word.start + assignment[0].length, text.slice(assignment[0].length)));\n\t\tconst option = new RegExp(`^--(?:${SECRET_OPTION_NAME}|authorization|cookie)=`, \"i\").exec(text);\n\t\tif (option !== null) ranges.push(credentialAtom(word.start + option[0].length, text.slice(option[0].length)));\n\t\tconst basic = /^(?:-[uU]=?|--(?:proxy-)?user=)/.exec(text);\n\t\tif (basic !== null && basic[0].length < text.length) {\n\t\t\tranges.push(credentialAtom(word.start + basic[0].length, text.slice(basic[0].length), true));\n\t\t}\n\t\tconst header = headerCredentialRange(text, word.start);\n\t\tif (header !== undefined) ranges.push(header);\n\t\tfor (const pair of queryPairs(text)) {\n\t\t\tif (QUERY_SECRET_NAME.test(pair.name)) {\n\t\t\t\tranges.push(credentialAtom(word.start + pair.valueStart, text.slice(pair.valueStart, pair.valueEnd)));\n\t\t\t}\n\t\t}\n\t\tfor (const match of text.matchAll(/\\b[a-z][a-z0-9+.-]*:\\/\\/[^/\\s:@]+:([^/\\s@]+)@/dgi)) {\n\t\t\tconst value = match[1];\n\t\t\tconst indices = match.indices?.[1];\n\t\t\tif (value !== undefined && indices !== undefined) ranges.push(credentialAtom(word.start + indices[0], value));\n\t\t}\n\t}\n\treturn ranges;\n}\n\nfunction hasDynamicCredentialName(word: string, previous: string | undefined): boolean {\n\tconst equals = word.indexOf(\"=\");\n\tif (word.startsWith(\"--\") && word.slice(0, equals < 0 ? word.length : equals).includes(\"$\")) return true;\n\tconst headerLike =\n\t\tprevious === \"-H\" || previous === \"--header\" || word.startsWith(\"-H\") || word.startsWith(\"--header=\");\n\tif (headerLike) {\n\t\tconst start = word.startsWith(\"-H\") ? 2 : word.startsWith(\"--header=\") ? 9 : 0;\n\t\tconst separator = Math.min(...[word.indexOf(\":\", start), word.indexOf(\"=\", start)].filter((value) => value >= 0));\n\t\tif ((separator === Infinity ? word.length : separator) > start && word.slice(start, separator).includes(\"$\"))\n\t\t\treturn true;\n\t}\n\treturn queryPairs(word).some((pair) => pair.rawName.includes(\"$\"));\n}\n\nfunction assertStaticShellCredentialProvenance(shell: NormalizedStaticShell): void {\n\tconst ranges = credentialRanges(shell);\n\tfor (let index = 0; index < shell.words.length; index++) {\n\t\tconst word = shell.words[index];\n\t\tconst previousWord = shell.words[index - 1];\n\t\tconst previous = previousWord === undefined ? undefined : shell.text.slice(previousWord.start, previousWord.end);\n\t\tif (hasDynamicCredentialName(shell.text.slice(word.start, word.end), previous)) staticShellError();\n\t}\n\tfor (const range of ranges) {\n\t\tconst atom = shell.text.slice(range.atomStart, range.atomEnd);\n\t\tconst variables = shell.variables.filter((variable) => variable.start < range.end && variable.end > range.start);\n\t\tif (variables.length === 0) {\n\t\t\tif (atom.includes(\"$\")) staticShellError();\n\t\t\tcontinue;\n\t\t}\n\t\tif (variables.length !== 1 || variables[0].start !== range.atomStart || variables[0].end !== range.atomEnd) {\n\t\t\tstaticShellError();\n\t\t}\n\t}\n\tfor (const variable of shell.variables) {\n\t\tconst covered = ranges.some((range) => variable.start >= range.atomStart && variable.end <= range.atomEnd);\n\t\tif (!covered) staticShellError();\n\t}\n}\n\nfunction scanCredentialShapedValue(\n\ttext: string,\n\tboundary: HeaderValueBoundary,\n\tspans?: RedactionSpan[],\n\tincludeBasic = false,\n): boolean {\n\tconst shell = boundary === \"shell\" ? normalizeStaticShell(text) : undefined;\n\tif (shell !== undefined) assertStaticShellCredentialProvenance(shell);\n\tconst scannedText = shell?.text ?? text;\n\tconst candidates: RedactionSpan[] | undefined = spans === undefined ? undefined : [];\n\tlet found = false;\n\t// Classify complete headers and query values first so narrower token forms\n\t// cannot steal their replacement spans or placeholder types.\n\tif (shell === undefined) {\n\t\tif (scanHeaderCredentials(scannedText, candidates)) found = true;\n\t\tif (scanUrlQueryCredentials(scannedText, candidates)) found = true;\n\t} else {\n\t\tif (scanStaticShellHeaders(shell, candidates)) found = true;\n\t\tif (scanStaticShellQueries(shell, candidates)) found = true;\n\t}\n\tfor (const scan of [ENV_SCAN, CLI_SCAN, BEARER_SCAN, KNOWN_TOKEN_SCAN, URL_SCAN]) {\n\t\tif (scanPattern(scannedText, withFreshPattern(scan), candidates, boundary, shell?.words)) found = true;\n\t}\n\tif (includeBasic && scanPattern(scannedText, withFreshPattern(BASIC_SCAN), candidates, boundary, shell?.words)) {\n\t\tfound = true;\n\t}\n\tspans?.push(...(shell === undefined ? (candidates ?? []) : mapStaticShellSpans(shell, candidates ?? [])));\n\treturn found;\n}\n\nfunction containsCredentialShapedValue(text: string, boundary: HeaderValueBoundary): boolean {\n\treturn scanCredentialShapedValue(text, boundary);\n}\n\nfunction containsLiteralBasicAuth(text: string, boundary: HeaderValueBoundary): boolean {\n\tconst shell = boundary === \"shell\" ? normalizeStaticShell(text) : undefined;\n\treturn scanPattern(shell?.text ?? text, withFreshPattern(BASIC_SCAN), undefined, boundary, shell?.words);\n}\n\nconst CREDENTIAL_OPTION_PAIR = new RegExp(`^--(?:${SECRET_OPTION_NAME}|authorization|cookie)$`, \"i\");\nconst BASIC_AUTH_OPTION_PAIR = /^(?:-[uU]|--user|--proxy-user)$/;\nconst SHELL_EXECUTABLE = /(?:^|[\\\\/])(?:ba|da|k|z)?sh(?:\\.exe)?$/i;\n\nfunction argvElementBoundary(executable: string, previous: string | undefined): HeaderValueBoundary {\n\tconst shellScript =\n\t\tSHELL_EXECUTABLE.test(executable) && (previous === \"--command\" || /^-[A-Za-z]*c[A-Za-z]*$/.test(previous ?? \"\"));\n\treturn shellScript ? \"shell\" : \"argument\";\n}\n\nfunction assertCredentialFreeEvidenceCommandImpl(command: EvidenceCommandDescriptor): void {\n\tconst basicAuthText = command.kind === \"argv\" ? command.argv.join(\"\\n\") : command.script;\n\tconst credentialShaped =\n\t\tcommand.kind === \"argv\"\n\t\t\t? containsCredentialShapedValue(command.executable, \"argument\") ||\n\t\t\t\tcommand.argv.some((value, index) =>\n\t\t\t\t\tcontainsCredentialShapedValue(value, argvElementBoundary(command.executable, command.argv[index - 1])),\n\t\t\t\t)\n\t\t\t: containsCredentialShapedValue(command.shell, \"argument\") ||\n\t\t\t\tcontainsCredentialShapedValue(command.script, \"shell\");\n\tconst literalBasicAuth = containsLiteralBasicAuth(basicAuthText, command.kind === \"argv\" ? \"argument\" : \"shell\");\n\tif (credentialShaped || literalBasicAuth) {\n\t\tthrow new CommandRedactionError(\"command descriptor contains credential-shaped inline data\");\n\t}\n\tif (command.kind === \"argv\") {\n\t\tfor (let index = 0; index < command.argv.length - 1; index++) {\n\t\t\tif (CREDENTIAL_OPTION_PAIR.test(command.argv[index]) && !isCredentialPlaceholder(command.argv[index + 1])) {\n\t\t\t\tthrow new CommandRedactionError(\"command descriptor contains credential-shaped inline data\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/** Throw without echoing data when a persisted command is secret-bearing or ambiguous. */\nexport function assertCredentialFreeEvidenceCommand(command: EvidenceCommandDescriptor): void {\n\ttry {\n\t\tassertCredentialFreeEvidenceCommandImpl(command);\n\t} catch (error) {\n\t\tif (error instanceof CommandRedactionError) {\n\t\t\tthrow new CommandRedactionError(\"command descriptor contains credential-shaped or ambiguous inline data\");\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n// ============================================================================\n// Tokenization\n// ============================================================================\n\ntype PlaceholderCounts = Map<CommandRedactionPlaceholderType, number>;\n\nfunction overlaps(a: RedactionSpan, b: RedactionSpan): boolean {\n\treturn a.start < b.end && b.start < a.end;\n}\n\n/** Replace every detected literal credential in one text with `[REDACTED]`. */\nfunction redactText(text: string, boundary: HeaderValueBoundary, counts: PlaceholderCounts): string {\n\tconst candidates: RedactionSpan[] = [];\n\tscanCredentialShapedValue(text, boundary, candidates, true);\n\tconst accepted: RedactionSpan[] = [];\n\tfor (const candidate of candidates) {\n\t\t// In argv elements whitespace is literal data, so the tail after a secret is\n\t\t// unsplittable; extend to the element end instead of leaking fragments.\n\t\tconst span =\n\t\t\tboundary === \"argument\" && candidate.exactArgumentEnd !== true\n\t\t\t\t? { ...candidate, end: text.length }\n\t\t\t\t: candidate;\n\t\tif (span.start >= span.end) continue;\n\t\tif (accepted.some((existing) => overlaps(existing, span))) continue;\n\t\taccepted.push(span);\n\t}\n\tlet redacted = text;\n\tfor (const span of [...accepted].sort((a, b) => b.start - a.start)) {\n\t\tredacted = `${redacted.slice(0, span.start)}${REDACTED}${redacted.slice(span.end)}`;\n\t}\n\tfor (const span of accepted) {\n\t\tcounts.set(span.type, (counts.get(span.type) ?? 0) + 1);\n\t}\n\treturn redacted;\n}\n\nexport interface RedactedCommandDescriptor {\n\t/** Credential-free representation safe to persist in a receipt core. */\n\treadonly command: EvidenceCommandDescriptor;\n\t/** Bounded placeholder metadata describing what was tokenized. */\n\treadonly summary: CommandRedactionSummary;\n}\n\n/**\n * Tokenize secret-bearing CLI forms into a persisted-safe representation with\n * `[REDACTED]` placeholders, preserving placeholder count and type. Fails closed\n * when the result is unrepresentable or the placeholder metadata is oversize.\n * The original command is never stored, echoed, or hashed here.\n */\nexport function redactCommandDescriptor(value: unknown): RedactedCommandDescriptor {\n\tconst command = parseEvidenceCommandShape(value);\n\tconst counts: PlaceholderCounts = new Map();\n\tlet redacted: EvidenceCommandDescriptor;\n\tif (command.kind === \"shell\") {\n\t\tredacted = Object.freeze({\n\t\t\tkind: \"shell\",\n\t\t\tshell: redactText(command.shell, \"argument\", counts),\n\t\t\tscript: redactText(command.script, \"shell\", counts),\n\t\t});\n\t} else {\n\t\tconst executable = redactText(command.executable, \"argument\", counts);\n\t\tconst argv = [...command.argv];\n\t\tconst consumed = new Set<number>();\n\t\tfor (let index = 0; index < argv.length - 1; index++) {\n\t\t\tif (CREDENTIAL_OPTION_PAIR.test(argv[index]) && !isCredentialPlaceholder(argv[index + 1])) {\n\t\t\t\targv[index + 1] = REDACTED;\n\t\t\t\tcounts.set(\"cli-option-value\", (counts.get(\"cli-option-value\") ?? 0) + 1);\n\t\t\t\tconsumed.add(index + 1);\n\t\t\t} else if (BASIC_AUTH_OPTION_PAIR.test(argv[index]) && !isBasicAuthPlaceholder(argv[index + 1])) {\n\t\t\t\targv[index + 1] = REDACTED;\n\t\t\t\tcounts.set(\"basic-auth\", (counts.get(\"basic-auth\") ?? 0) + 1);\n\t\t\t\tconsumed.add(index + 1);\n\t\t\t}\n\t\t}\n\t\tfor (let index = 0; index < argv.length; index++) {\n\t\t\tif (consumed.has(index)) continue;\n\t\t\targv[index] = redactText(argv[index], argvElementBoundary(command.executable, argv[index - 1]), counts);\n\t\t}\n\t\tredacted = Object.freeze({ kind: \"argv\", executable, argv: Object.freeze(argv) });\n\t}\n\tlet total = 0;\n\tfor (const count of counts.values()) total += count;\n\tif (total > MAX_COMMAND_REDACTION_PLACEHOLDERS) {\n\t\tthrow new CommandRedactionError(\"redacted command placeholder metadata exceeds the supported bound\");\n\t}\n\ttry {\n\t\tassertCredentialFreeEvidenceCommand(redacted);\n\t} catch {\n\t\tthrow new CommandRedactionError(\"command redaction produced an unrepresentable result; failing closed\");\n\t}\n\tconst placeholders = [...counts.entries()]\n\t\t.map(([type, count]) => Object.freeze({ type, count }))\n\t\t.sort((a, b) => (a.type < b.type ? -1 : 1));\n\treturn {\n\t\tcommand: redacted,\n\t\tsummary: Object.freeze({\n\t\t\tpolicyId: EVIDENCE_COMMAND_REDACTION_POLICY_ID,\n\t\t\tplaceholders: Object.freeze(placeholders),\n\t\t}),\n\t};\n}\n\n// ============================================================================\n// Persisted metadata validation (structurally bounded, fail closed)\n// ============================================================================\n\n/** Strict bounded parse of persisted command redaction placeholder metadata. */\nexport function parseCommandRedactionSummary(value: unknown): CommandRedactionSummary {\n\tconst raw = exactObject(value, \"commandRedaction\", [\"policyId\", \"placeholders\"]);\n\tconst policyId = nonEmptyString(raw.policyId, \"commandRedaction policyId\");\n\tif (policyId.length > 256) throw new CommandRedactionError(\"commandRedaction policyId is too long\");\n\tconst rawPlaceholders = exactArray(raw.placeholders, \"commandRedaction placeholders\");\n\tif (rawPlaceholders.length > PLACEHOLDER_TYPES.length) {\n\t\tthrow new CommandRedactionError(\"commandRedaction placeholder metadata exceeds the supported bound\");\n\t}\n\tconst placeholders: CommandRedactionPlaceholder[] = [];\n\tlet total = 0;\n\tlet previousType = \"\";\n\tfor (const entry of rawPlaceholders) {\n\t\tconst parsed = exactObject(entry, \"commandRedaction placeholder\", [\"type\", \"count\"]);\n\t\tconst type = parsed.type;\n\t\tif (typeof type !== \"string\" || !PLACEHOLDER_TYPE_SET.has(type)) {\n\t\t\tthrow new CommandRedactionError(\"commandRedaction placeholder type is invalid\");\n\t\t}\n\t\tif (type <= previousType) {\n\t\t\tthrow new CommandRedactionError(\"commandRedaction placeholder types must be unique and ascending\");\n\t\t}\n\t\tpreviousType = type;\n\t\tconst count = positiveBoundedInteger(\n\t\t\tparsed.count,\n\t\t\t\"commandRedaction placeholder count\",\n\t\t\tMAX_COMMAND_REDACTION_PLACEHOLDERS,\n\t\t);\n\t\ttotal += count;\n\t\tplaceholders.push(Object.freeze({ type: type as CommandRedactionPlaceholderType, count }));\n\t}\n\tif (total > MAX_COMMAND_REDACTION_PLACEHOLDERS) {\n\t\tthrow new CommandRedactionError(\"commandRedaction placeholder metadata exceeds the supported bound\");\n\t}\n\treturn Object.freeze({ policyId, placeholders: Object.freeze(placeholders) });\n}\n\n/** Strict bounded parse of a persisted keyed command binding. */\nexport function parseCommandHmacBinding(value: unknown): CommandHmacBinding {\n\tconst raw = exactObject(value, \"commandBinding\", [\"algorithm\", \"keyId\", \"nonce\", \"mac\"]);\n\tif (raw.algorithm !== \"hmac-sha256\") {\n\t\tthrow new CommandRedactionError(\"commandBinding algorithm must be hmac-sha256\");\n\t}\n\tif (typeof raw.keyId !== \"string\" || !KEY_ID_HEX.test(raw.keyId)) {\n\t\tthrow new CommandRedactionError(\"commandBinding keyId is invalid\");\n\t}\n\tif (typeof raw.nonce !== \"string\" || !NONCE_HEX.test(raw.nonce)) {\n\t\tthrow new CommandRedactionError(\"commandBinding nonce is invalid\");\n\t}\n\tif (typeof raw.mac !== \"string\" || !MAC_HEX.test(raw.mac)) {\n\t\tthrow new CommandRedactionError(\"commandBinding mac is invalid\");\n\t}\n\treturn Object.freeze({\n\t\talgorithm: \"hmac-sha256\",\n\t\tkeyId: raw.keyId,\n\t\tnonce: raw.nonce,\n\t\tmac: raw.mac as Sha256Hex,\n\t});\n}\n\n// Compatibility re-exports; implementation lives at the attestation trust boundary.\nexport {\n\tbindEvidenceCommandHmac,\n\ttype CommandHmacBinder,\n\tcreateCommandHmacBinder,\n} from \"./evidence-attestation.ts\";\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CommandHmacBinding, CommandRedactionSummary, EvidenceCommandDescriptor, ReplayEvent, VerifiedReplayLedgerSnapshot, WorkspaceFingerprint, WorkspaceScope } from "../types/evidence.ts";
|
|
2
|
+
export interface CommandHmacBinder {
|
|
3
|
+
readonly keyId: string;
|
|
4
|
+
bind(command: EvidenceCommandDescriptor): CommandHmacBinding;
|
|
5
|
+
verify(command: EvidenceCommandDescriptor, binding: CommandHmacBinding): boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Ephemeral keyed attestation binder. Key bytes never leave this closure. */
|
|
8
|
+
export declare function createCommandHmacBinder(): CommandHmacBinder;
|
|
9
|
+
/** Compatibility binder for callers that do not need later strict verification. */
|
|
10
|
+
export declare function bindEvidenceCommandHmac(command: EvidenceCommandDescriptor): CommandHmacBinding;
|
|
11
|
+
export interface TrustBindingIssue {
|
|
12
|
+
readonly detail: string;
|
|
13
|
+
readonly hard: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function verifyCommandAttestation(input: {
|
|
16
|
+
readonly receiptId: string;
|
|
17
|
+
readonly binding: CommandHmacBinding | undefined;
|
|
18
|
+
readonly persistedCommand: EvidenceCommandDescriptor;
|
|
19
|
+
readonly persistedSummary: CommandRedactionSummary | undefined;
|
|
20
|
+
readonly binder: Pick<CommandHmacBinder, "verify"> | undefined;
|
|
21
|
+
readonly resolveCommand: ((receiptId: string) => EvidenceCommandDescriptor | undefined) | undefined;
|
|
22
|
+
readonly redact: (command: EvidenceCommandDescriptor) => {
|
|
23
|
+
readonly command: EvidenceCommandDescriptor;
|
|
24
|
+
readonly summary: CommandRedactionSummary;
|
|
25
|
+
};
|
|
26
|
+
}): TrustBindingIssue | undefined;
|
|
27
|
+
export declare function latestRelevantWorkspaceMutationSeq(events: readonly ReplayEvent[], scope: WorkspaceScope): number | null;
|
|
28
|
+
export declare function verifyWorkspaceBinding(expected: WorkspaceFingerprint, capture: ((scope: WorkspaceFingerprint["scope"]) => unknown) | undefined): TrustBindingIssue | undefined;
|
|
29
|
+
export declare function parseVerifiedLedgerSnapshot(value: unknown, goalId: string, parseEvents: (bytes: Buffer, goalId: string) => ReplayEvent[]): VerifiedReplayLedgerSnapshot;
|
|
30
|
+
export declare function replayPayloadMatches(payload: unknown, receiptId: string, coreSha256: string): boolean;
|
|
31
|
+
//# sourceMappingURL=evidence-attestation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-attestation.d.ts","sourceRoot":"","sources":["../../src/guardrails/evidence-attestation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EACzB,WAAW,EAGX,4BAA4B,EAC5B,oBAAoB,EACpB,cAAc,EACd,MAAM,sBAAsB,CAAC;AA2C9B,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAAC;IAC7D,MAAM,CAAC,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;CACjF;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,IAAI,iBAAiB,CA4B3D;AAID,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAE9F;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACvB;AASD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;IACrD,QAAQ,CAAC,gBAAgB,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACpG,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK;QACxD,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;QAC5C,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;KAC1C,CAAC;CACF,GAAG,iBAAiB,GAAG,SAAS,CAchC;AAgBD,wBAAgB,kCAAkC,CACjD,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,KAAK,EAAE,cAAc,GACnB,MAAM,GAAG,IAAI,CAMf;AAED,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,oBAAoB,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,GAAG,SAAS,GACtE,iBAAiB,GAAG,SAAS,CAW/B;AAED,wBAAgB,2BAA2B,CAC1C,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,WAAW,EAAE,GAC3D,4BAA4B,CA4B9B;AAYD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAkBrG","sourcesContent":["import { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type {\n\tCommandHmacBinding,\n\tCommandRedactionSummary,\n\tEvidenceCommandDescriptor,\n\tReplayEvent,\n\tReplayLedgerHead,\n\tSha256Hex,\n\tVerifiedReplayLedgerSnapshot,\n\tWorkspaceFingerprint,\n\tWorkspaceScope,\n} from \"../types/evidence.ts\";\nimport { parseWorkspaceFingerprint } from \"./workspace-fingerprint.ts\";\n\nconst COMMAND_HMAC_DOMAIN = \"omk:evidence:receipt-v3:command-hmac\\0\";\nconst KEY_ID_HEX = /^[0-9a-f]{16}$/;\nconst NONCE_HEX = /^[0-9a-f]{32}$/;\nconst MAC_HEX = /^[0-9a-f]{64}$/;\n\nfunction canonicalCommandPayload(command: EvidenceCommandDescriptor): string {\n\tif (command.kind === \"argv\") {\n\t\tif (\n\t\t\ttypeof command.executable !== \"string\" ||\n\t\t\tcommand.executable.length === 0 ||\n\t\t\t!Array.isArray(command.argv) ||\n\t\t\tcommand.argv.some((value) => typeof value !== \"string\" || value.includes(\"\\0\"))\n\t\t) {\n\t\t\tthrow new Error(\"invalid argv command attestation input\");\n\t\t}\n\t\treturn JSON.stringify([\"argv\", command.executable, ...command.argv]);\n\t}\n\tif (\n\t\tcommand.kind !== \"shell\" ||\n\t\ttypeof command.shell !== \"string\" ||\n\t\tcommand.shell.length === 0 ||\n\t\ttypeof command.script !== \"string\" ||\n\t\tcommand.script.length === 0 ||\n\t\tcommand.shell.includes(\"\\0\") ||\n\t\tcommand.script.includes(\"\\0\")\n\t) {\n\t\tthrow new Error(\"invalid shell command attestation input\");\n\t}\n\treturn JSON.stringify([\"shell\", command.shell, command.script]);\n}\n\nfunction validBinding(binding: CommandHmacBinding): boolean {\n\treturn (\n\t\tbinding?.algorithm === \"hmac-sha256\" &&\n\t\tKEY_ID_HEX.test(binding.keyId) &&\n\t\tNONCE_HEX.test(binding.nonce) &&\n\t\tMAC_HEX.test(binding.mac)\n\t);\n}\n\nexport interface CommandHmacBinder {\n\treadonly keyId: string;\n\tbind(command: EvidenceCommandDescriptor): CommandHmacBinding;\n\tverify(command: EvidenceCommandDescriptor, binding: CommandHmacBinding): boolean;\n}\n\n/** Ephemeral keyed attestation binder. Key bytes never leave this closure. */\nexport function createCommandHmacBinder(): CommandHmacBinder {\n\tconst key = randomBytes(32);\n\tconst keyId = randomBytes(8).toString(\"hex\");\n\tconst compute = (nonce: string, payload: string): Buffer =>\n\t\tcreateHmac(\"sha256\", key).update(COMMAND_HMAC_DOMAIN).update(nonce).update(payload).digest();\n\treturn Object.freeze({\n\t\tkeyId,\n\t\tbind(command: EvidenceCommandDescriptor): CommandHmacBinding {\n\t\t\tconst nonce = randomBytes(16).toString(\"hex\");\n\t\t\treturn Object.freeze({\n\t\t\t\talgorithm: \"hmac-sha256\" as const,\n\t\t\t\tkeyId,\n\t\t\t\tnonce,\n\t\t\t\tmac: compute(nonce, canonicalCommandPayload(command)).toString(\"hex\") as Sha256Hex,\n\t\t\t});\n\t\t},\n\t\tverify(command: EvidenceCommandDescriptor, binding: CommandHmacBinding): boolean {\n\t\t\ttry {\n\t\t\t\tif (!validBinding(binding) || binding.keyId !== keyId) return false;\n\t\t\t\treturn timingSafeEqual(\n\t\t\t\t\tcompute(binding.nonce, canonicalCommandPayload(command)),\n\t\t\t\t\tBuffer.from(binding.mac, \"hex\"),\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t});\n}\n\nconst processCommandHmacBinder = createCommandHmacBinder();\n\n/** Compatibility binder for callers that do not need later strict verification. */\nexport function bindEvidenceCommandHmac(command: EvidenceCommandDescriptor): CommandHmacBinding {\n\treturn processCommandHmacBinder.bind(command);\n}\n\nexport interface TrustBindingIssue {\n\treadonly detail: string;\n\treadonly hard: boolean;\n}\n\nconst COMMAND_ISSUES = {\n\tmissing: { detail: \"is missing\", hard: false },\n\tverifier: { detail: \"verifier is missing\", hard: false },\n\tinvalid: { detail: \"is invalid\", hard: true },\n\tredaction: { detail: \"does not match its redaction\", hard: true },\n} as const satisfies Record<string, TrustBindingIssue>;\n\nexport function verifyCommandAttestation(input: {\n\treadonly receiptId: string;\n\treadonly binding: CommandHmacBinding | undefined;\n\treadonly persistedCommand: EvidenceCommandDescriptor;\n\treadonly persistedSummary: CommandRedactionSummary | undefined;\n\treadonly binder: Pick<CommandHmacBinder, \"verify\"> | undefined;\n\treadonly resolveCommand: ((receiptId: string) => EvidenceCommandDescriptor | undefined) | undefined;\n\treadonly redact: (command: EvidenceCommandDescriptor) => {\n\t\treadonly command: EvidenceCommandDescriptor;\n\t\treadonly summary: CommandRedactionSummary;\n\t};\n}): TrustBindingIssue | undefined {\n\tif (input.binding === undefined) return COMMAND_ISSUES.missing;\n\tif (!input.binder || !input.resolveCommand) return COMMAND_ISSUES.verifier;\n\ttry {\n\t\tconst command = input.resolveCommand(input.receiptId);\n\t\tif (command === undefined || !input.binder.verify(command, input.binding)) return COMMAND_ISSUES.invalid;\n\t\tconst redacted = input.redact(command);\n\t\treturn JSON.stringify(redacted.command) === JSON.stringify(input.persistedCommand) &&\n\t\t\tJSON.stringify(redacted.summary) === JSON.stringify(input.persistedSummary)\n\t\t\t? undefined\n\t\t\t: COMMAND_ISSUES.redaction;\n\t} catch {\n\t\treturn COMMAND_ISSUES.invalid;\n\t}\n}\n\nfunction workspaceMutationOutOfScope(payload: unknown, scope: WorkspaceScope): boolean {\n\tif (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) return false;\n\tconst record = payload as Record<string, unknown>;\n\tif (record.root !== scope.root || !Array.isArray(record.paths) || record.paths.length === 0) return false;\n\treturn record.paths.every(\n\t\t(path) =>\n\t\t\ttypeof path === \"string\" &&\n\t\t\tpath.length > 0 &&\n\t\t\tscope.artifactPaths.every(\n\t\t\t\t(artifact) => path !== artifact && !path.startsWith(`${artifact}/`) && !artifact.startsWith(`${path}/`),\n\t\t\t),\n\t);\n}\n\nexport function latestRelevantWorkspaceMutationSeq(\n\tevents: readonly ReplayEvent[],\n\tscope: WorkspaceScope,\n): number | null {\n\tlet latest: number | null = null;\n\tfor (const event of events) {\n\t\tif (event.type === \"workspace_mutation\" && !workspaceMutationOutOfScope(event.payload, scope)) latest = event.seq;\n\t}\n\treturn latest;\n}\n\nexport function verifyWorkspaceBinding(\n\texpected: WorkspaceFingerprint,\n\tcapture: ((scope: WorkspaceFingerprint[\"scope\"]) => unknown) | undefined,\n): TrustBindingIssue | undefined {\n\tif (!capture) return { detail: \"freshness binding is missing\", hard: false };\n\ttry {\n\t\tconst current = parseWorkspaceFingerprint(capture(expected.scope));\n\t\tif (current.kind !== expected.kind) return { detail: \"workspace kind changed after verification\", hard: true };\n\t\treturn safeDigestEqual(current.manifestSha256, expected.manifestSha256)\n\t\t\t? undefined\n\t\t\t: { detail: \"artifact-changed-after-verification\", hard: true };\n\t} catch {\n\t\treturn { detail: \"freshness check failed\", hard: true };\n\t}\n}\n\nexport function parseVerifiedLedgerSnapshot(\n\tvalue: unknown,\n\tgoalId: string,\n\tparseEvents: (bytes: Buffer, goalId: string) => ReplayEvent[],\n): VerifiedReplayLedgerSnapshot {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) throw new Error(\"snapshot is invalid\");\n\tconst record = value as Record<string, unknown>;\n\tif (!Array.isArray(record.events) || typeof record.head !== \"object\" || record.head === null) {\n\t\tthrow new Error(\"snapshot fields are invalid\");\n\t}\n\tconst serialized = record.events.map((event) => JSON.stringify(event)).join(\"\\n\");\n\tconst events = parseEvents(Buffer.from(serialized + (serialized ? \"\\n\" : \"\")), goalId);\n\tconst head = record.head as Record<string, unknown>;\n\tconst last = events.at(-1);\n\tif (\n\t\t!Number.isSafeInteger(head.size) ||\n\t\t(head.size as number) < 0 ||\n\t\thead.lastSeq !== (last?.seq ?? 0) ||\n\t\thead.lastHash !== (last?.eventHash ?? \"genesis\") ||\n\t\t(last !== undefined && (typeof head.fileIdentity !== \"object\" || head.fileIdentity === null))\n\t) {\n\t\tthrow new Error(\"snapshot committed head is invalid\");\n\t}\n\treturn structuredClone({\n\t\tevents,\n\t\thead: {\n\t\t\tfileIdentity: head.fileIdentity as ReplayLedgerHead[\"fileIdentity\"],\n\t\t\tsize: head.size as number,\n\t\t\tlastSeq: head.lastSeq as number,\n\t\t\tlastHash: head.lastHash as string,\n\t\t},\n\t});\n}\n\nfunction safeDigestEqual(left: unknown, right: unknown): boolean {\n\treturn (\n\t\ttypeof left === \"string\" &&\n\t\ttypeof right === \"string\" &&\n\t\t/^[0-9a-f]{64}$/.test(left) &&\n\t\t/^[0-9a-f]{64}$/.test(right) &&\n\t\ttimingSafeEqual(Buffer.from(left, \"hex\"), Buffer.from(right, \"hex\"))\n\t);\n}\n\nexport function replayPayloadMatches(payload: unknown, receiptId: string, coreSha256: string): boolean {\n\tif (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) return false;\n\tconst descriptors = Object.getOwnPropertyDescriptors(payload);\n\tconst keys = Object.entries(descriptors)\n\t\t.filter(([, value]) => value.enumerable)\n\t\t.map(([key]) => key)\n\t\t.sort();\n\tconst id = descriptors.receiptId;\n\tconst digest = descriptors.coreSha256;\n\treturn (\n\t\tkeys.join(\",\") === \"coreSha256,receiptId\" &&\n\t\tid !== undefined &&\n\t\t\"value\" in id &&\n\t\tid.value === receiptId &&\n\t\tdigest !== undefined &&\n\t\t\"value\" in digest &&\n\t\tsafeDigestEqual(digest.value, coreSha256)\n\t);\n}\n"]}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { parseWorkspaceFingerprint } from "./workspace-fingerprint.js";
|
|
3
|
+
const COMMAND_HMAC_DOMAIN = "omk:evidence:receipt-v3:command-hmac\0";
|
|
4
|
+
const KEY_ID_HEX = /^[0-9a-f]{16}$/;
|
|
5
|
+
const NONCE_HEX = /^[0-9a-f]{32}$/;
|
|
6
|
+
const MAC_HEX = /^[0-9a-f]{64}$/;
|
|
7
|
+
function canonicalCommandPayload(command) {
|
|
8
|
+
if (command.kind === "argv") {
|
|
9
|
+
if (typeof command.executable !== "string" ||
|
|
10
|
+
command.executable.length === 0 ||
|
|
11
|
+
!Array.isArray(command.argv) ||
|
|
12
|
+
command.argv.some((value) => typeof value !== "string" || value.includes("\0"))) {
|
|
13
|
+
throw new Error("invalid argv command attestation input");
|
|
14
|
+
}
|
|
15
|
+
return JSON.stringify(["argv", command.executable, ...command.argv]);
|
|
16
|
+
}
|
|
17
|
+
if (command.kind !== "shell" ||
|
|
18
|
+
typeof command.shell !== "string" ||
|
|
19
|
+
command.shell.length === 0 ||
|
|
20
|
+
typeof command.script !== "string" ||
|
|
21
|
+
command.script.length === 0 ||
|
|
22
|
+
command.shell.includes("\0") ||
|
|
23
|
+
command.script.includes("\0")) {
|
|
24
|
+
throw new Error("invalid shell command attestation input");
|
|
25
|
+
}
|
|
26
|
+
return JSON.stringify(["shell", command.shell, command.script]);
|
|
27
|
+
}
|
|
28
|
+
function validBinding(binding) {
|
|
29
|
+
return (binding?.algorithm === "hmac-sha256" &&
|
|
30
|
+
KEY_ID_HEX.test(binding.keyId) &&
|
|
31
|
+
NONCE_HEX.test(binding.nonce) &&
|
|
32
|
+
MAC_HEX.test(binding.mac));
|
|
33
|
+
}
|
|
34
|
+
/** Ephemeral keyed attestation binder. Key bytes never leave this closure. */
|
|
35
|
+
export function createCommandHmacBinder() {
|
|
36
|
+
const key = randomBytes(32);
|
|
37
|
+
const keyId = randomBytes(8).toString("hex");
|
|
38
|
+
const compute = (nonce, payload) => createHmac("sha256", key).update(COMMAND_HMAC_DOMAIN).update(nonce).update(payload).digest();
|
|
39
|
+
return Object.freeze({
|
|
40
|
+
keyId,
|
|
41
|
+
bind(command) {
|
|
42
|
+
const nonce = randomBytes(16).toString("hex");
|
|
43
|
+
return Object.freeze({
|
|
44
|
+
algorithm: "hmac-sha256",
|
|
45
|
+
keyId,
|
|
46
|
+
nonce,
|
|
47
|
+
mac: compute(nonce, canonicalCommandPayload(command)).toString("hex"),
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
verify(command, binding) {
|
|
51
|
+
try {
|
|
52
|
+
if (!validBinding(binding) || binding.keyId !== keyId)
|
|
53
|
+
return false;
|
|
54
|
+
return timingSafeEqual(compute(binding.nonce, canonicalCommandPayload(command)), Buffer.from(binding.mac, "hex"));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const processCommandHmacBinder = createCommandHmacBinder();
|
|
63
|
+
/** Compatibility binder for callers that do not need later strict verification. */
|
|
64
|
+
export function bindEvidenceCommandHmac(command) {
|
|
65
|
+
return processCommandHmacBinder.bind(command);
|
|
66
|
+
}
|
|
67
|
+
const COMMAND_ISSUES = {
|
|
68
|
+
missing: { detail: "is missing", hard: false },
|
|
69
|
+
verifier: { detail: "verifier is missing", hard: false },
|
|
70
|
+
invalid: { detail: "is invalid", hard: true },
|
|
71
|
+
redaction: { detail: "does not match its redaction", hard: true },
|
|
72
|
+
};
|
|
73
|
+
export function verifyCommandAttestation(input) {
|
|
74
|
+
if (input.binding === undefined)
|
|
75
|
+
return COMMAND_ISSUES.missing;
|
|
76
|
+
if (!input.binder || !input.resolveCommand)
|
|
77
|
+
return COMMAND_ISSUES.verifier;
|
|
78
|
+
try {
|
|
79
|
+
const command = input.resolveCommand(input.receiptId);
|
|
80
|
+
if (command === undefined || !input.binder.verify(command, input.binding))
|
|
81
|
+
return COMMAND_ISSUES.invalid;
|
|
82
|
+
const redacted = input.redact(command);
|
|
83
|
+
return JSON.stringify(redacted.command) === JSON.stringify(input.persistedCommand) &&
|
|
84
|
+
JSON.stringify(redacted.summary) === JSON.stringify(input.persistedSummary)
|
|
85
|
+
? undefined
|
|
86
|
+
: COMMAND_ISSUES.redaction;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return COMMAND_ISSUES.invalid;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function workspaceMutationOutOfScope(payload, scope) {
|
|
93
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload))
|
|
94
|
+
return false;
|
|
95
|
+
const record = payload;
|
|
96
|
+
if (record.root !== scope.root || !Array.isArray(record.paths) || record.paths.length === 0)
|
|
97
|
+
return false;
|
|
98
|
+
return record.paths.every((path) => typeof path === "string" &&
|
|
99
|
+
path.length > 0 &&
|
|
100
|
+
scope.artifactPaths.every((artifact) => path !== artifact && !path.startsWith(`${artifact}/`) && !artifact.startsWith(`${path}/`)));
|
|
101
|
+
}
|
|
102
|
+
export function latestRelevantWorkspaceMutationSeq(events, scope) {
|
|
103
|
+
let latest = null;
|
|
104
|
+
for (const event of events) {
|
|
105
|
+
if (event.type === "workspace_mutation" && !workspaceMutationOutOfScope(event.payload, scope))
|
|
106
|
+
latest = event.seq;
|
|
107
|
+
}
|
|
108
|
+
return latest;
|
|
109
|
+
}
|
|
110
|
+
export function verifyWorkspaceBinding(expected, capture) {
|
|
111
|
+
if (!capture)
|
|
112
|
+
return { detail: "freshness binding is missing", hard: false };
|
|
113
|
+
try {
|
|
114
|
+
const current = parseWorkspaceFingerprint(capture(expected.scope));
|
|
115
|
+
if (current.kind !== expected.kind)
|
|
116
|
+
return { detail: "workspace kind changed after verification", hard: true };
|
|
117
|
+
return safeDigestEqual(current.manifestSha256, expected.manifestSha256)
|
|
118
|
+
? undefined
|
|
119
|
+
: { detail: "artifact-changed-after-verification", hard: true };
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return { detail: "freshness check failed", hard: true };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function parseVerifiedLedgerSnapshot(value, goalId, parseEvents) {
|
|
126
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
127
|
+
throw new Error("snapshot is invalid");
|
|
128
|
+
const record = value;
|
|
129
|
+
if (!Array.isArray(record.events) || typeof record.head !== "object" || record.head === null) {
|
|
130
|
+
throw new Error("snapshot fields are invalid");
|
|
131
|
+
}
|
|
132
|
+
const serialized = record.events.map((event) => JSON.stringify(event)).join("\n");
|
|
133
|
+
const events = parseEvents(Buffer.from(serialized + (serialized ? "\n" : "")), goalId);
|
|
134
|
+
const head = record.head;
|
|
135
|
+
const last = events.at(-1);
|
|
136
|
+
if (!Number.isSafeInteger(head.size) ||
|
|
137
|
+
head.size < 0 ||
|
|
138
|
+
head.lastSeq !== (last?.seq ?? 0) ||
|
|
139
|
+
head.lastHash !== (last?.eventHash ?? "genesis") ||
|
|
140
|
+
(last !== undefined && (typeof head.fileIdentity !== "object" || head.fileIdentity === null))) {
|
|
141
|
+
throw new Error("snapshot committed head is invalid");
|
|
142
|
+
}
|
|
143
|
+
return structuredClone({
|
|
144
|
+
events,
|
|
145
|
+
head: {
|
|
146
|
+
fileIdentity: head.fileIdentity,
|
|
147
|
+
size: head.size,
|
|
148
|
+
lastSeq: head.lastSeq,
|
|
149
|
+
lastHash: head.lastHash,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function safeDigestEqual(left, right) {
|
|
154
|
+
return (typeof left === "string" &&
|
|
155
|
+
typeof right === "string" &&
|
|
156
|
+
/^[0-9a-f]{64}$/.test(left) &&
|
|
157
|
+
/^[0-9a-f]{64}$/.test(right) &&
|
|
158
|
+
timingSafeEqual(Buffer.from(left, "hex"), Buffer.from(right, "hex")));
|
|
159
|
+
}
|
|
160
|
+
export function replayPayloadMatches(payload, receiptId, coreSha256) {
|
|
161
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload))
|
|
162
|
+
return false;
|
|
163
|
+
const descriptors = Object.getOwnPropertyDescriptors(payload);
|
|
164
|
+
const keys = Object.entries(descriptors)
|
|
165
|
+
.filter(([, value]) => value.enumerable)
|
|
166
|
+
.map(([key]) => key)
|
|
167
|
+
.sort();
|
|
168
|
+
const id = descriptors.receiptId;
|
|
169
|
+
const digest = descriptors.coreSha256;
|
|
170
|
+
return (keys.join(",") === "coreSha256,receiptId" &&
|
|
171
|
+
id !== undefined &&
|
|
172
|
+
"value" in id &&
|
|
173
|
+
id.value === receiptId &&
|
|
174
|
+
digest !== undefined &&
|
|
175
|
+
"value" in digest &&
|
|
176
|
+
safeDigestEqual(digest.value, coreSha256));
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=evidence-attestation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-attestation.js","sourceRoot":"","sources":["../../src/guardrails/evidence-attestation.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type {\n\tCommandHmacBinding,\n\tCommandRedactionSummary,\n\tEvidenceCommandDescriptor,\n\tReplayEvent,\n\tReplayLedgerHead,\n\tSha256Hex,\n\tVerifiedReplayLedgerSnapshot,\n\tWorkspaceFingerprint,\n\tWorkspaceScope,\n} from \"../types/evidence.ts\";\nimport { parseWorkspaceFingerprint } from \"./workspace-fingerprint.ts\";\n\nconst COMMAND_HMAC_DOMAIN = \"omk:evidence:receipt-v3:command-hmac\\0\";\nconst KEY_ID_HEX = /^[0-9a-f]{16}$/;\nconst NONCE_HEX = /^[0-9a-f]{32}$/;\nconst MAC_HEX = /^[0-9a-f]{64}$/;\n\nfunction canonicalCommandPayload(command: EvidenceCommandDescriptor): string {\n\tif (command.kind === \"argv\") {\n\t\tif (\n\t\t\ttypeof command.executable !== \"string\" ||\n\t\t\tcommand.executable.length === 0 ||\n\t\t\t!Array.isArray(command.argv) ||\n\t\t\tcommand.argv.some((value) => typeof value !== \"string\" || value.includes(\"\\0\"))\n\t\t) {\n\t\t\tthrow new Error(\"invalid argv command attestation input\");\n\t\t}\n\t\treturn JSON.stringify([\"argv\", command.executable, ...command.argv]);\n\t}\n\tif (\n\t\tcommand.kind !== \"shell\" ||\n\t\ttypeof command.shell !== \"string\" ||\n\t\tcommand.shell.length === 0 ||\n\t\ttypeof command.script !== \"string\" ||\n\t\tcommand.script.length === 0 ||\n\t\tcommand.shell.includes(\"\\0\") ||\n\t\tcommand.script.includes(\"\\0\")\n\t) {\n\t\tthrow new Error(\"invalid shell command attestation input\");\n\t}\n\treturn JSON.stringify([\"shell\", command.shell, command.script]);\n}\n\nfunction validBinding(binding: CommandHmacBinding): boolean {\n\treturn (\n\t\tbinding?.algorithm === \"hmac-sha256\" &&\n\t\tKEY_ID_HEX.test(binding.keyId) &&\n\t\tNONCE_HEX.test(binding.nonce) &&\n\t\tMAC_HEX.test(binding.mac)\n\t);\n}\n\nexport interface CommandHmacBinder {\n\treadonly keyId: string;\n\tbind(command: EvidenceCommandDescriptor): CommandHmacBinding;\n\tverify(command: EvidenceCommandDescriptor, binding: CommandHmacBinding): boolean;\n}\n\n/** Ephemeral keyed attestation binder. Key bytes never leave this closure. */\nexport function createCommandHmacBinder(): CommandHmacBinder {\n\tconst key = randomBytes(32);\n\tconst keyId = randomBytes(8).toString(\"hex\");\n\tconst compute = (nonce: string, payload: string): Buffer =>\n\t\tcreateHmac(\"sha256\", key).update(COMMAND_HMAC_DOMAIN).update(nonce).update(payload).digest();\n\treturn Object.freeze({\n\t\tkeyId,\n\t\tbind(command: EvidenceCommandDescriptor): CommandHmacBinding {\n\t\t\tconst nonce = randomBytes(16).toString(\"hex\");\n\t\t\treturn Object.freeze({\n\t\t\t\talgorithm: \"hmac-sha256\" as const,\n\t\t\t\tkeyId,\n\t\t\t\tnonce,\n\t\t\t\tmac: compute(nonce, canonicalCommandPayload(command)).toString(\"hex\") as Sha256Hex,\n\t\t\t});\n\t\t},\n\t\tverify(command: EvidenceCommandDescriptor, binding: CommandHmacBinding): boolean {\n\t\t\ttry {\n\t\t\t\tif (!validBinding(binding) || binding.keyId !== keyId) return false;\n\t\t\t\treturn timingSafeEqual(\n\t\t\t\t\tcompute(binding.nonce, canonicalCommandPayload(command)),\n\t\t\t\t\tBuffer.from(binding.mac, \"hex\"),\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t});\n}\n\nconst processCommandHmacBinder = createCommandHmacBinder();\n\n/** Compatibility binder for callers that do not need later strict verification. */\nexport function bindEvidenceCommandHmac(command: EvidenceCommandDescriptor): CommandHmacBinding {\n\treturn processCommandHmacBinder.bind(command);\n}\n\nexport interface TrustBindingIssue {\n\treadonly detail: string;\n\treadonly hard: boolean;\n}\n\nconst COMMAND_ISSUES = {\n\tmissing: { detail: \"is missing\", hard: false },\n\tverifier: { detail: \"verifier is missing\", hard: false },\n\tinvalid: { detail: \"is invalid\", hard: true },\n\tredaction: { detail: \"does not match its redaction\", hard: true },\n} as const satisfies Record<string, TrustBindingIssue>;\n\nexport function verifyCommandAttestation(input: {\n\treadonly receiptId: string;\n\treadonly binding: CommandHmacBinding | undefined;\n\treadonly persistedCommand: EvidenceCommandDescriptor;\n\treadonly persistedSummary: CommandRedactionSummary | undefined;\n\treadonly binder: Pick<CommandHmacBinder, \"verify\"> | undefined;\n\treadonly resolveCommand: ((receiptId: string) => EvidenceCommandDescriptor | undefined) | undefined;\n\treadonly redact: (command: EvidenceCommandDescriptor) => {\n\t\treadonly command: EvidenceCommandDescriptor;\n\t\treadonly summary: CommandRedactionSummary;\n\t};\n}): TrustBindingIssue | undefined {\n\tif (input.binding === undefined) return COMMAND_ISSUES.missing;\n\tif (!input.binder || !input.resolveCommand) return COMMAND_ISSUES.verifier;\n\ttry {\n\t\tconst command = input.resolveCommand(input.receiptId);\n\t\tif (command === undefined || !input.binder.verify(command, input.binding)) return COMMAND_ISSUES.invalid;\n\t\tconst redacted = input.redact(command);\n\t\treturn JSON.stringify(redacted.command) === JSON.stringify(input.persistedCommand) &&\n\t\t\tJSON.stringify(redacted.summary) === JSON.stringify(input.persistedSummary)\n\t\t\t? undefined\n\t\t\t: COMMAND_ISSUES.redaction;\n\t} catch {\n\t\treturn COMMAND_ISSUES.invalid;\n\t}\n}\n\nfunction workspaceMutationOutOfScope(payload: unknown, scope: WorkspaceScope): boolean {\n\tif (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) return false;\n\tconst record = payload as Record<string, unknown>;\n\tif (record.root !== scope.root || !Array.isArray(record.paths) || record.paths.length === 0) return false;\n\treturn record.paths.every(\n\t\t(path) =>\n\t\t\ttypeof path === \"string\" &&\n\t\t\tpath.length > 0 &&\n\t\t\tscope.artifactPaths.every(\n\t\t\t\t(artifact) => path !== artifact && !path.startsWith(`${artifact}/`) && !artifact.startsWith(`${path}/`),\n\t\t\t),\n\t);\n}\n\nexport function latestRelevantWorkspaceMutationSeq(\n\tevents: readonly ReplayEvent[],\n\tscope: WorkspaceScope,\n): number | null {\n\tlet latest: number | null = null;\n\tfor (const event of events) {\n\t\tif (event.type === \"workspace_mutation\" && !workspaceMutationOutOfScope(event.payload, scope)) latest = event.seq;\n\t}\n\treturn latest;\n}\n\nexport function verifyWorkspaceBinding(\n\texpected: WorkspaceFingerprint,\n\tcapture: ((scope: WorkspaceFingerprint[\"scope\"]) => unknown) | undefined,\n): TrustBindingIssue | undefined {\n\tif (!capture) return { detail: \"freshness binding is missing\", hard: false };\n\ttry {\n\t\tconst current = parseWorkspaceFingerprint(capture(expected.scope));\n\t\tif (current.kind !== expected.kind) return { detail: \"workspace kind changed after verification\", hard: true };\n\t\treturn safeDigestEqual(current.manifestSha256, expected.manifestSha256)\n\t\t\t? undefined\n\t\t\t: { detail: \"artifact-changed-after-verification\", hard: true };\n\t} catch {\n\t\treturn { detail: \"freshness check failed\", hard: true };\n\t}\n}\n\nexport function parseVerifiedLedgerSnapshot(\n\tvalue: unknown,\n\tgoalId: string,\n\tparseEvents: (bytes: Buffer, goalId: string) => ReplayEvent[],\n): VerifiedReplayLedgerSnapshot {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) throw new Error(\"snapshot is invalid\");\n\tconst record = value as Record<string, unknown>;\n\tif (!Array.isArray(record.events) || typeof record.head !== \"object\" || record.head === null) {\n\t\tthrow new Error(\"snapshot fields are invalid\");\n\t}\n\tconst serialized = record.events.map((event) => JSON.stringify(event)).join(\"\\n\");\n\tconst events = parseEvents(Buffer.from(serialized + (serialized ? \"\\n\" : \"\")), goalId);\n\tconst head = record.head as Record<string, unknown>;\n\tconst last = events.at(-1);\n\tif (\n\t\t!Number.isSafeInteger(head.size) ||\n\t\t(head.size as number) < 0 ||\n\t\thead.lastSeq !== (last?.seq ?? 0) ||\n\t\thead.lastHash !== (last?.eventHash ?? \"genesis\") ||\n\t\t(last !== undefined && (typeof head.fileIdentity !== \"object\" || head.fileIdentity === null))\n\t) {\n\t\tthrow new Error(\"snapshot committed head is invalid\");\n\t}\n\treturn structuredClone({\n\t\tevents,\n\t\thead: {\n\t\t\tfileIdentity: head.fileIdentity as ReplayLedgerHead[\"fileIdentity\"],\n\t\t\tsize: head.size as number,\n\t\t\tlastSeq: head.lastSeq as number,\n\t\t\tlastHash: head.lastHash as string,\n\t\t},\n\t});\n}\n\nfunction safeDigestEqual(left: unknown, right: unknown): boolean {\n\treturn (\n\t\ttypeof left === \"string\" &&\n\t\ttypeof right === \"string\" &&\n\t\t/^[0-9a-f]{64}$/.test(left) &&\n\t\t/^[0-9a-f]{64}$/.test(right) &&\n\t\ttimingSafeEqual(Buffer.from(left, \"hex\"), Buffer.from(right, \"hex\"))\n\t);\n}\n\nexport function replayPayloadMatches(payload: unknown, receiptId: string, coreSha256: string): boolean {\n\tif (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) return false;\n\tconst descriptors = Object.getOwnPropertyDescriptors(payload);\n\tconst keys = Object.entries(descriptors)\n\t\t.filter(([, value]) => value.enumerable)\n\t\t.map(([key]) => key)\n\t\t.sort();\n\tconst id = descriptors.receiptId;\n\tconst digest = descriptors.coreSha256;\n\treturn (\n\t\tkeys.join(\",\") === \"coreSha256,receiptId\" &&\n\t\tid !== undefined &&\n\t\t\"value\" in id &&\n\t\tid.value === receiptId &&\n\t\tdigest !== undefined &&\n\t\t\"value\" in digest &&\n\t\tsafeDigestEqual(digest.value, coreSha256)\n\t);\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { EvidenceReceipt } from "../types/evidence.ts";
|
|
2
|
+
export type EvidenceReceiptStoreFaultStage = "before-root-parent-directory-fsync" | "after-receipt-directory" | "after-temp-open" | "after-temp-write" | "after-temp-fsync" | "after-temp-close" | "before-link" | "after-link" | "after-temp-unlink" | "before-temp-cleanup-directory-fsync" | "before-receipt-directory-cleanup-root-fsync" | "after-receipt-directory-fsync" | "after-root-directory-fsync";
|
|
3
|
+
export interface EvidenceReceiptStoreOptions {
|
|
4
|
+
/** Tests only: throw or mutate paths at a selected persistence stage. */
|
|
5
|
+
readonly faultInjector?: (stage: EvidenceReceiptStoreFaultStage) => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Owner-only, no-overwrite receipt persistence rooted at one trusted directory.
|
|
9
|
+
* Phase A assumes same-UID path mutation is quiescent; identity checks detect observed
|
|
10
|
+
* replacement but are not filesystem isolation, and persistence alone must not activate EvidenceGate.
|
|
11
|
+
*/
|
|
12
|
+
export declare class EvidenceReceiptStore {
|
|
13
|
+
private readonly root;
|
|
14
|
+
private readonly rootIdentity;
|
|
15
|
+
private readonly faultInjector;
|
|
16
|
+
constructor(root: string, options?: EvidenceReceiptStoreOptions);
|
|
17
|
+
getRoot(): string;
|
|
18
|
+
getReceiptPath(receiptId: string): string;
|
|
19
|
+
private assertReceiptId;
|
|
20
|
+
private assertRoot;
|
|
21
|
+
private captureReceiptDirectory;
|
|
22
|
+
private assertReceiptDirectory;
|
|
23
|
+
private assertReceiptFile;
|
|
24
|
+
private assertFinalAbsent;
|
|
25
|
+
private inject;
|
|
26
|
+
private cleanupTemp;
|
|
27
|
+
private cleanupReceiptDirectory;
|
|
28
|
+
/** Persist once using hard-link publication, which cannot replace an existing destination. */
|
|
29
|
+
write(receipt: EvidenceReceipt): string;
|
|
30
|
+
/** Read only bytes whose live path remains bound to the opened owner-controlled file. */
|
|
31
|
+
read(receiptId: string): EvidenceReceipt;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=evidence-receipt-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence-receipt-store.d.ts","sourceRoot":"","sources":["../../src/guardrails/evidence-receipt-store.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQ5D,MAAM,MAAM,8BAA8B,GACvC,oCAAoC,GACpC,yBAAyB,GACzB,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,GAClB,aAAa,GACb,YAAY,GACZ,mBAAmB,GACnB,qCAAqC,GACrC,6CAA6C,GAC7C,+BAA+B,GAC/B,4BAA4B,CAAC;AAEhC,MAAM,WAAW,2BAA2B;IAC3C,yEAAyE;IACzE,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,IAAI,CAAC;CACzE;AA4KD;;;;GAIG;AACH,qBAAa,oBAAoB;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgE;IAE9F,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,2BAAgC,EAkDlE;IAED,OAAO,IAAI,MAAM,CAEhB;IAED,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxC;IAED,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,uBAAuB;IAS/B,8FAA8F;IAC9F,KAAK,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CA6GtC;IAED,yFAAyF;IACzF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,CAiCvC;CACD","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { Stats } from \"node:fs\";\nimport {\n\tchmodSync,\n\tcloseSync,\n\tconstants as fsConstants,\n\tfstatSync,\n\tfsyncSync,\n\tlinkSync,\n\tlstatSync,\n\tmkdirSync,\n\topenSync,\n\treadFileSync,\n\trealpathSync,\n\trmdirSync,\n\tunlinkSync,\n\twriteSync,\n} from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport type { EvidenceReceipt } from \"../types/evidence.ts\";\nimport {\n\tisSafeEvidenceReceiptId,\n\tparseEvidenceReceipt,\n\tserializeEvidenceReceipt,\n\tvalidateEvidenceReceipt,\n} from \"./evidence-receipt.ts\";\n\nexport type EvidenceReceiptStoreFaultStage =\n\t| \"before-root-parent-directory-fsync\"\n\t| \"after-receipt-directory\"\n\t| \"after-temp-open\"\n\t| \"after-temp-write\"\n\t| \"after-temp-fsync\"\n\t| \"after-temp-close\"\n\t| \"before-link\"\n\t| \"after-link\"\n\t| \"after-temp-unlink\"\n\t| \"before-temp-cleanup-directory-fsync\"\n\t| \"before-receipt-directory-cleanup-root-fsync\"\n\t| \"after-receipt-directory-fsync\"\n\t| \"after-root-directory-fsync\";\n\nexport interface EvidenceReceiptStoreOptions {\n\t/** Tests only: throw or mutate paths at a selected persistence stage. */\n\treadonly faultInjector?: (stage: EvidenceReceiptStoreFaultStage) => void;\n}\n\ntype FileStat = Stats;\n\ninterface FileIdentity {\n\treadonly dev: number;\n\treadonly ino: number;\n}\n\ninterface DirectoryIdentity {\n\treadonly path: string;\n\treadonly identity: FileIdentity;\n}\n\nfunction errorCode(error: unknown): string | undefined {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error\n\t\t? String((error as { code?: unknown }).code)\n\t\t: undefined;\n}\n\nconst UNSUPPORTED_DIRECTORY_FSYNC_CODES: ReadonlySet<string> = new Set([\n\t\"EBADF\",\n\t\"EINVAL\",\n\t\"EISDIR\",\n\t\"ENOSYS\",\n\t\"ENOTSUP\",\n]);\n\nfunction classifiedDirectoryFsyncError(path: string, error: unknown): unknown {\n\tconst code = errorCode(error);\n\tif (code === undefined || !UNSUPPORTED_DIRECTORY_FSYNC_CODES.has(code)) return error;\n\treturn new Error(`receipt store strict durability unavailable: directory fsync unsupported for ${path} (${code})`, {\n\t\tcause: error,\n\t});\n}\n\nfunction fsyncDirectory(path: string): void {\n\tlet fd: number | undefined;\n\tlet failure: unknown;\n\ttry {\n\t\tfd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_DIRECTORY ?? 0) | (fsConstants.O_NOFOLLOW ?? 0));\n\t\tfsyncSync(fd);\n\t} catch (error) {\n\t\tfailure = classifiedDirectoryFsyncError(path, error);\n\t} finally {\n\t\tif (fd !== undefined) {\n\t\t\ttry {\n\t\t\t\tcloseSync(fd);\n\t\t\t} catch (error) {\n\t\t\t\tif (failure === undefined) failure = error;\n\t\t\t}\n\t\t}\n\t}\n\tif (failure !== undefined) throw failure;\n}\n\nfunction writeAll(fd: number, bytes: Uint8Array): void {\n\tlet offset = 0;\n\twhile (offset < bytes.byteLength) {\n\t\tconst written = writeSync(fd, bytes, offset, bytes.byteLength - offset);\n\t\tif (written <= 0) throw new Error(\"receipt store could not complete the file write\");\n\t\toffset += written;\n\t}\n}\n\nfunction identityFrom(stat: FileStat): FileIdentity {\n\treturn { dev: stat.dev, ino: stat.ino };\n}\n\nfunction hasFileIdentity(identity: FileIdentity): boolean {\n\treturn identity.dev !== 0 || identity.ino !== 0;\n}\n\nfunction matchesFileIdentity(expected: FileIdentity, actual: FileStat): boolean {\n\tconst actualIdentity = identityFrom(actual);\n\tconst expectedHasIdentity = hasFileIdentity(expected);\n\tconst actualHasIdentity = hasFileIdentity(actualIdentity);\n\treturn (\n\t\t(!expectedHasIdentity && !actualHasIdentity) ||\n\t\t(expectedHasIdentity &&\n\t\t\tactualHasIdentity &&\n\t\t\texpected.dev === actualIdentity.dev &&\n\t\t\texpected.ino === actualIdentity.ino)\n\t);\n}\n\nfunction missingDirectoryPaths(path: string): string[] {\n\tconst missing: string[] = [];\n\tlet current = path;\n\twhile (true) {\n\t\ttry {\n\t\t\tlstatSync(current);\n\t\t\treturn missing;\n\t\t} catch (error) {\n\t\t\tif (errorCode(error) !== \"ENOENT\") throw error;\n\t\t\tmissing.push(current);\n\t\t\tconst parent = dirname(current);\n\t\t\tif (parent === current) throw new Error(\"receipt store root has no existing ancestor\");\n\t\t\tcurrent = parent;\n\t\t}\n\t}\n}\n\nfunction captureDirectoryIdentity(path: string, label: string): DirectoryIdentity {\n\tconst stat = lstatSync(path);\n\tconst canonicalPath = realpathSync(path);\n\tconst canonicalStat = lstatSync(canonicalPath);\n\tif (\n\t\tstat.isSymbolicLink() ||\n\t\t!stat.isDirectory() ||\n\t\tcanonicalStat.isSymbolicLink() ||\n\t\t!canonicalStat.isDirectory() ||\n\t\trealpathSync(canonicalPath) !== canonicalPath ||\n\t\t!matchesFileIdentity(identityFrom(stat), canonicalStat)\n\t) {\n\t\tthrow new Error(`${label} is not a trusted directory`);\n\t}\n\treturn { path: canonicalPath, identity: identityFrom(canonicalStat) };\n}\n\nfunction assertDirectoryIdentity(directory: DirectoryIdentity, label: string): void {\n\tconst stat = lstatSync(directory.path);\n\tif (\n\t\tstat.isSymbolicLink() ||\n\t\t!stat.isDirectory() ||\n\t\trealpathSync(directory.path) !== directory.path ||\n\t\t!matchesFileIdentity(directory.identity, stat)\n\t) {\n\t\tthrow new Error(`${label} changed during root durability setup`);\n\t}\n}\n\nfunction cleanupCreatedDirectories(directories: readonly DirectoryIdentity[]): unknown | undefined {\n\tlet failure: unknown;\n\tfor (const directory of directories) {\n\t\tlet removed = false;\n\t\ttry {\n\t\t\tassertDirectoryIdentity(directory, \"new receipt store directory\");\n\t\t\trmdirSync(directory.path);\n\t\t\tremoved = true;\n\t\t} catch (error) {\n\t\t\tif (failure === undefined) failure = error;\n\t\t}\n\t\tif (!removed) continue;\n\t\ttry {\n\t\t\t// Persist each successful removal in its still-existing parent before moving outward.\n\t\t\tfsyncDirectory(dirname(directory.path));\n\t\t} catch (error) {\n\t\t\tif (failure === undefined) failure = error;\n\t\t}\n\t}\n\treturn failure;\n}\n\nfunction isStrictlyUnder(root: string, path: string): boolean {\n\tconst relativePath = relative(root, path);\n\treturn (\n\t\trelativePath !== \"\" && relativePath !== \"..\" && !relativePath.startsWith(`..${sep}`) && !isAbsolute(relativePath)\n\t);\n}\n\nfunction atomicNoOverwritePublish(tempPath: string, finalPath: string): void {\n\ttry {\n\t\tlinkSync(tempPath, finalPath);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`receipt store atomic no-overwrite publish failed (${errorCode(error) ?? \"unknown\"}); destination was not replaced`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n\n/**\n * Owner-only, no-overwrite receipt persistence rooted at one trusted directory.\n * Phase A assumes same-UID path mutation is quiescent; identity checks detect observed\n * replacement but are not filesystem isolation, and persistence alone must not activate EvidenceGate.\n */\nexport class EvidenceReceiptStore {\n\tprivate readonly root: string;\n\tprivate readonly rootIdentity: FileIdentity;\n\tprivate readonly faultInjector: ((stage: EvidenceReceiptStoreFaultStage) => void) | undefined;\n\n\tconstructor(root: string, options: EvidenceReceiptStoreOptions = {}) {\n\t\tif (typeof root !== \"string\" || root.length === 0) throw new Error(\"receipt store root must be non-empty\");\n\t\tconst resolvedRoot = resolve(root);\n\t\tconst missingPaths = missingDirectoryPaths(resolvedRoot);\n\t\tlet canonicalRoot: string;\n\t\tif (missingPaths.length === 0) {\n\t\t\tconst stat = lstatSync(resolvedRoot);\n\t\t\tif (stat.isSymbolicLink()) throw new Error(\"receipt store root must not be a symlink\");\n\t\t\tif (!stat.isDirectory()) throw new Error(\"receipt store root must be a directory\");\n\t\t\tchmodSync(resolvedRoot, 0o700);\n\t\t\tcanonicalRoot = realpathSync(resolvedRoot);\n\t\t} else {\n\t\t\tmkdirSync(resolvedRoot, { recursive: true, mode: 0o700 });\n\t\t\tchmodSync(resolvedRoot, 0o700);\n\t\t\tcanonicalRoot = realpathSync(resolvedRoot);\n\t\t\tconst createdDirectories = missingPaths.map((path) =>\n\t\t\t\tcaptureDirectoryIdentity(path, \"new receipt store directory\"),\n\t\t\t);\n\t\t\tconst outermostCreated = createdDirectories.at(-1);\n\t\t\tif (outermostCreated === undefined) throw new Error(\"receipt store root creation was not observed\");\n\t\t\ttry {\n\t\t\t\t// Persist each new directory before its parent, walking from the root outward.\n\t\t\t\tfor (const directory of createdDirectories) {\n\t\t\t\t\tassertDirectoryIdentity(directory, \"new receipt store directory\");\n\t\t\t\t\tfsyncDirectory(directory.path);\n\t\t\t\t\tassertDirectoryIdentity(directory, \"new receipt store directory\");\n\t\t\t\t}\n\t\t\t\tconst parent = captureDirectoryIdentity(dirname(outermostCreated.path), \"receipt store root parent\");\n\t\t\t\toptions.faultInjector?.(\"before-root-parent-directory-fsync\");\n\t\t\t\tassertDirectoryIdentity(parent, \"receipt store root parent\");\n\t\t\t\tfsyncDirectory(parent.path);\n\t\t\t\tassertDirectoryIdentity(parent, \"receipt store root parent\");\n\t\t\t} catch (error) {\n\t\t\t\tconst failure = classifiedDirectoryFsyncError(dirname(outermostCreated.path), error);\n\t\t\t\tconst cleanupFailure = cleanupCreatedDirectories(createdDirectories);\n\t\t\t\tif (cleanupFailure !== undefined) {\n\t\t\t\t\tconst message = failure instanceof Error ? failure.message : String(failure);\n\t\t\t\t\tconst cleanupMessage = cleanupFailure instanceof Error ? cleanupFailure.message : String(cleanupFailure);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`receipt store root durability failed and cleanup was incomplete: ${message}; cleanup failure: ${cleanupMessage}`,\n\t\t\t\t\t\t{ cause: new AggregateError([failure, cleanupFailure], \"receipt store root rollback failed\") },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow failure;\n\t\t\t}\n\t\t}\n\t\tthis.root = canonicalRoot;\n\t\tthis.rootIdentity = identityFrom(lstatSync(this.root));\n\t\tthis.faultInjector = options.faultInjector;\n\t\tthis.assertRoot();\n\t}\n\n\tgetRoot(): string {\n\t\treturn this.root;\n\t}\n\n\tgetReceiptPath(receiptId: string): string {\n\t\tthis.assertReceiptId(receiptId);\n\t\treturn join(this.root, receiptId, \"receipt.json\");\n\t}\n\n\tprivate assertReceiptId(receiptId: unknown): asserts receiptId is string {\n\t\tif (!isSafeEvidenceReceiptId(receiptId)) throw new Error(\"receiptId is not safe for storage\");\n\t}\n\n\tprivate assertRoot(): void {\n\t\tconst stat = lstatSync(this.root);\n\t\tif (\n\t\t\tstat.isSymbolicLink() ||\n\t\t\t!stat.isDirectory() ||\n\t\t\trealpathSync(this.root) !== this.root ||\n\t\t\t!matchesFileIdentity(this.rootIdentity, stat)\n\t\t) {\n\t\t\tthrow new Error(\"receipt store root is no longer the trusted directory\");\n\t\t}\n\t}\n\n\tprivate captureReceiptDirectory(receiptDirectory: string): FileIdentity {\n\t\tthis.assertRoot();\n\t\tconst stat = lstatSync(receiptDirectory);\n\t\tconst livePath = realpathSync(receiptDirectory);\n\t\tif (\n\t\t\tstat.isSymbolicLink() ||\n\t\t\t!stat.isDirectory() ||\n\t\t\tlivePath !== receiptDirectory ||\n\t\t\t!isStrictlyUnder(this.root, livePath)\n\t\t) {\n\t\t\tthrow new Error(\"receipt directory is not a trusted directory\");\n\t\t}\n\t\tthis.assertRoot();\n\t\treturn identityFrom(stat);\n\t}\n\n\tprivate assertReceiptDirectory(receiptDirectory: string, expected: FileIdentity): void {\n\t\tthis.assertRoot();\n\t\tconst stat = lstatSync(receiptDirectory);\n\t\tconst livePath = realpathSync(receiptDirectory);\n\t\tif (\n\t\t\tstat.isSymbolicLink() ||\n\t\t\t!stat.isDirectory() ||\n\t\t\tlivePath !== receiptDirectory ||\n\t\t\t!isStrictlyUnder(this.root, livePath) ||\n\t\t\t!matchesFileIdentity(expected, stat)\n\t\t) {\n\t\t\tthrow new Error(\"receipt directory changed during persistence\");\n\t\t}\n\t\tthis.assertRoot();\n\t}\n\n\tprivate assertReceiptFile(\n\t\tpath: string,\n\t\treceiptDirectory: string,\n\t\tdirectoryIdentity: FileIdentity,\n\t\texpectedFileIdentity: FileIdentity,\n\t\tlabel: string,\n\t): FileStat {\n\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\tconst stat = lstatSync(path);\n\t\tconst livePath = realpathSync(path);\n\t\tif (\n\t\t\tstat.isSymbolicLink() ||\n\t\t\t!stat.isFile() ||\n\t\t\tlivePath !== path ||\n\t\t\tdirname(livePath) !== receiptDirectory ||\n\t\t\t!isStrictlyUnder(this.root, livePath) ||\n\t\t\t!matchesFileIdentity(expectedFileIdentity, stat)\n\t\t) {\n\t\t\tthrow new Error(`${label} path changed during persistence`);\n\t\t}\n\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\treturn stat;\n\t}\n\n\tprivate assertFinalAbsent(finalPath: string, receiptDirectory: string, directoryIdentity: FileIdentity): void {\n\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\ttry {\n\t\t\tlstatSync(finalPath);\n\t\t} catch (error) {\n\t\t\tif (errorCode(error) === \"ENOENT\") {\n\t\t\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\"receipt destination already exists\");\n\t}\n\n\tprivate inject(stage: EvidenceReceiptStoreFaultStage): void {\n\t\tthis.faultInjector?.(stage);\n\t}\n\n\tprivate cleanupTemp(\n\t\ttempPath: string,\n\t\treceiptDirectory: string,\n\t\tdirectoryIdentity: FileIdentity,\n\t\ttempIdentity: FileIdentity,\n\t): void {\n\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\t\tunlinkSync(tempPath);\n\t\tthis.inject(\"before-temp-cleanup-directory-fsync\");\n\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\tfsyncDirectory(receiptDirectory);\n\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t}\n\n\tprivate cleanupReceiptDirectory(receiptDirectory: string, directoryIdentity: FileIdentity): void {\n\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\trmdirSync(receiptDirectory);\n\t\tthis.inject(\"before-receipt-directory-cleanup-root-fsync\");\n\t\tthis.assertRoot();\n\t\tfsyncDirectory(this.root);\n\t\tthis.assertRoot();\n\t}\n\n\t/** Persist once using hard-link publication, which cannot replace an existing destination. */\n\twrite(receipt: EvidenceReceipt): string {\n\t\tconst validated = validateEvidenceReceipt(receipt);\n\t\tconst receiptId = validated.core.receiptId;\n\t\tthis.assertReceiptId(receiptId);\n\t\tthis.assertRoot();\n\t\tconst receiptDirectory = join(this.root, receiptId);\n\t\tconst finalPath = join(receiptDirectory, \"receipt.json\");\n\t\tconst tempPath = join(receiptDirectory, `.receipt-${randomUUID()}.tmp`);\n\t\tconst bytes = Buffer.from(`${serializeEvidenceReceipt(validated)}\\n`, \"utf8\");\n\t\tlet fd: number | undefined;\n\t\tlet directoryIdentity: FileIdentity | undefined;\n\t\tlet tempIdentity: FileIdentity | undefined;\n\t\tlet tempExists = false;\n\t\tlet published = false;\n\t\tlet failure: unknown;\n\t\tconst cleanupFailures: unknown[] = [];\n\n\t\ttry {\n\t\t\t// mkdir without recursive atomically reserves this receipt ID.\n\t\t\tmkdirSync(receiptDirectory, { mode: 0o700 });\n\t\t\tdirectoryIdentity = this.captureReceiptDirectory(receiptDirectory);\n\t\t\tthis.inject(\"after-receipt-directory\");\n\t\t\tthis.assertReceiptDirectory(receiptDirectory, directoryIdentity);\n\n\t\t\tfd = openSync(\n\t\t\t\ttempPath,\n\t\t\t\tfsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY | (fsConstants.O_NOFOLLOW ?? 0),\n\t\t\t\t0o600,\n\t\t\t);\n\t\t\ttempExists = true;\n\t\t\ttempIdentity = identityFrom(fstatSync(fd));\n\t\t\tthis.inject(\"after-temp-open\");\n\t\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\n\t\t\twriteAll(fd, bytes);\n\t\t\tthis.inject(\"after-temp-write\");\n\t\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\t\t\tfsyncSync(fd);\n\t\t\tthis.inject(\"after-temp-fsync\");\n\t\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\t\t\tcloseSync(fd);\n\t\t\tfd = undefined;\n\t\t\tthis.inject(\"after-temp-close\");\n\t\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\t\t\tthis.assertFinalAbsent(finalPath, receiptDirectory, directoryIdentity);\n\t\t\tthis.inject(\"before-link\");\n\t\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\n\t\t\tatomicNoOverwritePublish(tempPath, finalPath);\n\t\t\tpublished = true;\n\t\t\tthis.inject(\"after-link\");\n\t\t\tthis.assertReceiptFile(tempPath, receiptDirectory, directoryIdentity, tempIdentity, \"receipt temp file\");\n\t\t\tthis.assertReceiptFile(finalPath, receiptDirectory, directoryIdentity, tempIdentity, \"stored receipt\");\n\t\t\tunlinkSync(tempPath);\n\t\t\ttempExists = false;\n\t\t\tthis.inject(\"after-temp-unlink\");\n\t\t\tthis.assertReceiptFile(finalPath, receiptDirectory, directoryIdentity, tempIdentity, \"stored receipt\");\n\n\t\t\tfsyncDirectory(receiptDirectory);\n\t\t\tthis.inject(\"after-receipt-directory-fsync\");\n\t\t\tthis.assertReceiptFile(finalPath, receiptDirectory, directoryIdentity, tempIdentity, \"stored receipt\");\n\t\t\tthis.assertRoot();\n\t\t\tfsyncDirectory(this.root);\n\t\t\tthis.inject(\"after-root-directory-fsync\");\n\t\t\tthis.assertReceiptFile(finalPath, receiptDirectory, directoryIdentity, tempIdentity, \"stored receipt\");\n\t\t} catch (error) {\n\t\t\tfailure = error;\n\t\t} finally {\n\t\t\tif (fd !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tcloseSync(fd);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcleanupFailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (failure !== undefined) {\n\t\t\tif (tempExists && directoryIdentity !== undefined && tempIdentity !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.cleanupTemp(tempPath, receiptDirectory, directoryIdentity, tempIdentity);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcleanupFailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!published && directoryIdentity !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.cleanupReceiptDirectory(receiptDirectory, directoryIdentity);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcleanupFailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (cleanupFailures.length > 0) {\n\t\t\t\tconst message = failure instanceof Error ? failure.message : String(failure);\n\t\t\t\tconst cleanupMessage = cleanupFailures\n\t\t\t\t\t.map((cleanupFailure) =>\n\t\t\t\t\t\tcleanupFailure instanceof Error ? cleanupFailure.message : String(cleanupFailure),\n\t\t\t\t\t)\n\t\t\t\t\t.join(\"; \");\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`receipt store persistence failed and cleanup was incomplete: ${message}; cleanup failure: ${cleanupMessage}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tcause: new AggregateError([failure, ...cleanupFailures], \"receipt store write rollback failed\"),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow failure;\n\t\t}\n\t\treturn finalPath;\n\t}\n\n\t/** Read only bytes whose live path remains bound to the opened owner-controlled file. */\n\tread(receiptId: string): EvidenceReceipt {\n\t\tthis.assertReceiptId(receiptId);\n\t\tthis.assertRoot();\n\t\tconst receiptDirectory = join(this.root, receiptId);\n\t\tconst directoryIdentity = this.captureReceiptDirectory(receiptDirectory);\n\t\tconst path = this.getReceiptPath(receiptId);\n\t\tconst fd = openSync(path, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));\n\t\ttry {\n\t\t\tconst before = fstatSync(fd);\n\t\t\tif (!before.isFile()) throw new Error(\"stored receipt is not a regular file\");\n\t\t\tconst fileIdentity = identityFrom(before);\n\t\t\tthis.assertReceiptFile(path, receiptDirectory, directoryIdentity, fileIdentity, \"stored receipt\");\n\t\t\tconst bytes = readFileSync(fd);\n\t\t\tconst after = fstatSync(fd);\n\t\t\tthis.assertReceiptFile(path, receiptDirectory, directoryIdentity, fileIdentity, \"stored receipt\");\n\t\t\tif (\n\t\t\t\t!after.isFile() ||\n\t\t\t\t!matchesFileIdentity(fileIdentity, after) ||\n\t\t\t\tbefore.size !== after.size ||\n\t\t\t\tbefore.mtimeMs !== after.mtimeMs ||\n\t\t\t\tbefore.ctimeMs !== after.ctimeMs ||\n\t\t\t\tafter.size !== bytes.byteLength\n\t\t\t) {\n\t\t\t\tthrow new Error(\"stored receipt changed while it was read\");\n\t\t\t}\n\t\t\tconst receipt = parseEvidenceReceipt(bytes.toString(\"utf8\"));\n\t\t\tif (receipt.core.receiptId !== receiptId) {\n\t\t\t\tthrow new Error(\"stored receiptId does not match its storage key\");\n\t\t\t}\n\t\t\treturn receipt;\n\t\t} finally {\n\t\t\tcloseSync(fd);\n\t\t}\n\t}\n}\n"]}
|