@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 +80 -130
- package/README.zh-CN.md +82 -119
- package/docs/ADR-0001.md +1 -1
- package/docs/ADR-0002.md +1 -1
- package/docs/ADR-0003.md +1 -1
- package/docs/ADR-0004.md +33 -0
- package/docs/ADR-0005.md +31 -0
- package/docs/ADR-0006.md +58 -0
- package/dsh.plugin.json +9 -4
- package/lib/client.js +1738 -494
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +18 -10
- package/src/approval-review.js +24 -2
- package/src/config.js +12 -35
- package/src/control.js +29 -17
- package/src/credential-paths.js +29 -0
- package/src/credential-reads.js +227 -0
- package/src/credential-text.js +361 -0
- package/src/execution-evidence.js +115 -0
- package/src/gate.js +37 -31
- package/src/host-runtime.js +159 -0
- package/src/human-approval.js +64 -0
- package/src/index.js +175 -203
- package/src/model-route.js +10 -29
- package/src/policy.js +39 -78
- package/src/review-context.js +35 -0
- package/src/review-paths.js +53 -0
- package/src/reviewer.js +61 -120
- package/src/shell-command.js +547 -0
- package/src/ui-host.js +60 -43
- package/src/escalation.js +0 -118
package/README.md
CHANGED
|
@@ -1,174 +1,124 @@
|
|
|
1
|
-
# Safe Auto
|
|
1
|
+
# Safe Auto
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14
|
+
After 0.2.0 is published to npm:
|
|
36
15
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
20
|
+
From a checked source checkout instead:
|
|
48
21
|
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
32
|
+
## How it works
|
|
56
33
|
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
deepProvider: your-deep-review-provider
|
|
74
|
-
deepModel: your-deep-review-model
|
|
75
|
-
```
|
|
50
|
+
## Configuration
|
|
76
51
|
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
+
## The reviewer model
|
|
89
71
|
|
|
90
|
-
|
|
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
|
-
|
|
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
|
-
|
|
76
|
+
## Policy
|
|
95
77
|
|
|
96
|
-
|
|
|
78
|
+
| Request | Outcome |
|
|
97
79
|
| --- | --- |
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
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
|
-
|
|
88
|
+
Native `approval: never` still rejects before any answerer. Never stack this with another automatic approval answerer.
|
|
129
89
|
|
|
130
|
-
|
|
90
|
+
## Reading configuration and session files
|
|
131
91
|
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
98
|
+
## Migrating from 0.1.x
|
|
139
99
|
|
|
140
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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`
|
|
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
|
-
|
|
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
|
-
|
|
3
|
+
<!-- release-state-note -->
|
|
4
|
+
插件生命周期见[仓库状态清单](../../README.zh-CN.md#插件生命周期):草稿 → 测试中 → 已发布,只向前推进。已发布插件的修复、测试和升版保持已发布;每次更新仍须通过发布检查。首次发布须明确选择测试中的包,并在 npm 归档验证成功后登记。详见[发布规则](../../RELEASING.zh-CN.md)。
|
|
4
5
|
|
|
5
|
-
|
|
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
|
-
|
|
10
|
+
> **0.2.0 是破坏性简化。** 0.1.x 的精确规则预检、workspace/shell/escalation 候选名单、`shadow`/`smart`/`unattended` 模式、深度审核阶段和 HTTP 端点均已删除。见[从 0.1.x 迁移](#从-01x-迁移)。
|
|
10
11
|
|
|
11
|
-
|
|
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
|
-
|
|
14
|
+
0.2.0 发布到 npm 后:
|
|
18
15
|
|
|
19
|
-
```
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
28
|
+
bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。之后输入框的权限菜单里会在原生档位旁出现第四个选项——选择 **安全自动** 即为本会话启用,选回任意原生档位即停用。在此之前没有任何自动行为:会话不继承启用状态,重启、切换权限或卸载都会撤销它。插件页只保留审核配置、安全说明和只读的预算边界,按页签分区。
|
|
66
29
|
|
|
67
|
-
|
|
30
|
+
> 输入框的权限控件是替换型插槽:安装 Safe Auto 期间由插件自己渲染这个控件(包含原生档位),选项才能出现在菜单里。如果宿主以后重新设计这个控件,插件的副本在新版本跟进前可能落后。
|
|
68
31
|
|
|
69
|
-
|
|
70
|
-
deepProvider: your-deep-review-provider
|
|
71
|
-
deepModel: your-deep-review-model
|
|
72
|
-
```
|
|
32
|
+
## 工作原理
|
|
73
33
|
|
|
74
|
-
|
|
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
|
-
|
|
40
|
+
宿主禁止、结构性拒绝、证据变化、取消或请求失效不能被覆盖。人工确认需要 UI 条目和已认证的浏览器客户端;没有界面或把人工超时设为零时,保持原来的不放行处理。Headless 会话不会获得自动回退权限。
|
|
77
41
|
|
|
78
|
-
|
|
42
|
+
审核模型看到有界动作、按时间排序的真人指令和本地证据,不继承主代理提示词、隐藏推理或工具。授权按实际含义判断:完成开发任务所需的本地安装、构建和测试可以属于已授权工作,无须用户逐条点名命令。询问进度或说“继续”不会丢掉先前授权,后续限制仍然有效。只有低/中风险、至少中等授权且副作用有界才自动放行。
|
|
79
43
|
|
|
80
|
-
|
|
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
|
-
|
|
46
|
+
原生 `load_workspace_dependencies` 的结果可用于识别当前 agent 的本地 Node/pnpm 入口。以明确字面量执行这一精确组合时,不再把入口路径误判为读取受保护的 `.dsh` 文件;原命令仍走正常策略与提权审核。插件复核工具定义和本地文件身份,数据参数、凭据、重定向及复合命令不享有例外。插件或 agent 重启、运行器替换后需再次调用依赖工具;聊天文本不能登记可信路径。
|
|
88
47
|
|
|
89
|
-
|
|
48
|
+
相对路径遵循原生工具的基准:PowerShell 使用会话 cwd,Bash 与文件修改优先使用沙箱 workspace root。解析后的审核路径单独参与绑定,不改写工具参数。命令超时接受有限正数(包括 240000–600000 ms),实际限制由原生执行器负责;审核超时和 30 秒批准有效期仍各自独立。
|
|
90
49
|
|
|
91
|
-
##
|
|
50
|
+
## 配置
|
|
92
51
|
|
|
93
|
-
|
|
52
|
+
全部可选;不配置时审核模型跟随当前对话。编辑 profile 条目的 `config` 并重载:
|
|
94
53
|
|
|
95
|
-
|
|
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
|
-
|
|
68
|
+
未知键会直接校验失败,而不是被忽略。审核模型、思考强度和提示词也可以在插件页配置;保存的值覆盖 profile 路由,但永远不覆盖预算。
|
|
98
69
|
|
|
99
|
-
|
|
70
|
+
## 审核模型
|
|
100
71
|
|
|
101
|
-
|
|
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
|
-
|
|
74
|
+
**固定模型。** 成对设置 `provider` 和 `model`,对话切换模型时审核路由保持不变。路由缺失或非法时直接拒绝,不做静默回退。
|
|
120
75
|
|
|
121
|
-
|
|
76
|
+
## 策略
|
|
122
77
|
|
|
123
|
-
|
|
78
|
+
| 请求 | 结果 |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| 绑定的 `write`/`edit`/`bash`/`pwsh` 单次提权,审查通过 | `allowed-once`,仅此一次 |
|
|
81
|
+
| 同时通过静态修改与信息暴露检查的 `bash` 提权 | `allowed-once`,不调模型、不耗预算 |
|
|
82
|
+
| 受保护的凭据/安全文件、密钥、危险程序(完整解析的命令中任何位置) | 审查前硬拒绝 |
|
|
83
|
+
| 符合请求范围的模型拒绝(含风险意见)、不确定或审查故障 | 限时人工确认;未明确批准就不放行 |
|
|
84
|
+
| 未知工具、子代理、嵌套或未绑定请求 | 不自动放行 |
|
|
85
|
+
| 人工拒绝或确认超时 | 拒绝;再次执行须重新审查 |
|
|
86
|
+
| 证据变化、请求失效、审计故障或取消 | 不放行并给出终止原因 |
|
|
124
87
|
|
|
125
|
-
|
|
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
|
-
|
|
94
|
+
原生 `read` 对 JSON/JSONC、JSONL、YAML、TOML、ENV/INI 和普通文本中的已识别凭据值隐藏显示,保留非秘密字段、引用路径、原行号和宿主输出上限。脱敏后的结构化值同时生成显示内容和元数据。原生 `grep` 在宿主落盘完整搜索结果之前脱敏或隐藏敏感匹配。包含秘密的编辑器查看操作、已知的 shell 原文转储会提示改用原生 `read`。
|
|
139
95
|
|
|
140
|
-
|
|
96
|
+
结构化文件以完整内容检查,上限 1 MiB;较大的 JSONL 会话按完整的所选行处理(每行 1 MiB、所选原文合计 8 MiB)。损坏、不支持或超限的结构化内容返回安全错误,不返回原文片段。通过当前挂载的文件系统核对真实目标、版本和返回窗口。没有特征的任意秘密无法仅凭文本识别。这些检查覆盖已核对的原生工具,不构成任意 Full Access 脚本、自定义工具或远程 provider 的秘密隔离沙箱。shell 结果不能靠执行后脱敏保证安全,因为 jobs 可能已经保存了原始输出。
|
|
141
97
|
|
|
142
|
-
|
|
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
|
-
|
|
104
|
+
## 边界与限制
|
|
147
105
|
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|