@klarkxy/dsh-safe-auto 0.2.0-rc.3 → 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,6 +1,9 @@
1
- # Safe Auto (release candidate)
1
+ # Safe Auto
2
2
 
3
- 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 — except a `bash` call the built-in static proof can show is read-only, which is granted 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.
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).
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.
4
7
 
5
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)
6
9
 
@@ -8,8 +11,10 @@ Automatic review of native sandbox escalation requests. When a real `write`/`edi
8
11
 
9
12
  ## Install and enable
10
13
 
14
+ After 0.2.0 is published to npm:
15
+
11
16
  ```sh
12
- dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto
17
+ dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto@0.2.0
13
18
  ```
14
19
 
15
20
  From a checked source checkout instead:
@@ -28,9 +33,9 @@ The bundle inserts the `dsh-safe-auto` and `dsh-safe-auto-ui` profile rows. Safe
28
33
 
29
34
  1. A native tool call asks for `sandbox_permissions` widening (`workspace-write` or `danger-full-access`).
30
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.
31
- 3. A fully literal `bash` command is granted without evidence or a model only when every invocation matches an exact positive grammar: case-sensitive POSIX program names, supported flags and values, input-only operand counts, safe redirects and bounded environment prefixes. Unknown options, abbreviations, clusters, output operands and assignment-only statements continue to review. Ordinary reads such as `ls -la`, `cat input | jq .name`, `grep -rn pattern src`, `find . -name "*.md"` and `ps aux` retain this fast path; `pwsh` does not.
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.
32
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.
33
- 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, requested permission, 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.
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.
34
39
 
35
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.
36
41
 
@@ -38,6 +43,10 @@ The reviewer sees the bounded action, chronological direct-human instructions an
38
43
 
39
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.
40
45
 
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.
47
+
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.
49
+
41
50
  ## Configuration
42
51
 
43
52
  Everything is optional; with no configuration the reviewer follows the current conversation's model. Edit the profile row's `config` and reload:
@@ -54,7 +63,7 @@ Everything is optional; with no configuration the reviewer follows the current c
54
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. |
55
64
  | `maxReviewsPerTask` | `20` | Review calls per direct user task. |
56
65
  | `consecutiveDenials` | `3` | Consecutive explicit denials before the breaker opens. Uncertainty and failures reset the streak but still consume review reservations. |
57
- | `staticReadonly` | `true` | Grant provably read-only `bash` escalations without a model call. `false` sends everything to the reviewer. |
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. |
58
67
 
59
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.
60
69
 
@@ -69,7 +78,7 @@ Unknown keys fail validation rather than being ignored. Reviewer model, effort a
69
78
  | Request | Outcome |
70
79
  | --- | --- |
71
80
  | Bound single escalation of `write`/`edit`/`bash`/`pwsh`, reviewer passes | `allowed-once`, this call only |
72
- | Bound `bash` escalation proven read-only by the strict static parse | `allowed-once`, no model call, no budget consumed |
81
+ | Bound `bash` escalation passing both static mutation and exposure checks | `allowed-once`, no model call, no budget consumed |
73
82
  | Protected credentials/security files, secrets, dangerous programs (anywhere in a fully parsed command) | Hard denial before review |
74
83
  | Model denial (including risk opinions), uncertainty or review failure for an eligible action | Timed human confirmation; no grant without explicit approval |
75
84
  | Unknown tools, subagents, nested or unbound requests | No automatic grant |
@@ -78,6 +87,14 @@ Unknown keys fail validation rather than being ignored. Reviewer model, effort a
78
87
 
79
88
  Native `approval: never` still rejects before any answerer. Never stack this with another automatic approval answerer.
80
89
 
90
+ ## Reading configuration and session files
91
+
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.
93
+
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`.
95
+
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.
97
+
81
98
  ## Migrating from 0.1.x
82
99
 
83
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.
@@ -89,7 +106,7 @@ Native `approval: never` still rejects before any answerer. Never stack this wit
89
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.
90
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.
91
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.
92
- - **Git is not read-only by subcommand name.** Bare `git status`, worktree diffs, `git ls-files --modified` and other content-checking worktree operations remain under review because refresh/conversion can execute configured clean/process filters. Supported object/index reads require the original `--no-pager --no-optional-locks --no-lazy-fetch -c core.fsmonitor=false`; cached/staged diff also requires `--no-ext-diff --no-textconv --ignore-submodules=all`. History reads additionally need `--no-show-signature` and a supported fixed format such as `--oneline`. The plugin never prepends controls or rewrites argv. Exact `git version` and `git --no-pager config --get user.name` are narrow independent reads; transport helpers, editors, filters and mixed config mutations do not qualify. Ordinary `sort` can spill to temporary files, so only its check mode qualifies.
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.
93
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.
94
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.
95
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.
package/README.zh-CN.md CHANGED
@@ -1,6 +1,9 @@
1
- # 安全自动(候选版)
1
+ # 安全自动
2
2
 
3
- 自动审核原生沙箱提权请求。当真实的 `write`/`edit`/`bash`/`pwsh` 调用要求把沙箱放宽到 Workspace Write 之外时,由独立审核模型把关这一次调用——内置静态证明能判定为只读的 `bash` 命令除外,它们不调模型直接放行。通过就自动继续;其他审核结果会在当前会话显示完整操作,给你 60 秒选择“仅批准这一次”或拒绝。无人响应则到期拒绝。插件不会把整个会话切成 Full Access。
3
+ <!-- release-state-note -->
4
+ 插件生命周期见[仓库状态清单](../../README.zh-CN.md#插件生命周期):草稿 → 测试中 → 已发布,只向前推进。已发布插件的修复、测试和升版保持已发布;每次更新仍须通过发布检查。首次发布须明确选择测试中的包,并在 npm 归档验证成功后登记。详见[发布规则](../../RELEASING.zh-CN.md)。
5
+
6
+ 自动审核原生沙箱提权请求。当真实的 `write`/`edit`/`bash`/`pwsh` 调用要求把沙箱放宽到 Workspace Write 之外时,由独立审核模型把关这一次调用。少量只列元数据或输出字面量的 `bash` 命令,可通过静态检查而不调模型。通过就自动继续;其他审核结果会在当前会话显示完整操作,给你 60 秒选择“仅批准这一次”或拒绝。无人响应则到期拒绝。插件不会把整个会话切成 Full Access。
4
7
 
5
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)
6
9
 
@@ -8,8 +11,10 @@
8
11
 
9
12
  ## 安装与启用
10
13
 
14
+ 0.2.0 发布到 npm 后:
15
+
11
16
  ```sh
12
- dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto
17
+ dsh plugin --profile <profile> add @klarkxy/dsh-safe-auto@0.2.0
13
18
  ```
14
19
 
15
20
  使用源码检出安装:
@@ -28,9 +33,9 @@ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。
28
33
 
29
34
  1. 原生工具调用请求 `sandbox_permissions` 提权(`workspace-write` 或 `danger-full-access`)。
30
35
  2. 插件绑定当前活跃执行——agent、callId、signal、完整参数、cwd、沙箱策略,以及按时间排序的真人指令,包含后续限制和撤销。
31
- 3. 完全按字面解析的 `bash` 命令,只有每次调用都符合精确正向语法才会不收集证据、不调模型直接放行:区分大小写的 POSIX 程序名、支持的选项和值、只含输入的操作数数量、安全重定向和受限环境前缀。未知选项、缩写、未列出的短选项组合、输出文件操作数及仅赋值的语句继续审核。`ls -la`、`cat input | jq .name`、`grep -rn pattern src`、`find . -name "*.md"`、`ps aux` 等普通读取保留快速通道;`pwsh` 不走此通道。
36
+ 3. 完全按字面解析的 `bash` 命令,只有每次调用同时通过“不修改”和“仅元数据/字面量输出”两项检查,才会不收集证据、不调模型直接放行,例如 `ls -la`、`pwd`、`find . -name "*.md"`。`printenv`、`ps`、文件内容读取、递归内容搜索、Git 内容及配置枚举均继续审核。未知选项、缩写、输出文件操作数和持久赋值也继续审核;`pwsh` 不走静态通道。
32
37
  4. 审核模型审查一次完整请求。Shell 调用会补充有界的工作区包配置和所引用本地脚本作为非可信证据;放行前重新核对路径与内容。
33
- 5. 审核通过返回 `allowed-once`。请求本身符合范围时,模型拒绝、不确定、故障或预算耗尽会进入限时人工确认。窗口显示完整操作、请求权限、审核意见和倒计时;明确批准后再次核对绑定及证据,只放行这一调用。拒绝、关闭窗口或超时返回 `rejected`,不交给下游审批器。
38
+ 5. 审核通过返回 `allowed-once`。请求本身符合范围时,模型拒绝、不确定、故障或预算耗尽会进入限时人工确认。窗口显示完整操作、审核意见和倒计时;明确批准后再次核对绑定及证据,只放行这一调用。拒绝、关闭窗口或超时返回 `rejected`,不交给下游审批器。
34
39
 
35
40
  宿主禁止、结构性拒绝、证据变化、取消或请求失效不能被覆盖。人工确认需要 UI 条目和已认证的浏览器客户端;没有界面或把人工超时设为零时,保持原来的不放行处理。Headless 会话不会获得自动回退权限。
36
41
 
@@ -38,6 +43,10 @@ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。
38
43
 
39
44
  真人文本完整保留,合计最多 12 KiB。敏感文本、非文本约束或超限会阻止自动审查,不会静默丢掉限制;请求本身有效时,仍可在限时窗口中明确批准当前完整操作,不把这段历史发给模型。证据最多八个文件、每个 6 KiB、合计 12 KiB;受保护、越界、敏感或不可读内容会被标记并排除。证据并非完整安全证明:不会穷举依赖、导入代码或整个 workspace 的脚本,仍有实质不确定性时不得自动放行。
40
45
 
46
+ 原生 `load_workspace_dependencies` 的结果可用于识别当前 agent 的本地 Node/pnpm 入口。以明确字面量执行这一精确组合时,不再把入口路径误判为读取受保护的 `.dsh` 文件;原命令仍走正常策略与提权审核。插件复核工具定义和本地文件身份,数据参数、凭据、重定向及复合命令不享有例外。插件或 agent 重启、运行器替换后需再次调用依赖工具;聊天文本不能登记可信路径。
47
+
48
+ 相对路径遵循原生工具的基准:PowerShell 使用会话 cwd,Bash 与文件修改优先使用沙箱 workspace root。解析后的审核路径单独参与绑定,不改写工具参数。命令超时接受有限正数(包括 240000–600000 ms),实际限制由原生执行器负责;审核超时和 30 秒批准有效期仍各自独立。
49
+
41
50
  ## 配置
42
51
 
43
52
  全部可选;不配置时审核模型跟随当前对话。编辑 profile 条目的 `config` 并重载:
@@ -54,7 +63,7 @@ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。
54
63
  | `outputTokens` | `1024` | 审核输出上限,含模型计入的思考预算。已有 profile 显式值保持不变;不完整或无效结论仍需人工确认。 |
55
64
  | `maxReviewsPerTask` | `20` | 每个真人任务的审查次数上限。 |
56
65
  | `consecutiveDenials` | `3` | 连续明确拒绝达到该值后熔断。不确定和故障重置拒绝计数,但仍消耗审查预算。 |
57
- | `staticReadonly` | `true` | 可证明只读的 `bash` 提权不调模型直接放行;`false` 则一律送审核模型。 |
66
+ | `staticReadonly` | `true` | 同时证明不修改且只输出元数据/字面量的 `bash` 提权不调模型放行;`false` 将符合范围的请求送审核模型。 |
58
67
 
59
68
  未知键会直接校验失败,而不是被忽略。审核模型、思考强度和提示词也可以在插件页配置;保存的值覆盖 profile 路由,但永远不覆盖预算。
60
69
 
@@ -69,7 +78,7 @@ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。
69
78
  | 请求 | 结果 |
70
79
  | --- | --- |
71
80
  | 绑定的 `write`/`edit`/`bash`/`pwsh` 单次提权,审查通过 | `allowed-once`,仅此一次 |
72
- | 严格静态解析可证明只读的 `bash` 提权 | `allowed-once`,不调模型、不耗预算 |
81
+ | 同时通过静态修改与信息暴露检查的 `bash` 提权 | `allowed-once`,不调模型、不耗预算 |
73
82
  | 受保护的凭据/安全文件、密钥、危险程序(完整解析的命令中任何位置) | 审查前硬拒绝 |
74
83
  | 符合请求范围的模型拒绝(含风险意见)、不确定或审查故障 | 限时人工确认;未明确批准就不放行 |
75
84
  | 未知工具、子代理、嵌套或未绑定请求 | 不自动放行 |
@@ -78,6 +87,14 @@ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。
78
87
 
79
88
  原生 `approval: never` 仍在任何应答者之前拒绝。不要与其他自动审批应答者叠加使用。
80
89
 
90
+ ## 读取配置和会话文件
91
+
92
+ `.codex`、`.dsh`、`.claude`、`.agents`、`.config` 等目录里的普通会话、技能和配置仍可读取。保护依据是专用凭据存储和实际凭据字段,不是整个目录。认证/凭据存储、SSH 私钥与私钥仓库被拒绝,普通公钥和证书可以读取。修改文件的限制仍更严格。
93
+
94
+ 原生 `read` 对 JSON/JSONC、JSONL、YAML、TOML、ENV/INI 和普通文本中的已识别凭据值隐藏显示,保留非秘密字段、引用路径、原行号和宿主输出上限。脱敏后的结构化值同时生成显示内容和元数据。原生 `grep` 在宿主落盘完整搜索结果之前脱敏或隐藏敏感匹配。包含秘密的编辑器查看操作、已知的 shell 原文转储会提示改用原生 `read`。
95
+
96
+ 结构化文件以完整内容检查,上限 1 MiB;较大的 JSONL 会话按完整的所选行处理(每行 1 MiB、所选原文合计 8 MiB)。损坏、不支持或超限的结构化内容返回安全错误,不返回原文片段。通过当前挂载的文件系统核对真实目标、版本和返回窗口。没有特征的任意秘密无法仅凭文本识别。这些检查覆盖已核对的原生工具,不构成任意 Full Access 脚本、自定义工具或远程 provider 的秘密隔离沙箱。shell 结果不能靠执行后脱敏保证安全,因为 jobs 可能已经保存了原始输出。
97
+
81
98
  ## 从 0.1.x 迁移
82
99
 
83
100
  - profile 键 `mode`、`workspaceRoots`、`shellCandidates`、`escalationCandidates`、`endpoint`、`apiKeyEnv`、`tokenField`、`fast*`/`deep*` 以及熔断 `sessionBudgetUnits`/`totalDenials` 已删除;仍携带这些键的 profile 会校验失败。0.1.x 的 `approvalReview: true` 加插件页启用,现在就是唯一行为。
@@ -89,7 +106,7 @@ bundle 会插入 `dsh-safe-auto` 与 `dsh-safe-auto-ui` 两个 profile 条目。
89
106
  - **不是经过审计的安全边界。** 审核方是语言模型,可能出错,尤其在对抗性上下文中。保留你原本依赖的原生沙箱、隔离和备份。
90
107
  - **静态证明以操作者信任 PATH 和运行时为前提。** 它检查原始命令文本,不核验已安装二进制、shell 函数或环境运行时的完整性。显式程序路径、`.exe`/`.cmd` 后缀、大小写变体、可执行 pager/配置环境前缀和会持久化的赋值都不符合条件。解析器或语法缺陷仍可能造成错误证明;这不是运行时认证,也不保证绝对安全。无法证明的命令回到审核/人工确认,不新增硬拒绝。
91
108
  - **引号不能绕过硬拒绝。** 保护路径和秘密检查先读取解码后的字面参数、环境及重定向值,包括相邻引号片段拼接;退出静态通道时仍执行这些检查,模型或人工确认不能覆盖。引号旁的未引用通配符仍使静态证明失败。Bash 的 `/dev/tcp`、`/dev/udp` 文件重定向回到审核,包括引用过的路径及编号 fd 输入重定向;普通文件输入、fd 合并和 `/dev/null` 输出保留原有规则。
92
- - **Git 的子命令名不能证明只读。** 裸 `git status`、工作区 diff、`git ls-files --modified` 及其他工作区内容检查继续审核,因为刷新和内容转换可能执行配置中的 clean/process filter。支持的对象/索引读取必须在原始参数中带 `--no-pager --no-optional-locks --no-lazy-fetch -c core.fsmonitor=false`;暂存区 diff 还需 `--no-ext-diff --no-textconv --ignore-submodules=all`。历史读取另需 `--no-show-signature` 和受支持的固定格式,例如 `--oneline`。插件不会补参数或重写命令。精确的 `git version`、`git --no-pager config --get user.name` 是独立的窄范围读取;传输 helper、编辑器、filter 和混合配置修改都不能走快速通道。普通 `sort` 可能写临时文件,因此只保留其检查模式。
109
+ - **Git 的子命令名不能证明安全。** 内容、历史、远程 URL 和配置枚举即使带有防修改参数,也要经过审核。元数据命令仍须满足“不修改”语法要求的原始控制参数。精确的 `git version`、`git --no-pager config --get user.name`/`user.email` 可走窄范围静态通道。插件不会补参数或重写命令。
93
110
  - **独立确认通道。** 当前 DSH 0.2.0-rc.2 的审批和问答链允许自动应答器。人工确认改用插件已认证的浏览器 HTTP 入口和不可预测、单次使用的请求 ID。Fetch Metadata 与宿主的来源、认证检查用于防跨站请求,并不证明物理真人点击;已认证客户端、其传输层和同进程插件仍然可信。不向模型注册审批工具。
94
111
  - **服务端掌握时限。** 请求发布后开始计时,用单调时钟判定到期,只接受第一个有效答案。重复、迟到和跨会话回答均失败。停用、修改设置、卸载或取消会使待审批失效;请求仅存内存,重启不会恢复。兼容直接浏览器请求与已认证的 DSH 桌面传输;不符合要求的请求类型仍会被拒绝。
95
112
  - **其他插件的原生审批保持原生流程。** 没有 Safe Auto 自有执行上下文时,Blueprint 顺序审批、Classmates 模型审批会继续交给后续处理器。已有自有上下文中的不匹配、过期、已领取请求,以及无上下文却冒用 `bash`/`pwsh`/`write`/`edit` 的请求仍然关闭放行。
package/docs/ADR-0006.md CHANGED
@@ -15,13 +15,13 @@ Two sibling harnesses informed the redesign. ZCode's build/edit modes downgrade
15
15
 
16
16
  Parse shell commands with `unbash` (Apache-2.0, zero-dependency bash parser, runtime dependency) in a new `src/shell-command.js`. The analysis accepts only a fully literal command: Statement/AndOr/Pipeline/Command/Time nodes, no backgrounding, no heredoc bodies, and every word, assignment value and redirect target free of expansions, globs and tilde prefixes. Anything else returns `ok: false` and changes nothing about the existing pipeline.
17
17
 
18
- **Read-only fast path.** When the structural assessment reaches `review`, a fully literal bash escalation is granted `allowed-once` with `STATIC_READONLY` only if every invocation satisfies its complete positive grammar. Exact case-sensitive POSIX executable names select policies. `rootName` normalization (paths, case and Windows suffixes) is only for danger detection. There are no arbitrary-argument policies, unknown option abbreviations, general short-option clusters or deny-list proofs. Registered options have exact arity and value validators; each operation checks input/output operand counts and incompatible modes. `--` makes later flag-shaped tokens filenames. Unsupported syntax falls back to the existing reviewer/manual channel, not a hard denial.
18
+ **Static fast path.** When the structural assessment reaches `review`, a fully literal bash escalation is granted `allowed-once` with `STATIC_READONLY` only if every invocation satisfies both its complete no-mutation grammar and the separate `isSafeStaticExposure` metadata/literal-output check. Exact case-sensitive POSIX executable names select policies. `rootName` normalization (paths, case and Windows suffixes) is only for danger detection. Registered options have exact arity and value validators; each operation checks input/output operand counts and incompatible modes. Unsupported syntax falls back to the existing reviewer/manual channel, not a hard denial.
19
19
 
20
- Ordinary `ls -la`, `cat input | jq .name`, `grep -rn pattern src`, `find . -name "*.md"` and `ps aux` remain fast reads. `rg --pre`, archive/helper modes in `file`, reverse/output forms of `xxd`, a second output operand in `uniq`, executable pagers and mixed Git read/write operations do not qualify. `date --debug` and `--resolution` take no values, so they cannot consume a following set option. Only streaming `sort --check` qualifies: ordinary sorting can spill to temporary files. Bash `printf -v` and `%n` do not qualify because they assign shell variables.
20
+ `ls -la`, `pwd` and `find . -name "*.md"` retain the fast path. File-content readers, transformations, recursive content searches, process arguments and environment enumeration require review: no mutation does not imply no credential exposure. `printenv` is excluded. `rg --pre`, archive/helper modes, output operands, executable pagers and mixed Git read/write operations also fail the no-mutation grammar. `date --file` cannot pass the exposure check because parse errors may repeat source content. Bash `printf -v` and `%n` cannot pass because they assign shell variables.
21
21
 
22
22
  Environment prefixes are checked before handling empty argv. Only explicit bounded values for CI, locale, color, terminal dimensions and UTC/GMT timezone settings are allowed, without duplicate names. Assignment-only statements do not qualify, including safe-looking assignments, because they persist into later compound invocations. Thus `PATH=.; ls` and `PAGER=node; git log` cannot alter subsequent resolution inside a supposedly read-only compound. PAGER, GIT_PAGER, Git configuration/transport and dynamic-loader environment prefixes are excluded.
23
23
 
24
- **Git proof scope.** A read-like subcommand is insufficient. Worktree status/diff can invoke configured clean/process filters during index refresh or conversion; no generic argv-only switch disables every named filter, so these operations always fall back. Supported object/index reads require the original global `--no-pager --no-optional-locks --no-lazy-fetch -c core.fsmonitor=false`. Diff proof is limited to `--cached`/`--staged` with at most one operand (also excluding implicit two-path no-index mode) and requires `--no-ext-diff --no-textconv --ignore-submodules=all`. History reads require the same diff controls, `--no-show-signature`, and a supported fixed format (`--oneline` or a bounded non-signature format), excluding `%G*` verification placeholders. Exact version calls and `git --no-pager config` with one getter/list operation and correct arity are independently narrow reads. Editors, reflog mutations, transport commands, external diff/textconv/filter modes, unknown options and mixed config mutations never qualify. Controls are recognized in the unchanged original argv; nothing is prepended or rewritten.
24
+ **Git proof scope.** A read-like subcommand is insufficient. Worktree status/diff can invoke configured clean/process filters. The no-mutation grammar retains explicit controls for object/index commands, but content, history, remote URLs and configuration enumeration fail the separate exposure check and continue to review. Metadata listings retain their original disabling controls. Exact version calls and `git --no-pager config --get user.name` / `user.email` are narrow static cases. Controls are recognized in unchanged argv; nothing is prepended or rewritten.
25
25
 
26
26
  `pwsh` always uses review because its grammar differs. The static grant keeps the complete execution binding, one claim, cancellation, control epoch, audit and recheck-before-grant machinery. It consumes no model review budget and touches no denial streak. Profile key `staticReadonly` (default `true`, operator-owned, not UI-editable) disables the fast path.
27
27
 
@@ -39,7 +39,15 @@ This is not the return of candidate rules. Nothing is enrolled, persisted, prefi
39
39
 
40
40
  ## Trust and limitations
41
41
 
42
- The accepted trust boundary remains operator-trusted PATH resolution and installed runtimes. This is a proof over the unchanged command text, not binary identity, shell-function integrity or runtime attestation. Within that boundary the supported grammar excludes known filesystem writes, network/helper execution and persistent environment changes; it is intentionally incomplete. Output can still expose workspace contents to the model context, which is already trusted with them. Unsupported commands cost review, never a new denial. Parser or grammar defects may produce incorrect proofs; strict parsing and positive rules reduce that risk but do not establish an absolute guarantee.
42
+ The accepted trust boundary remains operator-trusted PATH resolution and installed runtimes. This is a proof over unchanged command text, not binary identity, shell-function integrity or runtime attestation. Unknown commands cost review; known dedicated credential targets remain hard refusals. Parser or grammar defects may produce incorrect proofs; strict parsing and positive rules reduce that risk but do not establish an absolute guarantee.
43
+
44
+ ## Credential reads (2026-10-13 correction)
45
+
46
+ Read protection follows dedicated credential stores and recognized values, not whole agent directories. Write protection retains the prior stricter configuration/instruction boundary. Native `read` runs its own validation, caps and observation logic; the around-execution layer replaces successful structured values before post-execute, rendering and persistence. Complete-source parsers preserve original character positions, allowing the original offset, line and byte windows to remain exact. Native grep results are similarly projected before its formatted-result spill callback. Secret-bearing `str_replace_editor view` calls direct callers to `read`.
47
+
48
+ The verified native read body retains raw content only in memory before returning; its `fs/observed` event contains kind/version, not content. The wrapper returns a fresh minimal result, without copying raw content or metadata. The mounted provider resolves canonical targets and source versions. Complete structured sources are bounded at 1 MiB; large JSONL uses complete selected lines, with per-line/window caps. Errors and incoherent windows withhold content. The implementation uses `jsonc-parser`, `yaml` and `toml-eslint-parser` for grammar/range handling, not a custom configuration parser.
49
+
50
+ Shell jobs may retain raw output before around-execution returns. Therefore known credential or secret-bearing absolute file inputs are refused before execution; no post-output secrecy guarantee is claimed. Relative and opaque shell programs are not proven safe by the new static path. Arbitrary Full Access scripts, custom/remote readers and opaque secrets remain outside this recognizer's guarantee. The README documents supported formats and size limits.
43
51
 
44
52
  The fast path skips execution evidence collection and the model assessment row. Its approval audit row carries `STATIC_READONLY` with `static` as the source. Local `staticReadonly: false`, disable or unload remains the rollback. Tests challenge helper/value/cluster alternatives, output operands, persistent assignments, executable identity and Git configuration effects, then exercise the actual adapter fallback and pinned Cordis/ToolRuntime/ApprovalService waterfall. These are source and fixture-runtime checks, not live OS confinement or real-user acceptance.
45
53
 
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "@klarkxy/dsh-safe-auto",
3
- "version": "0.2.0-rc.3",
3
+ "version": "0.2.0",
4
4
  "main": "src/index.js",
5
5
  "description": "Safe Auto: an independent reviewer vets each native sandbox escalation; only a pass auto-approves that one call.",
6
6
  "engines": {