@goodandready/dsh-approval-gate 0.1.3

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 ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ ## 0.1.3
4
+
5
+ - First public npmjs release under the canonical @goodandready/dsh-approval-gate identity.
6
+
7
+ - Extend bounded shell analysis to command and process substitutions, backticks, common redirects and here-documents; inspect nested commands.
8
+ - Allow ordinary safe reads and route uncertain syntax or execution targets through DSH approval with a visible rule reason and redacted excerpt.
9
+ - Keep recognized destructive commands and protected-file writes denied, and request approval before shell-expanded Authorization values reach curl.
10
+ - Keep security hooks active when the optional locale service is unavailable.
11
+
12
+
13
+ ## 0.1.2
14
+
15
+ - Inspect bash argv after quote concatenation instead of regex over the raw string.
16
+ - Fail closed on unparseable shell (`$IFS`, command substitution, heredoc, unclosed quotes).
17
+ - Guard file-write tools against secret paths.
18
+ - Tests for block/pass cases. Denial text no longer names a person.
19
+ - Ignore `openwiki/` in git.
20
+
21
+ ## 0.1.1
22
+
23
+ - Initial distribution used an internal package route before the public npmjs identity introduced in 0.1.3.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GooDAnDReaDY
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # 📦 @goodandready/dsh-approval-gate
2
+
3
+ <div align="center">
4
+
5
+ <h3>Last-line command gate for DeepSeek Harness</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-approval-gate"><img src="https://img.shields.io/npm/v/@goodandready/dsh-approval-gate.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-approval-gate.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/All_projects-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="GoodAndReady Showcase"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>English</b></a> ·
20
+ <a href="README.zh.md"><b>中文说明</b></a> ·
21
+ <a href="README.ru.md"><b>Русский</b></a>
22
+ </p>
23
+
24
+ <table align="center">
25
+ <tr>
26
+ <td align="center">
27
+ ⭐ <strong>If you like this plugin, please star it on GitHub</strong> — it shows me that the plugin is useful to you and motivates me to keep developing it.
28
+ <br><br>
29
+ 🐛 <strong>If you find a bug or would like to request a feature</strong>, open a GitHub issue in any language — I will review your proposal and implement useful suggestions in a future plugin version.
30
+ </td>
31
+ </tr>
32
+ </table>
33
+
34
+ </div>
35
+
36
+ ---
37
+
38
+ ## Overview
39
+
40
+ DeepSeek Harness can still let an agent run a dangerous tool call when sandbox mode is loose. This host-only plugin registers a monotonic `tools.guard` and denies the call before the tool body runs.
41
+
42
+ Commands the guard cannot fully inspect are routed through DSH’s native approval flow. This plugin does not implement a separate approval word.
43
+
44
+ ## How it works
45
+
46
+ ```mermaid
47
+ graph LR
48
+ A[bash / file-write tool] --> B[dsh-approval-gate]
49
+ B -->|known safe| C[tool runs]
50
+ B -->|known dangerous| D[denial string]
51
+ B -->|uncertain syntax or target| E[DSH approval request]
52
+ ```
53
+
54
+ `lib/inspect.js` tokenizes the bash `command` (quotes, backslashes, pipelines, wrappers) and inspects the real argv. File-write tools are classified by path, not by regex over prose.
55
+
56
+ ## Architecture and modules
57
+
58
+ | Module | Responsibility |
59
+ |---|---|
60
+ | lib/index.js | Registers the monotonic tools.guard and pre-execution approval hook; wires the shell and file-write inspectors into DSH. |
61
+ | lib/inspect.js | Tokenizes bounded Bash syntax, inspects command argv and expansions, applies destructive-command and protected-write rules, and returns pass, deny, or ask decisions. |
62
+ | lib/messages.js | Provides English and Simplified Chinese rule names, explanations, and redacted-result labels. |
63
+ | cordis.patch.yml | Declares the host-side plugin bundle and optional tool configuration. |
64
+
65
+ The guard runs before the tool body. A recognized dangerous action is denied even if a prompt could otherwise be shown. Uncertain syntax or targets are sent to DSH approval; DSH policy still decides whether a prompt is available.
66
+
67
+ ## Coverage
68
+
69
+ | Call | Result |
70
+ |---|---|
71
+ | `rm -rf /tmp/x`, `sudo rm -r ...` | block |
72
+ | `kill` / `pkill` / `killall` as the command | block |
73
+ | `k''ill -9 1` (quoted fragments) | block |
74
+ | `systemctl restart\|stop\|disable ...` | block |
75
+ | `systemctl is-active dsh-web` | pass |
76
+ | `service name stop\|restart` | block |
77
+ | `sqlite3 ... DROP/ALTER/...` | block |
78
+ | `echo x > .env`, `tee`/`sed -i` on secret files | block |
79
+ | `write`/`edit` to `.env`, `credentials.yaml`, `settings.yaml`, `cordis.patch.yml` | block |
80
+ | `grep kill-all docs/`, `echo 'do not rm -rf'` | pass |
81
+ | `python3 -c "print('rm -rf')"` | pass |
82
+ | `$IFS`, `$(...)`, backticks, unclosed quotes, heredoc `<<` | request DSH approval |
83
+ | `bash -c "rm -rf /tmp/x"` | block (nested shell) |
84
+ | empty / missing `command` | pass (nothing to run) |
85
+ | non-string `command` | block (unknown format) |
86
+
87
+ ## What it does not guarantee
88
+
89
+ - It is not a full bash parser. Unknown or incomplete syntax requests approval; if approval is unavailable or approval=never is configured, DSH denies the call.
90
+ - Interpreter `-c`/`-e` is not a second language parser. Nested `bash -c` is inspected.
91
+ - Cron and systemd never pass through `tools.guard`.
92
+ - A script file created earlier and then executed as `bash ./run.sh` is not opened and scanned.
93
+
94
+ ## Install
95
+
96
+ Install from the public npm registry:
97
+
98
+ ```sh
99
+ dsh plugin --profile web add @goodandready/dsh-approval-gate@0.1.3
100
+ ```
101
+
102
+ Keep the guard enabled in profiles that need command-safety protection.
103
+
104
+ ## Configuration
105
+
106
+ Optional fields on the Cordis patch entry:
107
+
108
+ | Field | Type | Default | Meaning |
109
+ |---|---|---|---|
110
+ | `toolName` | string | `bash` | Tool whose `command` argument is inspected |
111
+ | `fileWriteTools` | string[] | `write`, `edit`, `Write`, `Edit`, `str_replace`, `apply_patch` | Tools classified by path |
112
+
113
+
114
+
115
+ Example Cordis patch configuration:
116
+
117
+ <pre><code>- insert:
118
+ - id: dsh-approval-gate
119
+ name: @goodandready/dsh-approval-gate
120
+ config:
121
+ toolName: bash
122
+ fileWriteTools:
123
+ - write
124
+ - edit
125
+ - Write
126
+ - Edit
127
+ - str_replace
128
+ - apply_patch
129
+ </code></pre>
130
+
131
+ ## HTTP routes and CLI
132
+
133
+ The plugin adds no HTTP routes and no standalone CLI. Install and remove it through the DSH plugin CLI. The plugin only guards supported DSH tool calls; it is not an operating-system sandbox.
134
+
135
+ ## License
136
+
137
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
138
+
139
+ ## Changes in v0.1.3
140
+
141
+ This is the first public npmjs release under the canonical @goodandready/dsh-approval-gate identity.
142
+
143
+ Changed in v0.1.3: earlier internal instructions described a separate operator confirmation word. The public package routes uncertain commands through DSH native approval and does not define its own word. Earlier builds used internal distribution; new installs use the public npmjs identity.
144
+
145
+ This release adds bounded shell syntax analysis and routes uncertain cases through DSH approval while preserving denies for recognized destructive operations and protected-file writes.
146
+
147
+ The shell analyzer now understands command substitutions, backticks, process substitutions, common redirects including 2> and &>, pipelines, and here-documents. It recursively checks nested shell commands and executable expansions. Ordinary safe reads can pass. Shell-expanded authorization headers request approval because curl receives the credential as a process argument. This package does not provide a credential-safe API helper; keep tokenized API calls out of command-line arguments.
148
+
149
+ The locale service is optional; the security hooks remain active with English fallback messages when it is unavailable.
150
+
151
+ Recognized destructive commands and writes to protected files remain denied. This includes recursive rm, process signals, service stop/restart operations, destructive SQL, protected-file writes, git reset --hard, forced git clean, mkfs, device-targeted dd, and downloaded content piped to a shell.
152
+
153
+ Unsupported or incomplete syntax, dynamic command names or redirect targets, and script files whose contents cannot be inspected request approval through DSH. If approval is unavailable or approval=never is configured, DSH rejects the request. The plugin does not read script files or implement a separate approval word. Messages identify the rule and include a redacted excerpt. This is a bounded shell analyzer, not a complete Bash grammar.
package/README.ru.md ADDED
@@ -0,0 +1,126 @@
1
+ # 📦 @goodandready/dsh-approval-gate
2
+
3
+ <div align="center">
4
+
5
+ <h3>Дополнительная защита командных инструментов DSH</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-approval-gate"><img src="https://img.shields.io/npm/v/@goodandready/dsh-approval-gate.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-approval-gate.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/Все_проекты-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="GoodAndReady Showcase"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>🇬🇧 English</b></a> •
20
+ <a href="README.zh.md"><b>🇨🇳 中文说明</b></a> •
21
+ <a href="README.ru.md"><b>🇷🇺 Русский</b></a>
22
+ </p>
23
+
24
+ <table align="center">
25
+ <tr><td align="center">⭐ <strong>Если вам нравится этот плагин, поставьте ему Star на GitHub</strong> — это покажет, что он полезен, и мотивирует продолжать его развитие.<br><br>🐛 <strong>Если вы нашли ошибку или хотите предложить функцию</strong>, создайте Issue на GitHub на любом языке — полезные предложения будут рассмотрены для следующих версий.</td></tr>
26
+ </table>
27
+
28
+ </div>
29
+
30
+ ---
31
+
32
+ ## Обзор
33
+
34
+ Плагин безопасности для хоста DSH: до запуска тела инструмента блокирует опасные вызовы bash и запись в защищённые файлы. Неопределённые команды передаются штатному механизму подтверждения DSH; плагин не вводит отдельное слово подтверждения.
35
+
36
+ Таблица покрытия, ограничения и конфигурация — в [README.md](README.md).
37
+
38
+ Установка (публичный пакет npm):
39
+
40
+ ```sh
41
+ dsh plugin --profile web add @goodandready/dsh-approval-gate@0.1.3
42
+ ```
43
+
44
+ ## Изменения в v0.1.3
45
+
46
+ Первый публичный выпуск под идентичностью @goodandready/dsh-approval-gate.
47
+
48
+ Изменено в v0.1.3: прежние внутренние инструкции описывали отдельное слово подтверждения оператора. Публичная версия передаёт неопределённые команды штатному подтверждению DSH и не определяет собственное слово; новые установки используют публичный пакет npmjs.
49
+
50
+ Выпуск добавляет ограниченный разбор shell-синтаксиса и передаёт неопределённые случаи в запрос подтверждения DSH, сохраняя запреты на распознанные разрушительные команды и запись в защищённые файлы.
51
+
52
+ Анализатор shell-команд теперь понимает подстановки команд, обратные кавычки, подстановки процессов, основные перенаправления, включая 2> и &>, конвейеры и here-document. Он рекурсивно проверяет вложенные shell-команды и исполняемые раскрытия. Обычные безопасные чтения разрешены. Подстановка секрета в заголовок Authorization требует подтверждения: curl получает его как аргумент процесса. В этом пакете пока нет безопасного помощника для работы с учётными данными; не передавайте токен в аргументах команды.
53
+
54
+ Сервис локализации необязателен: если его нет, защитные хуки работают с английскими сообщениями.
55
+
56
+ Известные разрушительные команды и записи в защищённые файлы по-прежнему запрещены. К ним относятся рекурсивный rm, сигналы процессам, остановка и перезапуск служб, разрушительный SQL, запись в защищённые файлы, git reset --hard, принудительный git clean, mkfs, запись dd на устройство и передача загруженного содержимого shell.
57
+
58
+ Для незакрытого или неподдерживаемого синтаксиса, динамического имени команды или цели перенаправления, а также файла скрипта, содержимое которого невозможно проверить, DSH запрашивает подтверждение. Если подтверждение недоступно или задано approval=never, DSH отклоняет запрос. Плагин не читает файлы скриптов и не вводит отдельное слово подтверждения. Сообщение называет правило и показывает обезличенный фрагмент команды. Это ограниченный анализатор shell, а не полный парсер Bash.
59
+
60
+ ## Архитектура и возможности
61
+
62
+ | Модуль | Назначение |
63
+ |---|---|
64
+ | lib/index.js | Регистрирует монотонный tools.guard и штатный pre-execution approval hook DSH, подключает проверки shell и файловых записей. |
65
+ | lib/inspect.js | Разбирает ограниченный shell-синтаксис, проверяет argv и подстановки, применяет правила опасных команд и защищённых записей, возвращает pass, deny или ask. |
66
+ | lib/messages.js | Содержит английские и китайские названия правил, пояснения и подписи для обезличенного фрагмента. |
67
+ | cordis.patch.yml | Объявляет host-пакет плагина и необязательную конфигурацию инструментов. |
68
+
69
+ ```mermaid
70
+ graph LR
71
+ A[Вызов инструмента агентом] --> B[dsh-approval-gate]
72
+ B -->|Команда распознана и безопасна| C[Запуск инструмента]
73
+ B -->|Известное опасное действие| D[Запрет]
74
+ B -->|Синтаксис или цель неясны| E[Подтверждение DSH]
75
+ ```
76
+
77
+ Распознанные опасные действия запрещаются. Если нельзя проверить синтаксис, имя команды, аргументы, цель перенаправления или записи, плагин передаёт запрос штатному подтверждению DSH. При approval=never DSH отклоняет неопределённый запрос. Безопасные и полностью проверенные команды проходят.
78
+
79
+ ### Что проверяется
80
+
81
+ | Пример вызова | Результат |
82
+ |---|---|
83
+ | rm -rf /tmp/x, sudo rm -r ... | Запрет |
84
+ | kill, pkill, killall | Запрет |
85
+ | systemctl stop/restart/disable | Запрет; systemctl is-active проходит |
86
+ | service name stop/restart | Запрет |
87
+ | Разрушительные DROP/ALTER и подобный SQL | Запрет |
88
+ | Запись в .env, credentials.yaml, settings.yaml или cordis.patch.yml | Запрет |
89
+ | Чтение защищённой настройки и упоминание опасной команды в обычном тексте | Разрешено |
90
+ | Незакрытый heredoc, динамическое имя команды или непроверяемый файл скрипта | Запрос подтверждения DSH |
91
+
92
+ ### Настройка
93
+
94
+ В элементе плагина в Cordis patch можно задать поля:
95
+
96
+ | Поле | Тип | По умолчанию | Назначение |
97
+ |---|---|---|---|
98
+ | toolName | string | bash | Имя инструмента, аргумент command которого проверяется |
99
+ | fileWriteTools | string[] | write, edit, Write, Edit, str_replace, apply_patch | Инструменты записи, проверяемые по целевому пути |
100
+
101
+ ### Пример Cordis-конфигурации
102
+
103
+ <pre><code>- insert:
104
+ - id: dsh-approval-gate
105
+ name: @goodandready/dsh-approval-gate
106
+ config:
107
+ toolName: bash
108
+ fileWriteTools:
109
+ - write
110
+ - edit
111
+ - Write
112
+ - Edit
113
+ - str_replace
114
+ - apply_patch
115
+ </code></pre>
116
+
117
+ ### Установка и ограничения
118
+
119
+ <pre><code>dsh plugin --profile web add @goodandready/dsh-approval-gate@0.1.3</code></pre>
120
+
121
+ Плагин не добавляет HTTP-маршруты или отдельную CLI-команду и не читает содержимое файлов скриптов. Это не системная песочница: команды cron и systemd, запущенные отдельно от инструментов DSH, он не перехватывает.
122
+
123
+
124
+ ## Лицензия
125
+
126
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
package/README.zh.md ADDED
@@ -0,0 +1,126 @@
1
+ # 📦 @goodandready/dsh-approval-gate
2
+
3
+ <div align="center">
4
+
5
+ <h3>DSH shell 命令的最后一道安全防线</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-approval-gate"><img src="https://img.shields.io/npm/v/@goodandready/dsh-approval-gate.svg?style=for-the-badge&color=6366f1&labelColor=1e1b4b" alt="npm version"></a>
9
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/GooDAnDReaDY/dsh-approval-gate.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
+ <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://goodandready.app/"><img src="https://img.shields.io/badge/所有项目-goodandready.app-ff4500.svg?style=for-the-badge&logo=rocket&logoColor=white&labelColor=1a1a2e" alt="GoodAndReady Showcase"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="README.md"><b>🇬🇧 English</b></a> •
20
+ <a href="README.zh.md"><b>🇨🇳 中文说明</b></a> •
21
+ <a href="README.ru.md"><b>🇷🇺 Русский</b></a>
22
+ </p>
23
+
24
+ <table align="center">
25
+ <tr><td align="center">⭐ <strong>如果您喜欢这个插件,请在 GitHub 上为它点亮 Star</strong> — 这能让我知道插件对您有用,并鼓励我继续开发和维护它。<br><br>🐛 <strong>如果您发现 Bug 或希望增加功能</strong>,请使用任意语言在 GitHub 上提交 Issue — 我会评估您的建议,并在后续版本中实现有价值的改进。</td></tr>
26
+ </table>
27
+
28
+ </div>
29
+
30
+ ---
31
+
32
+ ## 概述
33
+
34
+ 仅运行于 DSH 主机的安全插件:在工具正文运行前拦截危险的 bash 调用以及对受保护文件的写入。无法完整检查的命令会通过 DSH 原生审批流程请求确认;本插件不实现单独的审批口令。
35
+
36
+ 完整覆盖表、限制和配置见 [README.md](README.md)。
37
+
38
+ 从公开 npm registry 安装:
39
+
40
+ ```sh
41
+ dsh plugin --profile web add @goodandready/dsh-approval-gate@0.1.3
42
+ ```
43
+
44
+ ## v0.1.3 变更
45
+
46
+ 这是以 @goodandready/dsh-approval-gate 身份发布到公开 npm registry 的首个版本。
47
+
48
+ 变更说明:早期内部说明曾提到单独的操作者确认词。从 v0.1.3 起,无法确认的命令由 DSH 原生审批流程处理,本插件不定义自己的确认口令;新安装使用公开 npmjs 包。
49
+
50
+ 本节说明 0.1.3 中的行为:扩展有界 shell 语法分析,并在无法确定语法或执行目标时请求 DSH 审批,同时保留对已识别破坏性操作和受保护文件写入的拒绝规则。
51
+
52
+ shell 分析器现在支持命令替换、反引号、进程替换、常见重定向(包括 2> 和 &>)、管道和 here-document,并递归检查嵌套 shell 命令及可执行展开。普通安全读取可以通过。展开的 Authorization 请求头需要审批,因为 curl 会把凭据作为进程参数接收。本包暂不提供安全的凭据 API 助手;请勿将令牌放入命令行参数。
53
+
54
+ 语言服务是可选的;如果服务不可用,安全钩子仍会使用英文回退消息运行。
55
+
56
+ 已识别的破坏性操作和受保护文件写入仍会被拒绝,包括递归 rm、进程信号、服务停止或重启、破坏性 SQL、受保护文件写入、git reset --hard、强制 git clean、mkfs、写入设备的 dd,以及将下载内容传给 shell。
57
+
58
+ 未闭合或不支持的语法、动态命令名或重定向目标,以及无法检查内容的脚本文件,会通过 DSH 请求审批。审批不可用或配置为 approval=never 时,DSH 会拒绝请求。本插件不会读取脚本文件,也不实现独立审批口令。提示会显示规则名称和脱敏后的命令片段。这是有界 shell 分析器,并非完整 Bash 语法解析器。
59
+
60
+ ## 架构与功能
61
+
62
+ | 模块 | 职责 |
63
+ |---|---|
64
+ | lib/index.js | 注册单调的 tools.guard 和 DSH 原生预执行审批钩子,并连接 shell 与文件写入检查器。 |
65
+ | lib/inspect.js | 对有界 shell 语法进行分词,检查 argv 和展开内容,应用危险命令与受保护写入规则,并返回通过、拒绝或请求审批的结果。 |
66
+ | lib/messages.js | 提供英文和简体中文规则名称、说明及脱敏提示。 |
67
+ | cordis.patch.yml | 声明 host 端插件包和可选工具配置。 |
68
+
69
+ ```mermaid
70
+ graph LR
71
+ A[Agent tool call] --> B[dsh-approval-gate]
72
+ B -->|Safe and inspected| C[Tool runs]
73
+ B -->|Known dangerous| D[Denied]
74
+ B -->|Uncertain syntax or target| E[DSH approval]
75
+ ```
76
+
77
+ 已识别的危险操作会被拒绝。无法确认语法、命令名、参数、重定向目标或写入目标时,插件请求 DSH 审批。approval=never 时,DSH 仍会拒绝不确定请求。普通、安全且可检查的命令会通过。
78
+
79
+ ### 覆盖范围
80
+
81
+ | 调用示例 | 结果 |
82
+ |---|---|
83
+ | rm -rf /tmp/x、sudo rm -r ... | 拒绝 |
84
+ | kill、pkill、killall | 拒绝 |
85
+ | systemctl stop/restart/disable | 拒绝;systemctl is-active 可通过 |
86
+ | service name stop/restart | 拒绝 |
87
+ | sqlite3 中的 DROP、ALTER 等破坏性 SQL | 拒绝 |
88
+ | 向 .env、credentials.yaml、settings.yaml 或 cordis.patch.yml 写入 | 拒绝 |
89
+ | 读取受保护配置、在普通文本中提及危险命令 | 通过 |
90
+ | 未闭合 heredoc、动态命令名或无法检查的脚本文件 | 请求 DSH 审批 |
91
+
92
+ ### 配置
93
+
94
+ 在 Cordis patch 的插件项中可选设置以下字段:
95
+
96
+ | 字段 | 类型 | 默认值 | 说明 |
97
+ |---|---|---|---|
98
+ | toolName | string | bash | 要检查 command 参数的工具名称 |
99
+ | fileWriteTools | string[] | write、edit、Write、Edit、str_replace、apply_patch | 按目标路径检查的文件写入工具 |
100
+
101
+ ### Cordis 配置示例
102
+
103
+ <pre><code>- insert:
104
+ - id: dsh-approval-gate
105
+ name: @goodandready/dsh-approval-gate
106
+ config:
107
+ toolName: bash
108
+ fileWriteTools:
109
+ - write
110
+ - edit
111
+ - Write
112
+ - Edit
113
+ - str_replace
114
+ - apply_patch
115
+ </code></pre>
116
+
117
+ ### 安装与限制
118
+
119
+ <pre><code>dsh plugin --profile web add @goodandready/dsh-approval-gate@0.1.3</code></pre>
120
+
121
+ 本插件不添加 HTTP 路由或独立 CLI,也不读取脚本文件内容。它不是操作系统沙箱,不会检查 cron 或 systemd 自行执行的命令。
122
+
123
+
124
+ ## 许可证
125
+
126
+ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
@@ -0,0 +1,6 @@
1
+ # dsh-approval-gate bundle layer: applied automatically when the package is
2
+ # installed as a profile bundle (package.json declares dsh.bundle.patch).
3
+ - insert:
4
+ - id: dsh-approval-gate
5
+ name: '@goodandready/dsh-approval-gate'
6
+ config: {}
package/lib/index.js ADDED
@@ -0,0 +1,82 @@
1
+ // dsh-approval-gate - approval gate for DeepSeek Harness.
2
+ //
3
+ // Registers tools.guard on the tool runtime and denies dangerous bash
4
+ // commands and writes to secret files even when sandbox mode would allow
5
+ // them. A guard return value (non-undefined) denies execution, so the
6
+ // dangerous call never runs on its own - it needs an explicit owner
7
+ // Approval is handled by DSH's native flow; no separate word is implemented.
8
+ //
9
+ // Only the agent tool calls pass through the guard (cron/systemd scripts
10
+ // do not), so legitimate unattended operations are unaffected.
11
+ import Schema from "@deepseek-ai/schemastery";
12
+ import {
13
+ DEFAULT_BASH_TOOL,
14
+ DEFAULT_FILE_WRITE_TOOLS,
15
+ askMessage,
16
+ denyMessage,
17
+ inspectExecution,
18
+ sessionTag,
19
+ } from "./inspect.js";
20
+ import { LOCALE_NS, MESSAGES } from "./messages.js";
21
+
22
+ export const name = "dsh-approval-gate";
23
+ export const inject = ["tools"];
24
+
25
+ export const Config = Schema.object({
26
+ /** Name of the tool whose `command` arg is inspected (the DSH bash tool). */
27
+ toolName: Schema.string().default(DEFAULT_BASH_TOOL),
28
+ /** Extra tool names treated as file writes; paths are matched against secret files. */
29
+ fileWriteTools: Schema.array(Schema.string()).default(DEFAULT_FILE_WRITE_TOOLS.slice()),
30
+ });
31
+
32
+ function logBlocked(ctx, hit, who) {
33
+ const line = "[dsh-approval-gate] blocked rule=" + (hit.reason || "unknown") + who;
34
+ if (ctx && ctx.logger && typeof ctx.logger.warn === "function") ctx.logger.warn(line);
35
+ }
36
+
37
+ export function apply(ctx, config) {
38
+ const cfg = Config(config || {}) || {};
39
+ const toolName = cfg.toolName || DEFAULT_BASH_TOOL;
40
+ const fileWriteTools = cfg.fileWriteTools || DEFAULT_FILE_WRITE_TOOLS.slice();
41
+ const getLocale = function () {
42
+ if (ctx && typeof ctx.get === "function") return ctx.get("locale");
43
+ return ctx && ctx.locale;
44
+ };
45
+ const registerLocale = function () {
46
+ const locale = getLocale();
47
+ if (locale && typeof locale.register === "function") return locale.register(LOCALE_NS, MESSAGES);
48
+ };
49
+ if (ctx && typeof ctx.effect === "function") ctx.effect(registerLocale, "dsh-approval-gate: dictionaries");
50
+ else registerLocale();
51
+
52
+ const translate = function (key) {
53
+ const locale = getLocale();
54
+ if (locale && typeof locale.bind === "function") return locale.bind(LOCALE_NS)(key);
55
+ return key;
56
+ };
57
+ const hasPreExecute = ctx && typeof ctx.on === "function";
58
+ if (hasPreExecute) {
59
+ ctx.on("tools/pre-execute", function (execution, next) {
60
+ const hit = inspectExecution(execution, { toolName: toolName, fileWriteTools: fileWriteTools });
61
+ if (hit.ask) return { kind: "ask", reason: askMessage(hit, sessionTag(execution), translate, ctx && ctx.logger) };
62
+ return next();
63
+ });
64
+ }
65
+
66
+ const guard = function (execution) {
67
+ const hit = inspectExecution(execution, { toolName: toolName, fileWriteTools: fileWriteTools });
68
+ if (!hit.deny && !(hit.ask && !hasPreExecute)) return undefined;
69
+ const who = sessionTag(execution);
70
+ logBlocked(ctx, hit, who);
71
+ return denyMessage(hit, who, translate, ctx && ctx.logger);
72
+ };
73
+
74
+ const mount = function () {
75
+ return ctx.tools.guard(guard);
76
+ };
77
+ if (ctx && typeof ctx.effect === "function") {
78
+ ctx.effect(mount, "dsh-approval-gate: tools guard");
79
+ return;
80
+ }
81
+ return mount();
82
+ }