@sema-agent/core 7.51.2 → 7.52.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 +504 -2
- package/dist/agents/agent-transcript-tool.d.ts +1 -1
- package/dist/agents/cascade.js +4 -0
- package/dist/agents/cumulative-stats.d.ts +3 -0
- package/dist/agents/cumulative-stats.js +3 -0
- package/dist/agents/list-agents-tool.d.ts +1 -1
- package/dist/agents/read-inbox-tool.d.ts +1 -1
- package/dist/agents/repair-loop.js +4 -0
- package/dist/agents/send-message-tool.d.ts +11 -16
- package/dist/agents/send-message-tool.js +11 -13
- package/dist/agents/subagent.js +6 -4
- package/dist/agents/tool-filter.d.ts +40 -13
- package/dist/agents/tool-filter.js +28 -14
- package/dist/bench/metrics.d.ts +1 -0
- package/dist/brain/anthropic.js +16 -12
- package/dist/brain/model-presets.d.ts +4 -5
- package/dist/brain/model-presets.js +4 -4
- package/dist/brain/open-responses.js +16 -12
- package/dist/brain/openai.js +16 -12
- package/dist/brain/request-params.d.ts +12 -33
- package/dist/brain/request-params.js +5 -2
- package/dist/brain/request-route.d.ts +9 -8
- package/dist/brain/request-route.js +1 -0
- package/dist/brain/route-adjudicator.d.ts +117 -47
- package/dist/brain/route-adjudicator.js +171 -42
- package/dist/brain/route-conformance.js +2 -2
- package/dist/brain/status-sink.d.ts +18 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/core/allow-entry.d.ts +40 -8
- package/dist/core/allow-entry.js +23 -16
- package/dist/core/auto-compaction.d.ts +23 -20
- package/dist/core/auto-compaction.js +37 -16
- package/dist/core/auto-promote.d.ts +2 -1
- package/dist/core/auto-promote.js +2 -2
- package/dist/core/caller-tool-name.d.ts +9 -0
- package/dist/core/caller-tool-name.js +13 -0
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +36 -12
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/child-clamp-seats.d.ts +6 -0
- package/dist/core/child-clamp-seats.js +2 -1
- package/dist/core/credential-vocabulary.d.ts +33 -8
- package/dist/core/credential-vocabulary.js +32 -7
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/delegation-frames.d.ts +9 -2
- package/dist/core/delegation-name.d.ts +18 -0
- package/dist/core/delegation-name.js +47 -0
- package/dist/core/engine-capabilities.d.ts +8 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +36 -19
- package/dist/core/frontmatter-fence.d.ts +10 -0
- package/dist/core/frontmatter-fence.js +6 -0
- package/dist/core/gate-fold.js +5 -23
- package/dist/core/gate-lanes.js +356 -270
- package/dist/core/governance-codes.d.ts +9 -4
- package/dist/core/governance-codes.js +9 -3
- package/dist/core/hooks.d.ts +276 -734
- package/dist/core/hooks.js +97 -192
- package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
- package/dist/{tools/fs → core}/image-admission.js +24 -6
- package/dist/core/mcp-connection-pool.d.ts +4 -1
- package/dist/core/mcp-connection-pool.js +7 -2
- package/dist/core/mcp-probe.d.ts +12 -9
- package/dist/core/mcp-probe.js +2 -2
- package/dist/core/mcp-server-spec.d.ts +16 -0
- package/dist/core/mcp.d.ts +11 -7
- package/dist/core/mcp.js +11 -5
- package/dist/core/memory-engine/data-plane.js +5 -1
- package/dist/core/memory-engine/distiller.js +16 -2
- package/dist/core/memory-engine/engine.d.ts +8 -11
- package/dist/core/memory-engine/engine.js +9 -5
- package/dist/core/memory-engine/frontmatter.d.ts +6 -0
- package/dist/core/memory-engine/frontmatter.js +19 -16
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/mode-policy.d.ts +4 -0
- package/dist/core/mode-policy.js +7 -5
- package/dist/core/model-seat.d.ts +4 -1
- package/dist/core/mods/dollar.d.ts +109 -0
- package/dist/core/mods/dollar.js +154 -0
- package/dist/core/mods/host.d.ts +23 -0
- package/dist/core/mods/host.js +21 -0
- package/dist/core/mods/kernel/budget.d.ts +43 -0
- package/dist/core/mods/kernel/budget.js +83 -0
- package/dist/core/mods/kernel/dispatch.d.ts +100 -0
- package/dist/core/mods/kernel/dispatch.js +701 -0
- package/dist/core/mods/kernel/events.d.ts +242 -0
- package/dist/core/mods/kernel/events.js +210 -0
- package/dist/core/mods/kernel/index.d.ts +6 -0
- package/dist/core/mods/kernel/index.js +5 -0
- package/dist/core/mods/kernel/receive.d.ts +65 -0
- package/dist/core/mods/kernel/receive.js +123 -0
- package/dist/core/mods/kernel/registration.d.ts +131 -0
- package/dist/core/mods/kernel/registration.js +102 -0
- package/dist/core/mods/kernel/site-rules.d.ts +84 -0
- package/dist/core/mods/kernel/site-rules.js +104 -0
- package/dist/core/mods/stations.d.ts +350 -0
- package/dist/core/mods/stations.js +444 -0
- package/dist/core/own-property-receipt.js +11 -23
- package/dist/core/parent-spec-seat.d.ts +18 -7
- package/dist/core/parent-spec-seat.js +6 -2
- package/dist/core/path-identity.js +2 -1
- package/dist/core/permission-rule-syntax.d.ts +15 -0
- package/dist/core/permission-rule-syntax.js +24 -16
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +26 -15
- package/dist/core/prompt-section-seat.d.ts +15 -27
- package/dist/core/prompt-section-seat.js +73 -40
- package/dist/core/protocol-http-auth.d.ts +3 -1
- package/dist/core/protocol-http-auth.js +2 -0
- package/dist/core/reminder-mint.d.ts +2 -2
- package/dist/core/remote-env.d.ts +24 -12
- package/dist/core/remote-env.js +1 -0
- package/dist/core/resume-startup-cause.d.ts +16 -1
- package/dist/core/resume-startup-cause.js +4 -1
- package/dist/core/retired-keys.d.ts +4 -0
- package/dist/core/retired-keys.js +3 -0
- package/dist/core/runner/announce-once-ledger.d.ts +31 -1
- package/dist/core/runner/announce-once-ledger.js +22 -0
- package/dist/core/runner/assemble-result.d.ts +9 -0
- package/dist/core/runner/assemble-result.js +3 -1
- package/dist/core/runner/call-hook-stations.d.ts +23 -27
- package/dist/core/runner/call-hook-stations.js +58 -42
- package/dist/core/runner/caller-stop-gate.d.ts +25 -0
- package/dist/core/runner/caller-stop-gate.js +7 -0
- package/dist/core/runner/compaction-seams.d.ts +8 -22
- package/dist/core/runner/compaction-seams.js +28 -53
- package/dist/core/runner/construction-doors.js +11 -1
- package/dist/core/runner/contracts.d.ts +85 -83
- package/dist/core/runner/credential-origin-seat.d.ts +2 -0
- package/dist/core/runner/credential-origin-seat.js +19 -0
- package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
- package/dist/core/runner/gate-exit.d.ts +47 -36
- package/dist/core/runner/gate-exit.js +8 -2
- package/dist/core/runner/image.js +1 -2
- package/dist/core/runner/inline-image.js +1 -1
- package/dist/core/runner/notice-seat-input.d.ts +11 -0
- package/dist/core/runner/notice-seat-input.js +1 -0
- package/dist/core/runner/person-path-rows.js +1 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
- package/dist/core/runner/prepare-ask-lane.js +6 -15
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
- package/dist/core/runner/prepare-config-doors.d.ts +5 -0
- package/dist/core/runner/prepare-config-doors.js +9 -0
- package/dist/core/runner/prepare-defer-classify.js +3 -4
- package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
- package/dist/core/runner/prepare-gate-stations.js +11 -10
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
- package/dist/core/runner/prepare-inherited-gate.js +8 -21
- package/dist/core/runner/prepare-memory-engine-session.js +1 -1
- package/dist/core/runner/prepare-park-ask.js +10 -14
- package/dist/core/runner/prepare-policy-chain.d.ts +17 -15
- package/dist/core/runner/prepare-policy-chain.js +95 -100
- package/dist/core/runner/prepare-project-context.js +7 -10
- package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
- package/dist/core/runner/prepare-prompt-assembly.js +134 -101
- package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
- package/dist/core/runner/prepare-prompt-inputs.js +5 -7
- package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
- package/dist/core/runner/prepare-protocol-tools.js +2 -2
- package/dist/core/runner/prepare-safety-scan.js +6 -10
- package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -5
- package/dist/core/runner/prepare-task.js +33 -15
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
- package/dist/core/runner/prepare-turn-wiring.js +29 -27
- package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -6
- package/dist/core/runner/prepare-wiring-manifest.js +7 -7
- package/dist/core/runner/resume-apply.d.ts +5 -2
- package/dist/core/runner/resume-apply.js +24 -42
- package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
- package/dist/core/runner/resume-checkpoint-screen.js +9 -1
- package/dist/core/runner/resume-preflight.js +38 -16
- package/dist/core/runner/retired-runner-deps.js +3 -1
- package/dist/core/runner/run-brain-sinks.d.ts +3 -2
- package/dist/core/runner/run-brain-sinks.js +5 -1
- package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
- package/dist/core/runner/run-compaction-machinery.js +7 -33
- package/dist/core/runner/run-harness-handlers.js +4 -2
- package/dist/core/runner/run-identity-wiring.d.ts +3 -1
- package/dist/core/runner/run-identity-wiring.js +3 -2
- package/dist/core/runner/run-leg.js +62 -84
- package/dist/core/runner/run-notification-lane.js +1 -0
- package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
- package/dist/core/runner/run-recovery-lanes.js +11 -10
- package/dist/core/runner/run-settle-and-teardown.js +9 -28
- package/dist/core/runner/run-stop-and-final-verify.js +18 -25
- package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
- package/dist/core/runner/run-terminal-adoption.js +33 -22
- package/dist/core/runner/run-tool-mount-facts.js +5 -3
- package/dist/core/runner/run-turn-boundary.js +23 -34
- package/dist/core/runner/runtask.d.ts +6 -7
- package/dist/core/runner/runtask.js +14 -72
- package/dist/core/runner/session-rule-policy.d.ts +5 -5
- package/dist/core/runner/session-rule-policy.js +13 -8
- package/dist/core/runner/side-call-account.d.ts +68 -0
- package/dist/core/runner/side-call-account.js +61 -0
- package/dist/core/runner/stream-halt-verbs.js +12 -17
- package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
- package/dist/core/runner/stream-steer-verb.d.ts +1 -1
- package/dist/core/runner/stream-steer-verb.js +20 -38
- package/dist/core/runner/sub-agent-deny-lists.d.ts +121 -22
- package/dist/core/runner/sub-agent-deny-lists.js +228 -71
- package/dist/core/runner/tool-end-body.d.ts +5 -6
- package/dist/core/runner/tool-end-body.js +6 -4
- package/dist/core/runner/tool-not-executed.d.ts +15 -0
- package/dist/core/runner/tool-not-executed.js +30 -0
- package/dist/core/runner/tool-occurrence.d.ts +8 -7
- package/dist/core/runner/tool-occurrence.js +5 -5
- package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
- package/dist/core/runner-deps.d.ts +20 -28
- package/dist/core/safety-merge-corpus.js +18 -2
- package/dist/core/secret-env.d.ts +88 -20
- package/dist/core/secret-env.js +192 -38
- package/dist/core/session-policy-store.d.ts +52 -16
- package/dist/core/session-policy-store.js +118 -28
- package/dist/core/session-reconcile.d.ts +4 -0
- package/dist/core/session-reconcile.js +2 -1
- package/dist/core/shell-read-silence.js +3 -32
- package/dist/core/side-query.d.ts +5 -3
- package/dist/core/skill-grant.d.ts +3 -2
- package/dist/core/skill-grant.js +17 -9
- package/dist/core/skills-directory.d.ts +31 -11
- package/dist/core/skills-directory.js +655 -104
- package/dist/core/task-event.d.ts +13 -3
- package/dist/core/task-result.d.ts +8 -0
- package/dist/core/task-spec.d.ts +20 -19
- package/dist/core/task-stream.d.ts +14 -4
- package/dist/core/tighten-task-spec.d.ts +4 -3
- package/dist/core/tighten-task-spec.js +2 -4
- package/dist/core/tool-check-reading.d.ts +74 -0
- package/dist/core/tool-check-reading.js +80 -0
- package/dist/core/tool-policy.d.ts +59 -18
- package/dist/core/tool-policy.js +77 -12
- package/dist/core/tool-registry.d.ts +20 -0
- package/dist/core/tool-registry.js +4 -0
- package/dist/core/tool-spec.d.ts +10 -6
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +51 -32
- package/dist/core/unc-spelling.d.ts +10 -0
- package/dist/core/unc-spelling.js +3 -0
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-egress.js +4 -1
- package/dist/core/user-attachment.d.ts +12 -2
- package/dist/core/user-attachment.js +17 -2
- package/dist/core/wiring-manifest.d.ts +14 -13
- package/dist/core/wiring-manifest.js +2 -2
- package/dist/engine/compaction/utils.js +1 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
- package/dist/engine/execution-env/symlink-chain.js +1 -1
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/engine/harness/agent-harness.js +3 -3
- package/dist/engine/harness/types.d.ts +17 -16
- package/dist/engine/harness/types.js +7 -1
- package/dist/engine/llm/types.d.ts +12 -7
- package/dist/engine/loop/agent-loop.js +1 -1
- package/dist/engine/loop/types.d.ts +1 -1
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.js +3 -10
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/engine/session/session.js +4 -4
- package/dist/index.d.ts +20 -16
- package/dist/index.js +13 -11
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/orchestration/run-spec.d.ts +4 -6
- package/dist/orchestration/run-spec.js +39 -63
- package/dist/orchestration/run-workflow-tool.js +1 -2
- package/dist/orchestration/workflow.d.ts +11 -3
- package/dist/orchestration/workflow.js +11 -2
- package/dist/prompt-assembly/artifact-store.d.ts +37 -56
- package/dist/prompt-assembly/artifact-store.js +31 -49
- package/dist/prompt-assembly/artifact.d.ts +89 -76
- package/dist/prompt-assembly/artifact.js +167 -146
- package/dist/prompt-assembly/assemble.d.ts +34 -29
- package/dist/prompt-assembly/assemble.js +33 -220
- package/dist/prompt-assembly/bands.d.ts +20 -0
- package/dist/prompt-assembly/bands.js +18 -0
- package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
- package/dist/prompt-assembly/catalog/constitution.js +69 -0
- package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
- package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
- package/dist/prompt-assembly/catalog/index.d.ts +11 -0
- package/dist/prompt-assembly/catalog/index.js +59 -0
- package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
- package/dist/prompt-assembly/catalog/modes.js +137 -0
- package/dist/prompt-assembly/catalog/role.d.ts +10 -0
- package/dist/prompt-assembly/catalog/role.js +157 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +124 -0
- package/dist/prompt-assembly/catalog/schema.js +25 -0
- package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
- package/dist/prompt-assembly/catalog/sections.js +98 -0
- package/dist/prompt-assembly/catalog/team.d.ts +4 -0
- package/dist/prompt-assembly/catalog/team.js +258 -0
- package/dist/prompt-assembly/composer.d.ts +24 -28
- package/dist/prompt-assembly/composer.js +124 -46
- package/dist/prompt-assembly/epoch.d.ts +89 -79
- package/dist/prompt-assembly/epoch.js +115 -142
- package/dist/prompt-assembly/explain.d.ts +58 -34
- package/dist/prompt-assembly/explain.js +21 -24
- package/dist/prompt-assembly/overlay.d.ts +127 -0
- package/dist/prompt-assembly/overlay.js +301 -0
- package/dist/prompt-assembly/renderers.d.ts +21 -0
- package/dist/prompt-assembly/renderers.js +39 -0
- package/dist/prompt-assembly/section-usage.d.ts +3 -3
- package/dist/prompt-assembly/section-usage.js +1 -1
- package/dist/prompt-assembly/select.d.ts +56 -0
- package/dist/prompt-assembly/select.js +69 -0
- package/dist/prompt-assembly/sugar.d.ts +31 -0
- package/dist/prompt-assembly/sugar.js +20 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
- package/dist/prompt-assembly/types.d.ts +45 -148
- package/dist/prompts/coordinator.d.ts +2 -21
- package/dist/prompts/coordinator.js +3 -255
- package/dist/prompts/cowork.d.ts +27 -16
- package/dist/prompts/cowork.js +2 -23
- package/dist/prompts/default.d.ts +38 -500
- package/dist/prompts/default.js +20 -285
- package/dist/prompts/supervisor.d.ts +6 -71
- package/dist/prompts/supervisor.js +6 -117
- package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
- package/dist/tools/fs/dir-entries.d.ts +4 -2
- package/dist/tools/fs/dir-entries.js +16 -4
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +22 -11
- package/dist/tools/fs/fs-pdf.js +17 -13
- package/dist/tools/fs/fs-read.js +4 -3
- package/dist/tools/fs/fs-shared.d.ts +1 -10
- package/dist/tools/fs/fs-shared.js +3 -4
- package/dist/tools/fs/fs-write.js +2 -1
- package/dist/tools/fs/notebook.js +1 -1
- package/dist/tools/fs/pdf.d.ts +20 -10
- package/dist/tools/fs/pdf.js +19 -10
- package/dist/tools/fs/program-read-model.d.ts +68 -8
- package/dist/tools/fs/program-read-model.js +112 -33
- package/dist/tools/fs/program-read-model.rows.js +30 -10
- package/dist/tools/fs/read-deny-home.d.ts +25 -9
- package/dist/tools/fs/read-deny-home.js +28 -27
- package/dist/tools/fs/read-deny.d.ts +41 -11
- package/dist/tools/fs/read-deny.js +51 -5
- package/dist/tools/fs/safety.d.ts +4 -26
- package/dist/tools/fs/safety.js +10 -32
- package/dist/tools/fs/search.js +15 -10
- package/dist/tools/fs/shell-read-argv.d.ts +3 -2
- package/dist/tools/fs/shell-read-argv.js +118 -38
- package/dist/tools/fs/shell-read-establish.d.ts +5 -5
- package/dist/tools/fs/shell-read-establish.js +11 -61
- package/dist/tools/fs/shell-read-identity.js +6 -3
- package/dist/tools/fs/shell-read-judge.d.ts +13 -15
- package/dist/tools/fs/shell-read-judge.js +18 -4
- package/dist/tools/fs/shell-read-plan.d.ts +2 -2
- package/dist/tools/web.js +1 -1
- package/package.json +13 -1
- package/test/export-surface.snapshot.json +242 -99
- package/wire-changes/core@7.52.0.json +5859 -0
- package/dist/core/hook-seats.d.ts +0 -66
- package/dist/core/hook-seats.js +0 -37
- package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
- package/dist/prompt-assembly/packs/sema-default.js +0 -147
- package/dist/prompts/simple-sections.d.ts +0 -58
- package/dist/prompts/simple-sections.js +0 -43
|
@@ -159,12 +159,12 @@ export interface RunnerDeps {
|
|
|
159
159
|
*/
|
|
160
160
|
rosterStore?: import("../agents/roster-store.js").RosterStore;
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* (+ memory/file artifact & source-state stores); a server
|
|
167
|
-
*
|
|
162
|
+
* The center prompt-artifact source (artifact v2 only — INTEGRATION-CORE §12.11). `current()` supplies the verified
|
|
163
|
+
* candidate a top-level session adopts at session start and at a compaction; `get(digest)` resolves a PINNED center
|
|
164
|
+
* layer on resume (a miss is fail-loud `prompt.snapshot_unavailable` — core never recomposes a hybrid from newer
|
|
165
|
+
* content); `sourceState()` is the tri-state every adoption decision keys on. What a source hands a run is re-checked
|
|
166
|
+
* before it is adopted. Core bundles `CenterPromptSource` (+ memory/file artifact & source-state stores); a server
|
|
167
|
+
* feeds it published artifacts via `applySnapshot`. Omitted = no center layer.
|
|
168
168
|
*/
|
|
169
169
|
promptSource?: import("../prompt-assembly/artifact-store.js").PromptArtifactSource;
|
|
170
170
|
/**
|
|
@@ -518,7 +518,7 @@ export interface RunnerDeps {
|
|
|
518
518
|
resumePreflight?: (info: ResumePreflightInfo, signal: AbortSignal) => Promise<ResumePreflightVerdict>;
|
|
519
519
|
/**
|
|
520
520
|
* design/380 O2 — the {@link resumePreflight} deadline in ms. Default 10s (its own bound,
|
|
521
|
-
* deliberately
|
|
521
|
+
* deliberately its own: a resume preflight sits on every redeem attempt of a
|
|
522
522
|
* parked row and must answer promptly or get out of the way). Bad values (non-finite, ≤ 0,
|
|
523
523
|
* non-number) are DISCLOSED loudly through `onError` and fall back to the default (the bad-value
|
|
524
524
|
* loudness default: announce, never silently absorb).
|
|
@@ -1117,7 +1117,7 @@ export interface RunnerDeps {
|
|
|
1117
1117
|
* CLAUDE.md/git injection — the cure for "say hi → only greets"). The deployment/profile owns the CONTENT
|
|
1118
1118
|
* (read CLAUDE.md / `.claude/` + fold in `git log -5`/status + a byte budget); core owns the seam + fence +
|
|
1119
1119
|
* cache placement and NEVER hardcodes a filename (same trust posture as {@link executionEnvFactory}/
|
|
1120
|
-
* {@link
|
|
1120
|
+
* {@link mods}/{@link modelKnowledgeCutoffs}). A RunnerDeps FUNCTION, not a `TaskSpec` field: it is
|
|
1121
1121
|
* unserializable (durable resume) and reading files for an UNTRUSTED caller would be a confused-deputy hole
|
|
1122
1122
|
* (design/44 §7 Q4). DECOUPLED from `memoryStore` — injects even with NO long-term memory configured (H5).
|
|
1123
1123
|
*
|
|
@@ -1189,8 +1189,6 @@ export interface RunnerDeps {
|
|
|
1189
1189
|
path: string;
|
|
1190
1190
|
contentHash: string | null;
|
|
1191
1191
|
}> | null>;
|
|
1192
|
-
/** Override system-prompt assembly. Defaults to `defaultPromptProvider`. */
|
|
1193
|
-
promptProvider?: import("../prompts/default.js").PromptProvider;
|
|
1194
1192
|
/**
|
|
1195
1193
|
* design/99 §E23 — the LIVE-ONLY inbound-elicitation seam (an MCP server asking the END USER for input
|
|
1196
1194
|
* mid-tool-call). Wired ONLY for servers that opted in via {@link McpServerSpec.elicitation}; absent ⇒ core
|
|
@@ -1269,20 +1267,13 @@ export interface RunnerDeps {
|
|
|
1269
1267
|
*/
|
|
1270
1268
|
artifactHost?: import("./artifact-host.js").ArtifactHost;
|
|
1271
1269
|
/**
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
* it), `postToolUseFailure` / `postToolBatch` / `permissionDenied` (failure, batch-boundary and
|
|
1280
|
-
* deny observers), `preCompact` / `postCompact` (compaction gate + observer), `stopFailure`
|
|
1281
|
-
* (API-error terminal observer) and the `preToolUseObservational` declaration flag — each member's
|
|
1282
|
-
* contract is documented on the `Hooks` interface itself. A task's own `hooks` overrides this. A
|
|
1283
|
-
* PreToolUse hook's `allow` never bypasses `toolPolicy` — the policy is always the final say.
|
|
1284
|
-
*/
|
|
1285
|
-
hooks?: import("./hooks.js").Hooks;
|
|
1270
|
+
* The deployment seat of the mods bus: extension registrations every task of this Runner carries (every leg — root,
|
|
1271
|
+
* delegated child, resume — admits them at its own prepare). Each declares its tier (`prepend`, `user` or `append`;
|
|
1272
|
+
* absent or another word refuses the prepare, `config.mods_invalid`). A task's own `TaskSpec.mods` run beside these,
|
|
1273
|
+
* never instead of them. A `classic.PreToolUse` handler's `allow` never bypasses `toolPolicy` — the policy is always
|
|
1274
|
+
* the final say.
|
|
1275
|
+
*/
|
|
1276
|
+
mods?: readonly import("./mods/kernel/index.js").ModRegistration<import("./mods/dollar.js").EngineDollar>[];
|
|
1286
1277
|
/**
|
|
1287
1278
|
* Policy for remote image URLs (`TaskSpec.images[].url`). Return false to reject. When set it
|
|
1288
1279
|
* **replaces** the built-in SSRF guard (https-only + private/reserved-host block) — e.g. supply a
|
|
@@ -1295,9 +1286,10 @@ export interface RunnerDeps {
|
|
|
1295
1286
|
* summaries) is invisible without this and lets a session grow until it tops the window.
|
|
1296
1287
|
* - `"prompt-cache"` — a prefix-cache hazard on the wire: a detected cache break (design/31), or a
|
|
1297
1288
|
* mis-declared/mismatched `promptCacheFamily`. The prefix cache will miss. Log/alert on both.
|
|
1298
|
-
* - `"prompt-constitution"` — a
|
|
1299
|
-
*
|
|
1300
|
-
*
|
|
1289
|
+
* - `"prompt-constitution"` — a prompt overlay did not take effect as written: a later source (or a later
|
|
1290
|
+
* declaration in the same source) superseded it on the same target, its target was not in this run's
|
|
1291
|
+
* prompt, or a mods handler's `prompt.compose` answer was skipped (it rewrote another's overlay, or wrote
|
|
1292
|
+
* what the band table does not grant its seat). Each overlay is named once per run.
|
|
1301
1293
|
* - `"degraded"` — the task kept running with a capability quietly reduced: a question auto-answered
|
|
1302
1294
|
* with no human present, a skipped env git snapshot, a lost checkpoint-put confirmation, an
|
|
1303
1295
|
* unroutable descendant notification, and similar best-effort arms. The run proceeds; the reduced
|
|
@@ -1496,7 +1488,7 @@ export interface RunnerDeps {
|
|
|
1496
1488
|
* trusted control-plane injection), so it lives on `RunnerDeps` — NOT `TaskSpec`: `TaskSpec` is the
|
|
1497
1489
|
* serializable, untrusted-caller, durable-resume-round-trippable per-task config (a function can be
|
|
1498
1490
|
* neither serialized nor durably checkpointed, and the sandbox/env-class injections deliberately sit on
|
|
1499
|
-
* `RunnerDeps` for the same trust reason). Same placement as `
|
|
1491
|
+
* `RunnerDeps` for the same trust reason). Same placement as `mods` / `executionEnvFactory`.
|
|
1500
1492
|
*
|
|
1501
1493
|
* When `summaryProvider` is set, BOTH compaction call sites (the within-task turn boundary AND `finish()`
|
|
1502
1494
|
* at task end) consult it: a NON-EMPTY string is reused verbatim (the real `generateSummary` LLM call is
|
|
@@ -177,12 +177,28 @@ export const SAFETY_MERGE_CONFORMANCE_CORPUS = [
|
|
|
177
177
|
},
|
|
178
178
|
{
|
|
179
179
|
name: "inert-deny-entry-removed-safe",
|
|
180
|
-
intent: "removing a deny entry
|
|
181
|
-
prior: { toolDeny: ["Bash", "
|
|
180
|
+
intent: "removing a deny entry the grammar reads that names nothing (a wildcard peer, a `__` name with no protocol prefix) relaxes nothing — the comparison reads the EFFECTIVE entries on both sides",
|
|
181
|
+
prior: { toolDeny: ["Bash", "mcp__*", "github__x"] },
|
|
182
182
|
next: { toolDeny: ["Bash"] },
|
|
183
183
|
loosens: false,
|
|
184
184
|
reasons: [],
|
|
185
185
|
},
|
|
186
|
+
{
|
|
187
|
+
name: "unreadable-deny-prior-loosened",
|
|
188
|
+
intent: "rules whose toolDeny holds an entry no rule grammar reads (an empty entry) cannot be read and refuse every call — an override that can be read loosens them",
|
|
189
|
+
prior: { toolDeny: ["Bash", ""] },
|
|
190
|
+
next: { toolDeny: ["Bash"] },
|
|
191
|
+
loosens: true,
|
|
192
|
+
reasons: ['the prior rules refuse every call — their toolDeny holds "" (grammar), which no grammar reads'],
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: "unreadable-deny-next-safe",
|
|
196
|
+
intent: "an override whose toolDeny holds an entry no rule grammar reads refuses every call — it loosens nothing, whatever else it drops",
|
|
197
|
+
prior: { toolDeny: ["Bash"], allowDirs: ["/repo"] },
|
|
198
|
+
next: { toolDeny: [""] },
|
|
199
|
+
loosens: false,
|
|
200
|
+
reasons: [],
|
|
201
|
+
},
|
|
186
202
|
{
|
|
187
203
|
name: "inert-allow-entry-added-safe",
|
|
188
204
|
intent: "adding an allowlist entry that reads as nothing admits nothing, so it widens nothing",
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* A child the engine spawns may run what the MODEL chose (a tool shell, a gate over model-written code, a language
|
|
5
5
|
* server). Under the `"scrub"` policy (the default) it inherits every variable but those the judgment below names —
|
|
6
6
|
* deleted whole, never rewritten; `"all"` and a `string[]` allow list are the caller's explicit alternatives
|
|
7
|
-
* ({@link inheritedHostEnv}). Whatever the policy,
|
|
8
|
-
*
|
|
7
|
+
* ({@link inheritedHostEnv}). Whatever the policy, an entry that is this deployment's own credential is never inherited:
|
|
8
|
+
* its name is one the deployment declared, or its value equals a credential value the deployment declared or the
|
|
9
|
+
* engine holds ({@link declareWithheldEnv}, {@link holdOwnCredentialValues}). One judgment per variable ({@link classifySecretEnvEntry}), the first rule that answers:
|
|
9
10
|
* 1. exempt — git's environment config and the proxy variables, handed on as written ({@link isExemptEnvName});
|
|
10
11
|
* 2. `exact-name` — a known credential name (the vocabulary's exact env names);
|
|
11
12
|
* 3. `prefix-rule` — the OpenTelemetry settings ({@link OTEL_ENV_RE});
|
|
@@ -26,8 +27,9 @@ import { type EngineNotice } from "./engine-notice.js";
|
|
|
26
27
|
* Reads the first {@link VALUE_SCAN_LIMIT} code units. The value half of the judgment, exported apart from the env
|
|
27
28
|
* entry's exemptions ({@link isExemptEnvName}): a caller holding a value that is no environment variable asks this. */
|
|
28
29
|
export declare function looksLikeCredentialValue(value: string): boolean;
|
|
29
|
-
/** Which rule withheld an entry: one of the scrub's rules, or `own-credential` — the
|
|
30
|
-
*
|
|
30
|
+
/** Which rule withheld an entry: one of the scrub's rules, or `own-credential` — the entry is this deployment's own
|
|
31
|
+
* credential (its name is declared, or its value equals a declared or engine-held credential value:
|
|
32
|
+
* {@link declareWithheldEnv}), which every policy withholds. */
|
|
31
33
|
export type SecretEnvFindingKind = "exact-name" | "name-rule" | "namespace-rule" | "prefix-rule" | "value-rule" | "own-credential";
|
|
32
34
|
/** One env entry withheld (deleted) from a child's environment: its name — never its value, so the record is
|
|
33
35
|
* loggable —, the rule that withheld it, how strong that claim is, and the minting module. */
|
|
@@ -50,34 +52,100 @@ export declare function isSecretEnvKey(key: string, value?: string): boolean;
|
|
|
50
52
|
export declare function scrubSecretEnv(env: NodeJS.ProcessEnv, findings?: SecretEnvFinding[]): NodeJS.ProcessEnv;
|
|
51
53
|
/** How much of this process's environment a child spawned on this host inherits — the `inheritEnv` value. */
|
|
52
54
|
export type InheritEnvPolicy = "all" | "scrub" | string[];
|
|
55
|
+
/** What {@link declareWithheldEnv} takes: this deployment's own credentials in this process's environment. */
|
|
56
|
+
export interface WithheldEnvDeclaration {
|
|
57
|
+
/** Names of variables that are this deployment's own credentials: never inherited, and an allow list naming one is refused. */
|
|
58
|
+
readonly names: readonly string[];
|
|
59
|
+
/** Credential values this deployment holds: an inherited entry whose value equals one — the same string, compared
|
|
60
|
+
* whole, never as a part — is never inherited, whatever its name. A value must be a credential: not white space only,
|
|
61
|
+
* a flag or placeholder word, one character repeated, or fewer than eight characters. */
|
|
62
|
+
readonly values: readonly string[];
|
|
63
|
+
}
|
|
53
64
|
/**
|
|
54
|
-
* Declare
|
|
55
|
-
*
|
|
56
|
-
* every spawn site reads its environment through {@link inheritedHostEnv}, which subtracts
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
65
|
+
* Declare this deployment's OWN credentials in this process's environment — the engine's or its host's: an approval
|
|
66
|
+
* bearer, a service token — by name and by value. From then on no child spawned on this host inherits one, whatever the
|
|
67
|
+
* policy: every spawn site reads its environment through {@link inheritedHostEnv}, which subtracts from `"all"`, from the
|
|
68
|
+
* scrub's result and from an allow list's every entry that is this deployment's own credential (each one present is a
|
|
69
|
+
* finding of kind `own-credential`), and {@link inheritEnvPolicyProblem} refuses an allow list naming a declared name.
|
|
70
|
+
* A NAME is compared as the platform compares variable names: exactly, but case-blind on Windows. A VALUE is compared
|
|
71
|
+
* whole, as the same string: an entry holding it as a part (`Bearer <value>`, a URL, an encoding of it) is not its value.
|
|
72
|
+
* Besides the declared values, every value the engine took in itself ({@link holdOwnCredentialValues}) is withheld the
|
|
73
|
+
* same way. A variable a host hands a child itself (a shell's `shellEnv`, a per-exec `env`, a language server's `env`,
|
|
74
|
+
* an MCP server entry's `env`) is its explicit grant and is not read against the table.
|
|
61
75
|
*
|
|
62
|
-
* Declared once, at start-up, before anything spawns; a later call REPLACES the
|
|
63
|
-
* from the next spawn on — a spawn whose environment is already read (one announcing its findings) keeps
|
|
64
|
-
*
|
|
65
|
-
*
|
|
76
|
+
* Declared once, at start-up, before anything spawns; a later call REPLACES the declaration whole (a configuration
|
|
77
|
+
* reload), read from the next spawn on — a spawn whose environment is already read (one announcing its findings) keeps
|
|
78
|
+
* it; the values the engine took in stay. The lists are copied, and a value is kept only as a digest (no credential is
|
|
79
|
+
* held by the table). A malformed table — not a plain object `{ names, values }` (the names-only list of earlier releases
|
|
80
|
+
* included), a member besides those two, a list that is a Proxy or whose element throws while it is read, a name that
|
|
81
|
+
* is no variable name or that the host hands every child anyway ({@link runtimeSuppliedEnv}), a value that is not a
|
|
82
|
+
* string a variable can hold or is no credential ({@link notACredentialReason}: white space only, a flag or placeholder
|
|
83
|
+
* word, one character repeated, fewer than {@link CREDENTIAL_MIN_CHARS} characters — withholding it would take a setting
|
|
84
|
+
* such as `CI=true` from every child) or that is, in this process's environment now, the value of such a variable —
|
|
85
|
+
* throws and leaves the declaration as it was. A value listed twice is the one value (the declaration is a set). No
|
|
86
|
+
* refusal sentence repeats a value.
|
|
66
87
|
*
|
|
67
88
|
* Two Windows readings, measured on a real machine: a withheld name that the child's own shell or runtime re-creates
|
|
68
89
|
* with a DEFAULT of its own (`ComSpec`, `PATHEXT`, `HOME`, `CommonProgramFiles`, …) shows up in the child's table with
|
|
69
90
|
* that default, never with this process's value — withheld, not leaked; and the disclosure (`detail.ownCredentials`)
|
|
70
91
|
* spells each withheld name as this process's environment spells it, not as the declaration spelled it.
|
|
71
92
|
*/
|
|
72
|
-
export declare function declareWithheldEnv(
|
|
73
|
-
/**
|
|
93
|
+
export declare function declareWithheldEnv(table: WithheldEnvDeclaration): void;
|
|
94
|
+
/**
|
|
95
|
+
* The engine takes credential values in — each where the engine receives it: a first-party brain's construction
|
|
96
|
+
* credential (`brainConfigSnapshot`), a model entry's own credential headers (`resolveRouteCredential`), a protocol
|
|
97
|
+
* peer's credential headers (`resolveProtocolHttpHeaders`), the memory distiller's chat seat key (`openAiCompatChatSeat`,
|
|
98
|
+
* and `RunnerDeps.memoryConsolidationDriver.chat` at `new Runner`, before that seat is built). From then on, for the
|
|
99
|
+
* life of the process, no child spawned on this host inherits an entry whose value equals one: the same table, the same
|
|
100
|
+
* subtraction, finding and disclosure as a declared value ({@link declareWithheldEnv}). A credential the engine is handed
|
|
101
|
+
* per request (a per-model auth hook's answer) is not taken in: the host that resolves it owns it and declares it.
|
|
102
|
+
* An absent or empty value adds nothing. A value that is no credential ({@link notACredentialReason}: white space, a
|
|
103
|
+
* flag or placeholder word, one character repeated, fewer than {@link CREDENTIAL_MIN_CHARS} characters — the key a local
|
|
104
|
+
* gateway is told to be handed) is not taken in: its holder uses it as given (it is no bad value), and the variables
|
|
105
|
+
* that hold the same string stay with every child. Said once per process per value, never the value, as the notice
|
|
106
|
+
* `config.credential_not_withheld` through the engine's one notice throat ({@link deliverEngineNotice}): to `onNotice`
|
|
107
|
+
* when the intake has the structured seat in hand (the `RunnerDeps` receipt at `new Runner`), else as that notice's
|
|
108
|
+
* line on `console.warn` (the throat's own arm for an absent seat — a brain's construction, a request's route reading,
|
|
109
|
+
* a peer's dial, a directly built distiller seat). A value that is, in this process's
|
|
110
|
+
* environment now, the value of a variable every child is handed whatever the spawn passes cannot be withheld: the intake
|
|
111
|
+
* throws (`config.invalid_argument`, the variable named, never the value) and takes nothing in — the brain is not built,
|
|
112
|
+
* the peer is not dialed.
|
|
113
|
+
*/
|
|
114
|
+
export declare function holdOwnCredentialValues(values: Iterable<string | undefined>, onNotice?: (notice: EngineNotice) => void): void;
|
|
115
|
+
/** THE one reading of which HTTP header carries a credential by its NAME — the credential vocabulary's header-name
|
|
116
|
+
* reading ({@link isSensitiveHeaderName}: `Authorization`, `Proxy-Authorization`, `X-Api-Key`, Azure's `api-key`,
|
|
117
|
+
* `x-goog-api-key`, `Cookie`, any name holding a credential word; not a gateway's own spelling of a name the
|
|
118
|
+
* vocabulary declares non-secret, `cf-aig-cache-key` / `X-Idempotency-Key`). The reading of a record MEMBER's name
|
|
119
|
+
* (`isSensitiveRecordKey`), which decides what a record shows, takes those declared names whole only. Every face that
|
|
120
|
+
* asks "which header is a credential, by its name" reads this one: the withheld-value intake below
|
|
121
|
+
* ({@link credentialHeaderValues}) and the route law — which bag carries a credential, which header values a per-model
|
|
122
|
+
* credential's identity is read from, which headers the per-model winner strips, which the user-header merge leaves to
|
|
123
|
+
* that strip, which the run-static stream options refuse. The NAME is the shared half: the intake adds a half of its
|
|
124
|
+
* own, a value that looks like a credential under any name ({@link looksLikeCredentialValue}) — a guess it may make,
|
|
125
|
+
* because withholding a value from a child costs little; the route law does not, because a header it reads as a
|
|
126
|
+
* credential replaces the deployment's key and is bound to an origin, and a guess that is wrong drops a key that should
|
|
127
|
+
* have gone out. */
|
|
128
|
+
export declare function isCredentialHeaderName(name: string): boolean;
|
|
129
|
+
/** Whether a credential header's value is `<auth-scheme> <credentials>` by definition (RFC 9110 §11.6.2 / §11.7.2:
|
|
130
|
+
* `Authorization`, `Proxy-Authorization`) — the scheme word is public and the credentials part is the secret. Any other
|
|
131
|
+
* credential header's value is opaque, read whole. */
|
|
132
|
+
export declare function isSchemedCredentialHeader(name: string): boolean;
|
|
133
|
+
/** The credential values a header bag carries: each header whose name is a credential header ({@link isCredentialHeaderName})
|
|
134
|
+
* or whose value carries one ({@link looksLikeCredentialValue}), as written and, when it reads `<scheme> <credentials>`,
|
|
135
|
+
* its credentials part too — the spelling a variable copied from it would carry. A schemed header's
|
|
136
|
+
* ({@link isSchemedCredentialHeader}) value over a credentials part that is no credential (`Bearer 1`) gives that part
|
|
137
|
+
* alone — the engine's intake then does not take it in — and not the whole value, which carries nothing else. Any other
|
|
138
|
+
* header (`User-Agent`, `Accept`, a region) is no credential. */
|
|
139
|
+
export declare function credentialHeaderValues(headers: Readonly<Record<string, string>> | undefined): string[];
|
|
140
|
+
/** Test seam: never called by production code (a host re-declares `{ names: [], values: [] }`; what the engine took in stays). */
|
|
74
141
|
export declare function __resetWithheldEnv(): void;
|
|
75
142
|
/**
|
|
76
|
-
* THE environment a child spawned ON THIS HOST inherits: the policy's arm, less
|
|
77
|
-
*
|
|
143
|
+
* THE environment a child spawned ON THIS HOST inherits: the policy's arm, less this deployment's own credentials — a
|
|
144
|
+
* declared name, or a value equal to a declared or engine-held credential value ({@link declareWithheldEnv},
|
|
145
|
+
* {@link holdOwnCredentialValues}). The arms: `"scrub"` (and absent) is this process's environment through
|
|
78
146
|
* {@link scrubSecretEnv}; `"all"` is this process's environment as written; a `string[]` is exactly the named
|
|
79
147
|
* variables that are set, as written — a strict allow list, so a name it leaves out (`PATH` included) is not
|
|
80
|
-
* inherited. `findings` collects every entry withheld: the scrub's, and each
|
|
148
|
+
* inherited. `findings` collects every entry withheld: the scrub's, and each own credential the arm held.
|
|
81
149
|
*
|
|
82
150
|
* A policy {@link inheritEnvPolicyProblem} refuses throws that reason HERE, at every spawn, read against the
|
|
83
151
|
* declaration as it stands: a value that is no policy at all (never read as the scrub), and an allow list naming a
|
package/dist/core/secret-env.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { types } from "node:util";
|
|
3
|
+
import { CREDENTIAL_MIN_CHARS, CREDENTIAL_VOCABULARY, envNameView, isSensitiveHeaderName, splitCamelCase } from "./credential-vocabulary.js";
|
|
2
4
|
import { DEFAULT_INHERITED_ENV_VARS } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
5
|
import { deliverEngineNotice } from "./engine-notice.js";
|
|
6
|
+
import { receiveOwnProperties } from "./own-property-receipt.js";
|
|
4
7
|
const GIT_CONFIG_ENV_RE = /^GIT_CONFIG_(?:COUNT|PARAMETERS|(?:KEY|VALUE)_[0-9]+)$/;
|
|
5
8
|
const PROXY_ENV_RE = /^(?:(?:https?|ftp|all|no)_proxy|npm_config_(?:https?_)?proxy|npm_config_noproxy|yarn_proxy|(?:yarn|global_agent|docker|claude_code)_(?:https?|no)_proxy|cloudsdk_proxy_[a-z]+|electron_get_use_proxy)$/i;
|
|
6
9
|
function isExemptEnvName(name) {
|
|
@@ -66,13 +69,14 @@ function carriesSchemelessUserinfo(text) {
|
|
|
66
69
|
const at = text.lastIndexOf("@", text.search(/\s|$/));
|
|
67
70
|
return !isHostPortPathBeforeAt(text.slice(0, at), text.slice(at + 1)) && !/^(?:mailto|sips?|xmpp|im|acct):/i.test(text);
|
|
68
71
|
}
|
|
69
|
-
const
|
|
72
|
+
const FLAG_WORDS = ["true", "false", "none", "null", "yes", "no", "on", "off", "enabled", "disabled", "required", "optional"];
|
|
73
|
+
const CREDENTIAL_ASSIGNMENT_RE = new RegExp(String.raw `(?:(?:^|[;&?#,{]|\/:)\s*|\s)["']?(?!-*jobserver-auth\s*[=:])(?:[a-z0-9_.-]{0,64}(?:password|passwd|pwd|secret|token|(?:account|access|api|private|subscription)[-_]?key|signature|sig|credential)|[a-z0-9_.-]{0,63}[_.-]auth)["']?\s*[=:]\s*["']?(?!(?:${FLAG_WORDS.join("|")})(?:$|[;&,\s"']))[^;&,\s"']+`, "i");
|
|
70
74
|
const WEBHOOK_URL_RE = /https:\/\/(?:hooks\.slack\.com\/(?:services|workflows|triggers)\/|(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/|[\w.-]+\.webhook\.office\.com\/webhookb2\/)[\w\/@.~-]{16,}/i;
|
|
71
|
-
const SONAR_LOGIN_RE =
|
|
75
|
+
const SONAR_LOGIN_RE = new RegExp(String.raw `["']?sonar\.login["']?\s*[:=]\s*["']?[^\s"',}]{${CREDENTIAL_MIN_CHARS},}`);
|
|
72
76
|
const PRIVATE_KEY_HEADER_RE = /-----BEGIN [A-Z ]*PRIVATE KEY(?: BLOCK)?-----/;
|
|
73
|
-
const AUTHORIZATION_HEADER_RE =
|
|
77
|
+
const AUTHORIZATION_HEADER_RE = new RegExp(String.raw `\bauthorization\s*[:=]\s*["']?[a-z][a-z0-9_-]*\s+[A-Za-z0-9._~+\/=-]{${CREDENTIAL_MIN_CHARS},}`, "i");
|
|
74
78
|
const TOKEN_WORD_RE = /\b(?:[Tt]oken|TOKEN)\s+(?=[A-Za-z0-9_~+=-]*[0-9])(?=[A-Za-z0-9_~+=-]*[A-Z])(?=([A-Za-z0-9_~+=-]{20,}))\1(?![\/.])/;
|
|
75
|
-
const BEARER_BASIC_RE =
|
|
79
|
+
const BEARER_BASIC_RE = new RegExp(String.raw `\b(?:Bearer|Basic)\s+(?=[A-Za-z._~+\/=-]*[0-9]|(?:[A-Za-z0-9._~+\/=-]*?[a-z][A-Z](?![a-z])){2}|[A-Za-z0-9.-]*[_~+\/=])[A-Za-z0-9._~+\/=-]{${CREDENTIAL_MIN_CHARS},}`);
|
|
76
80
|
export function looksLikeCredentialValue(value) {
|
|
77
81
|
const text = value.length > VALUE_SCAN_LIMIT ? value.slice(0, VALUE_SCAN_LIMIT) : value;
|
|
78
82
|
for (let at = text.indexOf("://"); at !== -1; at = text.indexOf("://", at + 3)) {
|
|
@@ -149,39 +153,188 @@ const WINDOWS_REQUIRED_ENV = Object.freeze(["HOMEDRIVE", "HOMEPATH", "LOGONSERVE
|
|
|
149
153
|
function runtimeSuppliedEnv() {
|
|
150
154
|
return ["NODE_V8_COVERAGE", ...DEFAULT_INHERITED_ENV_VARS, ...(process.platform === "win32" ? WINDOWS_REQUIRED_ENV : [])];
|
|
151
155
|
}
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
const valueDigest = (value) => createHash("sha256").update(value, "utf16le").digest("base64");
|
|
157
|
+
const indexHas = (index, value) => {
|
|
158
|
+
const digests = index.get(value.length);
|
|
159
|
+
return digests !== undefined && digests.has(valueDigest(value));
|
|
160
|
+
};
|
|
161
|
+
const indexAdd = (index, value) => {
|
|
162
|
+
const digests = index.get(value.length);
|
|
163
|
+
if (digests === undefined)
|
|
164
|
+
index.set(value.length, new Set([valueDigest(value)]));
|
|
165
|
+
else
|
|
166
|
+
digests.add(valueDigest(value));
|
|
157
167
|
};
|
|
158
|
-
const
|
|
159
|
-
|
|
168
|
+
const WITHHELD_ENV = Symbol.for("sema.core.withheldEnvTable");
|
|
169
|
+
const NOTHING_NAMED = Object.freeze([]);
|
|
170
|
+
const isWithheldEnvTable = (t) => typeof t === "object" && t !== null && Array.isArray(t.names) && t.declared instanceof Map && t.held instanceof Map;
|
|
171
|
+
const withheldEnvOf = () => {
|
|
172
|
+
const slot = Reflect.get(globalThis, WITHHELD_ENV);
|
|
173
|
+
if (isWithheldEnvTable(slot))
|
|
174
|
+
return slot;
|
|
175
|
+
const fresh = { names: NOTHING_NAMED, declared: new Map(), held: new Map() };
|
|
176
|
+
Reflect.set(globalThis, WITHHELD_ENV, fresh);
|
|
177
|
+
return fresh;
|
|
160
178
|
};
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
throw new Error(`declareWithheldEnv:
|
|
165
|
-
const
|
|
179
|
+
const kindOf = (v) => (v === null ? "null" : Array.isArray(v) ? "an array" : typeof v);
|
|
180
|
+
function listCopy(label, list) {
|
|
181
|
+
if (types.isProxy(list))
|
|
182
|
+
throw new Error(`declareWithheldEnv: ${label} must be a plain array, not a Proxy`);
|
|
183
|
+
const copy = [];
|
|
184
|
+
try {
|
|
185
|
+
for (let i = 0, n = list.length; i < n; i++)
|
|
186
|
+
copy[i] = list[i];
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
throw new Error(`declareWithheldEnv: an element of ${label} threw while it was read — refused`);
|
|
190
|
+
}
|
|
191
|
+
return Object.freeze(copy);
|
|
192
|
+
}
|
|
193
|
+
const CANNOT_BE_WITHHELD = "which a child is handed from this process's environment whatever the spawn passes (by Node, the MCP stdio transport or Windows) — it cannot be withheld";
|
|
194
|
+
function runtimeSuppliedHolderOf(value) {
|
|
195
|
+
const supplied = policyArm([...runtimeSuppliedEnv()]);
|
|
196
|
+
return Object.keys(supplied).find((k) => supplied[k] === value);
|
|
197
|
+
}
|
|
198
|
+
const PLACEHOLDER_KEY_WORDS = new Set([...FLAG_WORDS, "undefined", "placeholder", "lm-studio", "not-needed", "sk-no-key-required"]);
|
|
199
|
+
const ONE_REPEATED_CHARACTER_RE = /^(\S)\1{2,}$/u;
|
|
200
|
+
function notACredentialReason(value) {
|
|
201
|
+
const text = value.trim();
|
|
202
|
+
if (text === "")
|
|
203
|
+
return "white space only, which every blank variable equals";
|
|
204
|
+
if (text.length < CREDENTIAL_MIN_CHARS)
|
|
205
|
+
return `a string of fewer than ${CREDENTIAL_MIN_CHARS} characters, which names no secret`;
|
|
206
|
+
if (PLACEHOLDER_KEY_WORDS.has(text.toLowerCase()))
|
|
207
|
+
return "a flag or placeholder word, which names no secret";
|
|
208
|
+
if (ONE_REPEATED_CHARACTER_RE.test(text.replace(CREDENTIAL_VOCABULARY.tokenPrefix, "")))
|
|
209
|
+
return "one character repeated, which names no secret";
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
function credentialValueProblem(v) {
|
|
213
|
+
if (typeof v !== "string")
|
|
214
|
+
return kindOf(v);
|
|
215
|
+
if (v === "")
|
|
216
|
+
return "an empty string, which every variable set to nothing equals";
|
|
217
|
+
if (v.includes("\0") || UNPAIRED_SURROGATE_RE.test(v))
|
|
218
|
+
return `a value holding ${v.includes("\0") ? "a NUL" : "an unpaired surrogate"}, which no variable can hold`;
|
|
219
|
+
return notACredentialReason(v);
|
|
220
|
+
}
|
|
221
|
+
function credentialValueListProblem(value) {
|
|
222
|
+
for (const [i, v] of value.entries()) {
|
|
223
|
+
const why = credentialValueProblem(v);
|
|
224
|
+
if (why !== undefined)
|
|
225
|
+
return `values[${i}] is not a credential value (got ${why})`;
|
|
226
|
+
}
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
export function declareWithheldEnv(table) {
|
|
230
|
+
const given = table;
|
|
231
|
+
if (given === null || typeof given !== "object" || Array.isArray(given)) {
|
|
232
|
+
throw new Error(`declareWithheldEnv: the declaration must be a table { names, values } (got ${Array.isArray(given) ? "an array — a names-only list is no longer a declaration: pass { names, values }" : kindOf(given)})`);
|
|
233
|
+
}
|
|
234
|
+
const received = receiveOwnProperties(given, { subject: "declareWithheldEnv's table", unit: "member", moment: "at the declaration" });
|
|
235
|
+
const stray = Object.keys(received).find((k) => k !== "names" && k !== "values");
|
|
236
|
+
if (stray !== undefined)
|
|
237
|
+
throw new Error(`declareWithheldEnv: the table has a member ${JSON.stringify(stray.slice(0, 64))} — it holds names and values only`);
|
|
238
|
+
const givenNames = received.names;
|
|
239
|
+
if (!Array.isArray(givenNames))
|
|
240
|
+
throw new Error(`declareWithheldEnv: names must be an array of variable names (got ${kindOf(givenNames)})`);
|
|
241
|
+
const names = listCopy("names", givenNames);
|
|
242
|
+
const problem = variableNameListProblem("names", names);
|
|
166
243
|
if (problem !== undefined)
|
|
167
244
|
throw new Error(`declareWithheldEnv: ${problem}`);
|
|
168
245
|
const supplied = new Set(runtimeSuppliedEnv().map(envNameKey));
|
|
169
|
-
const unwithholdable =
|
|
246
|
+
const unwithholdable = names.findIndex((k) => supplied.has(envNameKey(k)));
|
|
170
247
|
if (unwithholdable !== -1)
|
|
171
|
-
throw new Error(`declareWithheldEnv: names[${unwithholdable}] is ${
|
|
172
|
-
|
|
248
|
+
throw new Error(`declareWithheldEnv: names[${unwithholdable}] is ${String(names[unwithholdable])}, ${CANNOT_BE_WITHHELD}`);
|
|
249
|
+
const givenValues = received.values;
|
|
250
|
+
if (!Array.isArray(givenValues))
|
|
251
|
+
throw new Error(`declareWithheldEnv: values must be an array of credential values (got ${kindOf(givenValues)})`);
|
|
252
|
+
const values = listCopy("values", givenValues);
|
|
253
|
+
const valueProblem = credentialValueListProblem(values);
|
|
254
|
+
if (valueProblem !== undefined)
|
|
255
|
+
throw new Error(`declareWithheldEnv: ${valueProblem}`);
|
|
256
|
+
for (const [i, v] of values.entries()) {
|
|
257
|
+
const holder = runtimeSuppliedHolderOf(v);
|
|
258
|
+
if (holder !== undefined)
|
|
259
|
+
throw new Error(`declareWithheldEnv: values[${i}] is the value of ${holder}, ${CANNOT_BE_WITHHELD}`);
|
|
260
|
+
}
|
|
261
|
+
const declared = new Map();
|
|
262
|
+
for (const v of values)
|
|
263
|
+
indexAdd(declared, v);
|
|
264
|
+
Reflect.set(globalThis, WITHHELD_ENV, { names: names, declared, held: withheldEnvOf().held });
|
|
265
|
+
}
|
|
266
|
+
export function holdOwnCredentialValues(values, onNotice) {
|
|
267
|
+
const given = [...values].filter((v) => typeof v === "string" && v.length > 0);
|
|
268
|
+
const taken = given.filter((v) => {
|
|
269
|
+
const why = notACredentialReason(v);
|
|
270
|
+
if (why !== undefined)
|
|
271
|
+
sayNotTaken(v, why, onNotice);
|
|
272
|
+
return why === undefined;
|
|
273
|
+
});
|
|
274
|
+
for (const v of taken) {
|
|
275
|
+
const holder = runtimeSuppliedHolderOf(v);
|
|
276
|
+
if (holder !== undefined)
|
|
277
|
+
throw Object.assign(new Error(`a credential the engine was handed is the value of ${holder}, ${CANNOT_BE_WITHHELD}; the credential is refused`), { code: "config.invalid_argument" });
|
|
278
|
+
}
|
|
279
|
+
const { held } = withheldEnvOf();
|
|
280
|
+
for (const v of taken)
|
|
281
|
+
indexAdd(held, v);
|
|
282
|
+
}
|
|
283
|
+
const AUTH_SCHEME_VALUE_RE = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+ +(\S[\s\S]*)$/;
|
|
284
|
+
const SCHEMED_HEADER_RE = /^(?:proxy-)?authorization$/i;
|
|
285
|
+
export function isCredentialHeaderName(name) {
|
|
286
|
+
return isSensitiveHeaderName(name);
|
|
287
|
+
}
|
|
288
|
+
export function isSchemedCredentialHeader(name) {
|
|
289
|
+
return SCHEMED_HEADER_RE.test(name);
|
|
290
|
+
}
|
|
291
|
+
export function credentialHeaderValues(headers) {
|
|
292
|
+
const out = [];
|
|
293
|
+
for (const [name, value] of Object.entries(headers ?? {})) {
|
|
294
|
+
if (typeof value !== "string" || !(isCredentialHeaderName(name) || looksLikeCredentialValue(value)))
|
|
295
|
+
continue;
|
|
296
|
+
const credentials = AUTH_SCHEME_VALUE_RE.exec(value)?.[1];
|
|
297
|
+
if (credentials !== undefined && isSchemedCredentialHeader(name) && notACredentialReason(credentials) !== undefined) {
|
|
298
|
+
out.push(credentials);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
out.push(value);
|
|
302
|
+
if (credentials !== undefined)
|
|
303
|
+
out.push(credentials);
|
|
304
|
+
}
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
307
|
+
const intakeSaid = new Set();
|
|
308
|
+
function sayNotTaken(value, why, onNotice) {
|
|
309
|
+
const key = valueDigest(value.trim());
|
|
310
|
+
if (intakeSaid.has(key))
|
|
311
|
+
return;
|
|
312
|
+
intakeSaid.add(key);
|
|
313
|
+
try {
|
|
314
|
+
deliverEngineNotice(onNotice, {
|
|
315
|
+
code: "config.credential_not_withheld",
|
|
316
|
+
message: `a credential the engine was handed is ${why} — it is used as given, but a variable holding the same string is not withheld from a spawned child (said once per value; the value is not repeated)`,
|
|
317
|
+
detail: { reason: why },
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
}
|
|
173
322
|
}
|
|
174
323
|
export function __resetWithheldEnv() {
|
|
175
|
-
|
|
324
|
+
Reflect.set(globalThis, WITHHELD_ENV, { names: NOTHING_NAMED, declared: new Map(), held: new Map() });
|
|
325
|
+
intakeSaid.clear();
|
|
176
326
|
}
|
|
177
327
|
function withholdOwnCredentials(inherited, findings) {
|
|
178
|
-
|
|
328
|
+
const table = withheldEnvOf();
|
|
329
|
+
if (table.names.length === 0 && table.declared.size === 0 && table.held.size === 0)
|
|
179
330
|
return inherited;
|
|
180
|
-
const own = new Set(
|
|
331
|
+
const own = new Set(table.names.map(envNameKey));
|
|
181
332
|
const kept = [];
|
|
182
333
|
for (const key of Object.keys(inherited)) {
|
|
183
|
-
|
|
184
|
-
|
|
334
|
+
const value = inherited[key];
|
|
335
|
+
const ownValue = typeof value === "string" && (indexHas(table.declared, value) || indexHas(table.held, value));
|
|
336
|
+
if (!own.has(envNameKey(key)) && !ownValue)
|
|
337
|
+
kept.push([key, value]);
|
|
185
338
|
else
|
|
186
339
|
findings?.push({ key, kind: "own-credential", confidence: SECRET_ENV_KIND_CONFIDENCE["own-credential"], source: "secret-env" });
|
|
187
340
|
}
|
|
@@ -198,24 +351,25 @@ export function inheritedHostEnv(policy, findings) {
|
|
|
198
351
|
const problem = inheritEnvPolicyProblem(policy);
|
|
199
352
|
if (problem !== undefined)
|
|
200
353
|
throw new Error(problem);
|
|
201
|
-
|
|
354
|
+
return withholdOwnCredentials(policyArm(policy, findings), findings);
|
|
355
|
+
}
|
|
356
|
+
function policyArm(policy, findings) {
|
|
202
357
|
if (policy === "all")
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
arm = scrubSecretEnv(process.env, findings);
|
|
212
|
-
return withholdOwnCredentials(arm, findings);
|
|
358
|
+
return { ...process.env };
|
|
359
|
+
if (!Array.isArray(policy))
|
|
360
|
+
return scrubSecretEnv(process.env, findings);
|
|
361
|
+
const arm = {};
|
|
362
|
+
for (const k of policy)
|
|
363
|
+
if (process.env[k] !== undefined)
|
|
364
|
+
arm[k] = process.env[k];
|
|
365
|
+
return arm;
|
|
213
366
|
}
|
|
214
367
|
export function inheritEnvPolicyProblem(value) {
|
|
215
368
|
const shape = policyShapeProblem(value);
|
|
216
|
-
|
|
369
|
+
const { names } = withheldEnvOf();
|
|
370
|
+
if (shape !== undefined || !Array.isArray(value) || names.length === 0)
|
|
217
371
|
return shape;
|
|
218
|
-
const own = new Set(
|
|
372
|
+
const own = new Set(names.map(envNameKey));
|
|
219
373
|
const named = value.findIndex((k) => own.has(envNameKey(k)));
|
|
220
374
|
return named === -1 ? undefined : `inheritEnv[${named}] names ${value[named]}, which is this deployment's own credential and cannot be inherited by a child (a configuration error: no retry succeeds until the policy or the declaration changes)`;
|
|
221
375
|
}
|