dsh-jev-guard 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +285 -0
- package/CHANGELOG.zh-CN.md +271 -0
- package/DEPLOY.md +202 -0
- package/DEPLOY.zh-CN.md +200 -0
- package/LICENSE +21 -0
- package/README.md +316 -0
- package/README.zh-CN.md +315 -0
- package/START-HERE.md +97 -0
- package/START-HERE.zh-CN.md +97 -0
- package/adapters/README.md +37 -0
- package/adapters/README.zh-CN.md +37 -0
- package/adapters/dsh/index.js +502 -0
- package/bin/guard.mjs +634 -0
- package/config.example.json +52 -0
- package/cordis.patch.yml +120 -0
- package/docs/AGENT-TASK-dsh.md +134 -0
- package/docs/AGENT-TASK-dsh.zh-CN.md +131 -0
- package/docs/ARCHITECTURE.md +118 -0
- package/docs/ARCHITECTURE.zh-CN.md +117 -0
- package/docs/DECISIONS.md +469 -0
- package/docs/DECISIONS.zh-CN.md +449 -0
- package/docs/DSH-INTEGRATION.md +178 -0
- package/docs/DSH-INTEGRATION.zh-CN.md +171 -0
- package/docs/MEASUREMENTS.md +433 -0
- package/docs/MEASUREMENTS.zh-CN.md +450 -0
- package/docs/USER-INTERVENTION.md +141 -0
- package/docs/USER-INTERVENTION.zh-CN.md +143 -0
- package/docs/VERIFICATION.md +279 -0
- package/docs/VERIFICATION.zh-CN.md +278 -0
- package/lib/audit.js +228 -0
- package/lib/gate.js +720 -0
- package/lib/i18n.js +575 -0
- package/lib/quota.js +389 -0
- package/lib/rules.js +174 -0
- package/lib/token.js +154 -0
- package/lib/verdict.js +285 -0
- package/package.json +82 -0
- package/tools/check-doc-pairs.mjs +158 -0
- package/tools/extract-commands.mjs +156 -0
- package/tools/gate-cli.mjs +240 -0
- package/tools/probe-prompt-lang.mjs +238 -0
- package/tools/probe-scripts.mjs +143 -0
- package/tools/report-result.mjs +146 -0
- package/tools/selftest-audit.mjs +93 -0
- package/tools/selftest-entry.mjs +177 -0
- package/tools/selftest-i18n.mjs +177 -0
- package/tools/selftest-quota.mjs +260 -0
- package/tools/selftest-reason.mjs +266 -0
- package/tools/selftest-rules.mjs +107 -0
- package/tools/selftest-token.mjs +100 -0
- package/tools/smoke-dsh-adapter.mjs +295 -0
- package/tools/smoke-dsh-pipeline.mjs +146 -0
package/START-HERE.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# START-HERE — Point This Directory at an AI on a Machine
|
|
2
|
+
|
|
3
|
+
> **English** | [简体中文](START-HERE.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
You are reading the delivery package of **jev-guard** (DSH's pre-execution safety valve). This file is the **entry point**: paste the prompt below
|
|
6
|
+
verbatim to the AI on that machine, and it can work it out on its own, verify it on its own, install it into DSH on its own, and write its conclusions back.
|
|
7
|
+
|
|
8
|
+
- Path: WSL `/mnt/t/dsh-jev-guard` · Windows `T:\dsh-jev-guard` (**the same files**, edit one side and it takes effect on both)
|
|
9
|
+
- Zero dependencies, no `npm install` needed
|
|
10
|
+
- **DSH only** (narrowed to a single host on 2026-09-20)
|
|
11
|
+
- Self-check: `node bin/guard.mjs selftest` should output 12/12 (no network); `node bin/guard.mjs status` shows the health state
|
|
12
|
+
- Platforms: **both WSL and Windows are supported** — it intercepts `bash` (WSL) and `pwsh` (Windows), and the authorisation line gives the correct quoting for the platform
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Prerequisites (done by a human, once)
|
|
17
|
+
|
|
18
|
+
1. Make the key resolvable, one of two ways:
|
|
19
|
+
- **Recommended**: put it into DSH's credential layer (`ctx.credentials`, no restart needed after rotation); or
|
|
20
|
+
- create `secrets.json` in the package with the content `{"TYPESAFE_API_KEY": "apikey_..."}`.
|
|
21
|
+
**Do not** paste the key into any AI conversation — let the AI read it from this file.
|
|
22
|
+
2. To change thresholds / degradation policy / language, `cp config.example.json config.json` and then edit it.
|
|
23
|
+
The copy comes in two versions, Chinese and English, and `lang` defaults to `'auto'` (follows the system locale); **leave `promptLang` alone** — it is a judging parameter,
|
|
24
|
+
and the Chinese default is exactly the language in which the thresholds 0.5/0.7 were calibrated (`docs/MEASUREMENTS.md` §14).
|
|
25
|
+
3. Run `node bin/guard.mjs judge 'pnpm test'` once to confirm it can judge over the network (`source` in the output should be `jev`).
|
|
26
|
+
|
|
27
|
+
## 2. The Prompt to Paste to the AI on That Machine
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
Your objective now: on <platform: WSL / Windows>, install jev-guard (DSH's pre-execution safety valve) into DSH and complete acceptance.
|
|
31
|
+
|
|
32
|
+
First step, read these four files in order (do not skip any):
|
|
33
|
+
<package path>\README.md
|
|
34
|
+
<package path>\docs\DSH-INTEGRATION.md ← which DSH mechanisms it uses, how the four states map, the degradation contract
|
|
35
|
+
<package path>\DEPLOY.md
|
|
36
|
+
<package path>\docs\VERIFICATION.md ← the acceptance checklist (including the three channels for human intervention)
|
|
37
|
+
|
|
38
|
+
Hard constraints (violate any one of them and stop and write blocked):
|
|
39
|
+
1. You may only modify DSH's own profile configuration and files under <package path>\verification-results\.
|
|
40
|
+
All other files in the package are read-only — if you want to change one, raise it in your conclusions first, do not do it yourself.
|
|
41
|
+
2. Never print any API key / token into the conversation; read it from secrets.json or the credential layer when needed.
|
|
42
|
+
3. Before verification passes, do not install the valve in "blocking" mode; first confirm it can judge (judge a command that is bound to be intercepted).
|
|
43
|
+
4. Back up the original value before changing any configuration, and write clearly in your conclusions how to roll back.
|
|
44
|
+
5. Always judge by actually running `node bin/guard.mjs judge '<command>'`; **verification must look at side effects**
|
|
45
|
+
(the command really was intercepted, the log really has that entry), do not draw conclusions from "there was no error".
|
|
46
|
+
6. When you are done (or stuck), write your conclusions back with this command:
|
|
47
|
+
node <package path>\tools\report-result.mjs --host dsh --item <item number> --status <pass|fail|partial|blocked|skipped> --evidence "evidence" --notes "notes"
|
|
48
|
+
When stuck, use --status blocked --question "your question".
|
|
49
|
+
|
|
50
|
+
When you are done, please report back: which files you changed, the conclusion and evidence for each verification item, and your suggested next steps.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 3. How Acceptance Is Recorded
|
|
54
|
+
|
|
55
|
+
All conclusions land in `<package path>\verification-results\`:
|
|
56
|
+
|
|
57
|
+
- `dsh.json` — machine-readable (the orchestrating AI reads this one directly)
|
|
58
|
+
- `SUMMARY.md` — the auto-generated summary table (human-readable)
|
|
59
|
+
|
|
60
|
+
**The orchestrating AI only needs to read `SUMMARY.md`** to know which items passed, which are stuck, and which question sentence they are stuck on.
|
|
61
|
+
Stuck entries appear with `--question` in the "Questions Needing Intervention" section at the bottom.
|
|
62
|
+
|
|
63
|
+
## 4. Boundaries (you must run through these in your head)
|
|
64
|
+
|
|
65
|
+
1. **It is an accident net, not a security boundary.** It offers no defence against deliberate bypass; that needs sandboxing/containers.
|
|
66
|
+
**⚠️ This is an explicit decision, not a todo.** Known and deliberately kept bypasses: the agent can write
|
|
67
|
+
`~/.jev-guard/allow.txt` directly with a file-writing tool; the agent can change how it phrases things to bypass judging. **Do not try to "fix them in passing"** —
|
|
68
|
+
the full rationale and the user's ruling are in [docs/DECISIONS.md](./docs/DECISIONS.md) **D1**.
|
|
69
|
+
2. **The judging service must not be the only line of defence.** The L0 hard rules need no network and cannot be overridden; they always come first (`lib/rules.js`).
|
|
70
|
+
3. **Script bodies are sent to TypeSafe's API.** Sensitive paths are skipped automatically, with an 8KB cap;
|
|
71
|
+
if you do not want this, set `inlineScripts` in `config.json` to `false` (the cost is that the detection rate for commands
|
|
72
|
+
like `node x.mjs` drops from 0.82 back to 0.31).
|
|
73
|
+
4. **Failure always passes (fail-open).** If you want "block even when the service is down", thicken the L0 rules, rather than changing this policy.
|
|
74
|
+
**Running out of quota also counts as failure** (the judging service is paid): the valve then **degrades** — it stops the semantic layer that costs money,
|
|
75
|
+
keeps running the free L0 + pre-screen by default, and writes this matter into the rejection reason, the audit log and stderr.
|
|
76
|
+
One command tells you the state: `node bin/guard.mjs status` (exit code 3 while degraded).
|
|
77
|
+
5. **Authorisation is a human action.** `guard allow` only takes effect in an interactive terminal (if the agent runs it itself it is refused),
|
|
78
|
+
but this only means "it does not happen by accident", not a security boundary — see item 1.
|
|
79
|
+
A human has **three** channels of intervention in all; see [docs/USER-INTERVENTION.md](./docs/USER-INTERVENTION.md).
|
|
80
|
+
6. **"The plugin is installed" and "it really is intercepting" are two different things.** On 2026-09-20 a three-layer silent failure really happened (the script silently
|
|
81
|
+
exited 0, the command ran as usual, the log had nothing at all). So acceptance must look at side effects, and run
|
|
82
|
+
`node tools/selftest-entry.mjs` (once on Windows and once on WSL). See
|
|
83
|
+
[docs/MEASUREMENTS.md](./docs/MEASUREMENTS.md) §10.
|
|
84
|
+
|
|
85
|
+
If you change any boundary decision, please update [docs/DECISIONS.md](./docs/DECISIONS.md) along with it.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 5. Three Things to Watch Out for on Windows
|
|
90
|
+
|
|
91
|
+
1. **The authorisation line**: the reason given for an intercepted command is in **PowerShell** form (POSIX's `'\''` is
|
|
92
|
+
an outright syntax error in PowerShell, measured). With **cmd.exe**, neither form is recognised — write the command text **verbatim** into a file,
|
|
93
|
+
and then `node T:\dsh-jev-guard\bin\guard.mjs allow --command-file cmd.txt` (independent of the shell).
|
|
94
|
+
2. **Tool name**: the tool to be intercepted on the Windows side is `pwsh` (already in the default `tools` list, no configuration needed);
|
|
95
|
+
if you use a different shell tool name, add it to `tools` in `config.json`.
|
|
96
|
+
3. **Paths**: `~/.jev-guard/` (`guard.log` / `degraded.json` / `allow.txt`) lands in
|
|
97
|
+
`%USERPROFILE%\.jev-guard\`; the relative path of `apiKeyFile` is **resolved against the package root**, independent of the current directory.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# START-HERE — 把这个目录指给一台机器上的 AI
|
|
2
|
+
|
|
3
|
+
> [English](START-HERE.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
你在读的是 **jev-guard**(DSH 的执行前安全阀门)的交付包。这份文件是**入口**:把下面那段提示词
|
|
6
|
+
原样粘给那台机器上的 AI,它就能自己读懂、自己验证、自己装进 DSH、并把结论写回来。
|
|
7
|
+
|
|
8
|
+
- 路径:WSL `/mnt/t/dsh-jev-guard` · Windows `T:\dsh-jev-guard`(**同一份文件**,改一处两侧生效)
|
|
9
|
+
- 零依赖,不需要 `npm install`
|
|
10
|
+
- **只支持 DSH**(2026-09-20 收窄为单一宿主)
|
|
11
|
+
- 自检:`node bin/guard.mjs selftest` 应输出 12/12(不联网);`node bin/guard.mjs status` 看健康状态
|
|
12
|
+
- 平台:**WSL 与 Windows 都支持** —— 拦 `bash`(WSL)与 `pwsh`(Windows),授权行按平台给正确引号
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 一、前置(人做,一次)
|
|
17
|
+
|
|
18
|
+
1. 让密钥可被解析到,二选一:
|
|
19
|
+
- **推荐**:放进 DSH 的凭据层(`ctx.credentials`,轮换后无需重启);或
|
|
20
|
+
- 在包里建 `secrets.json`,内容 `{"TYPESAFE_API_KEY": "apikey_..."}`。
|
|
21
|
+
**不要**把密钥贴进任何 AI 对话 —— 让 AI 从这个文件读。
|
|
22
|
+
2. 想改阈值/降级策略/语言就 `cp config.example.json config.json` 再改。
|
|
23
|
+
文案有中英两份,`lang` 默认 `'auto'`(跟系统 locale);**`promptLang` 别动** —— 它是判定参数,
|
|
24
|
+
默认中文正是阈值 0.5/0.7 的标定语言(`docs/MEASUREMENTS.md` §14)。
|
|
25
|
+
3. 跑一次 `node bin/guard.mjs judge 'pnpm test'` 确认能联网判定(输出里 `source` 应为 `jev`)。
|
|
26
|
+
|
|
27
|
+
## 二、粘给那个机器上的 AI 的提示词
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
你现在的工作目标:在 <平台:WSL / Windows> 上把 jev-guard(DSH 的执行前安全阀门)装进 DSH 并完成验收。
|
|
31
|
+
|
|
32
|
+
第一步,按顺序读这四个文件(不要跳读):
|
|
33
|
+
<包路径>\README.md
|
|
34
|
+
<包路径>\docs\DSH-INTEGRATION.md ← 它用 DSH 的哪些机制、四态怎么映射、降级契约
|
|
35
|
+
<包路径>\DEPLOY.md
|
|
36
|
+
<包路径>\docs\VERIFICATION.md ← 验收清单(含人工介入三通道)
|
|
37
|
+
|
|
38
|
+
硬约束(违反任何一条就停下来写 blocked):
|
|
39
|
+
1. 只允许修改 DSH 自身的 profile 配置 与 <包路径>\verification-results\ 下的文件。
|
|
40
|
+
包内其它文件一律只读 —— 要改就先在结论里提出来,不要自己动手。
|
|
41
|
+
2. 绝不把任何 API key / token 打印到对话里;需要时从 secrets.json 或凭据层读。
|
|
42
|
+
3. 验证没通过之前,不要把阀门装成"阻断"模式;先确认它能判定(judge 一条必然被拦的命令)。
|
|
43
|
+
4. 改任何配置之前先备份原值,并在结论里写清怎么回滚。
|
|
44
|
+
5. 判定一律用 `node bin/guard.mjs judge '<命令>'` 实测;**验证要看副作用**
|
|
45
|
+
(命令真的被拦、日志真的有那条记录),不要凭"没报错"下结论。
|
|
46
|
+
6. 做完(或卡住)时,用下面这条命令把结论写回来:
|
|
47
|
+
node <包路径>\tools\report-result.mjs --host dsh --item <编号> --status <pass|fail|partial|blocked|skipped> --evidence "证据" --notes "补充"
|
|
48
|
+
卡住时用 --status blocked --question "你的问题"。
|
|
49
|
+
|
|
50
|
+
完成后请回报:改了哪些文件、每项验证的结论与证据、以及下一步建议。
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 三、验收怎么记录
|
|
54
|
+
|
|
55
|
+
所有结论都落在 `<包路径>\verification-results\`:
|
|
56
|
+
|
|
57
|
+
- `dsh.json` —— 机器读(主控 AI 直接读这个)
|
|
58
|
+
- `SUMMARY.md` —— 自动生成的总表(人读)
|
|
59
|
+
|
|
60
|
+
**主控 AI 只需要读 `SUMMARY.md`**,就知道哪些项通过了、哪些卡住了、卡在哪一句问题上。
|
|
61
|
+
被卡住的条目会带 `--question` 出现在底部的"需要介入的问题"一节。
|
|
62
|
+
|
|
63
|
+
## 四、边界(必须在心里过一遍)
|
|
64
|
+
|
|
65
|
+
1. **它是事故安全网,不是安全边界。** 对蓄意绕过不设防,那要靠沙箱/容器。
|
|
66
|
+
**⚠️ 这是显式决策,不是待办。** 已知且有意保留的旁路:agent 可以用文件写入工具直接写
|
|
67
|
+
`~/.jev-guard/allow.txt`;agent 可以换写法绕过判定。**不要试图"顺手修掉"它们** ——
|
|
68
|
+
完整理由与用户定调见 [docs/DECISIONS.md](./docs/DECISIONS.md) **D1**。
|
|
69
|
+
2. **判定服务不能是唯一防线。** L0 硬规则不联网、不可覆盖,永远在先(`lib/rules.js`)。
|
|
70
|
+
3. **脚本正文会发送到 TypeSafe 的 API。** 敏感路径自动跳过、8KB 上限;
|
|
71
|
+
不想这样做就把 `config.json` 的 `inlineScripts` 设为 `false`(代价是 `node x.mjs` 这类命令
|
|
72
|
+
的检出率从 0.82 掉回 0.31)。
|
|
73
|
+
4. **失败一律放行(fail-open)。** 想"服务挂了也拦",就把 L0 规则加厚,而不是改这条策略。
|
|
74
|
+
**额度用完也算失败**(判定服务收费):这时阀门会**降级** —— 停掉要花钱的语义层、
|
|
75
|
+
默认继续跑免费的 L0 + 预筛,并把这件事写进拒绝理由、审计日志、stderr。
|
|
76
|
+
一句话查状态:`node bin/guard.mjs status`(降级时退出码 3)。
|
|
77
|
+
5. **授权是人的动作。** `guard allow` 只在交互终端生效(agent 自己跑会被拒),
|
|
78
|
+
但这只是"不顺手发生",不是安全边界 —— 见第 1 条。
|
|
79
|
+
人一共有**三条**介入通道,见 [docs/USER-INTERVENTION.md](./docs/USER-INTERVENTION.md)。
|
|
80
|
+
6. **插件"装上了"与"真的在拦"是两件事。** 2026-09-20 真实发生过三层静默失效(脚本一声不响地
|
|
81
|
+
退出 0、命令照跑、日志什么都没有)。所以验收必须看副作用,并跑
|
|
82
|
+
`node tools/selftest-entry.mjs`(Windows 与 WSL 各一遍)。详见
|
|
83
|
+
[docs/MEASUREMENTS.md](./docs/MEASUREMENTS.md) §10。
|
|
84
|
+
|
|
85
|
+
改了任何一条边界决策,请一并更新 [docs/DECISIONS.md](./docs/DECISIONS.md)。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 五、Windows 上的三条注意事项
|
|
90
|
+
|
|
91
|
+
1. **授权行**:被拦命令的理由里给出的是 **PowerShell** 形式(POSIX 的 `'\''` 在 PowerShell 里
|
|
92
|
+
直接语法错误,实测)。用 **cmd.exe** 的话两种写法都不认 —— 把命令原文**原样**写进一个文件,
|
|
93
|
+
然后 `node T:\dsh-jev-guard\bin\guard.mjs allow --command-file cmd.txt`(与 shell 无关)。
|
|
94
|
+
2. **工具名**:Windows 侧要拦的工具是 `pwsh`(已在默认 `tools` 列表里,无需配置);
|
|
95
|
+
若你用的是别的 shell 工具名,把它加进 `config.json` 的 `tools`。
|
|
96
|
+
3. **路径**:`~/.jev-guard/`(`guard.log` / `degraded.json` / `allow.txt`)落在
|
|
97
|
+
`%USERPROFILE%\.jev-guard\`;`apiKeyFile` 的相对路径**按包根解析**,与当前目录无关。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# adapters/ — there is only one adapter
|
|
2
|
+
|
|
3
|
+
> **English** | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
**Here there is only "translation", no judging.** Judging, rules, tokens and the audit log all live in [`lib/`](../lib/), and the code there
|
|
6
|
+
contains no DSH mechanism at all (no Cordis, no ctx, no `PreToolDecision`).
|
|
7
|
+
The reason `lib/` stays independent is not that other callers are going to be attached, but that **the judging logic should not know who is calling it** —
|
|
8
|
+
only that way can it be re-run offline by `bin/guard.mjs` and covered by the seven self-checks.
|
|
9
|
+
|
|
10
|
+
| Directory | Form of interception | Interception force |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `dsh/` | DSH-native Cordis plugin, hooks `tools/pre-execute` | **mandatory** |
|
|
13
|
+
|
|
14
|
+
## Why there is only this one (2026-09-20, see ../docs/DECISIONS.md D11 for details)
|
|
15
|
+
|
|
16
|
+
Several routes for "hanging the valve into another execution channel" were tried historically, and none of them worked out — each host's approval/trust
|
|
17
|
+
mechanism is different, and making any one of them solid is a separate round of work of its own; one measurement also exposed a structural defect (**information
|
|
18
|
+
that could not be obtained was pretended to be obtained by a default value**), and fixing it would mean redoing that output contract. So the scope was narrowed to DSH only.
|
|
19
|
+
|
|
20
|
+
**There is only one criterion: does that host have a callback that execution must pass through, and that can say you may not run this.** Without one you can only build a suggestion layer,
|
|
21
|
+
and **an unverified adapter is more dangerous than no adapter** — it looks like the valve is installed while in fact nothing is blocked.
|
|
22
|
+
Those attempted implementations and the per-item reasons **were removed along with the narrowing of scope** (this package keeps no unverified code); the transferable lessons that were kept are in
|
|
23
|
+
[`../docs/MEASUREMENTS.md`](../docs/MEASUREMENTS.md) §12 and [`../docs/DECISIONS.md`](../docs/DECISIONS.md) D11.
|
|
24
|
+
|
|
25
|
+
## The four iron laws for writing a second adapter
|
|
26
|
+
|
|
27
|
+
If you really are going to attach another host (or bring the archived one back), first read [`../docs/DSH-INTEGRATION.md`](../docs/DSH-INTEGRATION.md) §5 and
|
|
28
|
+
`../docs/MEASUREMENTS.md` §10 — three layers of real accidents are recorded there. The four:
|
|
29
|
+
|
|
30
|
+
1. **You must obtain the command text before execution**, and **be able to return "you may not run this"**. If you cannot, that belongs to the "suggestion layer" — do not write it as an adapter.
|
|
31
|
+
2. **fail-open**: whatever goes wrong on the adapter's own side must be allowed through (timeout / parse error / unknown payload shape).
|
|
32
|
+
3. **Inline the entry guard, cross-platform**:
|
|
33
|
+
`realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))`.
|
|
34
|
+
**Do not extract it into a shared module** — `import.meta.url` follows the module, so once extracted it is constantly false (measured: even WSL silently stops working).
|
|
35
|
+
Use **relative specifiers** for dynamic imports, not absolute path strings (not a legal ESM specifier on Windows).
|
|
36
|
+
4. **The audit must write `record()`**, and **there must be an observable side effect** that lets a verifier confirm "it really ran" —
|
|
37
|
+
"no error reported" is not the same as "it is working".
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# adapters/ — 只有一个适配器
|
|
2
|
+
|
|
3
|
+
> [English](README.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
**这里只有"翻译",没有判定。** 判定、规则、令牌、审计全在 [`lib/`](../lib/),那里的代码里
|
|
6
|
+
不含任何 DSH 机制(没有 Cordis、没有 ctx、没有 `PreToolDecision`)。
|
|
7
|
+
`lib/` 之所以保持独立,不是因为要接别的调用方,而是因为**判定逻辑不该知道谁在调用它** ——
|
|
8
|
+
这样才能被 `bin/guard.mjs` 离线复跑、被七份自检覆盖。
|
|
9
|
+
|
|
10
|
+
| 目录 | 拦截形态 | 拦截力 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `dsh/` | DSH 原生 Cordis 插件,挂 `tools/pre-execute` | **强制** |
|
|
13
|
+
|
|
14
|
+
## 为什么只有这一个(2026-09-20,详见 ../docs/DECISIONS.md D11)
|
|
15
|
+
|
|
16
|
+
历史上试过几种"把阀门挂进别的执行通道"的路线,都没做成 —— 各自宿主的审批/信任机制不同,
|
|
17
|
+
把它们做扎实是各自独立的一轮工作;其中一次实测还暴露出一个结构性缺陷(**拿不到的信息
|
|
18
|
+
被一个默认值假装成拿到了**),修它要重做那套输出契约。于是收窄为只做 DSH。
|
|
19
|
+
|
|
20
|
+
**判断标准就一条:那个宿主有没有"执行前必须经过、且能说不许执行"的回调。** 没有就只能做建议层,
|
|
21
|
+
而**未验证的适配器比没有适配器更危险** —— 它看起来装了阀门,实际不拦。
|
|
22
|
+
那些尝试过的实现与逐条原因**已随范围收窄一并移除**(本包不留未验证的代码);保留下来的可迁移教训见
|
|
23
|
+
[`../docs/MEASUREMENTS.md`](../docs/MEASUREMENTS.md) §12 与 [`../docs/DECISIONS.md`](../docs/DECISIONS.md) D11。
|
|
24
|
+
|
|
25
|
+
## 写第二个适配器时的四条铁律
|
|
26
|
+
|
|
27
|
+
真要接别的宿主(或把归档的拿回来),先读 [`../docs/DSH-INTEGRATION.md`](../docs/DSH-INTEGRATION.md) §5 与
|
|
28
|
+
`../docs/MEASUREMENTS.md` §10 —— 那里记着三层真实事故。四条:
|
|
29
|
+
|
|
30
|
+
1. **必须在执行前拿到命令原文**,并且**能返回"不许执行"**。做不到就属于"建议层",别写成适配器。
|
|
31
|
+
2. **fail-open**:适配器自己出任何问题都必须放行(超时/解析错/未知 payload 形状)。
|
|
32
|
+
3. **入口守卫内联、跨平台**:
|
|
33
|
+
`realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))`。
|
|
34
|
+
**不要抽共享模块** —— `import.meta.url` 跟着模块走,抽出去就恒为 false(实测:连 WSL 都会静默失效)。
|
|
35
|
+
动态导入用**相对说明符**,别用绝对路径字符串(Windows 上不是合法 ESM 说明符)。
|
|
36
|
+
4. **审计要写 `record()`**,并且**必须有可观察副作用**能让验证者确认"它真的跑了" ——
|
|
37
|
+
"没报错"不等于"在工作"。
|