@klarkxy/dsh-safe-auto 0.1.0-rc.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,174 +1,124 @@
1
- # Safe Auto (release candidate)
1
+ # Safe Auto
2
2
 
3
- Budgeted preflight plus opt-in automatic approval of one native sandbox escalation at a time. **The reviewer follows the current conversation model by default, and can be configured independently.** The plugin reuses DSH's model adapters, tool loop and approval service. It never switches the standing session to Full Access, and never lets a model enlarge the envelope you configured.
3
+ <!-- release-state-note -->
4
+ The [repository registry](../../README.md#plugin-lifecycle) tracks Draft → Testing → Published, moving forward only. Fixes, testing and version updates keep published packages Published; each update still passes release checks. First publication explicitly selects Testing packages and records Published only after npm archive verification. See the [release guide](../../RELEASING.md).
4
5
 
5
- [简体中文](README.zh-CN.md) · [Preflight](docs/ADR-0001.md) · [One-shot escalation](docs/ADR-0002.md) · [Reviewer routing](docs/ADR-0003.md)
6
+ Automatic review of native sandbox escalation requests. When a real `write`/`edit`/`bash`/`pwsh` call asks to widen its sandbox beyond Workspace Write, an independent reviewer model vets that one call. A narrow set of metadata-only or literal-output `bash` commands can pass static checks without a model. A pass continues automatically; other review results offer an exact-call confirmation in the current session, with 60 seconds to approve once or reject. No response means rejection. The plugin never switches the standing session to Full Access.
6
7
 
7
- ## Install and configure
8
+ [简体中文](README.zh-CN.md) · [One-shot escalation](docs/ADR-0002.md) · [Reviewer routing](docs/ADR-0003.md) · [Authorization and evidence](docs/ADR-0004.md) · [Timed human confirmation](docs/ADR-0005.md) · [Static shell proof](docs/ADR-0006.md)
8
9
 
9
- Use a disposable profile from a checked repository checkout:
10
+ > **0.2.0 is a breaking simplification.** The 0.1.x exact-rule preflight, workspace/shell/escalation candidate lists, `shadow`/`smart`/`unattended` modes, the deep review stage and the HTTP endpoint were removed. See [Migrating from 0.1.x](#migrating-from-01x).
10
11
 
11
- ```sh
12
- pnpm install --frozen-lockfile
13
- pnpm --filter @klarkxy/dsh-safe-auto test
14
- dsh plugin --profile web add ./plugins/dsh-safe-auto
15
- ```
16
-
17
- A PR is not an npm release. The bundle inserts the `dsh-safe-auto` profile row. Configure its `config` through the profile patch mechanism:
18
-
19
- ```yaml
20
- id: dsh-safe-auto
21
- name: '@klarkxy/dsh-safe-auto'
22
- config:
23
- mode: shadow
24
- workspaceRoots:
25
- - /absolute/canonical/project
26
- shellCandidates:
27
- - git status --short
28
- # No endpoint or model override: follow this conversation's DSH provider/model.
29
- ```
30
-
31
- The enrolled canonical root must exactly match session cwd and the resolved sandbox root. Operator envelopes, candidates and budgets remain strictly validated profile configuration; reload after editing them.
32
-
33
- ## Plugin-page activation and independent approval review
12
+ ## Install and enable
34
13
 
35
- **What you do.** Select a live root session on the plugin page and click **Enable**. **Disable** only revokes automatic review; it does not change native permissions. Enable keeps **Workspace Write + ask**, never the official Full Access Auto preset. Opening, refreshing or saving the page never activates a session. Children, restarts and UI Host disposal do not inherit activation.
14
+ After 0.2.0 is published to npm:
36
15
 
37
- **What the plugin does.** Set `approvalReview: true` (default `false`), or save **Independent approval reviewer** in the plugin-page mode selector. Inspired by `dsh-approval-review@0.5.1`, this mode reviews real native single-call sandbox escalation requests for `pwsh/bash/write/edit`, including Windows, without POSIX candidate commands. It binds to the current tool execution, not free-text claims, a reused callId or old logs. Unknown tools, remote execution, nested calls, children, incomplete inputs and requests that cannot be bound to a live execution are rejected while independent approval is active. The tool-free reviewer receives the complete bounded action, direct human intent and additional restrictions only.
38
-
39
- Structured verdicts separate risk, authorization, scope and rationale. Automatic allowance requires low/medium risk, medium/high direct authorization and bounded scope. High/critical risk, uncertainty, unknown scripts lacking decisive evidence, malformed verdicts, errors, timeouts, insufficient budgets and invalidated grants are rejected. Explicit denials never fall back to another answerer. The default 64-token fast output budget may be too small for structured output; adjust profile budgets as needed. Truncated output never grants approval.
40
-
41
- This is an explicit delegation of native approval, not authority for arbitrary operations. Native `approval: never` rejects before the chain. The plugin page displays a fixed **Reject (default)** policy for inability to judge. The human approval option is disabled and not persisted, because no human-only DSH channel has been verified; calling waterfall `next()` could reach another automatic answerer and is not a human fallback. Independent approval does not delegate non-allowing decisions downstream. Legacy exact-rule behavior is unchanged. Source changes do not uninstall installed plugins or publish a release.
42
-
43
- ## Reviewer settings
44
-
45
- The updated bundle loads a separate UI Host row. Settings and session controls live on the plugin page; the native composer permission control is not replaced. Enable uses the native preset write path, without the official Full Access `registerAuto()` hook. Native `approval: never` remains authoritative.
16
+ ```sh
17
+ dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto@0.2.0
18
+ ```
46
19
 
47
- The Safe Auto plugin page selects fast/deep reviewer models, their advertised reasoning efforts, and an additional review prompt (up to 4096 characters). Empty fast route follows the current conversation; empty deep route disables deep review. Selecting a new model clears its previous effort; saved unlisted values are retained rather than silently replaced. Unsupported explicit efforts fail closed. The additional prompt can only add restrictions, never replace the fixed safety instructions or enlarge an envelope. Saving settings performs no inference, changes no session permission, keeps the budget ledger and invalidates pending old grants. Reasoning-heavy models may need larger `fastOutputTokens/deepOutputTokens` in the profile. HTTP mode is read-only in this panel and rejects native effort overrides.
20
+ From a checked source checkout instead:
48
21
 
49
- The `dsh-safe-auto-ui` Host row persists reviewer preferences through `storageDomain`, overriding corresponding profile model fields, but never persists session authorization. Activation belongs to the exact live session object: native selection, an external permission change, restart or UI Host disposal disables it, and forks and children do not inherit it. While UI control is attached, legacy smart/unattended profiles do not automatically activate untouched sessions; loading only the original core Host row retains legacy operation. Removing the Client restores the original permission control.
22
+ ```sh
23
+ pnpm install --frozen-lockfile
24
+ pnpm --filter @klarkxy/dsh-safe-auto test
25
+ dsh plugin --profile <profile> add ./plugins/dsh-safe-auto
26
+ ```
50
27
 
51
- ## Choose the approval model
28
+ The bundle inserts the `dsh-safe-auto` and `dsh-safe-auto-ui` profile rows. Safe Auto then appears as a fourth option in the composer's permission menu, next to the native presets — pick **Safe Auto** there to enable it for the current session, and pick any native preset to disable it again. Nothing is automatic until you do: no session inherits activation, and restart, a permission change or uninstall revokes it. The plugin page only holds reviewer configuration, safety notes and the read-only budget limits, grouped into tabs.
52
29
 
53
- ### Default: follow the conversation
30
+ > The composer permission control is a replacement slot: while Safe Auto is installed, the plugin renders that control itself (native presets included) so the option can appear in the menu. If the host redesigns this control, the plugin's copy may lag behind until updated.
54
31
 
55
- Leave `endpoint`, `fastProvider` and `fastModel` unset or empty. Each eligible review resolves the provider/model from the requesting session's accepted `requestHeader().config`; if no accepted header exists, it uses that same agent's `options`. A malformed header never falls back to another route. A new conversation request using a different model changes subsequent reviews; concurrent sessions do not share a global model selection.
32
+ ## How it works
56
33
 
57
- This reuses DSH's configured provider and credentials, so no additional API key or endpoint is required. **Only the model route is inherited**, not the conversation history, main-agent prompt, tools, replay state, reasoning setting or output budget. The reviewer is a separate tool-free one-shot with its own prompt and caps. A model requiring more reasoning tokens may need a larger reviewer cap; unsupported options fail closed rather than dropping limits.
34
+ 1. A native tool call asks for `sandbox_permissions` widening (`workspace-write` or `danger-full-access`).
35
+ 2. The plugin binds the live execution — agent, callId, signal, exact arguments, cwd, sandbox policy and the ordered direct-human instructions, including later restrictions and revocations.
36
+ 3. A fully literal `bash` command is granted without evidence or a model only when every invocation passes both the no-mutation grammar and the metadata/literal-output check. Examples include `ls -la`, `pwd`, and `find . -name "*.md"`. `printenv`, `ps`, file-content readers, recursive content searches, Git content and Git configuration enumeration always continue to review. Unknown options, abbreviations, output operands and persistent assignments also continue to review; `pwsh` has no static path.
37
+ 4. The exact request is reviewed once. For shell calls, bounded workspace package definitions and referenced local scripts provide untrusted evidence; their canonical paths and content are rechecked before granting.
38
+ 5. A reviewed pass returns `allowed-once`. For an otherwise eligible action, model denial, uncertainty, failure or budget exhaustion opens a timed confirmation. The dialog shows the exact operation, reviewer opinion and countdown. Explicit approval grants this call after another binding/evidence check; rejection or expiry returns `rejected`. Closing the dialog rejects. No downstream approval answerer is consulted.
58
39
 
59
- ### Independent DSH model
40
+ Native prohibitions, structural refusals, changed evidence, cancellation and invalidated requests cannot be overridden. Timed confirmation requires the UI row and an authenticated browser client; without them, or with the timeout set to zero, the existing non-grant path remains. Headless sessions do not gain an automatic fallback.
60
41
 
61
- Set both fields in the same `config`, using IDs from your DSH model configuration:
42
+ The reviewer sees the bounded action, chronological direct-human instructions and local evidence, with no main-agent prompt, private reasoning or tools. Authorization is judged by substance: necessary local installation, build and test steps may implement a requested development task without the user naming every command. Earlier authority remains visible after a progress question or “continue”; later restrictions still apply. Automatic allowance requires low/medium risk, medium/high authorization and bounded side effects.
62
43
 
63
- ```yaml
64
- fastProvider: your-review-provider
65
- fastModel: your-small-review-model
66
- ```
44
+ Human text is retained without lossy selection, up to 12 KiB. Sensitive text, nontext constraints or overflow prevent automatic review rather than silently dropping restrictions; an otherwise valid action can receive fresh explicit confirmation through the timed UI without sending that history to the model. Evidence is capped at eight files, 6 KiB per file and 12 KiB overall. Protected, escaped, sensitive or unreadable files are withheld with explicit omission markers. Evidence coverage is partial: dependencies, imported code and workspace-wide scripts are not exhaustively inspected. Material remaining uncertainty prevents automatic permission.
67
45
 
68
- The model can differ from the conversation in both provider and model. It stays fixed when the conversation switches models. Clearing both fields restores following. Invalid/missing providers or models do not trigger a silent fallback to the conversation, another provider, or HTTP.
46
+ The native `load_workspace_dependencies` result can identify the current agent's local Node/pnpm entry points. A single literal invocation of that exact pair is not treated as reading a protected `.dsh` path; the original command still goes through normal policy and escalation review. Tool identity and local file identity are rechecked. Data operands, credentials, redirects and compound commands receive no exemption. Run the dependency tool again after a plugin/agent restart or runtime replacement; transcript text cannot register paths.
69
47
 
70
- The optional deep stage is independently configurable, including while the primary reviewer follows the conversation:
48
+ Relative paths follow native tool bases: PowerShell uses the session cwd; Bash and file mutations prefer the sandbox workspace root. Resolved review paths are bound separately without rewriting tool arguments. Command timeouts accept positive finite values (including 240000–600000 ms); the native executor owns its limits. The review deadline and 30-second approval freshness window remain separate.
71
49
 
72
- ```yaml
73
- deepProvider: your-deep-review-provider
74
- deepModel: your-deep-review-model
75
- ```
50
+ ## Configuration
76
51
 
77
- Only a fast `review` decision invokes it. Both deep fields empty means no deep model; uncertainty is rejected in independent approval mode. Legacy exact-rule mode retains human handling in smart mode and rejection in unattended mode. There is no second implicit call to the conversation model. Native provider/model fields must be configured in pairs.
52
+ Everything is optional; with no configuration the reviewer follows the current conversation's model. Edit the profile row's `config` and reload:
78
53
 
79
- ### Independent HTTP endpoint (RC2-compatible)
54
+ | Key | Default | Meaning |
55
+ | --- | --- | --- |
56
+ | `enabled` | `true` | Master switch. `false` mounts nothing. |
57
+ | `provider` / `model` | *(follow conversation)* | Fixed reviewer route, configured as a pair using your DSH model IDs. |
58
+ | `reasoningEffort` | *(model default)* | Advertised reasoning effort of the fixed route. |
59
+ | `reviewerPrompt` | *(none)* | Extra review constraints (≤4096 chars); may only restrict, never widen. |
60
+ | `timeoutMs` | `30000` | Per-review deadline. |
61
+ | `humanApprovalTimeoutMs` | `60000` | Human confirmation window, separate from model review; `0` disables it. Maximum 300000 ms; profile-owned. |
62
+ | `maxInputBytes` | `32768` | Combined UTF-8 prompt/input cap; existing explicit values are retained. |
63
+ | `outputTokens` | `1024` | Reviewer output cap, including reasoning where the model counts it. Explicit profile values are retained; incomplete or invalid verdicts still require human confirmation. |
64
+ | `maxReviewsPerTask` | `20` | Review calls per direct user task. |
65
+ | `consecutiveDenials` | `3` | Consecutive explicit denials before the breaker opens. Uncertainty and failures reset the streak but still consume review reservations. |
66
+ | `staticReadonly` | `true` | Grant `bash` escalations proven non-mutating and limited to metadata/literal output without a model call. `false` sends eligible requests to the reviewer. |
80
67
 
81
- ```yaml
82
- endpoint: https://your-trusted-gateway.example/v1/chat/completions
83
- fastModel: your-http-review-model
84
- # deepModel: your-http-deep-model
85
- apiKeyEnv: DSH_SAFE_AUTO_API_KEY
86
- ```
68
+ Unknown keys fail validation rather than being ignored. Reviewer model, effort and prompt can also be set per deployment on the plugin page; those saved values override the profile route but never the budgets.
87
69
 
88
- `endpoint` is the complete OpenAI-compatible Chat Completions URL. This explicit endpoint uses the existing HTTP transport, including compatible lapp gateways; omit `fastProvider` and `deepProvider`. Combining native providers with an HTTP endpoint is rejected rather than guessed. Only this mode reads the named API key environment variable. HTTPS is required except loopback HTTP; redirects, URL credentials, query and fragment are rejected. To restore following, clear the endpoint and its fast model, not just the endpoint.
70
+ ## The reviewer model
89
71
 
90
- Both ordinary preflight and one-shot escalation use the selected reviewer. Routes are snapshotted for each review, and a change during an outstanding native review invalidates automatic allowance; the final guards recheck the route. Removing the model service leaves the policy guards installed, and switching models does not reset budgets. Explicit denials remain denials even if the route or user authority changes. Ordinary reviewed grants are bound before review to the action, workspace, sandbox policy and direct-user authority; the final guard rejects a stale grant after downstream policy completes.
72
+ **Default: follow the conversation.** Leave `provider`/`model` empty. Each review resolves the provider/model from the requesting session's accepted request header, reusing DSH's configured credentials — no extra API key. Only the model route is inherited, not history, prompt, tools or budgets.
91
73
 
92
- ## Policy and one-shot escalation
74
+ **Fixed model.** Set `provider` and `model` together to pin a reviewer that stays put when the conversation switches models. A missing or invalid route rejects instead of falling back silently.
93
75
 
94
- The following exact-rule smart-mode behavior is retained for compatibility (`approvalReview: false`); it is not the independent approval fallback policy.
76
+ ## Policy
95
77
 
96
- | Action | Smart behavior |
78
+ | Request | Outcome |
97
79
  | --- | --- |
98
- | Ordinary `read/read_image/write/edit` in an enrolled workspace | Deterministic pass to existing policy; no reviewer call |
99
- | Protected credentials/security configuration or selected dangerous programs | Hard denial, including escalation |
100
- | Exact enrolled simple `shell/bash` command | Reviewer, within the operator envelope only |
101
- | Exact separately enrolled native `write/edit` or eligible `bash` escalation | Review at native `approval/request`; a fresh allow returns `allowed-once` |
102
- | Unenrolled, unsupported or ambiguous operation | Native human approval; unattended rejects |
103
- | Explicit model denial | Rejected, no semantic retry |
104
- | Cancellation, binding mismatch or changed authority | No automatic grant |
105
-
106
- `escalationCandidates` defaults to `[]`. Ordinary `shellCandidates` do not authorize widening. Register exact rules separately:
107
-
108
- ```yaml
109
- escalationCandidates:
110
- - tool: write
111
- cwd: /absolute/canonical/project
112
- mode: danger-full-access
113
- filePath: /absolute/other-project/notes.txt
114
- - tool: edit
115
- cwd: /absolute/canonical/project
116
- mode: danger-full-access
117
- filePath: /absolute/other-project/notes.txt
118
- - tool: bash
119
- cwd: /absolute/canonical/project
120
- mode: danger-full-access
121
- command: git status --short
122
- escalationApprovalTtlMs: 30000
123
- escalationMaxTimeoutMs: 30000
124
- ```
125
-
126
- Rules require exactly tool/cwd/mode and filePath or command. No prefixes, globs or directory grants. Native DSH requests use `sandbox_permissions: danger-full-access` with `justification`, not Codex's `require_escalated`. Only widening from Workspace Write is supported. File targets must be absolute and canonical, with existing parents; links, hard-linked writes, protected/system targets and unknown arguments do not get automatic approval. The reviewer receives complete bounded file-write/edit arguments, including content, or refuses oversized/sensitive inputs without truncating them.
80
+ | Bound single escalation of `write`/`edit`/`bash`/`pwsh`, reviewer passes | `allowed-once`, this call only |
81
+ | Bound `bash` escalation passing both static mutation and exposure checks | `allowed-once`, no model call, no budget consumed |
82
+ | Protected credentials/security files, secrets, dangerous programs (anywhere in a fully parsed command) | Hard denial before review |
83
+ | Model denial (including risk opinions), uncertainty or review failure for an eligible action | Timed human confirmation; no grant without explicit approval |
84
+ | Unknown tools, subagents, nested or unbound requests | No automatic grant |
85
+ | Human rejection or confirmation expiry | Rejected; fresh execution needs fresh review |
86
+ | Changed evidence, invalidated grants, audit failure or cancellation | No grant; terminal feedback |
127
87
 
128
- **Automatic Bash escalation requires no `jobs` service**, a visible sandbox-capable shell, false/omitted `run_in_background`, an explicit positive `timeoutMs` within the configured limit, and no workdir change. A jobs-enabled DSH profile can promote even a foreground call after timeout. Such requests stay manual or are rejected in unattended mode; the plugin never silently disables jobs. Neither a timeout nor one-shot approval proves that arbitrary descendants cannot outlive the call.
88
+ Native `approval: never` still rejects before any answerer. Never stack this with another automatic approval answerer.
129
89
 
130
- The native tool consumes the grant; the plugin does not execute the command itself. Async context and opaque execution tokens bind the exact agent, call, signal, arguments, cwd, policy, user intent and filesystem state. Concurrent identical call IDs cannot borrow a grant. One execution consumes one approval slot; no cross-call grant cache exists. `escalationApprovalTtlMs` limits decision freshness, not process lifetime, revocation or rollback. Expiry asks a human or denies; side effects are not undone. See [ADR-0002](docs/ADR-0002.md) for the complete execution contract.
90
+ ## Reading configuration and session files
131
91
 
132
- ## Modes and composition
92
+ Ordinary sessions, skills and settings under `.codex`, `.dsh`, `.claude`, `.agents`, `.config` and other directories remain readable. Protection follows dedicated credential stores and actual credential fields, not whole directories. Auth/credential stores, private SSH keys and private-key stores are refused; ordinary public keys and certificates are readable. Mutation protection remains stricter.
133
93
 
134
- The following legacy mode behavior is retained with `approvalReview: false`. Active independent approval rejects unknown/unbound requests and every non-allowing verdict, error, timeout, budget exhaustion or invalidation, without human or downstream fallback.
94
+ Native `read` masks recognized credential values in JSON/JSONC, JSONL, YAML, TOML, ENV/INI and ordinary text, while keeping non-secret fields, references, line numbers and the host's original output caps. A fresh sanitized value regenerates both display text and metadata. Native `grep` masks or withholds sensitive matches before the host's result spill policy. Secret-bearing editor views and known raw shell dumps direct you to native `read`.
135
95
 
136
- `off` installs nothing. `shadow` observes ordinary candidates without protecting execution; **enrolled ordinary commands can now use the conversation model even without an explicit endpoint**, and consume reviewer tokens. Shadow escalation remains native/manual without automatic review. Empty candidate lists make no model requests on installation. `smart` enforces policy and sends uncertainty to native human approval. `unattended` can grant eligible reviewed one-shot escalations but rejects uncertainty and other approval requests.
96
+ Structured files are screened as complete sources up to 1 MiB; larger JSONL sessions are processed by complete selected lines (1 MiB per line, 8 MiB selected source). Malformed, unsupported or oversized structured content yields a safe error instead of raw fragments. Canonical targets, source versions and returned windows are checked through the mounted filesystem. Unknown opaque secrets cannot be identified by their content alone. These checks cover the pinned native tools; arbitrary Full Access scripts, custom tools and remote providers are not a secret-isolation sandbox. Shell output cannot be made safe by redacting it after execution because jobs may already have retained it.
137
97
 
138
- Native `approval: never` rejects before any answerer. For automatic escalation, keep native approval at `ask` even with plugin `unattended`; `ask` dispatches to an answerer, not necessarily a human. Missing native approval services fail closed. Ordinary passes call `next()`, preserving other policy denials and prompts. Never stack this with official experimental Auto, Autogate or another auto-answerer. Legacy rule-mode human fallback assumes the downstream native human channel; active independent approval never uses that fallback.
98
+ ## Migrating from 0.1.x
139
99
 
140
- ## Budgets and privacy
100
+ - Profile keys `mode`, `workspaceRoots`, `shellCandidates`, `escalationCandidates`, `endpoint`, `apiKeyEnv`, `tokenField`, `fast*`/`deep*` and the budget fuses `sessionBudgetUnits`/`totalDenials` were removed; a profile still carrying them fails validation. The equivalent of 0.1.x `approvalReview: true` plus a UI-enabled session is now the only behavior.
101
+ - `fastProvider`/`fastModel`/`fastReasoningEffort` became `provider`/`model`/`reasoningEffort`; `fastOutputTokens` became `outputTokens`; `fastCallsPerTask` became `maxReviewsPerTask`.
102
+ - Settings saved by the 0.1.x panel keep loading (retired keys are stripped), but the reviewer route falls back to following the conversation — re-pick a model on the plugin page if you had a fixed one.
141
103
 
142
- | Setting | Default | Meaning |
143
- | --- | --- | --- |
144
- | `timeoutMs`, `maxInputBytes` | `8000`, `8192` | Per-stage deadline and combined UTF-8 prompt/input cap |
145
- | `fastOutputTokens`, `deepOutputTokens` | `64`, `256` | Explicit native `maxTokens` or HTTP output caps |
146
- | `tokenField` | `max_tokens` | HTTP only; alternatively `max_completion_tokens` |
147
- | `fastCallsPerTask`, `deepCallsPerTask` | `20`, `3` | Atomic logical-review reservations per direct user task |
148
- | `sessionBudgetUnits` | `100000` | Prompt bytes + output cap + 1024 reserved per stage |
149
- | `consecutiveDenials`, `totalDenials` | `3`, `20` | Non-allowing review/error fuse per task/session |
150
-
151
- Fast JSON is `allow/review/deny`; deep JSON is `allow/ask/deny`. Extra fields, invalid JSON, tool calls, missing finish or output truncation cannot grant. Both transports have bounded responses, including native reasoning text, and an outer cancellation/timeout deadline. No plugin-level transport or semantic retry is added. Native adapters/middleware remain host-controlled and may implement their own transport policy; reservations count logical reviews, not every downstream wire attempt.
152
-
153
- Only the action and latest direct human text are supplied. No main transcript, assistant reasoning or tool results are copied. Descriptions and justifications do not authorize actions. Secret detection is heuristic; following a model or configuring a remote reviewer sends bounded review inputs to that provider, including file contents for escalation. Fixed routes never silently change data destinations on failure.
104
+ ## Boundaries and limits
154
105
 
155
- Preflight and escalation share a session ledger, reserved before I/O with no error refunds. Usage counts include DSH's disjoint cache counters when reported. Reservations are not exact billable tokens, currency limits or a cap on the main agent. Providers must honor limits. New direct user messages reset task counters but not session totals; model changes reset neither; plugin reload/restart resets in-memory counters. The fuse stops more reviews, not the whole agent loop.
106
+ - **Not an audited boundary.** The reviewer is a language model and can be wrong, especially in adversarial contexts. Keep the native sandbox, isolation and backups you already rely on.
107
+ - **Static proof assumes operator-trusted PATH and runtimes.** It checks the original command text, not installed binary identity, shell functions or ambient runtime integrity. Explicit executable paths, `.exe`/`.cmd` suffixes, case variants, executable pager/config environment prefixes and persistent assignments do not qualify. Parser or grammar defects can produce incorrect proofs; this is not a runtime attestation or an absolute safety guarantee. An unproven command returns to reviewer/manual confirmation, not a new hard refusal.
108
+ - **Quoting does not bypass hard refusals.** Literal argv, environment and redirect values are decoded before the protected-path/secret checks, including adjacent quote fragments. These checks also apply outside the static path and cannot be overridden by reviewer or manual confirmation. Unquoted wildcard fragments still invalidate proof even next to quoted text. Bash `/dev/tcp` and `/dev/udp` file redirects return to review, including quoted and numbered-fd input redirects; ordinary file input, fd merges and `/dev/null` output retain their existing rules.
109
+ - **Git is not safe by subcommand name.** Content, history, remote URLs and configuration enumeration require review even when their flags prevent mutation. Metadata commands retain the original disabling controls required by the no-mutation grammar. Exact `git version` and `git --no-pager config --get user.name` / `user.email` are narrow static cases. The plugin never prepends controls or rewrites argv.
110
+ - **Dedicated confirmation channel.** Pinned DSH 0.2.0-rc.2 approval and question waterfalls accept automatic answerers. Manual confirmation instead uses the plugin's authenticated browser HTTP endpoints and unpredictable single-use request IDs. Fetch metadata and host origin/authentication checks protect the browser channel against cross-site requests; they do not prove physical human action. Authenticated clients, their transport and same-process plugins remain trusted. No model tool is registered for approval.
111
+ - **Server-owned expiry.** The window starts when a pending request is published. The server uses a monotonic deadline and atomically accepts the first valid answer; duplicate, late or cross-session answers fail. Disabling, changing settings, unloading or cancelling invalidates pending requests. Requests are in memory only, so restarts do not restore them. Both direct browser requests and the authenticated DSH desktop carrier are supported; incompatible request metadata is rejected.
112
+ - **Foreign native approvals remain native.** Blueprint order and Classmates model approvals continue to downstream answerers when no Safe Auto-owned execution context exists. Requests in an owned context, including mismatches, stale/claimed requests, and unbound impersonation of `bash`/`pwsh`/`write`/`edit`, remain fail-closed.
113
+ - **Coverage stops at native single-call escalation.** Only `write`/`edit`/`bash`/`pwsh` widening from `workspace-write` is reviewed. Other tools, MCP, remote execution, subagent calls and standing permission changes stay outside the automatic envelope.
114
+ - **Evidence is checked, execution is not atomic.** Evidence paths, versions and SHA-256 digests are revalidated before granting, but files can still change between approval and execution. Other same-process plugins remain trusted; unloading removes the guards. Keep external isolation with restricted credentials and egress.
115
+ - **No guarantee is claimed.** There is no fail-open option, no durable audit database and no claim of absolute safety or savings.
156
116
 
157
117
  ## Verification
158
118
 
159
- Run `npm test`, `npm run build` (JavaScript syntax checks plus the browser bundle, not TypeScript checking), and `npm pack --dry-run` in this package, plus repository `pnpm check`. Tests cover routing, concurrent sessions, native streams, caps, stale decisions, model service removal, preflight/escalation binding, real loopback HTTP, and real Cordis/ToolRuntime/ApprovalService/LlmRuntime contracts. CI requires installed DSH dependencies; offline source-only tests may explicitly skip native contracts. POSIX-only file and escalation grant cases are explicitly skipped on Windows, while Windows tests assert fail-closed behavior; native model routing still runs. If the Windows sandbox blocks the test runner's subprocess pipes, run each test file separately with `node --test --test-isolation=none test/<file>.test.js`.
160
-
161
- The native test uses a controlled adapter and fixture session/tool/policy. It proves runtime integration, not live model accuracy, OS isolation or authenticated Web/Headless acceptance. These remain in [ADR-0002's checklist](docs/ADR-0002.md). Logs separate assessment, escalation outcome and final result without raw commands/prompts/keys; host retention is operator-managed.
162
-
163
- ## Boundaries and limits
119
+ Run `npm test`, `npm run build` and `npm pack --dry-run` in this package, plus repository `pnpm check`. Tests cover routing, concurrent sessions, native streams, caps, stale decisions, model service removal, execution binding, and real Cordis/ToolRuntime/ApprovalService/LlmRuntime contracts. CI requires installed DSH dependencies; offline source-only runs may skip the native contracts. If the Windows sandbox blocks the test runner's subprocess pipes, run each test file separately with `node --test --test-isolation=none test/<file>.test.js`.
164
120
 
165
- - **Not an audited boundary.** The exact-rule path (local POSIX/native-tool candidates) and independent approval mode (Windows native escalation included) are candidates, not an independently audited security boundary. Start with `shadow`, and keep the native sandbox providers, isolation and backups you already rely on.
166
- - **Human approval is not a fallback for independent review.** It remains available only in legacy rule mode or when independent approval is inactive.
167
- - **Exact rules are not a finer OS sandbox.** DSH `workspace-write` governs file effects, not network egress or all secret reads, and an approved `danger-full-access` call genuinely bypasses the DSH file sandbox.
168
- - **Exact rule mode does not enlarge the operator envelope.** With `approvalReview: false`, empty candidate lists authorize no model grants; Windows file auto-passes and exact-rule PowerShell escalation remain unsupported. Independent approval mode requires an explicit saved choice and session activation, as described above.
169
- - **Coverage stops at native single-call escalation.** `grep/glob`, PTC, MCP, remote execution and subagent model grants stay outside the automatic envelope, as does widening from read-only to workspace-write. Exact-rule mode also excludes PowerShell and complex shell; independent native approval mode can review them, but missing decisive script evidence is rejected.
170
- - **Enrolled content is not pinned and other plugins stay trusted.** Tests, builds, installation and Git hooks can run repository-controlled code and are not inherently safe; enrollment does not pin executable contents. Trusted same-process plugins and execution providers remain trusted, and unloading a policy removes its guards. Path rechecks cannot eliminate OS TOCTOU, so use external isolation with restricted credentials and egress.
171
- - **No guarantee is claimed.** There is no fail-open option, no read-only investigation tool and no claim of full Codex parity. No durable budget/audit database, cross-call grant cache or PI probe is bundled, and no absolute safety or savings percentage is claimed.
121
+ The native contract tests use controlled adapters and fixture sessions/tools. They prove runtime integration, not live model accuracy, OS isolation or authenticated Web/Headless acceptance; those remain in [ADR-0002's checklist](docs/ADR-0002.md). Logs separate assessment, outcome and final result without raw commands, prompts or keys; host retention is operator-managed.
172
122
 
173
123
  ## License
174
124
 
package/README.zh-CN.md CHANGED
@@ -1,162 +1,125 @@
1
- # 安全自动(候选版)
1
+ # 安全自动
2
2
 
3
- 在明确登记的范围内自动审核并批准单次原生沙箱提权,**审批模型默认跟随当前对话,也能单独指定 provider/model,或继续使用独立 HTTP 端点**。复用 DSH 原生工具循环、模型适配器和审批服务;不会把整个会话切成 Full Access,模型只能缩小规则给定的权限范围。
3
+ <!-- release-state-note -->
4
+ 插件生命周期见[仓库状态清单](../../README.zh-CN.md#插件生命周期):草稿 → 测试中 → 已发布,只向前推进。已发布插件的修复、测试和升版保持已发布;每次更新仍须通过发布检查。首次发布须明确选择测试中的包,并在 npm 归档验证成功后登记。详见[发布规则](../../RELEASING.zh-CN.md)。
4
5
 
5
- [English](README.md) · [预检](docs/ADR-0001.md) · [单次提权](docs/ADR-0002.md) · [审批模型路由](docs/ADR-0003.md)
6
+ 自动审核原生沙箱提权请求。当真实的 `write`/`edit`/`bash`/`pwsh` 调用要求把沙箱放宽到 Workspace Write 之外时,由独立审核模型把关这一次调用。少量只列元数据或输出字面量的 `bash` 命令,可通过静态检查而不调模型。通过就自动继续;其他审核结果会在当前会话显示完整操作,给你 60 秒选择“仅批准这一次”或拒绝。无人响应则到期拒绝。插件不会把整个会话切成 Full Access。
6
7
 
7
- ## 安装与默认配置
8
+ [English](README.md) · [单次提权](docs/ADR-0002.md) · [审核模型路由](docs/ADR-0003.md) · [授权与证据](docs/ADR-0004.md) · [限时人工确认](docs/ADR-0005.md) · [静态 Shell 证明](docs/ADR-0006.md)
8
9
 
9
- 在仓库检查通过后,向一次性测试 profile 安装本地包:
10
+ > **0.2.0 是破坏性简化。** 0.1.x 的精确规则预检、workspace/shell/escalation 候选名单、`shadow`/`smart`/`unattended` 模式、深度审核阶段和 HTTP 端点均已删除。见[从 0.1.x 迁移](#从-01x-迁移)。
10
11
 
11
- ```sh
12
- pnpm install --frozen-lockfile
13
- pnpm --filter @klarkxy/dsh-safe-auto test
14
- dsh plugin --profile web add ./plugins/dsh-safe-auto
15
- ```
12
+ ## 安装与启用
16
13
 
17
- PR 不等于 npm 已发布。bundle 会插入 `dsh-safe-auto` 条目,通过 profile 补丁机制配置它的 `config`:
14
+ 0.2.0 发布到 npm 后:
18
15
 
19
- ```yaml
20
- mode: shadow
21
- workspaceRoots:
22
- - /absolute/canonical/project
23
- shellCandidates:
24
- - git status --short
25
- # 模型字段不填,默认跟随本对话。
16
+ ```sh
17
+ dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto@0.2.0
26
18
  ```
27
19
 
28
- 工作区必须是规范绝对路径,与会话 cwd 和沙箱 root 完全相同。授权范围、候选命令、提权名单和预算仍通过 profile 配置,严格校验且修改后重载插件。
29
-
30
- ## 插件页启停与独立代审批
31
-
32
- **你做什么。** 在插件页 **替我审批** 区块选择活跃主会话并点击 **启用**。停用只关闭代审批,不修改会话原生权限。启用保留 **Workspace Write + ask**,不注册官方 Full Access Auto。打开页面、刷新、保存模型配置都不会自动启用会话。子会话、重启及 UI Host 卸载不继承启用状态。
33
-
34
- **插件做什么。** 新增 `approvalReview: true`(默认为 `false`),或在插件页审核模式选择 **独立模型替我审批** 并保存。这一模式参考 `dsh-approval-review@0.5.1` 的独立应答者原理,不要求 POSIX 精确候选命令;可以审核 Windows 原生 `pwsh` 以及 `bash/write/edit` 发出的真实单次沙箱提权请求。仅绑定当前工具执行的真实请求,不依据自由文本、同名 callId 或旧日志批准;启用独立审批时,未知工具、远程、嵌套、子代理、不完整参数及无法绑定当前执行的请求均拒绝。模型无工具,仅收到完整有界动作、当前直接用户意图和附加约束。
35
-
36
- 模型必须提供结构化风险、用户授权、有界范围和理由;只有低/中风险、至少中等直接授权且范围有界才可能自动批准。高/严重风险、不确定、证据不足的未知脚本、非法结果、模型错误、超时、预算不足及授权失效均直接拒绝;明确拒绝绝不回退给其他应答者。默认快速 64 token 可能不足以生成结构化结果,可通过 profile 调整预算;截断时不会放行。
37
-
38
- 此模式是对原生审批链的显式委托,不是任意操作授权;`approval: never` 仍在链前拒绝。插件页固定显示「无法自动判断时 → 直接拒绝」,该策略不可修改也不保存,因为尚未核验 DSH 的仅人工审批通道。调用 waterfall `next()` 可能到达其他自动应答者,不等于人工回退。独立审批的非允许结果不委托下游。旧版精确规则兼容行为不变。本次源码修改不会自动卸载已安装插件或发布新版本。
39
-
40
- ## 审核模型设置
41
-
42
- 新版 bundle 包含核心与 UI Host 两个条目;设置和会话操作统一位于插件页,不替换输入框原生权限菜单。启用操作使用宿主预设,不走官方 Full Access 的 `registerAuto()`;原生 `approval: never` 仍不可绕过。
43
-
44
- 在插件页 **安全自动设置** 中选择快速/深度审核模型、各自思考强度及最多 4096 字符的额外审核提示词。模型目录和档位来自宿主;快速模型为空表示跟随本会话,深审为空表示关闭。选新模型清空旧档位,未列出的已保存配置不会被静默替换。原生模型不支持指定档位时失败关闭。提示词只能增加审核条件,不能替换固定安全规则或扩大授权。保存不调用模型、不改变会话权限、不重置预算;会使未完成的旧授权失效。思考模型若需要更高输出预算,请在 profile 调整 `fastOutputTokens/deepOutputTokens`。HTTP 模式面板只读,仍保留 profile 配置,不支持原生思考档位。
45
-
46
- UI Host 条目 `dsh-safe-auto-ui` 使用 `storageDomain` 持久保存审核偏好,覆盖同名 profile 模型字段;不保存会话授权。启用状态仅属于当前活跃会话对象:切回原生选项、外部权限变更、重启或 UI Host 卸载都会关闭自动审核,分叉及子会话不继承。UI 接管后,旧版 profile 的 smart/unattended 不会自动启用未选择的会话;单独加载核心 Host 条目时保留旧配置模式。卸载 Client 后原生权限控件恢复。
47
-
48
- ## 审批模型可以单独设置
49
-
50
- ### 默认:跟随当前对话
20
+ 使用源码检出安装:
51
21
 
52
- `endpoint`、`fastProvider`、`fastModel` 均留空。每次需要模型审核时,读取请求会话已经接受的 `requestHeader().config` 的 provider/model;尚无请求 header 才使用同一 Agent 的 options。存在但不完整的 header 不会偷偷回退。对话下一轮接受了新模型,后续审核随之更新;不同会话不会共用一个全局模型选择。
53
-
54
- 直接复用 DSH 对应 provider 的适配器和凭据,**不用再填一遍 API Key**。只继承模型路由,不继承聊天历史、主 Agent 提示词、工具权限、回放状态、思考档位或输出预算。审批仍是独立、无工具的模型请求,使用自身的提示和成本上限。需要大量推理 token 的模型可能要提高审批输出上限;无法支持的参数应失败关闭,不能丢掉限制后执行。
55
-
56
- ### 独立指定 DSH 模型
57
-
58
- 在同一插件配置中成对设置,填写 DSH 已配置的实际 provider/model ID:
59
-
60
- ```yaml
61
- fastProvider: your-review-provider
62
- fastModel: your-small-review-model
22
+ ```sh
23
+ pnpm install --frozen-lockfile
24
+ pnpm --filter @klarkxy/dsh-safe-auto test
25
+ dsh plugin --profile <profile> add ./plugins/dsh-safe-auto
63
26
  ```
64
27
 
65
- 可以和对话完全不同;对话切换模型不会影响这个固定审批模型。清空两项恢复跟随。provider 不存在、模型不可用、凭据错误等在独立审批模式中直接拒绝;旧版精确规则模式保留原有人工或拒绝行为,**不静默改用对话模型或其他服务**。
28
+ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。之后输入框的权限菜单里会在原生档位旁出现第四个选项——选择 **安全自动** 即为本会话启用,选回任意原生档位即停用。在此之前没有任何自动行为:会话不继承启用状态,重启、切换权限或卸载都会撤销它。插件页只保留审核配置、安全说明和只读的预算边界,按页签分区。
66
29
 
67
- 可选深审也可单独指定,包括主审批模型继续跟随对话的情况:
30
+ > 输入框的权限控件是替换型插槽:安装 Safe Auto 期间由插件自己渲染这个控件(包含原生档位),选项才能出现在菜单里。如果宿主以后重新设计这个控件,插件的副本在新版本跟进前可能落后。
68
31
 
69
- ```yaml
70
- deepProvider: your-deep-review-provider
71
- deepModel: your-deep-review-model
72
- ```
32
+ ## 工作原理
73
33
 
74
- 只有快速审核返回 `review` 才调用深审。两项均为空表示不开启深审,不会默认再调用一次对话模型。独立审批模式中不确定直接拒绝;旧版精确规则模式仍是 Smart 回人工、无人值守拒绝。原生路由的 provider/model 必须成对填写。
34
+ 1. 原生工具调用请求 `sandbox_permissions` 提权(`workspace-write` 或 `danger-full-access`)。
35
+ 2. 插件绑定当前活跃执行——agent、callId、signal、完整参数、cwd、沙箱策略,以及按时间排序的真人指令,包含后续限制和撤销。
36
+ 3. 完全按字面解析的 `bash` 命令,只有每次调用同时通过“不修改”和“仅元数据/字面量输出”两项检查,才会不收集证据、不调模型直接放行,例如 `ls -la`、`pwd`、`find . -name "*.md"`。`printenv`、`ps`、文件内容读取、递归内容搜索、Git 内容及配置枚举均继续审核。未知选项、缩写、输出文件操作数和持久赋值也继续审核;`pwsh` 不走静态通道。
37
+ 4. 审核模型审查一次完整请求。Shell 调用会补充有界的工作区包配置和所引用本地脚本作为非可信证据;放行前重新核对路径与内容。
38
+ 5. 审核通过返回 `allowed-once`。请求本身符合范围时,模型拒绝、不确定、故障或预算耗尽会进入限时人工确认。窗口显示完整操作、审核意见和倒计时;明确批准后再次核对绑定及证据,只放行这一调用。拒绝、关闭窗口或超时返回 `rejected`,不交给下游审批器。
75
39
 
76
- ### 保留独立 HTTP 端点
40
+ 宿主禁止、结构性拒绝、证据变化、取消或请求失效不能被覆盖。人工确认需要 UI 条目和已认证的浏览器客户端;没有界面或把人工超时设为零时,保持原来的不放行处理。Headless 会话不会获得自动回退权限。
77
41
 
78
- RC2 的配置继续有效:
42
+ 审核模型看到有界动作、按时间排序的真人指令和本地证据,不继承主代理提示词、隐藏推理或工具。授权按实际含义判断:完成开发任务所需的本地安装、构建和测试可以属于已授权工作,无须用户逐条点名命令。询问进度或说“继续”不会丢掉先前授权,后续限制仍然有效。只有低/中风险、至少中等授权且副作用有界才自动放行。
79
43
 
80
- ```yaml
81
- endpoint: https://your-trusted-gateway.example/v1/chat/completions
82
- fastModel: your-http-review-model
83
- # deepModel: your-http-deep-model
84
- apiKeyEnv: DSH_SAFE_AUTO_API_KEY
85
- ```
44
+ 真人文本完整保留,合计最多 12 KiB。敏感文本、非文本约束或超限会阻止自动审查,不会静默丢掉限制;请求本身有效时,仍可在限时窗口中明确批准当前完整操作,不把这段历史发给模型。证据最多八个文件、每个 6 KiB、合计 12 KiB;受保护、越界、敏感或不可读内容会被标记并排除。证据并非完整安全证明:不会穷举依赖、导入代码或整个 workspace 的脚本,仍有实质不确定性时不得自动放行。
86
45
 
87
- 这是完整 OpenAI-compatible Chat Completions URL,可接兼容 lapp 网关。此模式不要填写 `fastProvider/deepProvider`;与原生路由混填会报错。只有 HTTP 模式读取上述 API Key 环境变量。仅允许 HTTPS 或 loopback HTTP,拒绝重定向、URL 凭据、查询参数和 fragment。恢复跟随时要同时清空 endpoint 和 HTTP fastModel,不能只删 endpoint。
46
+ 原生 `load_workspace_dependencies` 的结果可用于识别当前 agent 的本地 Node/pnpm 入口。以明确字面量执行这一精确组合时,不再把入口路径误判为读取受保护的 `.dsh` 文件;原命令仍走正常策略与提权审核。插件复核工具定义和本地文件身份,数据参数、凭据、重定向及复合命令不享有例外。插件或 agent 重启、运行器替换后需再次调用依赖工具;聊天文本不能登记可信路径。
88
47
 
89
- 普通预检和单次提权都使用这套选择。每次审核固定两阶段路由;审核期间模型变化会作废自动放行结果,最终 guard 再次核对。模型服务失效不会导致安全 guard 一并卸载。切换模型不重置预算;已经明确拒绝的操作也不会因为换模型或用户意图变化被改成可再次争取放行。普通模型预检也会在审查前绑定动作、工作区、沙箱策略和直接用户意图,并在下游策略结束后的最终 guard 中拒绝过期授权。
48
+ 相对路径遵循原生工具的基准:PowerShell 使用会话 cwd,Bash 与文件修改优先使用沙箱 workspace root。解析后的审核路径单独参与绑定,不改写工具参数。命令超时接受有限正数(包括 240000–600000 ms),实际限制由原生执行器负责;审核超时和 30 秒批准有效期仍各自独立。
90
49
 
91
- ## 默认行为与单次提权
50
+ ## 配置
92
51
 
93
- 以下为 `approvalReview: false` 的旧版精确规则兼容行为,不是独立审批的回退策略。启用独立审批时,未知或未绑定请求、不允许的结果、错误、超时、预算耗尽及授权失效均拒绝,不回人工或下游审批链。
52
+ 全部可选;不配置时审核模型跟随当前对话。编辑 profile 条目的 `config` 并重载:
94
53
 
95
- `off` 不安装策略。`shadow` 只观察,不保护执行;**登记了普通候选命令后,即使没有独立 endpoint,也可能使用对话模型产生审核费用**。提权在 Shadow 中仍交原生审批,不自动审查或批准。安装时候选列表默认全空,不自动产生审核请求。
54
+ | 键 | 默认 | 含义 |
55
+ | --- | --- | --- |
56
+ | `enabled` | `true` | 总开关。`false` 不挂载任何守卫。 |
57
+ | `provider` / `model` | *(跟随对话)* | 固定审核路由,用你的 DSH 模型 ID 成对配置。 |
58
+ | `reasoningEffort` | *(模型默认)* | 固定路由 advertised 的思考强度。 |
59
+ | `reviewerPrompt` | *(无)* | 额外审核约束(≤4096 字符);只能收紧,不能放宽。 |
60
+ | `timeoutMs` | `30000` | 单次审查超时。 |
61
+ | `humanApprovalTimeoutMs` | `60000` | 独立于模型审查的人工确认窗口;`0` 关闭,最多 300000 ms,只在 profile 配置。 |
62
+ | `maxInputBytes` | `32768` | 提示词与输入合计的 UTF-8 字节上限;已有显式配置保持原值。 |
63
+ | `outputTokens` | `1024` | 审核输出上限,含模型计入的思考预算。已有 profile 显式值保持不变;不完整或无效结论仍需人工确认。 |
64
+ | `maxReviewsPerTask` | `20` | 每个真人任务的审查次数上限。 |
65
+ | `consecutiveDenials` | `3` | 连续明确拒绝达到该值后熔断。不确定和故障重置拒绝计数,但仍消耗审查预算。 |
66
+ | `staticReadonly` | `true` | 同时证明不修改且只输出元数据/字面量的 `bash` 提权不调模型放行;`false` 将符合范围的请求送审核模型。 |
96
67
 
97
- `smart` 对普通工作区 `read/read_image/write/edit` 做零模型检查,保留其他原生策略;受保护凭据、安全配置和部分危险命令硬拒绝。未知情况交人工。`unattended` 可以批准符合条件的单次提权,但不确定和其他审批需求均拒绝。
68
+ 未知键会直接校验失败,而不是被忽略。审核模型、思考强度和提示词也可以在插件页配置;保存的值覆盖 profile 路由,但永远不覆盖预算。
98
69
 
99
- `escalationCandidates` 与 `shellCandidates` 独立,普通命令候选不授予沙箱外权限,默认 `[]`。例如:
70
+ ## 审核模型
100
71
 
101
- ```yaml
102
- escalationCandidates:
103
- - tool: write
104
- cwd: /absolute/canonical/project
105
- mode: danger-full-access
106
- filePath: /absolute/other-project/notes.txt
107
- - tool: edit
108
- cwd: /absolute/canonical/project
109
- mode: danger-full-access
110
- filePath: /absolute/other-project/notes.txt
111
- - tool: bash
112
- cwd: /absolute/canonical/project
113
- mode: danger-full-access
114
- command: git status --short
115
- escalationApprovalTtlMs: 30000
116
- escalationMaxTimeoutMs: 30000
117
- ```
72
+ **默认:跟随对话。** `provider`/`model` 留空。每次审查从请求会话已接受的请求头解析 provider/model,复用 DSH 已配置的凭据——不需要额外 API key。继承的只有模型路由,不包括历史、提示词、工具或预算。
118
73
 
119
- 每条规则只有 tool/cwd/mode 和 filePath 或 command 四项,不允许前缀、通配符或整个目录授权。原生 DSH 使用 `sandbox_permissions: danger-full-access` 加 justification,不是 Codex 的 require_escalated。当前只支持 Workspace Write 到单次 Full Access。文件目标要是规范绝对路径且父目录已存在;链接、硬链接写入、受保护/系统目标及未知参数不自动放行。write/edit 分别登记;完整有界内容交给 Reviewer,超长或命中敏感检测时不截断后批准。
74
+ **固定模型。** 成对设置 `provider` 和 `model`,对话切换模型时审核路由保持不变。路由缺失或非法时直接拒绝,不做静默回退。
120
75
 
121
- **Bash 自动提权要求没有 jobs 服务**、可确认的沙箱 shell、不请求后台、显式正数 timeoutMs 且不超过配置上限,workdir 不变。加载 jobs 的 DSH 可能把超时前台任务转后台;这种组合仍走人工或无人值守拒绝,不会偷偷关闭 jobs。超时和一次性批准不能证明所有派生进程都已经退出。
76
+ ## 策略
122
77
 
123
- 只在匹配的原生 approval/request 内返回 allowed-once,由原生工具消费,不自行执行或修改会话权限。批准绑定 opaque token、异步上下文、Agent、callId、signal、完整参数、cwd、权限模式、直接用户意图和文件状态。并发相同 callId 不能互借;每次执行只消费一次,无跨调用批准缓存。审批 TTL 是决定新鲜度,不是进程 TTL、撤销或回滚;操作副作用不会自动撤销。详见 [ADR-0002](docs/ADR-0002.md)。
78
+ | 请求 | 结果 |
79
+ | --- | --- |
80
+ | 绑定的 `write`/`edit`/`bash`/`pwsh` 单次提权,审查通过 | `allowed-once`,仅此一次 |
81
+ | 同时通过静态修改与信息暴露检查的 `bash` 提权 | `allowed-once`,不调模型、不耗预算 |
82
+ | 受保护的凭据/安全文件、密钥、危险程序(完整解析的命令中任何位置) | 审查前硬拒绝 |
83
+ | 符合请求范围的模型拒绝(含风险意见)、不确定或审查故障 | 限时人工确认;未明确批准就不放行 |
84
+ | 未知工具、子代理、嵌套或未绑定请求 | 不自动放行 |
85
+ | 人工拒绝或确认超时 | 拒绝;再次执行须重新审查 |
86
+ | 证据变化、请求失效、审计故障或取消 | 不放行并给出终止原因 |
124
87
 
125
- **原生 approval: never 优先拒绝所有审批。** 启用自动提权时,原生服务仍需设为 ask,即使插件模式是 unattended。ask 表示分发给审批者,不代表一定有人在线。缺少原生审批服务时不提权;普通放行调用 `next()`,保留下游的拒绝与提示。不要叠加官方 Auto、Autogate 或其他自动 answerer;旧版规则模式的人工 fallback 假定下游是原生人工通道,启用独立审批时不使用该回退。
88
+ 原生 `approval: never` 仍在任何应答者之前拒绝。不要与其他自动审批应答者叠加使用。
126
89
 
127
- ## 成本与隐私
90
+ ## 读取配置和会话文件
128
91
 
129
- | 设置 | 默认值 | 含义 |
130
- | --- | --- | --- |
131
- | `timeoutMs`、`maxInputBytes` | `8000`、`8192` | 每阶段超时与提示/输入合计 UTF-8 上限 |
132
- | `fastOutputTokens`、`deepOutputTokens` | `64`、`256` | 原生 `maxTokens` 或 HTTP 输出上限 |
133
- | `tokenField` | `max_tokens` | 仅 HTTP 模式,可选 `max_completion_tokens` |
134
- | `fastCallsPerTask`、`deepCallsPerTask` | `20`、`3` | 每个直接用户任务的逻辑审核预留次数 |
135
- | `sessionBudgetUnits` | `100000` | 提示字节数 + 输出上限 + 每阶段 1024 预留 |
136
- | `consecutiveDenials`、`totalDenials` | `3`、`20` | 单任务/单会话的非允许审核熔断 |
92
+ `.codex`、`.dsh`、`.claude`、`.agents`、`.config` 等目录里的普通会话、技能和配置仍可读取。保护依据是专用凭据存储和实际凭据字段,不是整个目录。认证/凭据存储、SSH 私钥与私钥仓库被拒绝,普通公钥和证书可以读取。修改文件的限制仍更严格。
137
93
 
138
- 快速返回 allow/review/deny,深审返回 allow/ask/deny。错误 JSON、额外字段、工具调用、缺失 finish 和截断不能批准;原生 reasoning 内容也受响应大小限制。插件不主动做传输/语义重试;宿主适配器或中间件可能有自身传输策略,预留计数是逻辑审核请求,不是所有底层 HTTP 尝试。
94
+ 原生 `read` 对 JSON/JSONC、JSONL、YAML、TOML、ENV/INI 和普通文本中的已识别凭据值隐藏显示,保留非秘密字段、引用路径、原行号和宿主输出上限。脱敏后的结构化值同时生成显示内容和元数据。原生 `grep` 在宿主落盘完整搜索结果之前脱敏或隐藏敏感匹配。包含秘密的编辑器查看操作、已知的 shell 原文转储会提示改用原生 `read`。
139
95
 
140
- 仅发送动作和最近直接人类文本,不发送完整历史、主 Agent 推理或工具结果。justification 不是授权。敏感检测是启发式;选定或跟随远端 provider 会发送这些有界输入,文件提权包含内容。固定配置失效时不偷偷更换数据目的地。
96
+ 结构化文件以完整内容检查,上限 1 MiB;较大的 JSONL 会话按完整的所选行处理(每行 1 MiB、所选原文合计 8 MiB)。损坏、不支持或超限的结构化内容返回安全错误,不返回原文片段。通过当前挂载的文件系统核对真实目标、版本和返回窗口。没有特征的任意秘密无法仅凭文本识别。这些检查覆盖已核对的原生工具,不构成任意 Full Access 脚本、自定义工具或远程 provider 的秘密隔离沙箱。shell 结果不能靠执行后脱敏保证安全,因为 jobs 可能已经保存了原始输出。
141
97
 
142
- 普通预检和提权共享网络前原子预算,失败不退额。sessionBudgetUnits 默认 100000,按提示 UTF-8 字节数 + 输出上限 + 1024 预留,不是精确账单或主 Agent 总成本。原生缓存计数按 DSH 的互斥计量合并。新用户消息只重置任务计数,换模型不重置;重载/重启仍会重置内存计数。熔断停止的是审核,不是整个 Agent 循环。
98
+ ## 从 0.1.x 迁移
143
99
 
144
- ## 验证与剩余范围
100
+ - profile 键 `mode`、`workspaceRoots`、`shellCandidates`、`escalationCandidates`、`endpoint`、`apiKeyEnv`、`tokenField`、`fast*`/`deep*` 以及熔断 `sessionBudgetUnits`/`totalDenials` 已删除;仍携带这些键的 profile 会校验失败。0.1.x 的 `approvalReview: true` 加插件页启用,现在就是唯一行为。
101
+ - `fastProvider`/`fastModel`/`fastReasoningEffort` 更名为 `provider`/`model`/`reasoningEffort`;`fastOutputTokens` 更名为 `outputTokens`;`fastCallsPerTask` 更名为 `maxReviewsPerTask`。
102
+ - 0.1.x 面板保存的设置仍可加载(废弃键会被剥离),但审核路由回退为跟随对话——如果你用过固定模型,请在插件页重新选择。
145
103
 
146
- 运行 npm test、npm run build(JavaScript 语法检查与浏览器 bundle 构建,不是 TypeScript typecheck)、npm pack --dry-run 和全仓 pnpm check。测试包括路由/并发/失效/取消,以及真实 DSH LlmRuntime、ToolRuntime、ApprovalService 和受控适配器集成。CI 必须运行真实 DSH tests;缺依赖的离线本地环境可以明确跳过。Windows 上显式跳过 POSIX 专用文件授权与提权用例,并验证失败关闭行为,原生模型路由测试仍运行。若 Windows 沙箱阻止测试运行器创建子进程管道,可逐文件执行 `node --test --test-isolation=none test/<file>.test.js`。
104
+ ## 边界与限制
147
105
 
148
- 受控模型和 fixture 的 session/tool/policy 不是在线模型准确率、OS 沙箱或 authenticated Web/Headless 验收。剩余清单在 [ADR-0002](docs/ADR-0002.md)。日志区分 assessment、escalation 和实际 result,不记录原始命令/提示/Key,留存由宿主管理。
106
+ - **不是经过审计的安全边界。** 审核方是语言模型,可能出错,尤其在对抗性上下文中。保留你原本依赖的原生沙箱、隔离和备份。
107
+ - **静态证明以操作者信任 PATH 和运行时为前提。** 它检查原始命令文本,不核验已安装二进制、shell 函数或环境运行时的完整性。显式程序路径、`.exe`/`.cmd` 后缀、大小写变体、可执行 pager/配置环境前缀和会持久化的赋值都不符合条件。解析器或语法缺陷仍可能造成错误证明;这不是运行时认证,也不保证绝对安全。无法证明的命令回到审核/人工确认,不新增硬拒绝。
108
+ - **引号不能绕过硬拒绝。** 保护路径和秘密检查先读取解码后的字面参数、环境及重定向值,包括相邻引号片段拼接;退出静态通道时仍执行这些检查,模型或人工确认不能覆盖。引号旁的未引用通配符仍使静态证明失败。Bash 的 `/dev/tcp`、`/dev/udp` 文件重定向回到审核,包括引用过的路径及编号 fd 输入重定向;普通文件输入、fd 合并和 `/dev/null` 输出保留原有规则。
109
+ - **Git 的子命令名不能证明安全。** 内容、历史、远程 URL 和配置枚举即使带有防修改参数,也要经过审核。元数据命令仍须满足“不修改”语法要求的原始控制参数。精确的 `git version`、`git --no-pager config --get user.name`/`user.email` 可走窄范围静态通道。插件不会补参数或重写命令。
110
+ - **独立确认通道。** 当前 DSH 0.2.0-rc.2 的审批和问答链允许自动应答器。人工确认改用插件已认证的浏览器 HTTP 入口和不可预测、单次使用的请求 ID。Fetch Metadata 与宿主的来源、认证检查用于防跨站请求,并不证明物理真人点击;已认证客户端、其传输层和同进程插件仍然可信。不向模型注册审批工具。
111
+ - **服务端掌握时限。** 请求发布后开始计时,用单调时钟判定到期,只接受第一个有效答案。重复、迟到和跨会话回答均失败。停用、修改设置、卸载或取消会使待审批失效;请求仅存内存,重启不会恢复。兼容直接浏览器请求与已认证的 DSH 桌面传输;不符合要求的请求类型仍会被拒绝。
112
+ - **其他插件的原生审批保持原生流程。** 没有 Safe Auto 自有执行上下文时,Blueprint 顺序审批、Classmates 模型审批会继续交给后续处理器。已有自有上下文中的不匹配、过期、已领取请求,以及无上下文却冒用 `bash`/`pwsh`/`write`/`edit` 的请求仍然关闭放行。
113
+ - **覆盖范围止于原生单次提权。** 只审核从 `workspace-write` 放宽的 `write`/`edit`/`bash`/`pwsh`。其他工具、MCP、远程执行、子代理调用和常驻权限变更都在自动范围之外。
114
+ - **证据会复核,执行并非原子操作。** 放行前复核证据路径、版本和 SHA-256 摘要,但审批与执行之间仍可能发生文件变化。同进程插件仍然可信,卸载会移除守卫;实际隔离仍依赖外部手段及受限的凭据与出站。
115
+ - **不作任何保证。** 没有 fail-open 选项,没有持久审计数据库,也不承诺绝对安全或节省比例。
149
116
 
150
- ## 边界与限制
117
+ ## 验证
118
+
119
+ 在本包运行 `npm test`、`npm run build` 和 `npm pack --dry-run`,以及仓库级 `pnpm check`。测试覆盖路由、并发会话、原生流、上限、过期决定、模型服务移除、执行绑定,以及真实 Cordis/ToolRuntime/ApprovalService/LlmRuntime 契约。CI 要求安装 DSH 依赖;离线纯源码运行可跳过原生契约。如果 Windows 沙箱拦截测试运行器的子进程管道,用 `node --test --test-isolation=none test/<file>.test.js` 逐文件运行。
151
120
 
152
- - **不是经过审计的安全边界。** 精确规则路径(本地 POSIX/native 工具候选)和独立审批模式(含 Windows 原生提权)都只是候选实现,未经独立安全审计。先用 `shadow`,并保留你原本依赖的原生沙箱、隔离与备份。
153
- - **人工审批不是独立审核的回退。** 它只存在于旧版规则模式或未启用独立审批时。
154
- - **精确规则不等于更细的 OS 沙箱。** DSH workspace-write 只约束文件效果,不是网络隔离或全面敏感读取防护;单次 Full Access 确实移除该次 DSH 文件沙箱。
155
- - **精确规则模式不扩大授权名单。** `approvalReview: false` 时,候选列表为空不产生模型自动批准,Windows 文件自动放行和 PowerShell 精确规则提权仍不支持。独立审批模式需明确保存选择并启用会话,适用范围见上节。
156
- - **覆盖范围止于原生单次提权。** PTC/MCP、远程、子代理模型提权和 `grep/glob` 仍在自动放行范围之外,read-only 到 workspace-write 的放宽同样未纳入。精确规则模式仍排除 PowerShell 和复杂 Shell;独立审批模式可以审查原生 Shell 提权,但缺少决定性脚本证据直接拒绝。
157
- - **登记内容不被固定,同进程插件仍受信任。** 测试、构建、安装和 Git hooks 可运行任意代码,命令登记不固定其未来内容;卸载策略会一并移除其 guard。可信同进程插件、工具和执行提供方仍属于信任基础。路径重查不能消除 TOCTOU;无人值守需额外隔离凭据与网络。
158
- - **不承诺任何保证。** 没有失败放行选项,不提供独立只读探针或 Codex 全功能等价保证;没有持久化预算/审计库、跨调用批准缓存或 PI probe,也不承诺绝对安全或固定节省比例。
121
+ 原生契约测试使用受控适配器和夹具会话/工具,证明的是运行时集成,不是真实模型准确率、OS 隔离或已认证的 Web/Headless 验收;这些仍在 [ADR-0002 的清单](docs/ADR-0002.md)中。日志分离评估、结果和最终状态,不含原始命令、提示词或密钥;宿主留存由运维管理。
159
122
 
160
123
  ## 许可证
161
124
 
162
- 原始实现使用 [SATA License 2.1](LICENSE),参考社区设计但未直接复制其代码。
125
+ 原创实现基于 [SATA License 2.1](LICENSE)。社区设计启发了本工作;未打包其代码。
package/docs/ADR-0001.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ADR-0001: bounded preflight, not an escalation auto-answerer
2
2
 
3
- Status: historical RC1 decision, partially superseded by [ADR-0002](ADR-0002.md) in `0.1.0-rc.2`.
3
+ Status: historical RC1 decision, partially superseded by [ADR-0002](ADR-0002.md) in `0.1.0-rc.2`. **The preflight mechanism itself (ordinary-command review, workspace/shell candidates, shadow/smart/unattended modes) was removed in `0.2.0-rc.0`**; only the execution-bound approval review of ADR-0002 remains.
4
4
 
5
5
  **The no-auto-escalation statements below describe RC1, not the current candidate.** RC2 adds separately enrolled, execution-bound native `allowed-once` approvals, including unattended mode, without changing standing sandbox policy. Use ADR-0002 and the current READMEs for configuration and deployment acceptance. The original decision is retained here as history.
6
6
 
package/docs/ADR-0002.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ADR-0002: native, execution-bound one-shot escalation
2
2
 
3
- Status: implemented in `0.1.0-rc.2`; automated contracts verified; live-profile acceptance pending.
3
+ Status: implemented in `0.1.0-rc.2`; automated contracts verified; live-profile acceptance pending. Since `0.2.0-rc.0` this execution-bound approval review is the plugin's only mechanism; the exact-rule candidate enrollment described below was removed along with preflight.
4
4
 
5
5
  This partially supersedes [ADR-0001](ADR-0001.md): its prohibition on returning `allowed-once` and blanket unattended escalation rejection were an RC1 limitation, not the final design. Ordinary preflight, explicit envelopes, bounded review, no global permission writes and conservative failure handling remain in force.
6
6