@sema-agent/core 7.48.0 → 7.49.1
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 +457 -0
- package/README.md +2 -2
- package/dist/agents/cascade.d.ts +2 -5
- package/dist/agents/child-failure.d.ts +20 -0
- package/dist/agents/child-failure.js +28 -0
- package/dist/agents/cross-session-ref.d.ts +11 -3
- package/dist/agents/cross-session-ref.js +6 -0
- package/dist/agents/cumulative-stats.d.ts +12 -15
- package/dist/agents/cumulative-stats.js +1 -1
- package/dist/agents/extra-tool-names.js +1 -1
- package/dist/agents/inherited-tool-pool.d.ts +17 -13
- package/dist/agents/inherited-tool-pool.js +4 -3
- package/dist/agents/peer-session-drain.d.ts +3 -2
- package/dist/agents/peer-session-drain.js +5 -4
- package/dist/agents/send-message-tool.js +2 -9
- package/dist/agents/subagent.d.ts +10 -29
- package/dist/agents/subagent.js +65 -53
- package/dist/agents/suspend-guard.d.ts +1 -1
- package/dist/agents/tool-filter.d.ts +76 -65
- package/dist/agents/tool-filter.js +122 -92
- package/dist/agents/verify.d.ts +4 -7
- package/dist/agents/verify.js +6 -7
- package/dist/bench/metrics.d.ts +1 -2
- package/dist/brain/anthropic.js +133 -79
- package/dist/brain/errors.d.ts +53 -6
- package/dist/brain/errors.js +22 -2
- package/dist/brain/input-too-long.d.ts +40 -19
- package/dist/brain/input-too-long.js +3 -16
- package/dist/brain/open-responses.js +19 -10
- package/dist/brain/openai.js +123 -32
- package/dist/brain/provider-dialect.d.ts +214 -0
- package/dist/brain/provider-dialect.js +186 -0
- package/dist/brain/request-params.d.ts +27 -8
- package/dist/brain/request-params.js +7 -12
- package/dist/brain/request-route.d.ts +84 -0
- package/dist/brain/request-route.js +41 -0
- package/dist/brain/retry.d.ts +8 -0
- package/dist/brain/retry.js +10 -4
- package/dist/brain/route-adjudicator.d.ts +7 -0
- package/dist/brain/route-adjudicator.js +5 -1
- package/dist/brain/status-sink.d.ts +20 -0
- package/dist/brain/status-sink.js +11 -0
- package/dist/brain/stream-engine.d.ts +52 -1
- package/dist/brain/stream-engine.js +81 -24
- package/dist/brain/stream-shared.d.ts +57 -11
- package/dist/brain/stream-shared.js +28 -2
- package/dist/core/a2a.d.ts +1 -0
- package/dist/core/agent-config-dir.js +3 -2
- package/dist/core/allow-entry.d.ts +21 -12
- package/dist/core/allow-entry.js +38 -31
- package/dist/core/arg-summary.d.ts +21 -28
- package/dist/core/arg-summary.js +235 -88
- package/dist/core/ask-origin.d.ts +42 -24
- package/dist/core/ask-origin.js +18 -13
- package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
- package/dist/core/auto-mode-prompt-assets.js +1 -1
- package/dist/core/auto-mode-prompt.d.ts +11 -1
- package/dist/core/auto-mode-prompt.js +13 -10
- package/dist/core/auto-mode-rebuild.d.ts +7 -0
- package/dist/core/auto-mode-rebuild.js +4 -1
- package/dist/core/canonical-json.d.ts +3 -0
- package/dist/core/canonical-json.js +2 -1
- package/dist/core/checkpoint-requirements.d.ts +892 -0
- package/dist/core/checkpoint-requirements.js +333 -0
- package/dist/core/checkpoint-store.d.ts +94 -65
- package/dist/core/checkpoint-store.js +14 -26
- package/dist/core/child-clamp-seats.d.ts +228 -69
- package/dist/core/child-clamp-seats.js +211 -17
- package/dist/core/classifier-unavailable-arm.d.ts +5 -1
- package/dist/core/classifier-unavailable-arm.js +3 -3
- package/dist/core/compliance.d.ts +3 -0
- package/dist/core/compliance.js +9 -4
- package/dist/core/credential-vocabulary.d.ts +140 -0
- package/dist/core/credential-vocabulary.js +131 -0
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/effective-path-target.d.ts +73 -16
- package/dist/core/effective-path-target.js +63 -33
- package/dist/core/engine-notice.d.ts +43 -11
- package/dist/core/file-history-store.js +2 -2
- package/dist/core/fs-write-gate-policy.d.ts +4 -0
- package/dist/core/fs-write-gate-policy.js +22 -5
- package/dist/core/gate-bounded-await.d.ts +28 -13
- package/dist/core/gate-bounded-await.js +41 -4
- package/dist/core/gate-fold.d.ts +1 -1
- package/dist/core/gate-fold.js +24 -25
- package/dist/core/gate-lanes.js +16 -15
- package/dist/core/gate-outcome.d.ts +20 -5
- package/dist/core/gate-outcome.js +5 -0
- package/dist/core/governance-codes.d.ts +11 -4
- package/dist/core/governance-codes.js +14 -3
- package/dist/core/hooks.d.ts +21 -0
- package/dist/core/locked-config.d.ts +8 -0
- package/dist/core/locked-config.js +14 -2
- package/dist/core/lsp.js +3 -5
- package/dist/core/mailbox-store.d.ts +3 -4
- package/dist/core/mcp-connection-pool.d.ts +75 -0
- package/dist/core/mcp-connection-pool.js +128 -0
- package/dist/core/mcp-failure.d.ts +2 -1
- package/dist/core/mcp-failure.js +13 -2
- package/dist/core/mcp.d.ts +4 -0
- package/dist/core/mcp.js +70 -43
- package/dist/core/memory-engine/content-origin.js +2 -14
- package/dist/core/memory-engine/engine.d.ts +32 -22
- package/dist/core/memory-engine/engine.js +103 -55
- package/dist/core/memory-engine/file-backend.d.ts +13 -30
- package/dist/core/memory-engine/file-backend.js +37 -252
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +139 -9
- package/dist/core/memory-engine/layout.js +350 -7
- package/dist/core/memory-engine/scope-contract.d.ts +10 -0
- package/dist/core/memory-engine/scope-contract.js +8 -0
- package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
- package/dist/core/memory-engine/session-incarnation.js +5 -2
- package/dist/core/memory-engine/types.d.ts +10 -1
- package/dist/core/memory.js +5 -17
- package/dist/core/model-seat.d.ts +4 -4
- package/dist/core/model-seat.js +1 -1
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +19 -0
- package/dist/core/namespaced-rule-name.d.ts +29 -0
- package/dist/core/namespaced-rule-name.js +52 -0
- package/dist/core/park-selfcheck.d.ts +1 -1
- package/dist/core/park-selfcheck.js +16 -6
- package/dist/core/path-guard-rows.d.ts +99 -0
- package/dist/core/path-guard-rows.js +45 -0
- package/dist/core/path-identity.d.ts +22 -16
- package/dist/core/path-identity.js +10 -10
- package/dist/core/path-rule-binding.d.ts +2 -1
- package/dist/core/path-rule-binding.js +3 -1
- package/dist/core/pause-registry.d.ts +16 -2
- package/dist/core/pause-registry.js +6 -0
- package/dist/core/permission-rule-consent.js +0 -7
- package/dist/core/permission-rule-model.d.ts +68 -24
- package/dist/core/permission-rule-model.js +105 -24
- package/dist/core/permission-rule-store.js +2 -2
- package/dist/core/permission-rules.d.ts +3 -30
- package/dist/core/permission-rules.js +4 -54
- package/dist/core/read-root-candidate.d.ts +1 -3
- package/dist/core/read-root-candidate.js +4 -15
- package/dist/core/real-approval.d.ts +4 -3
- package/dist/core/retired-keys.d.ts +13 -0
- package/dist/core/retired-keys.js +14 -0
- package/dist/core/roles.d.ts +2 -3
- package/dist/core/roles.js +15 -6
- package/dist/core/runner/assemble-result.d.ts +0 -7
- package/dist/core/runner/assemble-result.js +19 -31
- package/dist/core/runner/caller-roster.d.ts +78 -0
- package/dist/core/runner/caller-roster.js +219 -0
- package/dist/core/runner/checkpoint-scope.d.ts +16 -16
- package/dist/core/runner/checkpoint-scope.js +2 -2
- package/dist/core/runner/child-tree.js +2 -2
- package/dist/core/runner/contracts.d.ts +68 -35
- package/dist/core/runner/decide-continuation.d.ts +51 -3
- package/dist/core/runner/decide-continuation.js +76 -21
- package/dist/core/runner/denial-limit-arms.d.ts +17 -5
- package/dist/core/runner/denial-limit-arms.js +11 -9
- package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
- package/dist/core/runner/extra-body-dropped-seat.js +22 -0
- package/dist/core/runner/finish-reason-seat.d.ts +9 -0
- package/dist/core/runner/finish-reason-seat.js +40 -0
- package/dist/core/runner/gate-exit.d.ts +44 -32
- package/dist/core/runner/gate-exit.js +112 -25
- package/dist/core/runner/inherited-ask-grants.js +6 -4
- package/dist/core/runner/mcp-redial.d.ts +3 -3
- package/dist/core/runner/mcp-redial.js +3 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
- package/dist/core/runner/permission-rule-lanes.js +5 -4
- package/dist/core/runner/prepare-artifact.d.ts +4 -0
- package/dist/core/runner/prepare-artifact.js +2 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
- package/dist/core/runner/prepare-ask-lane.js +12 -6
- package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
- package/dist/core/runner/prepare-boundary-parks.js +4 -7
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
- package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
- package/dist/core/runner/prepare-config-doors.d.ts +9 -9
- package/dist/core/runner/prepare-config-doors.js +10 -5
- package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
- package/dist/core/runner/prepare-defer-classify.js +5 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
- package/dist/core/runner/prepare-delegation-surface.js +3 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
- package/dist/core/runner/prepare-gate-stations.js +9 -7
- package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
- package/dist/core/runner/prepare-hands-readface.js +7 -7
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
- package/dist/core/runner/prepare-inherited-gate.js +14 -15
- package/dist/core/runner/prepare-listings.d.ts +7 -24
- package/dist/core/runner/prepare-listings.js +4 -5
- package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
- package/dist/core/runner/prepare-memory-engine-session.js +4 -3
- package/dist/core/runner/prepare-memory.d.ts +6 -0
- package/dist/core/runner/prepare-memory.js +13 -13
- package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
- package/dist/core/runner/prepare-offload-wrappers.js +3 -3
- package/dist/core/runner/prepare-park-ask.d.ts +7 -8
- package/dist/core/runner/prepare-park-ask.js +17 -10
- package/dist/core/runner/prepare-policy-chain.js +24 -44
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +3 -4
- package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
- package/dist/core/runner/prepare-protocol-tools.js +3 -4
- package/dist/core/runner/prepare-run-refs.d.ts +3 -0
- package/dist/core/runner/prepare-run-refs.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
- package/dist/core/runner/prepare-suspend-saga.js +28 -12
- package/dist/core/runner/prepare-task.d.ts +1 -1
- package/dist/core/runner/prepare-task.js +67 -56
- package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
- package/dist/core/runner/prepare-wiring-manifest.js +5 -8
- package/dist/core/runner/resume-apply.js +7 -14
- package/dist/core/runner/resume-checkpoint-screen.js +11 -4
- package/dist/core/runner/resume-internals-and-config.js +2 -2
- package/dist/core/runner/resume-policy-outcome.js +5 -32
- package/dist/core/runner/resume-review-outcome.js +4 -1
- package/dist/core/runner/retired-runner-deps.d.ts +6 -0
- package/dist/core/runner/retired-runner-deps.js +10 -1
- package/dist/core/runner/run-brain-sinks.d.ts +4 -0
- package/dist/core/runner/run-brain-sinks.js +5 -2
- package/dist/core/runner/run-harness-handlers.js +29 -36
- package/dist/core/runner/run-leg.d.ts +0 -2
- package/dist/core/runner/run-leg.js +32 -33
- package/dist/core/runner/run-terminal-adoption.js +4 -3
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-rule-policy.js +5 -5
- package/dist/core/runner/stream-settle-backstop.js +7 -4
- package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
- package/dist/core/runner/sub-agent-deny-lists.js +111 -80
- package/dist/core/runner/terminal-account.d.ts +48 -0
- package/dist/core/runner/terminal-account.js +186 -0
- package/dist/core/runner/tool-end-body.d.ts +54 -17
- package/dist/core/runner/tool-end-body.js +27 -2
- package/dist/core/runner/tool-face-overlay.d.ts +3 -1
- package/dist/core/runner/tool-face-overlay.js +6 -4
- package/dist/core/runner/tool-occurrence.d.ts +106 -0
- package/dist/core/runner/tool-occurrence.js +123 -0
- package/dist/core/runner/tool-progress-lane.d.ts +16 -8
- package/dist/core/runner/tool-progress-lane.js +25 -34
- package/dist/core/runner/tool-turn-repair-seat.d.ts +28 -4
- package/dist/core/runner/tool-turn-repair-seat.js +36 -13
- package/dist/core/runner/turn-attachments.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +21 -9
- package/dist/core/runner/write-protection-station.js +20 -17
- package/dist/core/runner-deps.d.ts +12 -22
- package/dist/core/secret-env.d.ts +16 -5
- package/dist/core/secret-env.js +23 -63
- package/dist/core/sensitive-path-policy.d.ts +19 -18
- package/dist/core/sensitive-path-policy.js +73 -49
- package/dist/core/session-reconcile.d.ts +3 -0
- package/dist/core/session-reconcile.js +5 -4
- package/dist/core/session-store.d.ts +5 -0
- package/dist/core/session-store.js +12 -0
- package/dist/core/session.d.ts +13 -0
- package/dist/core/shared-memory/normalize.d.ts +17 -4
- package/dist/core/shared-memory/normalize.js +7 -7
- package/dist/core/shell-lexer.js +5 -4
- package/dist/core/shell-wrapper-projection.js +1 -1
- package/dist/core/skill-grant.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
- package/dist/core/stub-env.d.ts +2 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/synthetic-read-verdict.js +2 -2
- package/dist/core/task-event.d.ts +59 -5
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +42 -9
- package/dist/core/terminal-cause.d.ts +94 -11
- package/dist/core/tighten-task-spec.d.ts +5 -4
- package/dist/core/tighten-task-spec.js +20 -25
- package/dist/core/tool-catalog-entries.d.ts +5 -7
- package/dist/core/tool-catalog-entries.js +14 -15
- package/dist/core/tool-face.d.ts +47 -0
- package/dist/core/tool-face.js +5 -0
- package/dist/core/tool-model-gate.d.ts +5 -5
- package/dist/core/tool-name-aliases.d.ts +26 -2
- package/dist/core/tool-name-aliases.js +13 -0
- package/dist/core/tool-name-list.d.ts +30 -0
- package/dist/core/tool-name-list.js +55 -0
- package/dist/core/tool-name-readings.d.ts +1 -9
- package/dist/core/tool-name-readings.js +1 -3
- package/dist/core/tool-policy.d.ts +195 -85
- package/dist/core/tool-policy.js +165 -380
- package/dist/core/tool-registry.d.ts +44 -1
- package/dist/core/tool-registry.js +26 -0
- package/dist/core/tool-roster.d.ts +19 -1
- package/dist/core/tool-roster.js +21 -2
- package/dist/core/tool-spec-members.d.ts +45 -0
- package/dist/core/tool-spec-members.js +169 -0
- package/dist/core/tool-spec.d.ts +46 -8
- package/dist/core/tools.d.ts +6 -2
- package/dist/core/tools.js +8 -4
- package/dist/core/untrusted-egress.js +29 -26
- package/dist/core/untrusted-text.d.ts +13 -10
- package/dist/core/untrusted-text.js +6 -44
- package/dist/core/workflow-journal-store.d.ts +4 -1
- package/dist/core/write-protect.d.ts +65 -29
- package/dist/core/write-protect.js +235 -177
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
- package/dist/engine/execution-env/node-execution-env.js +16 -38
- package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
- package/dist/engine/execution-env/symlink-chain.js +32 -0
- package/dist/engine/harness/types.d.ts +7 -0
- package/dist/engine/llm/tool-turns.d.ts +3 -0
- package/dist/engine/llm/tool-turns.js +1 -0
- package/dist/engine/llm/types.d.ts +59 -23
- package/dist/engine/loop/agent-loop.js +16 -2
- package/dist/engine/session/memory-repo.js +11 -3
- package/dist/engine/session/repo-utils.d.ts +8 -0
- package/dist/engine/session/repo-utils.js +13 -0
- package/dist/index.d.ts +20 -23
- package/dist/index.js +17 -20
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/governance-baseline-validity.js +1 -1
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +16 -35
- package/dist/orchestration/run-workflow-tool.js +38 -78
- package/dist/orchestration/workflow-governance.d.ts +21 -25
- package/dist/orchestration/workflow-governance.js +38 -78
- package/dist/orchestration/workflow-primitives.d.ts +7 -22
- package/dist/orchestration/workflow-primitives.js +5 -12
- package/dist/orchestration/workflow-types.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +61 -11
- package/dist/orchestration/workflow.js +189 -117
- package/dist/scenarios/full-body.d.ts +1 -1
- package/dist/shell/lex.d.ts +0 -21
- package/dist/shell/lex.js +250 -68
- package/dist/shell/shell-words.d.ts +35 -0
- package/dist/shell/shell-words.js +65 -0
- package/dist/stores/file/checkpoint-store.d.ts +5 -5
- package/dist/stores/file/checkpoint-store.js +5 -2
- package/dist/stores/file/index.d.ts +0 -8
- package/dist/stores/file/index.js +0 -12
- package/dist/stores/file/session-store.d.ts +3 -0
- package/dist/stores/file/session-store.js +44 -19
- package/dist/tools/artifact/artifact-tool.js +2 -0
- package/dist/tools/fs/bash-program-position.d.ts +12 -4
- package/dist/tools/fs/bash-program-position.js +32 -9
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/bash-readonly-classifier.js +8 -7
- package/dist/tools/fs/containment-face.d.ts +4 -0
- package/dist/tools/fs/containment-face.js +3 -0
- package/dist/tools/fs/fs-shared.d.ts +10 -0
- package/dist/tools/fs/fs-shared.js +18 -0
- package/dist/tools/fs/fs-write.js +4 -2
- package/dist/tools/fs/index.d.ts +1 -1
- package/dist/tools/fs/program-read-model.d.ts +46 -20
- package/dist/tools/fs/program-read-model.js +50 -20
- package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
- package/dist/tools/fs/program-read-model.rows.js +16 -15
- package/dist/tools/fs/read-deny-home.d.ts +33 -47
- package/dist/tools/fs/read-deny-home.js +35 -49
- package/dist/tools/fs/read-deny.d.ts +23 -22
- package/dist/tools/fs/read-deny.js +114 -89
- package/dist/tools/fs/removal-targets.d.ts +56 -23
- package/dist/tools/fs/removal-targets.js +65 -87
- package/dist/tools/fs/safety.d.ts +29 -22
- package/dist/tools/fs/safety.js +17 -11
- package/dist/tools/fs/search.js +10 -8
- package/dist/tools/fs/shell-read-argv.js +1 -1
- package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
- package/dist/tools/fs/shell-read-bindings.js +324 -86
- package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
- package/dist/tools/fs/shell-read-builtins.js +43 -0
- package/dist/tools/fs/shell-read-check.d.ts +15 -1
- package/dist/tools/fs/shell-read-check.js +67 -43
- package/dist/tools/fs/shell-read-establish.js +6 -6
- package/dist/tools/fs/shell-read-functions.d.ts +22 -0
- package/dist/tools/fs/shell-read-functions.js +29 -0
- package/dist/tools/fs/shell-read-judge.d.ts +51 -18
- package/dist/tools/fs/shell-read-judge.js +40 -4
- package/dist/tools/fs/shell-read-plan.d.ts +12 -6
- package/dist/tools/fs/shell-read-plan.js +118 -113
- package/dist/tools/fs/shell-read-start.d.ts +29 -6
- package/dist/tools/fs/shell-read-start.js +16 -9
- package/dist/tools/fs/shell-read-word.js +4 -0
- package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
- package/dist/tools/fs/shell-read-workdir.js +281 -0
- package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
- package/dist/tools/fs/shell-read-write-targets.js +14 -5
- package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
- package/dist/tools/fs/shell-reentry-text.js +3 -11
- package/dist/tools/task-list.d.ts +1 -2
- package/dist/tools/web.js +1 -1
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +107 -143
- package/wire-changes/core@7.49.0.json +4765 -0
- package/dist/agents/teacher.d.ts +0 -159
- package/dist/agents/teacher.js +0 -577
- package/dist/agents/team.d.ts +0 -226
- package/dist/agents/team.js +0 -257
- package/dist/core/strategy-store.d.ts +0 -238
- package/dist/core/strategy-store.js +0 -253
- package/dist/orchestration/builtin-workflows.d.ts +0 -133
- package/dist/orchestration/builtin-workflows.js +0 -159
- package/dist/scenarios/env.d.ts +0 -40
- package/dist/scenarios/env.js +0 -39
- package/dist/scenarios/scenario-registry.d.ts +0 -110
- package/dist/scenarios/scenario-registry.js +0 -140
- package/dist/scenarios/teacher-quickstart.d.ts +0 -40
- package/dist/scenarios/teacher-quickstart.js +0 -12
- package/dist/stores/cc/lockfile.d.ts +0 -10
- package/dist/stores/cc/lockfile.js +0 -98
- package/dist/stores/cc/mailbox-store.d.ts +0 -20
- package/dist/stores/cc/mailbox-store.js +0 -255
- package/dist/stores/cc/roster-adapter.d.ts +0 -12
- package/dist/stores/cc/roster-adapter.js +0 -117
- package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
- package/dist/stores/cc/sidecar-transcript.js +0 -264
- package/dist/stores/cc/task-list-store.d.ts +0 -2
- package/dist/stores/cc/task-list-store.js +0 -125
- package/dist/stores/file/strategy-store.d.ts +0 -97
- package/dist/stores/file/strategy-store.js +0 -341
package/dist/core/allow-entry.js
CHANGED
|
@@ -3,15 +3,15 @@ import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermission
|
|
|
3
3
|
import { judgeRuleToolName, splitNamespacedName } from "./tool-name-aliases.js";
|
|
4
4
|
import { catalogToolNames, isShellFaceToolName } from "./tool-registry.js";
|
|
5
5
|
import { ALLOW_RULE_MEMBERS } from "./allow-rule-shadow.js";
|
|
6
|
-
import { COMMAND_RULE_TOOL,
|
|
6
|
+
import { COMMAND_RULE_TOOL, adjudicatePersistedDomainRules, adjudicatePersistedNameRules, domainRuleSubjectOf, findAdmittingRule, laneToolNamesOf, nameRuleSubjectOf, parseRuleText, programRunReachOf, ruleToolGrammarOf } from "./permission-rule-model.js";
|
|
7
7
|
import { pathRuleLaneAnswer } from "./runner/permission-rule-lanes.js";
|
|
8
8
|
import { callTargetReadingOf } from "./effective-path-target.js";
|
|
9
9
|
import { splitShellCompoundSegments } from "../tools/fs/bash-readonly-classifier.js";
|
|
10
10
|
import { mandateDisclosureOf } from "./ask-origin.js";
|
|
11
11
|
import { inlineUntrusted } from "./untrusted-text.js";
|
|
12
|
-
import { valueTypeLabel } from "
|
|
12
|
+
import { valueTypeLabel } from "./tool-name-list.js";
|
|
13
13
|
import { deliverEngineNotice } from "./engine-notice.js";
|
|
14
|
-
export const ALLOW_ENTRY_INERT_REASONS = Object.freeze(["wildcard_all", "namespace_wildcard", "
|
|
14
|
+
export const ALLOW_ENTRY_INERT_REASONS = Object.freeze(["wildcard_all", "namespace_wildcard", "content_unsupported", "grammar", "tool_name", "near_miss"]);
|
|
15
15
|
export function nonStringMemberLabel(value) {
|
|
16
16
|
return `<not a string: ${valueTypeLabel(value)}>`;
|
|
17
17
|
}
|
|
@@ -69,30 +69,21 @@ function readAllowEntry(raw, behavior, roster) {
|
|
|
69
69
|
}
|
|
70
70
|
return row(isShellFaceToolName(name) ? { kind: "shell", name } : { kind: "tool", name });
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
if (ruleToolGrammarOf(name) === "path") {
|
|
84
|
-
const read = parseRuleText(raw, behavior);
|
|
85
|
-
if ("rule" in read) {
|
|
86
|
-
if (read.rule.match === "subpath" && read.rule.tool === READ_RULE_TOOL && behavior === "allow")
|
|
87
|
-
return row({ kind: "read_dir", rule: ruleRowOf(read.rule) });
|
|
88
|
-
if (behavior === "deny")
|
|
89
|
-
return row({ kind: "path", rule: ruleRowOf(read.rule) });
|
|
90
|
-
}
|
|
91
|
-
return inert("path_pattern");
|
|
72
|
+
const grammar = ruleToolGrammarOf(name);
|
|
73
|
+
if (grammar === undefined)
|
|
74
|
+
return inert("content_unsupported");
|
|
75
|
+
const read = parseRuleText(raw, behavior);
|
|
76
|
+
if ("rule" in read)
|
|
77
|
+
return row({ kind: grammar, rule: ruleRowOf(read.rule) });
|
|
78
|
+
if (grammar === "command" && behavior === "allow" && read.reject.code === "invalid.bare_interpreter_prefix") {
|
|
79
|
+
const wide = parseRuleText(raw, "deny");
|
|
80
|
+
if ("rule" in wide)
|
|
81
|
+
return row({ kind: "command", rule: ruleRowOf({ ...wide.rule, behavior: "allow" }) });
|
|
92
82
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
83
|
+
return inert(inertReasonOf(read.reject.code));
|
|
84
|
+
}
|
|
85
|
+
function inertReasonOf(code) {
|
|
86
|
+
return code === "unsupported.tool" ? "content_unsupported" : "grammar";
|
|
96
87
|
}
|
|
97
88
|
export function compileAllowEntry(raw, behavior, roster) {
|
|
98
89
|
const read = readAllowEntry(raw, behavior, roster);
|
|
@@ -150,8 +141,9 @@ export function autoStripped(compiled, call) {
|
|
|
150
141
|
case "command":
|
|
151
142
|
return shellContentStripped(shellRuleContent(compiled.rule));
|
|
152
143
|
case "namespace":
|
|
153
|
-
case "read_dir":
|
|
154
144
|
case "path":
|
|
145
|
+
case "name":
|
|
146
|
+
case "domain":
|
|
155
147
|
return false;
|
|
156
148
|
default: {
|
|
157
149
|
const exhaustive = compiled;
|
|
@@ -199,8 +191,7 @@ export function judgeAllowEntries(rows, req, behavior, ctx) {
|
|
|
199
191
|
}
|
|
200
192
|
}
|
|
201
193
|
}
|
|
202
|
-
const
|
|
203
|
-
const pathRows = live.filter((r) => r.compiled.kind === pathKind);
|
|
194
|
+
const pathRows = live.filter((r) => r.compiled.kind === "path");
|
|
204
195
|
if (pathRows.length > 0) {
|
|
205
196
|
const table = pathRows.map((r) => r.compiled.rule);
|
|
206
197
|
for (const name of laneToolNamesOf(req).filter((n) => ruleToolGrammarOf(n) === "path")) {
|
|
@@ -212,6 +203,18 @@ export function judgeAllowEntries(rows, req, behavior, ctx) {
|
|
|
212
203
|
}
|
|
213
204
|
}
|
|
214
205
|
}
|
|
206
|
+
for (const grammar of ["name", "domain"]) {
|
|
207
|
+
const familyRows = live.filter((r) => r.compiled.kind === grammar);
|
|
208
|
+
if (familyRows.length === 0)
|
|
209
|
+
continue;
|
|
210
|
+
const table = familyRows.map((r) => r.compiled.rule);
|
|
211
|
+
for (const name of laneToolNamesOf(req).filter((n) => ruleToolGrammarOf(n) === grammar)) {
|
|
212
|
+
const at = { tool: name, cwd: ctx.root, ...(ctx.sessionId !== undefined ? { sessionId: ctx.sessionId } : {}) };
|
|
213
|
+
const verdict = grammar === "name" ? adjudicatePersistedNameRules(table, { ...at, name: nameRuleSubjectOf(name, req.args) }) : adjudicatePersistedDomainRules(table, { ...at, host: domainRuleSubjectOf(name, req.args) });
|
|
214
|
+
if (verdict !== undefined && verdict.behavior === behavior)
|
|
215
|
+
return [familyRows.find((r) => r.compiled.rule === verdict.rules[0]) ?? familyRows[0]];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
215
218
|
return undefined;
|
|
216
219
|
}
|
|
217
220
|
export function allowingRows(rows, req, mode) {
|
|
@@ -233,6 +236,9 @@ export class AllowEntryTable {
|
|
|
233
236
|
entries() {
|
|
234
237
|
return this.held.map((r) => r.entry);
|
|
235
238
|
}
|
|
239
|
+
holdsPathRows() {
|
|
240
|
+
return this.held.some((r) => r.compiled.kind === "path");
|
|
241
|
+
}
|
|
236
242
|
lane(ctx) {
|
|
237
243
|
return {
|
|
238
244
|
allowing: (req, mode) => {
|
|
@@ -319,6 +325,7 @@ const SHADOW_REASON = {
|
|
|
319
325
|
ancestor: "the task that delegated this one owns this question",
|
|
320
326
|
dangerous_delete: "this removal targets a protected location (the filesystem root, a top-level directory, a home directory, or a workspace directory or one of its ancestors) — it is cleared by confirming this call, never by an allow rule",
|
|
321
327
|
unverifiable_delete: "this removal could not be verified safe — it is cleared by confirming this call, never by an allow rule",
|
|
328
|
+
unverifiable_shell_text: "the text this shell will run cannot be read by the engine — it is cleared by confirming this call, never by an allow rule",
|
|
322
329
|
transcript_write: "this write targets the session transcript — it is cleared by confirming this call, never by an allow rule",
|
|
323
330
|
org_rule: "an organization policy rule requires approval for this call",
|
|
324
331
|
governance_unavailable: "this deployment is org-governed and cannot currently read its organization policy",
|
|
@@ -329,7 +336,7 @@ const SHADOW_REASON = {
|
|
|
329
336
|
requires_user_interaction: "this tool's server declares that a call must be put to a person",
|
|
330
337
|
operator_forced: "this call arrived already marked as requiring confirmation (an earlier layer of this run, or the task that delegated it, judged it so) — it is cleared by confirming this call, never by a standing allow rule",
|
|
331
338
|
shell_floor: mandateDisclosureOf("operator_always"),
|
|
332
|
-
|
|
339
|
+
target_unresolved: mandateDisclosureOf("target_unresolved"),
|
|
333
340
|
probe: mandateDisclosureOf("probe_mandate"),
|
|
334
341
|
write_protection: mandateDisclosureOf("write_protection"),
|
|
335
342
|
tool_marks_mcp: mandateDisclosureOf("tool_marks"),
|
|
@@ -422,7 +429,7 @@ export function allowedToolsNotGrantedNotice(inert, sessionId) {
|
|
|
422
429
|
return {
|
|
423
430
|
code: ALLOWED_TOOL_NOT_GRANTED_CODE,
|
|
424
431
|
message: `${inert.length} allowed-tools entr${inert.length === 1 ? "y grants" : "ies grant"} or refuse${inert.length === 1 ? "s" : ""} nothing — ${shown.join("; ")}${rest > 0 ? `; and ${rest} more` : ""}. ` +
|
|
425
|
-
"A list holding `*` voids the list, `mcp__*` names no server, a
|
|
432
|
+
"A list holding `*` voids the list, `mcp__*` names no server, a rule the grammar refuses (`grammar`) or one on a tool with no such rule form (`content_unsupported`: an allow by path is an `Edit(…)` or `Read(…)` rule) grants nothing, and a tool name must be spelled as the tool is mounted; name the tools (or `mcp__<server>`) instead." +
|
|
426
433
|
(refusing ? " Such an entry in a disallowed-tools list keeps its Skill from activating: a refusal that reads as nothing is not dropped." : ""),
|
|
427
434
|
detail: { ...(sessionId !== undefined ? { sessionId } : {}), entries: inert.map((e) => ({ ...e })) },
|
|
428
435
|
};
|
|
@@ -1,27 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/** every prefix is LEFT-ANCHORED with \`(?<![A-Za-z0-9])\` — without it, ordinary words whose
|
|
4
|
-
* TAIL spells a prefix were silently redacted (NETWORK-attached → NETWO[redacted], RTMARK-100,
|
|
5
|
-
* task_categories, monkey=abcd1234, MonkeyJumping…) while triggering unpredictably on suffix
|
|
6
|
-
* length. \`_\` is deliberately NOT in the anchor class: \`api_key=\`, \`STRIPE=sk_live_…\`-style glued
|
|
7
|
-
* assignments are REAL credential shapes that must keep scrubbing. The prefixed-token arm also
|
|
8
|
-
* drops the \`i\` flag: the real vendors' prefixes are lowercase-only (sk_/pk_/rk_/ghp_…), and the
|
|
9
|
-
* case-insensitive form is what turned every UPPERCASE technical word ending in RK/SK/PK into a
|
|
10
|
-
* false positive. */
|
|
11
|
-
export type RedactionConfidence = "high" | "medium" | "low";
|
|
12
|
-
/** Which module's rule table minted a finding (ANG-11 provenance). A closed set, and there is no public
|
|
13
|
-
* factory for a finding — a report's entries can only have been written by one of these tables running
|
|
14
|
-
* here, so "this finding says X" is an engine statement, not something a caller can hand-assemble into
|
|
15
|
-
* a report and have the pipeline endorse. */
|
|
16
|
-
export type RedactionSource = "arg-summary" | "untrusted-egress" | "secret-env";
|
|
1
|
+
import { type RedactionConfidence, type RedactionSource, type ValueFamilyRow } from "./credential-vocabulary.js";
|
|
2
|
+
export type { RedactionConfidence, RedactionSource } from "./credential-vocabulary.js";
|
|
17
3
|
/** One redaction hit: what was detected, where (ORIGINAL-input coordinates), how confidently, the marker
|
|
18
|
-
* literal written in its place,
|
|
4
|
+
* literal written in its place, which rule table minted it, and — present when a vocabulary row minted it — the
|
|
5
|
+
* value family (the row's stable id; a host-leak hit such as a URL or a path names none). */
|
|
19
6
|
export interface RedactionFinding {
|
|
20
7
|
kind: string;
|
|
21
8
|
span: readonly [number, number];
|
|
22
9
|
confidence: RedactionConfidence;
|
|
23
10
|
marker: string;
|
|
24
11
|
source: RedactionSource;
|
|
12
|
+
family?: string;
|
|
25
13
|
}
|
|
26
14
|
/** The minimum a finding must declare to be summarizable. Both text findings ({@link RedactionFinding})
|
|
27
15
|
* and the env arm's entry findings satisfy it, so {@link summarizeRedactions} is ONE helper rather than
|
|
@@ -56,13 +44,15 @@ export interface RedactionPass {
|
|
|
56
44
|
kind: string;
|
|
57
45
|
confidence: RedactionConfidence;
|
|
58
46
|
marker: string;
|
|
59
|
-
/** The
|
|
60
|
-
*
|
|
61
|
-
* {@link SECRET_PASSES}) still attributes its hits to the table that owns the rule, not to whoever ran it. */
|
|
47
|
+
/** The rule table that owns this pass's rule — copied verbatim onto every finding it mints (ANG-11), whoever
|
|
48
|
+
* runs the pass. */
|
|
62
49
|
source: RedactionSource;
|
|
63
50
|
re: RegExp;
|
|
64
51
|
/** A literal replacement (only `$1` substitution is used by these passes) or a replacer fn. */
|
|
65
52
|
replace: string | ((match: string, ...groups: string[]) => string);
|
|
53
|
+
/** The value family a hit belongs to: one id, or — for a pass joining several rows — the id of the row that
|
|
54
|
+
* matches at the hit's offset in the pass input. Absent = the pass is no vocabulary row. */
|
|
55
|
+
family?: string | ((input: string, at: number) => string);
|
|
66
56
|
}
|
|
67
57
|
/**
|
|
68
58
|
* Run the declared passes in order, collecting findings (original-input spans) when a report is given.
|
|
@@ -72,16 +62,19 @@ export interface RedactionPass {
|
|
|
72
62
|
* only the first (or neither) matches. The OUTPUT keeps every format character that sits OUTSIDE a
|
|
73
63
|
* replaced span — a joiner in an emoji sequence, a non-joiner in Persian text, a soft hyphen in a word
|
|
74
64
|
* — and drops only those INSIDE the span the marker replaces (they were part of the secret). A
|
|
75
|
-
* format-free input takes the exact historical path (byte-identical output).
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
65
|
+
* format-free input takes the exact historical path (byte-identical output). The view's replacements and
|
|
66
|
+
* every boundary scan's are taken as disjoint spans of their input (a later pass that matched across an
|
|
67
|
+
* earlier pass's inserted text is rendered from the removals instead), so the spans always map back
|
|
68
|
+
* exactly and no scan is skipped.
|
|
79
69
|
*/
|
|
80
70
|
export declare function runRedactionPasses(input: string, passes: readonly RedactionPass[], report?: RedactionReport): string;
|
|
81
|
-
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
|
|
71
|
+
/**
|
|
72
|
+
* The egress view rendered as passes, in the vocabulary's order: one pass per group (a group of several rows is ONE
|
|
73
|
+
* leftmost alternation, its hits attributed to the row that matches at the hit's offset). A row whose wide form
|
|
74
|
+
* captures a label keeps it ahead of the marker; `replacers` renders a kind whose marker placement is a policy (the
|
|
75
|
+
* URL userinfo).
|
|
76
|
+
*/
|
|
77
|
+
export declare function egressPasses(groups: ReadonlyArray<readonly ValueFamilyRow[]>, replacers?: Readonly<Record<string, (match: string, ...groups: string[]) => string>>): RedactionPass[];
|
|
85
78
|
export declare function scrubSecrets(s: string, report?: RedactionReport): string;
|
|
86
79
|
/** A SHORT, SECRET-SCRUBBED primary-arg summary. Abbreviation REDUCES the surface; a final {@link scrubSecrets}
|
|
87
80
|
* pass is the leak boundary (the value is PERSISTED + SSE-forwarded and may be read by a platform operator in a
|
package/dist/core/arg-summary.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { writtenAssignmentPrefix } from "../tools/fs/bash-program-position.js";
|
|
2
|
+
import { CREDENTIAL_VOCABULARY, egressPassGroups } from "./credential-vocabulary.js";
|
|
2
3
|
const ACTIVITY_ARG_MAX = 80;
|
|
3
4
|
const SENSITIVE_KEY = /token|secret|key|password|passwd|credential|auth/i;
|
|
4
5
|
export function summarizeRedactions(findings) {
|
|
@@ -12,72 +13,216 @@ export function summarizeRedactions(findings) {
|
|
|
12
13
|
const parts = [...counts].map(([label, n]) => `${label} x${n}`);
|
|
13
14
|
return `${findings.length} redaction${findings.length === 1 ? "" : "s"}: ${parts.join(", ")}`;
|
|
14
15
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
function passZeroMapper(batches) {
|
|
17
|
+
const cursors = batches.map(() => ({ i: 0, delta: 0 }));
|
|
18
|
+
return (pos) => {
|
|
19
|
+
let p = pos;
|
|
20
|
+
for (let b = batches.length - 1; b >= 0; b--) {
|
|
21
|
+
const edits = batches[b];
|
|
22
|
+
const c = cursors[b];
|
|
23
|
+
let mapped;
|
|
24
|
+
while (mapped === undefined && c.i < edits.length) {
|
|
25
|
+
const e = edits[c.i];
|
|
26
|
+
const outStart = e.at + c.delta;
|
|
27
|
+
if (p < outStart)
|
|
28
|
+
mapped = p - c.delta;
|
|
29
|
+
else if (p < outStart + e.insertedLen)
|
|
30
|
+
mapped = e.at;
|
|
31
|
+
else {
|
|
32
|
+
c.delta += e.insertedLen - e.removedLen;
|
|
33
|
+
c.i++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
p = mapped ?? p - c.delta;
|
|
37
|
+
}
|
|
38
|
+
return p;
|
|
39
|
+
};
|
|
27
40
|
}
|
|
28
41
|
const PREEXISTING_MARKER_RE = /\[redacted(?:-[a-z]+)?\]/g;
|
|
29
42
|
const FORMAT_CHAR_RE = /\p{Cf}/u;
|
|
30
43
|
const MAX_FORMAT_SLOT_SCANS = 64;
|
|
31
44
|
const REDACTED_WHOLE = "[redacted]";
|
|
32
|
-
function
|
|
45
|
+
function finding(pass, span, family) {
|
|
46
|
+
const f = { kind: pass.kind, confidence: pass.confidence, span, marker: pass.marker, source: pass.source };
|
|
47
|
+
if (family !== undefined)
|
|
48
|
+
f.family = family;
|
|
49
|
+
return f;
|
|
50
|
+
}
|
|
51
|
+
function insertedFor(pass, match, groups) {
|
|
52
|
+
return typeof pass.replace === "string"
|
|
53
|
+
? pass.replace.replace(/\$(\d)/g, (_m, d) => groups[Number(d) - 1] ?? "")
|
|
54
|
+
: pass.replace(match, ...groups);
|
|
55
|
+
}
|
|
56
|
+
function removedRegion(pass, match, groups, inserted) {
|
|
57
|
+
if (typeof pass.replace === "string") {
|
|
58
|
+
const parts = pass.replace.split(/(\$\d)/).filter((p) => p !== "");
|
|
59
|
+
const isRef = (p) => /^\$\d$/.test(p);
|
|
60
|
+
const refText = (p) => groups[Number(p[1]) - 1] ?? "";
|
|
61
|
+
let head = "";
|
|
62
|
+
for (const p of parts) {
|
|
63
|
+
if (!isRef(p))
|
|
64
|
+
break;
|
|
65
|
+
head += refText(p);
|
|
66
|
+
}
|
|
67
|
+
let tail = "";
|
|
68
|
+
for (let i = parts.length - 1; i >= 0 && isRef(parts[i]); i--)
|
|
69
|
+
tail = refText(parts[i]) + tail;
|
|
70
|
+
if (parts.every(isRef))
|
|
71
|
+
return [0, match.length];
|
|
72
|
+
if (!match.startsWith(head))
|
|
73
|
+
head = "";
|
|
74
|
+
if (!match.endsWith(tail) || head.length + tail.length > match.length)
|
|
75
|
+
tail = "";
|
|
76
|
+
return [head.length, match.length - tail.length];
|
|
77
|
+
}
|
|
78
|
+
let head = 0;
|
|
79
|
+
while (head < match.length && head < inserted.length && match[head] === inserted[head])
|
|
80
|
+
head++;
|
|
81
|
+
let tail = 0;
|
|
82
|
+
while (tail < match.length - head && tail < inserted.length - head && match[match.length - 1 - tail] === inserted[inserted.length - 1 - tail])
|
|
83
|
+
tail++;
|
|
84
|
+
return [head, match.length - tail];
|
|
85
|
+
}
|
|
86
|
+
function soloHits(input, passes) {
|
|
87
|
+
const hits = [];
|
|
88
|
+
passes.forEach((pass, i) => {
|
|
89
|
+
for (const m of input.matchAll(new RegExp(pass.re.source, pass.re.flags.includes("g") ? pass.re.flags : `${pass.re.flags}g`))) {
|
|
90
|
+
const inserted = insertedFor(pass, m[0], m.slice(1));
|
|
91
|
+
if (inserted === m[0])
|
|
92
|
+
continue;
|
|
93
|
+
const [a, b] = removedRegion(pass, m[0], m.slice(1), inserted);
|
|
94
|
+
if (b <= a)
|
|
95
|
+
continue;
|
|
96
|
+
const at = m.index;
|
|
97
|
+
const family = typeof pass.family === "function" ? pass.family(input, at) : pass.family;
|
|
98
|
+
hits.push({ start: at + a, end: at + b, marker: inserted.slice(a, inserted.length - (m[0].length - b)), pass: i, family, matchStart: at, matchEnd: at + m[0].length });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return hits;
|
|
102
|
+
}
|
|
103
|
+
function unremovedHits(hits, removals) {
|
|
104
|
+
const gone = [];
|
|
105
|
+
for (const r of [...removals].filter((x) => x.end > x.start).sort((x, y) => x.start - y.start || y.end - x.end)) {
|
|
106
|
+
const last = gone[gone.length - 1];
|
|
107
|
+
if (last !== undefined && r.start <= last[1])
|
|
108
|
+
last[1] = Math.max(last[1], r.end);
|
|
109
|
+
else
|
|
110
|
+
gone.push([r.start, r.end]);
|
|
111
|
+
}
|
|
112
|
+
return hits.filter((h) => {
|
|
113
|
+
let lo = 0;
|
|
114
|
+
let hi = gone.length - 1;
|
|
115
|
+
let at = -1;
|
|
116
|
+
while (lo <= hi) {
|
|
117
|
+
const mid = (lo + hi) >> 1;
|
|
118
|
+
if (gone[mid][0] <= h.start) {
|
|
119
|
+
at = mid;
|
|
120
|
+
lo = mid + 1;
|
|
121
|
+
}
|
|
122
|
+
else
|
|
123
|
+
hi = mid - 1;
|
|
124
|
+
}
|
|
125
|
+
return at === -1 || gone[at][1] < h.end;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function sequentialRemovals(batches) {
|
|
129
|
+
const removals = [];
|
|
130
|
+
for (let j = 0; j < batches.length; j++) {
|
|
131
|
+
const toPassZero = passZeroMapper(batches.slice(0, j));
|
|
132
|
+
for (const e of batches[j]) {
|
|
133
|
+
const start = toPassZero(e.at + e.head);
|
|
134
|
+
const end = toPassZero(e.at + e.removedLen - e.tail);
|
|
135
|
+
removals.push({ start, end: Math.max(start, end), marker: e.inserted.slice(e.head, e.insertedLen - e.tail), pass: e.pass, family: e.family });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return removals;
|
|
139
|
+
}
|
|
140
|
+
function renderRemovals(input, removals) {
|
|
141
|
+
const sorted = removals.filter((r) => r.end > r.start || r.marker !== "").sort((x, y) => x.start - y.start || y.end - x.end);
|
|
142
|
+
const edits = [];
|
|
143
|
+
let out = "";
|
|
144
|
+
let cursor = 0;
|
|
145
|
+
for (let i = 0; i < sorted.length;) {
|
|
146
|
+
const start = sorted[i].start;
|
|
147
|
+
let end = sorted[i].end;
|
|
148
|
+
let widest;
|
|
149
|
+
for (; i < sorted.length && (sorted[i].start < end || sorted[i].start === start || (sorted[i].marker === "" && sorted[i].start === end)); i++) {
|
|
150
|
+
const r = sorted[i];
|
|
151
|
+
if (r.end > end)
|
|
152
|
+
end = r.end;
|
|
153
|
+
if (r.marker !== "" && (widest === undefined || r.end - r.start > widest.end - widest.start))
|
|
154
|
+
widest = r;
|
|
155
|
+
}
|
|
156
|
+
const marker = widest?.marker ?? REDACTED_WHOLE;
|
|
157
|
+
out += input.slice(cursor, start) + marker;
|
|
158
|
+
cursor = end;
|
|
159
|
+
edits.push({ at: start, removedLen: end - start, insertedLen: marker.length, inserted: marker, family: widest?.family, head: 0, tail: 0, pass: widest?.pass ?? sorted[i - 1].pass });
|
|
160
|
+
}
|
|
161
|
+
return { out: out + input.slice(cursor), edits };
|
|
162
|
+
}
|
|
163
|
+
function runPasses(input, passes, findings, toOriginal) {
|
|
33
164
|
const batches = [];
|
|
34
165
|
let cur = input;
|
|
35
|
-
|
|
166
|
+
passes.forEach((pass, passIndex) => {
|
|
36
167
|
const edits = [];
|
|
168
|
+
const passInput = cur;
|
|
169
|
+
const toPassZero = passZeroMapper(batches.slice());
|
|
37
170
|
cur = cur.replace(pass.re, (...args) => {
|
|
38
171
|
const match = args[0];
|
|
39
172
|
const offset = args[args.length - 2];
|
|
40
173
|
const groups = args.slice(1, -2);
|
|
41
|
-
const inserted =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
s0 = mapBackOnePass(batches[i], s0);
|
|
50
|
-
e0 = mapBackOnePass(batches[i], e0);
|
|
51
|
-
}
|
|
52
|
-
report.findings.push({
|
|
53
|
-
kind: pass.kind,
|
|
54
|
-
confidence: pass.confidence,
|
|
55
|
-
span: [toOriginal(s0), toOriginal(e0)],
|
|
56
|
-
marker: pass.marker,
|
|
57
|
-
source: pass.source,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
edits.push({ at: offset, removedLen: match.length, insertedLen: inserted.length, inserted });
|
|
61
|
-
}
|
|
174
|
+
const inserted = insertedFor(pass, match, groups);
|
|
175
|
+
if (inserted === match)
|
|
176
|
+
return inserted;
|
|
177
|
+
const family = typeof pass.family === "function" ? pass.family(passInput, offset) : pass.family;
|
|
178
|
+
if (findings !== undefined)
|
|
179
|
+
findings.push({ pass: passIndex, f: finding(pass, [toOriginal(toPassZero(offset)), toOriginal(toPassZero(offset + match.length))], family) });
|
|
180
|
+
const [a, b] = removedRegion(pass, match, groups, inserted);
|
|
181
|
+
edits.push({ at: offset, removedLen: match.length, insertedLen: inserted.length, inserted, family, head: a, tail: match.length - b, pass: passIndex });
|
|
62
182
|
return inserted;
|
|
63
183
|
});
|
|
64
184
|
batches.push(edits);
|
|
65
|
-
}
|
|
185
|
+
});
|
|
66
186
|
return { out: cur, batches };
|
|
67
187
|
}
|
|
188
|
+
function applyPasses(input, passes, report, toOriginal, disjoint = false) {
|
|
189
|
+
const found = report === undefined ? undefined : [];
|
|
190
|
+
const plain = runPasses(input, passes, found, toOriginal);
|
|
191
|
+
const solo = soloHits(input, passes);
|
|
192
|
+
const sequential = solo.length === 0 ? [] : sequentialRemovals(plain.batches);
|
|
193
|
+
const outer = unremovedHits(solo, sequential);
|
|
194
|
+
const mappable = !disjoint || replacedSpans(plain.batches) !== undefined;
|
|
195
|
+
const whole = outer.length === 0 && mappable ? undefined : renderRemovals(input, [...sequential, ...outer]);
|
|
196
|
+
if (whole === undefined || (whole.out === plain.out && mappable)) {
|
|
197
|
+
if (report !== undefined)
|
|
198
|
+
report.findings.push(...found.map((x) => x.f));
|
|
199
|
+
return plain;
|
|
200
|
+
}
|
|
201
|
+
if (report !== undefined) {
|
|
202
|
+
const seen = new Set(found.map((x) => `${x.pass}:${x.f.span[0]}:${x.f.span[1]}`));
|
|
203
|
+
for (const h of outer) {
|
|
204
|
+
const span = [toOriginal(h.matchStart), toOriginal(h.matchEnd)];
|
|
205
|
+
const key = `${h.pass}:${span[0]}:${span[1]}`;
|
|
206
|
+
if (seen.has(key))
|
|
207
|
+
continue;
|
|
208
|
+
seen.add(key);
|
|
209
|
+
found.push({ pass: h.pass, f: finding(passes[h.pass], span, h.family) });
|
|
210
|
+
}
|
|
211
|
+
found.sort((x, y) => x.pass - y.pass || x.f.span[0] - y.f.span[0]);
|
|
212
|
+
report.findings.push(...found.map((x) => x.f));
|
|
213
|
+
}
|
|
214
|
+
return { out: whole.out, batches: [whole.edits] };
|
|
215
|
+
}
|
|
68
216
|
function replacedSpans(batches) {
|
|
69
217
|
const spans = [];
|
|
70
218
|
for (let j = 0; j < batches.length; j++) {
|
|
219
|
+
const toPassZero = passZeroMapper(batches.slice(0, j));
|
|
71
220
|
for (const e of batches[j]) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
for (let i = j - 1; i >= 0; i--) {
|
|
75
|
-
s0 = mapBackOnePass(batches[i], s0);
|
|
76
|
-
e0 = mapBackOnePass(batches[i], e0);
|
|
77
|
-
}
|
|
221
|
+
const s0 = toPassZero(e.at);
|
|
222
|
+
const e0 = toPassZero(e.at + e.removedLen);
|
|
78
223
|
if (e0 - s0 !== e.removedLen)
|
|
79
224
|
return undefined;
|
|
80
|
-
spans.push({ start: s0, end: e0, inserted: e.inserted, pass:
|
|
225
|
+
spans.push({ start: s0, end: e0, inserted: e.inserted, pass: e.pass, family: e.family });
|
|
81
226
|
}
|
|
82
227
|
}
|
|
83
228
|
spans.sort((a, b) => a.start - b.start);
|
|
@@ -125,10 +270,10 @@ export function runRedactionPasses(input, passes, report) {
|
|
|
125
270
|
const idx = offsetToCharIndex.get(pos);
|
|
126
271
|
return idx === undefined ? input.length : viewToOriginal[idx];
|
|
127
272
|
};
|
|
128
|
-
const {
|
|
273
|
+
const { batches } = applyPasses(view, passes, report, toOriginal, true);
|
|
129
274
|
const viewSpans = replacedSpans(batches);
|
|
130
275
|
if (viewSpans === undefined)
|
|
131
|
-
return
|
|
276
|
+
return REDACTED_WHOLE;
|
|
132
277
|
const spans = viewSpans.map((sp) => {
|
|
133
278
|
const startIdx = offsetToCharIndex.get(sp.start) ?? viewChars.length;
|
|
134
279
|
const endIdx = offsetToCharIndex.get(sp.end) ?? viewChars.length;
|
|
@@ -150,42 +295,49 @@ export function runRedactionPasses(input, passes, report) {
|
|
|
150
295
|
if (cutOffsets.length > MAX_FORMAT_SLOT_SCANS)
|
|
151
296
|
return REDACTED_WHOLE;
|
|
152
297
|
const extra = [];
|
|
153
|
-
const rawSpans = replacedSpans(applyPasses(input, passes, undefined, (pos) => pos).batches);
|
|
298
|
+
const rawSpans = replacedSpans(applyPasses(input, passes, undefined, (pos) => pos, true).batches);
|
|
154
299
|
if (rawSpans !== undefined)
|
|
155
300
|
extra.push(...rawSpans);
|
|
156
301
|
for (const cut of cutOffsets) {
|
|
157
|
-
const cutSpans = replacedSpans(applyPasses(view.slice(cut), passes, undefined, (pos) => pos).batches);
|
|
302
|
+
const cutSpans = replacedSpans(applyPasses(view.slice(cut), passes, undefined, (pos) => pos, true).batches);
|
|
158
303
|
if (cutSpans === undefined)
|
|
159
304
|
continue;
|
|
160
305
|
for (const c of cutSpans) {
|
|
161
306
|
const o = viewOffsetToOriginal(c.start + cut, c.end + cut);
|
|
162
|
-
extra.push({ start: o.start, end: o.end
|
|
307
|
+
extra.push({ ...c, start: o.start, end: o.end });
|
|
163
308
|
}
|
|
164
309
|
}
|
|
165
310
|
extra.sort((a, b) => a.start - b.start);
|
|
311
|
+
const firstEndingAfter = (pos) => {
|
|
312
|
+
let lo = 0;
|
|
313
|
+
let hi = spans.length;
|
|
314
|
+
while (lo < hi) {
|
|
315
|
+
const mid = (lo + hi) >> 1;
|
|
316
|
+
if (spans[mid].end > pos)
|
|
317
|
+
hi = mid;
|
|
318
|
+
else
|
|
319
|
+
lo = mid + 1;
|
|
320
|
+
}
|
|
321
|
+
return lo;
|
|
322
|
+
};
|
|
166
323
|
for (const r of extra) {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
324
|
+
const at = firstEndingAfter(r.start);
|
|
325
|
+
const hit = spans[at];
|
|
326
|
+
if (hit !== undefined && hit.start < r.end) {
|
|
327
|
+
if (r.start < hit.start)
|
|
328
|
+
hit.start = r.start;
|
|
329
|
+
if (r.end > hit.end)
|
|
330
|
+
hit.end = r.end;
|
|
331
|
+
let next = at + 1;
|
|
332
|
+
while (next < spans.length && spans[next].start < hit.end)
|
|
333
|
+
hit.end = Math.max(hit.end, spans[next++].end);
|
|
334
|
+
if (next > at + 1)
|
|
335
|
+
spans.splice(at + 1, next - at - 1);
|
|
173
336
|
continue;
|
|
174
337
|
}
|
|
175
|
-
spans.
|
|
176
|
-
if (report !== undefined)
|
|
177
|
-
|
|
178
|
-
report.findings.push({ kind: pass.kind, confidence: pass.confidence, span: [r.start, r.end], marker: pass.marker, source: pass.source });
|
|
179
|
-
}
|
|
180
|
-
spans.sort((a, b) => a.start - b.start);
|
|
181
|
-
}
|
|
182
|
-
for (let i = 1; i < spans.length;) {
|
|
183
|
-
if (spans[i].start < spans[i - 1].end) {
|
|
184
|
-
spans[i - 1].end = Math.max(spans[i - 1].end, spans[i].end);
|
|
185
|
-
spans.splice(i, 1);
|
|
186
|
-
}
|
|
187
|
-
else
|
|
188
|
-
i++;
|
|
338
|
+
spans.splice(at, 0, { start: r.start, end: r.end, inserted: r.inserted });
|
|
339
|
+
if (report !== undefined)
|
|
340
|
+
report.findings.push(finding(passes[r.pass], [r.start, r.end], r.family));
|
|
189
341
|
}
|
|
190
342
|
let result = "";
|
|
191
343
|
let cursor = 0;
|
|
@@ -196,27 +348,22 @@ export function runRedactionPasses(input, passes, report) {
|
|
|
196
348
|
result += input.slice(cursor);
|
|
197
349
|
return result;
|
|
198
350
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
source: "arg-summary",
|
|
214
|
-
re: /(?<![A-Za-z0-9])((?:token|secret|key|password|passwd|credential|authorization)["']?\s*[=:]\s*["']?)[^\s"';|&]{4,}/gi,
|
|
215
|
-
replace: "$1[redacted]",
|
|
216
|
-
},
|
|
217
|
-
];
|
|
351
|
+
const BRACKET_MARKER = { "url-credentials": "[redacted-credentials]" };
|
|
352
|
+
const bracketMarker = (kind) => BRACKET_MARKER[kind] ?? "[redacted]";
|
|
353
|
+
const capturesLabel = (re) => new RegExp(`${re.source}|`).exec("").length > 1;
|
|
354
|
+
export function egressPasses(groups, replacers = {}) {
|
|
355
|
+
return groups.map((rows) => {
|
|
356
|
+
const head = rows[0];
|
|
357
|
+
const marker = bracketMarker(head.kind);
|
|
358
|
+
const re = rows.length === 1 ? head.match : new RegExp(rows.map((r) => `(?:${r.match.source})`).join("|"), head.match.flags);
|
|
359
|
+
const sticky = rows.map((r) => ({ id: r.id, re: new RegExp(r.match.source, r.match.flags.replace("g", "") + "y") }));
|
|
360
|
+
const family = rows.length === 1 ? head.id : (input, at) => sticky.find((s) => ((s.re.lastIndex = at), s.re.test(input)))?.id ?? head.id;
|
|
361
|
+
return { kind: head.kind, confidence: head.confidence, marker, source: head.source, re, replace: replacers[head.kind] ?? (capturesLabel(head.match) ? `$1${marker}` : marker), family };
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
const SHAPE_PASSES = egressPasses(egressPassGroups(CREDENTIAL_VOCABULARY).filter((rows) => rows[0].source === "arg-summary"));
|
|
218
365
|
export function scrubSecrets(s, report) {
|
|
219
|
-
return runRedactionPasses(s,
|
|
366
|
+
return runRedactionPasses(s, SHAPE_PASSES, report);
|
|
220
367
|
}
|
|
221
368
|
function truncCodePoints(s) {
|
|
222
369
|
const cp = Array.from(s);
|