dsh-perm-gate 2.1.0 → 2.6.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.ja.md +108 -0
- package/CHANGELOG.ko.md +104 -0
- package/CHANGELOG.md +347 -0
- package/INSTALL.ja.md +84 -8
- package/INSTALL.ko.md +80 -9
- package/INSTALL.md +83 -8
- package/INSTALL.zh.md +70 -7
- package/README.ja.md +130 -16
- package/README.ko.md +128 -17
- package/README.md +179 -25
- package/README.zh.md +121 -12
- package/assets/allow1.png +0 -0
- package/assets/allow2.png +0 -0
- package/assets/gateoff.png +0 -0
- package/assets/llms.png +0 -0
- package/assets/permlist.png +0 -0
- package/assets/setting-head.png +0 -0
- package/assets/setting-rules.png +0 -0
- package/cordis.patch.yml +37 -3
- package/docs/baseline-guard.md +56 -0
- package/docs/plan-rules-to-settings.md +217 -0
- package/docs/rules-format.en.md +294 -0
- package/docs/rules-format.md +279 -0
- package/docs/ui-gap-analysis-and-branch-permissions.md +338 -0
- package/dsh.plugin.json +22 -0
- package/examples/permissions.example.yaml +16 -1
- package/lib/agent-identity.d.ts +43 -0
- package/lib/agent-identity.js +95 -0
- package/lib/allowlist.d.ts +27 -0
- package/lib/allowlist.js +103 -1
- package/lib/cli.js +11 -14
- package/lib/client.js +598 -6
- package/lib/client.js.map +1 -1
- package/lib/command-dispatcher.d.ts +22 -0
- package/lib/command-dispatcher.js +97 -0
- package/lib/command-semantics.d.ts +62 -0
- package/lib/command-semantics.js +6 -0
- package/lib/compiler.d.ts +50 -0
- package/lib/compiler.js +122 -0
- package/lib/config.d.ts +161 -7
- package/lib/config.js +78 -11
- package/lib/dry-run.d.ts +87 -0
- package/lib/dry-run.js +110 -0
- package/lib/engine.js +61 -4
- package/lib/evaluate.d.ts +9 -0
- package/lib/evaluate.js +264 -1
- package/lib/events.d.ts +69 -2
- package/lib/events.js +123 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +320 -11
- package/lib/network-lifecycle.d.ts +107 -0
- package/lib/network-lifecycle.js +180 -0
- package/lib/network.d.ts +109 -0
- package/lib/network.js +196 -0
- package/lib/parsers/git.d.ts +43 -0
- package/lib/parsers/git.js +404 -0
- package/lib/parsers/shell-cmds.d.ts +32 -0
- package/lib/parsers/shell-cmds.js +293 -0
- package/lib/preset.d.ts +13 -0
- package/lib/preset.js +17 -0
- package/lib/proxy.d.ts +160 -0
- package/lib/proxy.js +529 -0
- package/lib/risk.d.ts +17 -3
- package/lib/risk.js +19 -6
- package/lib/rule-chain.d.ts +39 -0
- package/lib/rule-chain.js +213 -0
- package/lib/rule-dims.d.ts +174 -0
- package/lib/rule-dims.js +230 -0
- package/lib/rule.d.ts +60 -0
- package/lib/rule.js +69 -7
- package/lib/rules-view.d.ts +52 -0
- package/lib/rules-view.js +126 -0
- package/lib/runtime.d.ts +208 -7
- package/lib/runtime.js +433 -27
- package/lib/session-sweep.d.ts +45 -0
- package/lib/session-sweep.js +153 -0
- package/lib/shadow.d.ts +34 -0
- package/lib/shadow.js +143 -0
- package/lib/shell.d.ts +14 -0
- package/lib/shell.js +17 -0
- package/lib/watch.d.ts +42 -0
- package/lib/watch.js +170 -0
- package/package.json +26 -3
- package/scripts/patch-permission-glyph.mjs +392 -0
package/README.ja.md
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
> | DSH バージョン | ブランチ | バージョン | npm タグ |
|
|
28
28
|
> | --- | --- | --- | --- |
|
|
29
29
|
> | 0.1.0-rc.7 ~ 0.1.1-rc.x | `legacy` | `1.x` | `@legacy` |
|
|
30
|
-
> | 0.1.2-alpha.1
|
|
30
|
+
> | 0.1.2-alpha.1 ~ 0.1.5-rc.0 | `main` | `2.x` | `@latest` / `@dsh-0.1.2` (`@2.x` は範囲) |
|
|
31
|
+
> | 0.1.5-rc.1+ | `sync/0.1.5-from-main`(=`compat/0.1.5`) | `3.x` | GitHub ref インストール(dist-tag 未公開) |
|
|
31
32
|
>
|
|
32
33
|
> バージョン系列は **DSH ライン**を追います(`1.x` = DSH ≤ 0.1.1、`2.x` = DSH 0.1.2+)。
|
|
33
34
|
> メジャー同士が互いを遮断するため、`^1.x` のインストールが `2.x` を解決することは
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
> メソッドであるため、`typeof` プロブで読み取り、欠落時やエラー時には「ポリシー
|
|
46
47
|
> 不明」にフォールバックします。
|
|
47
48
|
|
|
48
|
-
バージョン **2.
|
|
49
|
+
バージョン **2.6.1** — 変更履歴は [日本語 changelog](./CHANGELOG.ja.md) を参照。
|
|
49
50
|
|
|
50
51
|
DeepSeek Harness 向けの、単一・自己完結・決定論優先・fail-closed な権限ゲートです。
|
|
51
52
|
|
|
@@ -86,13 +87,38 @@ DSH の安全まわりのエコシステムでは、この役割が `dsh-permiss
|
|
|
86
87
|
モード**。汎用の「自動承認」でもなく、包括的な権限付与でもありません。フロントが露出する
|
|
87
88
|
のは**単一スイッチ**(`permissive`)だけで、バックエンドの 4 つの戦略は**組み合わせ
|
|
88
89
|
可能**でプラグイン設定から制御されます。P0 に対しては依然 fail-closed です。
|
|
89
|
-
|
|
90
|
+
権限ピッカーと設定行はいずれも製品名「自动审查」で表示します。アイコンについては後述(組み込みティアは標準装備、プラグイン提供ティアはパッチが必要)。
|
|
90
91
|
- **サンドボックス昇格の自動回答**(`trustEscalation`)— サンドボックス昇格は shell /
|
|
91
92
|
pwsh / edit ツールの**内部**(`tools/pre-execute` 後)から発生するためゲートはそれを
|
|
92
93
|
見ておらず、ゲートが自動許可した呼び出しでも確認プロンプトが表示されます。この戦略を
|
|
93
94
|
オンにすると、ゲートが許可した呼び出しを `callId` で正確に一致させてここで直接回答
|
|
94
95
|
します。
|
|
95
96
|
|
|
97
|
+
## スクリーンショット
|
|
98
|
+
|
|
99
|
+
**設定カード — 自动审查ティア**:フロントが露出するのは単一スイッチのみで、バックエンドの
|
|
100
|
+
4 戦略は組み合わせ可能です。`LlmAssist` はセッションの現在のモデルに追従するか、
|
|
101
|
+
Provider / Model を固定でき、ヘルスチェックと裁決学習を備えます:
|
|
102
|
+
|
|
103
|
+

|
|
104
|
+

|
|
105
|
+
|
|
106
|
+
**ゲートが実際に読み込んだルール** — `dsh-perm-gate-rules` 設定名前空間から直接読み出した
|
|
107
|
+
読み取り専用ビューです。パネルからは変更できません:
|
|
108
|
+
|
|
109
|
+

|
|
110
|
+
|
|
111
|
+
**権限承認記録** — このセッションのすべての裁決を新しい順に、モデルが見た理由つきで表示します:
|
|
112
|
+
|
|
113
|
+

|
|
114
|
+
|
|
115
|
+
**裁決ストリップ** — 自動許可は根拠(読み取り専用ツール、または LLM の `safe` 判定)を明示し、
|
|
116
|
+
ゲートの停止も決して無言では起きません:
|
|
117
|
+
|
|
118
|
+

|
|
119
|
+

|
|
120
|
+

|
|
121
|
+
|
|
96
122
|
## インストール
|
|
97
123
|
|
|
98
124
|
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) が導入済みである
|
|
@@ -117,7 +143,7 @@ dsh plugin --profile web add dsh-perm-gate
|
|
|
117
143
|
rulesFile: ./permissions.yaml # 任意。既定は $DSH_HOME/perm-gate/rules.yml
|
|
118
144
|
dshHome: $DSH_HOME # 保護対象チェックのルート固定
|
|
119
145
|
defaultAction: ask # allow | ask | deny
|
|
120
|
-
gatePresets: [permissive]
|
|
146
|
+
gatePresets: [permissive, permissive-full] # ゲートが有効なティア(既定)
|
|
121
147
|
```
|
|
122
148
|
|
|
123
149
|
### ルール ファイル
|
|
@@ -147,18 +173,100 @@ permissions:
|
|
|
147
173
|
|
|
148
174
|
完全な例: [examples/permissions.example.yaml](./examples/permissions.example.yaml)
|
|
149
175
|
|
|
176
|
+
### ネットワークポリシー(任意で有効化)
|
|
177
|
+
|
|
178
|
+
ローカル HTTP/CONNECT プロキシです。**同じルールファイル**で **shell サブプロセス**の
|
|
179
|
+
外向き通信を審査し、どのルールにも該当しない宛先には承認経路を提供します。**既定は無効** ——
|
|
180
|
+
有効にするとループバックポートを確保し、子プロセスのプロキシ環境変数を書き換えるため、
|
|
181
|
+
暗黙に有効化されることはありません。
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
- id: dsh-perm-gate
|
|
185
|
+
config:
|
|
186
|
+
networkEnabled: false # マスタースイッチ(既定 false)
|
|
187
|
+
networkMode: whitelist # deny-all | whitelist | allow-all
|
|
188
|
+
networkUnlisted: ask # ask | deny —— 未登録の宛先の扱い
|
|
189
|
+
networkUnattributed: allow # allow | deny —— shell 帰属のない通信
|
|
190
|
+
networkInjectEnv: true # 子プロセスに HTTP(S)_PROXY / ALL_PROXY を注入
|
|
191
|
+
networkAskTimeoutMs: 120000 # 承認待ちの上限。超過時は拒否
|
|
192
|
+
networkGrantTtlMs: 1800000 # 1 回の承認が有効なセッション期間
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**段階的な動作**:許可ルールがなければ、どの宛先にも到達できません。未登録の宛先は、
|
|
196
|
+
その接続を開いた shell コマンドのセッションに対して対話的承認へエスカレートし、承認すると
|
|
197
|
+
その宛先が当該セッションで許可されます。**`deny` ルールが承認に回ることはありません** ——
|
|
198
|
+
承認は「どのルールも禁止していない宛先」の到達性を広げられますが、禁止しているルールを
|
|
199
|
+
覆すことはできません。
|
|
200
|
+
|
|
201
|
+
**境界 —— 依存する前に必ず読んでください**:このプロキシは**協調型**のポリシー層であり、
|
|
202
|
+
強制境界ではありません。プロキシ環境変数を**読む**クライアントの通信しか見えません。
|
|
203
|
+
|
|
204
|
+
| クライアント | 遮断できるか |
|
|
205
|
+
|--------------|--------------|
|
|
206
|
+
| `curl`、`wget`、`git`、Go `net/http`、Python `requests` | ✅ |
|
|
207
|
+
| **Node.js `http` / `https` / `fetch`** | ❌ **直接接続。プロキシから見えない** |
|
|
208
|
+
| Java(`-D` プロキシ指定なし)、.NET `HttpClient` | ❌ |
|
|
209
|
+
| 生ソケット、独自 TCP | ❌ |
|
|
210
|
+
| DNS、QUIC/HTTP3、非 HTTP プロトコル | ❌ |
|
|
211
|
+
| リテラル IP への接続 | ❌ |
|
|
212
|
+
|
|
213
|
+
したがって `node -e "require('http').get('http://host/')"` のようなコマンドは**遮断されません**。
|
|
214
|
+
これは「誤操作を防ぐガードレールであり、意図を宣言する場所」と考えてください。密閉された
|
|
215
|
+
サンドボックスではありません。
|
|
216
|
+
|
|
217
|
+
DSH **自身**の通信 —— 組み込みネットワークツールと LLM トランスポート —— は意図的に対象外
|
|
218
|
+
です。これらの接続には shell 帰属がなく、`networkUnattributed: allow`(既定)がそのまま
|
|
219
|
+
通します。審査するとホストが**自分自身を遮断**してしまい、取り逃すよりはるかに悪い障害に
|
|
220
|
+
なります。ホストのクライアントがプロキシ環境変数を読まないと確信できる場合のみ `deny` に
|
|
221
|
+
してください。
|
|
222
|
+
|
|
223
|
+
稼働状態の照会:`GET /api/dsh-perm-gate/network`(モード / バインド / ポート / プロキシ稼働 /
|
|
224
|
+
環境注入状態 / 遮断カウンタ / 直近の遮断)。
|
|
225
|
+
|
|
150
226
|
## 自动审查ティア(マシン値 `permissive`)
|
|
151
227
|
|
|
152
228
|
自动审查は権限ピッカーの中で 読み取り専用 / ワークスペース内変更 / 完全権限 /
|
|
153
229
|
許可リストと並ぶ**独立した承認ティア**です。汎用の「自動承認」ではなく、包括的な権限を
|
|
154
230
|
発行することもありません。人間/LLM のシーム**の前**で判定を狭めたり広めたりする
|
|
155
|
-
だけで、P0
|
|
156
|
-
|
|
157
|
-
|
|
231
|
+
だけで、P0 ハード拒否は**ゲート自身のスコープ内で**単調かつ交渉不能のままです。
|
|
232
|
+
|
|
233
|
+
> **P0 はスコープ付きであり、グローバルではありません。** このゲートはセッションの権限プリセットが
|
|
234
|
+
> `gatePresets`(既定は `permissive` / `permissive-full`)のいずれかである間だけ動作します。それ以外の
|
|
235
|
+
> プリセット —— 読み取り専用 / ワークスペース内変更 / 完全権限 —— では **P0 ハード拒否を含むゲート
|
|
236
|
+
> 全体が停止**し、選択されたティア自身のポリシーがそのセッションを統治します。これは意図的な設計です
|
|
237
|
+
> (設定表の `gatePresets` を参照)が、「P0 は交渉不能」は**ゲートのティア内**で成立するものであり、
|
|
238
|
+
> すべてのティアに跨るものではありません。停止は**沈黙しません**: セッション/プリセットの遷移ごとに
|
|
239
|
+
> `stand-down` イベントを 1 件記録し、ブラウザは入力欄の上に **GATE OFF** の常駐ストリップを表示します。
|
|
240
|
+
> `gatePresets: ['*']` に設定すると P0 は再びグローバルになります。
|
|
241
|
+
|
|
242
|
+
**2 つのバリアントを同梱します。** プリセットの `sandbox` と `approval` は**独立した**ノブであり、
|
|
243
|
+
両者を結び付けると悪いトレードオフを強いられるためです。
|
|
244
|
+
|
|
245
|
+
| ピッカーの表示名 | マシン値 | sandbox | approval |
|
|
246
|
+
|------------------|----------|---------|----------|
|
|
247
|
+
| 自动审查 | `permissive` | `workspace-write` | `ask` |
|
|
248
|
+
| 自动审查(高権限) | `permissive-full` | `danger-full-access` | `ask` |
|
|
249
|
+
|
|
250
|
+
通常のティアは組み込みのファイルサンドボックスを維持します。そのサンドボックスは子プロセスの
|
|
251
|
+
起動に必要な名前付きパイプも拒否するため、`git clone`、MSYS2/Cygwin の `sh.exe`、ConPTY は
|
|
252
|
+
`Win32 error 5` / `couldn't create signal pipe` で失敗します。しかもゲートは
|
|
253
|
+
**`gatePresets` に列挙したティアでしか動作しない**ため、ゲートを使いたい場合はこの制限を受け入れる
|
|
254
|
+
必要がありました。「自动审查(高権限)」はこの結合を解きます —— **承認動作は同一のまま、ファイル
|
|
255
|
+
サンドボックスの制限だけを外します**。どちらも既定の `gatePresets` に含まれるため、どちらを選んでも
|
|
256
|
+
P0–P4 の全チェーンが動作します。ゲートはプリセットの**名前**だけを読み、sandbox モードは読みません。
|
|
257
|
+
|
|
258
|
+
ピッカーの表示名は**ホストが供給する製品名**で、言語別辞書の項目ではありません。DSH は
|
|
158
259
|
プラグイン提供ティアの `name:` を 2 つの権限サーフェス(一般設定の既定行と入力欄のピッカー)で
|
|
159
260
|
そのまま描画し、自前のローカライズ済みラベルは 3 つの組み込み値にしか与えないため、
|
|
160
|
-
`cordis.patch.yml`
|
|
161
|
-
|
|
261
|
+
`cordis.patch.yml` は全セッション共通で中国語ラベルを配布します。
|
|
262
|
+
|
|
263
|
+
**アイコンは別の話です。** 入力欄のグリフ表は閉じており、その表自身のコメントが規則を述べています:
|
|
264
|
+
*host-configured names outside the design set get none*。どちらのティアも組み込み値ではないため、
|
|
265
|
+
アイコンは `npx dsh-perm-gate-patch-glyph` がその表に 2 項目を足すことで初めて付きます ——
|
|
266
|
+
「自动审查」は `workspace-write` の盾+鉛筆を、「自动审查(高权限)」は `danger-full-access` の
|
|
267
|
+
盾+感嘆符をコピーし、それぞれが実際に共有するファイルサンドボックスのグリフになります。このパッチは
|
|
268
|
+
**ホスト**パッケージを書き換えるため、DSH アップグレードのたびに失われます ——
|
|
269
|
+
[DSH アップグレード後:入力欄アイコンのパッチを再適用](./INSTALL.ja.md) を参照してください。
|
|
162
270
|
|
|
163
271
|
`cordis.yml` では:
|
|
164
272
|
|
|
@@ -221,11 +329,13 @@ never` パススルー — は人手に変更なく委譲されるため、将
|
|
|
221
329
|
セッションの権限ピッカーには「auto-approval」ではなく、**独立して選択できる承認
|
|
222
330
|
ティア**として「自动审查」が並びます。
|
|
223
331
|
|
|
224
|
-
ゲートが動作するのは **`gatePresets` に列挙したティアの中だけ**です(既定
|
|
225
|
-
|
|
332
|
+
ゲートが動作するのは **`gatePresets` に列挙したティアの中だけ**です(既定
|
|
333
|
+
`['permissive', 'permissive-full']`、このプラグインが追加する 2 つのティア)。それ以外のティア(Read Only / Workspace Write /
|
|
226
334
|
Full access / `custom`)では、ゲートの判定フローは**一切実行されません**——許可も、ask も、
|
|
227
|
-
拒否も、P0
|
|
228
|
-
|
|
335
|
+
拒否も、P0 ハード拒否も、拒否キーワードの遮断も行いません。選択された
|
|
336
|
+
ティア自身の方針が呼び出しを決めます。ただし**沈黙はしません**: セッション/プリセットの遷移ごとに
|
|
337
|
+
`stand-down` イベントを 1 件だけ記録し(判定ではなく通知です)、ブラウザは入力欄の上に
|
|
338
|
+
**GATE OFF** の常駐ストリップを表示します。`danger-full-access` の定義は「承認プロンプトなしの
|
|
229
339
|
フルアクセス」であり、そこを ask で上書きしても意味がありません(その方針では DSH の承認シームが
|
|
230
340
|
**どの answerer よりも先に** `rejected` を返し、転送された ask はパネルを一度も表示せず
|
|
231
341
|
`the user rejected tool "..."` にしかなりません)。ハード拒否で上書きするのも、ユーザーが選んだ
|
|
@@ -247,7 +357,8 @@ Full access / `custom`)では、ゲートの判定フローは**一切実行
|
|
|
247
357
|
`llmAssist` 有効時、設定された LLM(OpenAI 互換エンドポイントなら任意——`classifierEndpoint` / `classifierModel` / `classifierApiKey` を自分の API に向けてください)が構造化プロトコルで `ask` を 1 件ずつ判定します。**判定はゲートの `tools/pre-execute` ウォーターフォール内、決定がホストへ返る前に行われます**:`safe` はそのまま委譲されるため承認パネルは一切表示されず、本当に判断できない判定だけが人手に回ります。
|
|
248
358
|
|
|
249
359
|
- `safe` → 自動許可(監査ソースは `classifier`)。パネルは表示されません。
|
|
250
|
-
- `risky` + **ハードリスクカテゴリ**(`deletion`、`credential`、`remote`、`system`、`bulk`)→
|
|
360
|
+
- `risky` + **ハードリスクカテゴリ**(`deletion`、`credential`、`remote`、`system`、`bulk`)→ **人間への確認(ask)を維持**します。分類器は**決して拒否しません**。拒否は決定論的レイヤー(P0 ハード拒否、拒否キーワードのブラックリスト、明示的な `deny:` ルール)だけに属するため、誤判定されたカテゴリは常に交渉可能で、異議を唱えられないブロックにはなりません。ハードカテゴリが `neutral` と異なる重要な点は一つだけです: **決して学習されない**ため、承認を繰り返しても自動許可に沈殿しません。
|
|
361
|
+
(モデルの判断を拒否の根拠にした結果は実測済みです: 無害な `git commit -F …` が `remote` と判定され、パネルも再試行用の grant もない自動拒否が発生しました。)
|
|
251
362
|
- `risky:neutral` → `riskLearning` 有効時(設定カード内、既定オフ)、人手で承認され実際に実行された neutral リスクは `tool|カテゴリ` ごとにカウントされ、`riskThreshold`(既定 3)到達かつ新呼び出しの操作指紋(コマンド語+対象の基底名)が確認済みサンプルに一致した場合、**同一操作のみ**自動許可されます。学習沈殿(`riskSediment`、既定オン)を有効にすると、しきい値に達したキーの確認サンプルは**決定論的な許可ルール**になります:指紋の正確一致は LLM を経由せず自動許可——llmAssist オフでも継続し、沈殿ルールは設定カードで確認・管理(終止 / サンプル削除)できます。
|
|
252
363
|
- タイムアウト(`riskTimeoutMs`、既定 20 秒、1 回リトライ)、通信失敗、プロトコル外出力は元の `ask` を維持します。
|
|
253
364
|
|
|
@@ -258,8 +369,11 @@ Full access / `custom`)では、ゲートの判定フローは**一切実行
|
|
|
258
369
|
人手に回した `ask` は回答が返るまで追跡されます。受動的な `approval/request` オブザーバが閉じた結果を記録し(`allowed-once` → **承認**、`rejected` → **拒否**、`cancelled` → **キャンセル**、`unavailable` → 拒否=承認チャネルなし)、オブザーバが関連付けできない場合(`callId` 欠落・approval サービスなし・上流リスナーの短絡)は `tools/result` が同じ ask をフォールバックとして解決します。承認時には承認後の学習進捗(`n`/しきい値)を表示し、通知バーも 3 つの終態にラベルを付けます。
|
|
259
370
|
|
|
260
371
|
さらにプリセットの**拒否キーワード黑名単**(dsh-approval-gate の `DEFAULT_DENY_KEYWORDS` を継承:`rm -rf`、`push --force`、`drop table`、`mkfs`、`git reset --hard`、`docker system prune` など)を備え、テキストがキーワードを含む呼び出し(大小文字を区別しない部分一致)は許可リスト / 許可 / LLM より先に拒否します。設定カードでリストとして編集でき(プリセット項目にはタグ付き、ワンクリック復元対応)、未設定・空ならプリセットを適用します——黑名単が静かに無効化されることはありません。
|
|
261
|
-
|
|
262
|
-
|
|
372
|
+
「自动审查」と「自动审查(高权限)」はどちらもピッカーにアイコンを描きます —— インストール
|
|
373
|
+
ガイドに書かれたホストパッチが、それぞれが共有するファイルサンドボックスのティア
|
|
374
|
+
(`workspace-write` と `danger-full-access`)からコピーしたものです。そのパッチが
|
|
375
|
+
ない場合、両ティアはどのサーフェスでもテキストのみになります。ラベルとゲートは影響を
|
|
376
|
+
受けません。
|
|
263
377
|
|
|
264
378
|
|
|
265
379
|
## CLI(スタンドアロン dry-run)
|
package/README.ko.md
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
> | DSH 버전 | 브랜치 | 버전 | npm 태그 |
|
|
28
28
|
> | --- | --- | --- | --- |
|
|
29
29
|
> | 0.1.0-rc.7 ~ 0.1.1-rc.x | `legacy` | `1.x` | `@legacy` |
|
|
30
|
-
> | 0.1.2-alpha.1
|
|
30
|
+
> | 0.1.2-alpha.1 ~ 0.1.5-rc.0 | `main` | `2.x` | `@latest` / `@dsh-0.1.2` (`@2.x`는 범위) |
|
|
31
|
+
> | 0.1.5-rc.1+ | `sync/0.1.5-from-main` (=`compat/0.1.5`) | `3.x` | GitHub ref 설치 (dist-tag 미게시) |
|
|
31
32
|
>
|
|
32
33
|
> 버전 계열은 **DSH 라인**을 따릅니다(`1.x` = DSH ≤ 0.1.1, `2.x` = DSH 0.1.2+). 메이저
|
|
33
34
|
> 버전이 서로를 차단하므로 `^1.x` 설치가 `2.x`를 해석하는 일은 없고 그 반대도
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
> 모두에서 user-approval 서비스의 **개인** 메소드이므로 `typeof` 프로브를 통해
|
|
44
45
|
> 읽으며, 누락되거나 예외 발생 시 "정책_unknown"으로 후퇴합니다.
|
|
45
46
|
|
|
46
|
-
버전 **2.
|
|
47
|
+
버전 **2.6.1** — 변경 내역은 [한국어 changelog](./CHANGELOG.ko.md)를 참고하세요.
|
|
47
48
|
|
|
48
49
|
DeepSeek Harness용 단일·자족적·결정론 우선·fail-closed 권한 게이트입니다.
|
|
49
50
|
|
|
@@ -84,12 +85,37 @@ DSH 안전 생태계에서는 이 역할이 `dsh-permission-rules` / `dsh-auto-m
|
|
|
84
85
|
모드**. 범용 "자동 승인"도 아니고 포괄적 권한 부여도 아닙니다. 프론트는 **단일 스위치**
|
|
85
86
|
(`permissive`)만 노출하고, 백엔드의 네 가지 전략은 **조합 가능**하며 플러그인
|
|
86
87
|
설정으로 제어됩니다. P0에 대해서는 여전히 fail-closed입니다.
|
|
87
|
-
권한 선택기와 설정 행 모두 제품명 「自动审查」로
|
|
88
|
+
권한 선택기와 설정 행 모두 제품명 「自动审查」로 표시합니다. 아이콘은 아래를 참고하세요(내장 티어는 기본 제공, 플러그인 티어는 패치 필요).
|
|
88
89
|
- **샌드박스 승격 자동 응답** (`trustEscalation`) — 샌드박스 승격은 shell / pwsh /
|
|
89
90
|
edit 도구의 **내부**(`tools/pre-execute` 이후)에서 발생하므로 게이트가 이를 볼 수
|
|
90
91
|
없고, 게이트가 자동 허용한 호출에도 확인 프롬프트가 나타납니다. 이 전략을 켜면 게이트가
|
|
91
92
|
`callId`로 이미 허용한 호출을 정확히 매칭하여 여기서 직접 응답합니다.
|
|
92
93
|
|
|
94
|
+
## 스크린샷
|
|
95
|
+
|
|
96
|
+
**설정 카드 — 自动审查 티어**: 프론트는 단일 스위치만 노출하고, 백엔드의 네 전략은 조합
|
|
97
|
+
가능합니다. `LlmAssist`는 세션의 현재 모델을 따르거나 Provider / Model을 고정할 수 있으며,
|
|
98
|
+
헬스 테스트와 판정 학습을 갖춥니다:
|
|
99
|
+
|
|
100
|
+

|
|
101
|
+

|
|
102
|
+
|
|
103
|
+
**게이트가 실제로 로드한 규칙** — `dsh-perm-gate-rules` 설정 네임스페이스에서 직접 읽은
|
|
104
|
+
읽기 전용 뷰입니다. 패널에서는 바꿀 수 없습니다:
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
**권한 승인 기록** — 이 세션의 모든 판정을 최신순으로, 모델이 본 이유와 함께 표시합니다:
|
|
109
|
+
|
|
110
|
+

|
|
111
|
+
|
|
112
|
+
**판정 스트립** — 자동 허용은 근거(읽기 전용 도구 또는 LLM의 `safe` 판정)를 밝히고,
|
|
113
|
+
게이트 정지도 결코 조용히 일어나지 않습니다:
|
|
114
|
+
|
|
115
|
+

|
|
116
|
+

|
|
117
|
+

|
|
118
|
+
|
|
93
119
|
## 설치
|
|
94
120
|
|
|
95
121
|
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)가 설치되어 있어야
|
|
@@ -114,7 +140,7 @@ dsh plugin --profile web add dsh-perm-gate
|
|
|
114
140
|
rulesFile: ./permissions.yaml # 선택. 기본값은 $DSH_HOME/perm-gate/rules.yml
|
|
115
141
|
dshHome: $DSH_HOME # 보호 대상 검사의 고정 루트
|
|
116
142
|
defaultAction: ask # allow | ask | deny
|
|
117
|
-
gatePresets: [permissive]
|
|
143
|
+
gatePresets: [permissive, permissive-full] # 게이트가 활성화되는 티어(기본)
|
|
118
144
|
```
|
|
119
145
|
|
|
120
146
|
### 규칙 파일
|
|
@@ -144,18 +170,98 @@ permissions:
|
|
|
144
170
|
|
|
145
171
|
전체 예시: [examples/permissions.example.yaml](./examples/permissions.example.yaml)
|
|
146
172
|
|
|
173
|
+
### 네트워크 정책(선택적 활성화)
|
|
174
|
+
|
|
175
|
+
로컬 HTTP/CONNECT 프록시입니다. **동일한 규칙 파일**로 **shell 서브프로세스**의 아웃바운드
|
|
176
|
+
트래픽을 심사하고, 어떤 규칙에도 해당하지 않는 대상에는 승인 경로를 제공합니다. **기본값은
|
|
177
|
+
비활성** —— 활성화하면 루프백 포트를 바인딩하고 자식 프로세스의 프록시 환경 변수를 다시 쓰기
|
|
178
|
+
때문에 암묵적으로 켜지지 않습니다.
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
- id: dsh-perm-gate
|
|
182
|
+
config:
|
|
183
|
+
networkEnabled: false # 마스터 스위치(기본 false)
|
|
184
|
+
networkMode: whitelist # deny-all | whitelist | allow-all
|
|
185
|
+
networkUnlisted: ask # ask | deny —— 미등록 대상 처리
|
|
186
|
+
networkUnattributed: allow # allow | deny —— shell 귀속 없는 트래픽
|
|
187
|
+
networkInjectEnv: true # 자식 프로세스에 HTTP(S)_PROXY / ALL_PROXY 주입
|
|
188
|
+
networkAskTimeoutMs: 120000 # 승인 대기 상한, 초과 시 거부
|
|
189
|
+
networkGrantTtlMs: 1800000 # 승인 1회가 유효한 세션 기간
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**단계적 동작**: 허용 규칙이 없으면 어떤 대상도 나갈 수 없습니다. 미등록 대상은 해당 연결을
|
|
193
|
+
연 shell 명령의 세션에 대해 대화형 승인으로 에스컬레이션되고, 승인하면 그 대상이 해당
|
|
194
|
+
세션에서 허용됩니다. **`deny` 규칙은 승인으로 올라가지 않습니다** —— 승인은 "어떤 규칙도
|
|
195
|
+
금지하지 않은 대상"의 도달 범위를 넓힐 수 있지만, 금지하는 규칙을 뒤집을 수는 없습니다.
|
|
196
|
+
|
|
197
|
+
**경계 —— 의존하기 전에 반드시 읽으십시오**: 이 프록시는 **협조형** 정책 계층이며 강제
|
|
198
|
+
경계가 아닙니다. 프록시 환경 변수를 **읽는** 클라이언트의 트래픽만 볼 수 있습니다.
|
|
199
|
+
|
|
200
|
+
| 클라이언트 | 차단 가능? |
|
|
201
|
+
|------------|------------|
|
|
202
|
+
| `curl`, `wget`, `git`, Go `net/http`, Python `requests` | ✅ |
|
|
203
|
+
| **Node.js `http` / `https` / `fetch`** | ❌ **직접 연결. 프록시가 보지 못함** |
|
|
204
|
+
| Java(`-D` 프록시 미지정), .NET `HttpClient` | ❌ |
|
|
205
|
+
| 원시 소켓, 직접 구현한 TCP | ❌ |
|
|
206
|
+
| DNS, QUIC/HTTP3, 비 HTTP 프로토콜 | ❌ |
|
|
207
|
+
| 리터럴 IP 연결 | ❌ |
|
|
208
|
+
|
|
209
|
+
따라서 `node -e "require('http').get('http://host/')"` 같은 명령은 **차단되지 않습니다**.
|
|
210
|
+
이것을 "실수를 막는 가드레일이자 의도를 선언하는 지점"으로 보십시오. 밀폐된 샌드박스가
|
|
211
|
+
아닙니다.
|
|
212
|
+
|
|
213
|
+
DSH **자신**의 트래픽 —— 내장 네트워크 도구와 LLM 전송 —— 은 의도적으로 대상에서 제외됩니다.
|
|
214
|
+
이 연결들은 shell 귀속이 없고, `networkUnattributed: allow`(기본값)가 그대로 통과시킵니다.
|
|
215
|
+
심사하면 호스트가 **스스로를 차단**하게 되며, 이는 놓치는 것보다 훨씬 나쁜 장애입니다.
|
|
216
|
+
호스트의 클라이언트가 프록시 환경 변수를 읽지 않는다고 확신할 때만 `deny`로 바꾸십시오.
|
|
217
|
+
|
|
218
|
+
실시간 상태 조회: `GET /api/dsh-perm-gate/network`(모드 / 바인드 / 포트 / 프록시 활성 /
|
|
219
|
+
환경 주입 상태 / 차단 카운터 / 최근 차단).
|
|
220
|
+
|
|
147
221
|
## 自动审查 티어(머신 값 `permissive`)
|
|
148
222
|
|
|
149
223
|
自动审查는 권한 선택기에서 읽기 전용 / 워크스페이스 내 수정 / 완전 권한 / 허용 목록과
|
|
150
224
|
나란한 **독립 승인 티어**입니다. 범용 "자동 승인"이 아니며 포괄적 권한을 발행하지도 않습니다.
|
|
151
|
-
사람/LLM 심 **이전에** 판정을 좁히거나 넓힐 뿐이고, P0 하드 거부는
|
|
152
|
-
불가능하게 유지됩니다.
|
|
153
|
-
|
|
154
|
-
|
|
225
|
+
사람/LLM 심 **이전에** 판정을 좁히거나 넓힐 뿐이고, P0 하드 거부는 **게이트 자체 범위 안에서**
|
|
226
|
+
단조롭고 협상 불가능하게 유지됩니다.
|
|
227
|
+
|
|
228
|
+
> **P0는 범위가 있으며 전역이 아닙니다.** 이 게이트는 세션 권한 프리셋이 `gatePresets`(기본값
|
|
229
|
+
> `permissive` / `permissive-full`) 중 하나일 때만 동작합니다. 그 밖의 프리셋 —— 읽기 전용 /
|
|
230
|
+
> 워크스페이스 내 수정 / 완전 권한 —— 에서는 **P0 하드 거부를 포함한 게이트 전체가 정지**하고,
|
|
231
|
+
> 선택된 티어 자체의 정책이 그 세션을 통치합니다. 의도된 설계이지만(설정 표의 `gatePresets` 참조),
|
|
232
|
+
> "P0는 협상 불가"는 **게이트의 티어 안에서** 성립하는 것이지 모든 티어에 걸친 것이 아닙니다.
|
|
233
|
+
> 정지는 **침묵하지 않습니다**: 세션/프리셋 전환마다 `stand-down` 이벤트 1건을 기록하고 브라우저는
|
|
234
|
+
> 입력창 위에 **GATE OFF** 상시 표시줄을 띄웁니다. `gatePresets: ['*']`로 설정하면 P0는 다시
|
|
235
|
+
> 전역이 됩니다.
|
|
236
|
+
|
|
237
|
+
**두 가지 변형을 함께 제공합니다.** 프리셋의 `sandbox`와 `approval`은 **독립된** 노브이며, 둘을
|
|
238
|
+
묶으면 나쁜 트레이드오프를 강요받기 때문입니다.
|
|
239
|
+
|
|
240
|
+
| 선택기 표시 이름 | 머신 값 | sandbox | approval |
|
|
241
|
+
|------------------|---------|---------|----------|
|
|
242
|
+
| 自动审查 | `permissive` | `workspace-write` | `ask` |
|
|
243
|
+
| 自动审查(고권한) | `permissive-full` | `danger-full-access` | `ask` |
|
|
244
|
+
|
|
245
|
+
일반 티어는 내장 파일 샌드박스를 유지합니다. 그 샌드박스는 자식 프로세스 시작에 필요한 이름 있는
|
|
246
|
+
파이프도 거부하므로 `git clone`, MSYS2/Cygwin의 `sh.exe`, ConPTY가 `Win32 error 5` /
|
|
247
|
+
`couldn't create signal pipe`로 실패합니다. 게다가 게이트는 **`gatePresets`에 나열한 티어에서만
|
|
248
|
+
동작**하므로, 게이트를 쓰려면 이 제한을 받아들여야 했습니다. 「自动审查(고권한)」는 이 결합을
|
|
249
|
+
풉니다 —— **승인 동작은 동일하게 유지하고 파일 샌드박스 제한만 해제합니다**. 둘 다 기본
|
|
250
|
+
`gatePresets`에 포함되므로 어느 쪽을 선택해도 P0–P4 전체 체인이 동작합니다. 게이트는 프리셋의
|
|
251
|
+
**이름**만 읽고 sandbox 모드는 읽지 않습니다.
|
|
252
|
+
|
|
253
|
+
선택기의 표시 이름은 **호스트가 공급하는 제품명**이며 언어별 사전 항목이 아닙니다. DSH는
|
|
155
254
|
플러그인 티어의 `name:`을 두 권한 화면(일반 설정 기본 행과 입력창 선택기)에 그대로 렌더링하고
|
|
156
255
|
자체 지역화 라벨은 세 가지 내장 값에만 부여하므로, `cordis.patch.yml`이 모든 세션에 중국어
|
|
157
|
-
라벨을 배포합니다.
|
|
158
|
-
|
|
256
|
+
라벨을 배포합니다.
|
|
257
|
+
|
|
258
|
+
**아이콘은 다른 이야기입니다.** 입력창의 글리프 표는 닫혀 있고, 그 표 자체의 주석이 규칙을
|
|
259
|
+
말합니다: *host-configured names outside the design set get none*. 두 티어 모두 내장 값이 아니므로
|
|
260
|
+
아이콘은 `npx dsh-perm-gate-patch-glyph`가 그 표에 항목 두 개를 넣어야 생깁니다 ——
|
|
261
|
+
「自动审查」는 `workspace-write`의 방패+연필을, 「自动审查(高权限)」는 `danger-full-access`의
|
|
262
|
+
방패+느낌표를 복사해 각자가 실제로 공유하는 파일 샌드박스의 글리프를 갖습니다.
|
|
263
|
+
이 패치는 **호스트** 패키지를 고치므로 DSH 업그레이드마다 사라집니다 ——
|
|
264
|
+
[DSH 업그레이드 후: 입력창 아이콘 패치 재적용](./INSTALL.ko.md)을 참고하세요.
|
|
159
265
|
|
|
160
266
|
`cordis.yml`에서:
|
|
161
267
|
|
|
@@ -221,11 +327,13 @@ never` 패스스루 — 는 사람에 그대로 위임되므로 향후 DSH 변
|
|
|
221
327
|
선택기에는 "auto-approval"이 아니라 **독립적으로 선택 가능한 승인 티어**인
|
|
222
328
|
「自动审查」가 놓입니다.
|
|
223
329
|
|
|
224
|
-
게이트가 동작하는 범위는 **`gatePresets`에 나열한 티어 안뿐**입니다(기본
|
|
225
|
-
이 플러그인이 추가하는 티어). 그 밖의 티어(Read Only / Workspace Write / Full access /
|
|
330
|
+
게이트가 동작하는 범위는 **`gatePresets`에 나열한 티어 안뿐**입니다(기본
|
|
331
|
+
`['permissive', 'permissive-full']`, 이 플러그인이 추가하는 두 티어). 그 밖의 티어(Read Only / Workspace Write / Full access /
|
|
226
332
|
`custom`)에서는 게이트의 판정 흐름이 **전혀 실행되지 않습니다** — 허용도, ask도, 거부도,
|
|
227
|
-
P0 하드 거부도, 거부 키워드
|
|
228
|
-
호출을 결정합니다.
|
|
333
|
+
P0 하드 거부도, 거부 키워드 차단도 하지 않습니다. 선택한 티어의 자체 정책이
|
|
334
|
+
호출을 결정합니다. 다만 **침묵하지는 않습니다**: 세션/프리셋 전환마다 `stand-down` 이벤트를 1건만
|
|
335
|
+
기록하고(판정이 아니라 알림입니다), 브라우저는 입력창 위에 **GATE OFF** 상시 표시줄을 띄웁니다.
|
|
336
|
+
`danger-full-access`의 정의는 "승인 프롬프트 없는 전체 접근"이며, 이를 ask로
|
|
229
337
|
덮어써도 의미가 없습니다(그 정책에서는 DSH 승인 시임이 **어떤 answerer보다도 먼저** `rejected`를
|
|
230
338
|
반환해 전달된 ask는 패널을 한 번도 띄우지 못하고 `the user rejected tool "..."`만 남습니다).
|
|
231
339
|
하드 거부로 덮어쓰는 것 역시 사용자가 고른 티어를 조용히 뒤집는 일입니다.
|
|
@@ -245,7 +353,8 @@ host는 네임스페이스를 live로 읽으므로 변경은 재시작 없이
|
|
|
245
353
|
`llmAssist`가 켜져 있으면 설정된 LLM(OpenAI 호환 엔드포인트라면 무엇이든 — `classifierEndpoint` / `classifierModel` / `classifierApiKey`을 자신의 API로 지정)이 구조화된 프로토콜로 `ask`를 하나씩 판정합니다. **판정은 게이트의 `tools/pre-execute` 워터폴 안에서, 결정이 호스트로 반환되기 전에 이루어집니다**: `safe`는 곧바로 위임되므로 승인 패널이 아예 표시되지 않고, 정말로 판단할 수 없는 판정만 사람에게 전달됩니다.
|
|
246
354
|
|
|
247
355
|
- `safe` → 자동 허용(감사 소스 `classifier`), 패널 없음.
|
|
248
|
-
- `risky` + **하드 위험 카테고리**(`deletion`, `credential`, `remote`, `system`, `bulk`) →
|
|
356
|
+
- `risky` + **하드 위험 카테고리**(`deletion`, `credential`, `remote`, `system`, `bulk`) → **사람 확인(ask)을 유지**합니다. 분류기는 **결코 거부하지 않습니다**. 거부는 결정론적 계층(P0 하드 거부, 거부 키워드 블랙리스트, 명시적 `deny:` 규칙)에만 속하므로, 잘못 판정된 카테고리는 언제나 협상 가능하며 이의를 제기할 수 없는 차단이 되지 않습니다. 하드 카테고리가 `neutral`과 다른 중요한 점은 하나뿐입니다: **결코 학습되지 않으므로** 승인을 반복해도 자동 허용으로 침전되지 않습니다.
|
|
357
|
+
(모델의 판단을 거부 근거로 삼은 결과는 실측되었습니다: 무해한 `git commit -F …`가 `remote`로 판정되어 패널도, 재시도용 grant도 없는 자동 거부가 발생했습니다.)
|
|
249
358
|
- `risky:neutral` → `riskLearning` 활성 시(설정 카드, 기본 꺼짐), 사람이 승인하고 실제 실행된 neutral 위험은 `tool|카테고리` 키로 카운트되며, `riskThreshold`(기본 3) 도달 및 새 호출의 작업 지문(명령어 단어 + 대상 기본 이름)이 확인된 샘플과 일치하면 **동일 작업만** 자동 허용됩니다. 학습 침전(`riskSediment`, 기본 켜짐)을 사용하면 임계값에 도달한 키의 확인 샘플이 **결정론적 허용 규칙**이 됩니다: 지문이 정확히 일치하면 LLM 호출 없이 바로 허용——llmAssist가 꺼져도 유지되며, 침전 규칙은 설정 카드에서 확인·관리(종료 / 샘플 삭제)할 수 있습니다.
|
|
250
359
|
- 시간 초과(`riskTimeoutMs`, 기본 20초, 1회 재시도), 전송 실패, 프로토콜 외 출력은 원래 `ask`를 유지합니다.
|
|
251
360
|
|
|
@@ -261,8 +370,10 @@ host는 네임스페이스를 live로 읽으므로 변경은 재시작 없이
|
|
|
261
370
|
카드에서 목록으로 편집할 수 있고(프리셋 항목에는 태그 표시, 원클릭 복원 지원) 미설정·빈 목록 시 프리셋이
|
|
262
371
|
적용됩니다——블랙리스트가 조용히 꺼지지 않습니다.
|
|
263
372
|
블랙리스트가 조용히 꺼지는 일은 없습니다.
|
|
264
|
-
|
|
265
|
-
|
|
373
|
+
「自动审查」와 「自动审查(高权限)」는 둘 다 선택기에 아이콘을 그립니다 — 설치 안내에 적힌
|
|
374
|
+
호스트 패치가 각자가 공유하는 파일 샌드박스 티어(`workspace-write`와 `danger-full-access`)에서
|
|
375
|
+
복사한 것입니다. 그 패치가 없으면 두 티어 모두 모든 화면에서 텍스트만 표시됩니다.
|
|
376
|
+
라벨과 게이트는 영향을 받지 않습니다.
|
|
266
377
|
|
|
267
378
|
|
|
268
379
|
## CLI(독립 실행 dry-run)
|