dsh-perm-gate 5.2.0 → 5.3.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 +64 -1
- package/CHANGELOG.ko.md +64 -1
- package/CHANGELOG.md +149 -4
- package/README.ja.md +44 -1
- package/README.ko.md +44 -2
- package/README.md +74 -1
- package/README.zh.md +42 -1
- package/cordis.patch.yml +16 -1
- package/dsh.plugin.json +2 -2
- package/lib/ask-context.d.ts +49 -1
- package/lib/ask-context.js +89 -5
- package/lib/client.js +714 -86
- package/lib/client.js.map +1 -1
- package/lib/config.d.ts +152 -1
- package/lib/config.js +20 -1
- package/lib/credential-paths.d.ts +35 -0
- package/lib/credential-paths.js +119 -0
- package/lib/engine.d.ts +4 -6
- package/lib/engine.js +53 -42
- package/lib/evaluate.d.ts +20 -0
- package/lib/evaluate.js +34 -11
- package/lib/feedback.d.ts +42 -0
- package/lib/feedback.js +85 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +119 -17
- package/lib/irreversible.js +109 -1
- package/lib/path.d.ts +31 -0
- package/lib/path.js +35 -0
- package/lib/preset.d.ts +8 -5
- package/lib/preset.js +15 -6
- package/lib/risk.d.ts +29 -1
- package/lib/risk.js +36 -2
- package/lib/runtime.d.ts +164 -0
- package/lib/runtime.js +423 -54
- package/lib/scan-text.d.ts +69 -0
- package/lib/scan-text.js +162 -0
- package/lib/script-review.d.ts +50 -0
- package/lib/script-review.js +202 -0
- package/lib/shell.d.ts +18 -0
- package/lib/shell.js +103 -1
- package/lib/unattended.d.ts +61 -0
- package/lib/unattended.js +77 -0
- package/package.json +8 -7
- package/scripts/patch-permission-glyph.mjs +27 -13
package/CHANGELOG.ja.md
CHANGED
|
@@ -5,6 +5,69 @@
|
|
|
5
5
|
形式は [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) に従い、
|
|
6
6
|
このプロジェクトは [Semantic Versioning](https://semver.org/spec/v2.0.0.html) に準拠します。
|
|
7
7
|
|
|
8
|
+
> 注: 2.4.1 から 5.1.2 までは英語版 `CHANGELOG.md` のみに記録されています(ja 版は追随済みではない)。
|
|
9
|
+
|
|
10
|
+
## [5.3.1] - 2026-10-17
|
|
11
|
+
|
|
12
|
+
### 追加
|
|
13
|
+
|
|
14
|
+
- **ホスト対応: DSH `0.2.1-rc.1`。** サポートホストの列挙(`package.json` engines.dsh、`dsh.plugin.json`、すべての `@deepseek-ai/dsh*` peer、README の管理ブロック)に `0.2.1-rc.1` を追加(区間表記なしの rc ごとの正確な列挙)。挙動は変更なし:宣言面のリリースであり、0.2.1-alpha.4 以降 engines.dsh のみを参照するホストゲートが 0.2.1-rc.1 ホストで本プラグインを許可します。
|
|
15
|
+
|
|
16
|
+
### 変更
|
|
17
|
+
|
|
18
|
+
- `publishConfig.registry` を `https://registry.npmjs.org` に固定(リリース衛生:公開先がミラー registry に漂移しない)。
|
|
19
|
+
|
|
20
|
+
## [5.3.0] - 2026-10-17
|
|
21
|
+
|
|
22
|
+
### 追加
|
|
23
|
+
|
|
24
|
+
- **YOLO ティア**(`yolo` — `permissive-yolo` を担当): 人手確認を一切要求しない。危険な ask(不可逆・学習不能・解読不能なペイロード、またはレビューモデルの重リスク判定)は遮断し、理由を `工具审核意见` メッセージでメイン LLM に返す。それ以外は実行する。モデルが不在・無回答の時も人には聞かず、機械スクリーニングで処理した上で `yolo-allow-no-reviewer` に記録する(下記)。
|
|
25
|
+
- **縮退レビュー**(`rulesFallback`): レビューモデル未設定、または判定が返らなかったときに、誰も答えない確認画面で処理を止めず決定論的ネットだけで裁定する。モデルが応答している間は挙動不変。通常の自動審査ティア(`permissive` / `permissive-full`)向けの項目で、実装を専有する 3 ティアは答える側を既に明示しているため縮退させない。
|
|
26
|
+
- **スクリプトレビュー**(`scriptReview`、既定オン): 呼び出しが実行するスクリプトの本文を読み(有界・非実行)、レビューモデル・人・決定論的ネットの三者に同じコードを見せる。ファイル名だけでは見えない削除がコードで判定される。全文を読み取れたら「解読不能」ティアを抜ける。オフにするとファイル内容は本機から出ないが、ワークスペース外スクリプトは U ティアに戻る。
|
|
27
|
+
- **ユーザー申告型の保護**(いずれも追記専用・即時反映): `credentialPaths`(`.ssh` と同格——ワークスペース外からの読み取りとファイルツールによる書き換えを拒否)、`denyKeywordsExtra`(プリセットを置き換えず追記)、`extraContentArgKeys` / `extraOperationArgKeys`(どの引数が文書で、どれが操作かを内蔵表に加えて宣言)。
|
|
28
|
+
- **3つの無人確認実装 — スイッチ1つ・権限ティア1つずつ**:`safenetAsk`(`permissive-snet`)は決定論的な機械スクリーニングで危険を絞った上で**依然として人に聞く**。レビューモデルは一切呼ばない — 審査 LLM 未接続時、またはトークンを費やさず人に裁かせたい時の形。`safenetPass`(`permissive-mech`)は同じスクリーニングで **ask を引き取る**:名指しした危険は遮断して主モデルへ返し、特定できないものは実行する。人確認なし・モデル呼び出しなし — `approval: never` の審査付き版。`yolo`(`permissive-yolo`)はモデル付きのティアで、人が答えるべき問いにモデルが代答し、人へは絶対に格上げしない。要点は対応関係そのもの:スイッチは脇に書いたティアの挙動だけを変え、実装をオフにするとそのティアは別ティアに化けず通常の人確認へ戻る。五ティアはいずれも**プラグイン同梱**の profile patch で配布されるため、インストール直後からピッカーにあり手編集は不要(`permissive` 自体は不変)。なお 2 リビジョンだけ存在した per-preset テーブル(`<preset>=<mode>`)は退役 — この三つのスイッチと二重になり、一つの姿勢に二つの制御があれば一方は必ず嘘をつく。
|
|
29
|
+
- **YOLO は得ていない審査者を名乗らない**:レビューモデル未設定、または `unresolved` を返した場合、ティアは依然として人に聞かず機械スクリーニングで処理する。ただし記録は `yolo-allow-no-reviewer` となり理由にもそう書かれる — ラベル無しのフォールバックでは、モデルが居ない時だけ YOLO と機械ティアが承認履歴で区別できなくなるため。
|
|
30
|
+
- **全ティア共通の下層機械審査**:決定論的判定(不可逆/学習不能/読めない)が YOLO・降格ゲート・新規 passthrough の三箇所に手書きで重複していた。単一の `mechanicalJudge` に統合し、ティアが変わるのは「残りを誰が決めるか」だけで、「何を危険と数えるか」は変わらない。テストで固定:同じ呼び出しは YOLO でも passthrough でも遮断され、どちらもモデル呼び出しを消費しない。
|
|
31
|
+
- 設定カードの boolean 項目は**楽観式ピルスイッチ**になった(36×20 カプセル、状態は `aria-checked` が単一源泉、テーマトークン+フォールバックで明暗両対応)。無人確認の各行は自分が制御するティア名も併記する。いずれもクリックで即反転し、書き込みの確定・拒否・未報告で表示権をストアへ返す。
|
|
32
|
+
- 承認履歴が素のタグで出していた判断経路にラベルを付与:`yolo-allow` / `yolo-block`、`rules-fallback-*`、`safety-net-passthrough-*`、および以前から未翻訳だった四つ(`cleanup-safe`、`escalation-auto`、`learned-granted`、`network-ask`)。
|
|
33
|
+
- プロファイルおよび保護された Windows ルートを**変数や glob 経由**で削除する処理の決定論ネット(`$HOME`、`~/.*`、`$env:USERPROFILE\.*`、`%WINDIR%`、`$PSHOME` など): プロファイル根は即時拒否、他の保護ルートは「消せない永遠の ask」になる。9B レビューアでは知識注入型プロンプトでも実測で漏れたため、コード層に置いている。
|
|
34
|
+
|
|
35
|
+
### 修正
|
|
36
|
+
|
|
37
|
+
- issue #2: 文書系ツールの本文を操作として読まなくなった。共有ルール `src/scan-text.ts` がツールの区分で可読キーを決める(read / internal / write は command・url・path・query のみ。未知のツール名は引き続き実行型として全読)。`exit_plan_mode` は実行する予定のステップを正直に書けるようになり、モデルが計画文言を言い換えてゲートを抜ける状況を防ぐ。
|
|
38
|
+
- 同報告の付随項: 引用符外の改行、および空白なしで詰めた `;` `|` `&&` `||` を文区切りとして `decomposeShellCommand` が見るようになり、複数行コマンドの第 2 文がルールに到達する。単独の `&` は切らず、`2>&1` とバックグラウンド実行の形を守る。
|
|
39
|
+
- issue #3: デフォルト安全スクリーンによる格上げは自分の理由を名乗る(`write target outside the workspace (…)` / `command carries a file-write or redirect pattern`)。`no rule matched` の偽装はやめ、モデル自身の文も確認・拒否文言に載る(改行除去・角括弧除去・マスク処理・180 字上限で、`[deny-rule:…]` の偽造を防止)。
|
|
40
|
+
- issue #4: `=>` と `->` をファイルへのリダイレクトと誤認しなくなった。
|
|
41
|
+
- `write` / `edit` による資格情報ストアの変更(`~/.ssh/authorized_keys`、`.git-credentials`、`.npmrc`、クラウド資格情報)を P0 で拒否。従来は削除しか守っておらず、自動許可される書き込みでアクセス権を埋め込めた。
|
|
42
|
+
- 鍵組の公開側(`id_ed25519.pub`)は引数全体の資格情報スクリーンに掛からなくなった(手で鍵を復元する運用が不服申立て不能だった)。
|
|
43
|
+
- `deny-keyword` の監査文言から、ユーザーが追記した項目に対する "preset" 表記を除去。
|
|
44
|
+
|
|
45
|
+
### 既知のギャップ
|
|
46
|
+
|
|
47
|
+
- `pathArgument` は `file_path` / `path` / `cwd` / `workdir` のみ参照し、複数形フィールド(`paths`・`files`・`urls`)は資格情報パス基準の外。
|
|
48
|
+
- 渡された文書を実行するツール(`workflow`・`skill`・`ralph`)の本文はフラットなスクリーンでは読まない。委譲先の作業は独立したツール呼び出しとして審査される。
|
|
49
|
+
|
|
50
|
+
## [5.2.0] - 2026-10-14
|
|
51
|
+
|
|
52
|
+
### 追加
|
|
53
|
+
|
|
54
|
+
- `src/preset-rules.ts`: cc-safety-net から移植した 51 件の `[deny-rule:*]`(MIT。帰属は `THIRD_PARTY_NOTICES.md`)。`mergePresetIntoRaw()` は `deny`/`ask` の末尾に追記し、id 単位で冪等、ユーザーが取り消した行を再投入しない。新しい volatile キー `presetRulesSeeded` を有効化時に一度だけ記録。
|
|
55
|
+
- `argv.pipeline` を連結文字列だけでなく個々の単純コマンドでも評価する(プリセット命中率がそれに依存)。ルール判定は `deny-rule:<id>` で帰属。
|
|
56
|
+
|
|
57
|
+
### 修正
|
|
58
|
+
|
|
59
|
+
- シードが `apply` の同期本文内で走っており、当時 settings サービスがまだマウントされていないため、どのホストでも黙って一度も適用されていなかった。inject コールバック内、各世代が名前空間を登録した後に移動(0.1.5 では `installSection` 前の書き込みが例外を投げる)。
|
|
60
|
+
- ルールと冪等フラグを 2 つの `update` に分けていたため、rc.1+ では 2 つ目が `Plugin entry "dsh-perm-gate" is no longer configurable` で落ち、フラグが永遠に立たず、ユーザーが全削除したはずの表が無限に再シードされていた。現在は 1 回の更新で、ルールの成功後にフラグを書く。
|
|
61
|
+
- `rawEntry()` が `params` 次元に**コンパイル済み**の `ParamCondition[]` を出していたため、シード後の文書が次回起動時に本プラグイン自身のリーダーで失敗し(`permissions.deny[22].params.params must be a mapping`)、perm-gate が起動しなくなった。mapping に戻し、`!glob` 否定接頭辞も復元。
|
|
62
|
+
- プラグイン自身の `perm-gate/rules.yml` へのフォールバックを廃止(作者判断 2026-10-14): 手入れのルール源に 51 件の注入行を混ぜるべきではなく、その分岐は旧ホストでしか動かず、二つのホスト世代で挙動が食い違う。settings サービスが無い今はシードせず、ファイル書き込みには劣化させず明示的に報告。
|
|
63
|
+
- 3 件目を捕まえられた門を追加: `test/preset-rules-roundtrip.spec.ts` がマージ済み文書をリーダーとコンパイラに再通過させる。ネガティブコントロール(修正 3 を戻すと 5 件中 3 件が失敗)も確認済み。
|
|
64
|
+
|
|
65
|
+
## [5.1.0] - 2026-10-05
|
|
66
|
+
|
|
67
|
+
### 変更
|
|
68
|
+
|
|
69
|
+
- 15-rc 列挙線を統一: 三つのホストサブパッケージ(`client-locale`・`client-ui-renderer`・`client-ui-settings`)の peer を完全列挙し、内容は検証環境で確認済みの `4.3.0-beta.2` と同一ツリー、バージョンは compat 線の `5.0.4` を超える。
|
|
70
|
+
|
|
8
71
|
## [2.4.1] - 2026-09-17
|
|
9
72
|
|
|
10
73
|
### 修正
|
|
@@ -124,7 +187,7 @@
|
|
|
124
187
|
`auto` ティアの盾グリフに合わせるためのもので、0.1.2 では `aria-haspopup="menu"` セレクタ経由で設定行にも
|
|
125
188
|
適用され、ピッカーのグリフは組み込み値にのみ紐づくためプラグイン ティアは描画しません。
|
|
126
189
|
|
|
127
|
-
## [
|
|
190
|
+
## [0.2.1-beta.4] - 2026-09-11
|
|
128
191
|
|
|
129
192
|
### 追加
|
|
130
193
|
|
package/CHANGELOG.ko.md
CHANGED
|
@@ -5,6 +5,69 @@
|
|
|
5
5
|
형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/)을 따르며,
|
|
6
6
|
이 프로젝트는 [Semantic Versioning](https://semver.org/spec/v2.0.0.html)을 준수합니다.
|
|
7
7
|
|
|
8
|
+
> 참고: 2.4.1부터 5.1.2까지는 영문 `CHANGELOG.md`에만 기록되어 있습니다 (ko판은 아직 미추적).
|
|
9
|
+
|
|
10
|
+
## [5.3.1] - 2026-10-17
|
|
11
|
+
|
|
12
|
+
### 추가
|
|
13
|
+
|
|
14
|
+
- **호스트 지원: DSH `0.2.1-rc.1`.** 지원 호스트 열거(`package.json` engines.dsh, `dsh.plugin.json`, 모든 `@deepseek-ai/dsh*` peer, README 관리 블록)에 `0.2.1-rc.1` 추가(구간 없이 rc 단위 정확한 열거). 동작 변화 없음: 선언면 릴리스로, 0.2.1-alpha.4부터 engines.dsh만 읽는 호스트 게이트가 0.2.1-rc.1 호스트에서 이 플러그인을 허용합니다.
|
|
15
|
+
|
|
16
|
+
### 변경
|
|
17
|
+
|
|
18
|
+
- `publishConfig.registry`를 `https://registry.npmjs.org`에 고정(릴리스 위생: 배포 대상이 미러 registry로 표류하지 않음).
|
|
19
|
+
|
|
20
|
+
## [5.3.0] - 2026-10-17
|
|
21
|
+
|
|
22
|
+
### 추가됨
|
|
23
|
+
|
|
24
|
+
- **YOLO 티어** (`yolo` — `permissive-yolo` 를 담당): 사람 확인을 절대 요구하지 않는다. 위험한 ask(되돌릴 수 없음·학습 불가·해독 불가 하중, 또는 검토 모델의 하드 위험 판정)는 차단하고 이유를 `工具审核意见` 메시지로 메인 LLM에 되돌려 준다. 나머지는 실행된다. 심사자가 부재하거나 무응답일 때도 사람에게 묻지 않고 기계 선별로 처리하되 `yolo-allow-no-reviewer` 로 명시한다(아래 항목).
|
|
25
|
+
- **축소 검토** (`rulesFallback`): 검토 모델이 설정되지 않았거나 판정을 내리지 못했을 때, 아무도 답하지 않는 확인 창에 처리를 멈추지 않고 결정론적 그물만으로 판정한다. 모델이 답하는 동안에는 동작이 그대로다. 보통의 자동 심사 등급(`permissive` / `permissive-full`)에 적용되는 항목이며, 구현을 독점하는 세 등급은 이미 답하는 주체를 명시하고 있으므로 강등하지 않는다.
|
|
26
|
+
- **스크립트 검토** (`scriptReview`, 기본 켬): 호출이 실행하는 스크립트 본문을 (용량 제한·절대 실행 없이) 읽어 검토 모델·사람·결정론적 그물이 같은 코드를 보게 한다. 파일명으로는 보이지 않는 삭제가 코드로 판정된다. 전부 읽혔다면 '해독 불가' 티어를 벗어난다. 끄면 파일 내용은 로컬에 남지만 워크스페이스 외부 스크립트는 U 티어로 돌아간다.
|
|
27
|
+
- **사용자 신고형 보호** (모두 추가 전용·즉시 반영): `credentialPaths`(`.ssh`와 같은 기준——워크스페이스 외부 읽기와 파일 도구를 통한 변경을 거부), `denyKeywordsExtra`(프리셋을 대체하지 않고 병합), `extraContentArgKeys` / `extraOperationArgKeys`(내장 목록 위에 어떤 인자가 문서이고 어떤 것이 동작 서술인지를 선언한다).
|
|
28
|
+
- **무인 구현 세 개 — 스위치 하나에 권한 등급 하나씩**: `safenetAsk`(`permissive-snet`)는 결정론 기계 선별로 위험을 걸러낸 뒤에도 **여전히 사람에게 묻는다**. 심사 모델은 전혀 부르지 않는다 — 심사 LLM 미연결시, 또는 토큰을 쓰지 않고 사람이 직접 판단하게 하고 싶을 때의 형태. `safenetPass`(`permissive-mech`)는 같은 선별로 **ask 를 인계받는다**: 지목한 위험은 차단하고 주모델에 돌려보내며, 특정하지 못한 것은 실행한다. 사람 확인 없음·모델 호출 없음 — `approval: never` 의 심사판. `yolo`(`permissive-yolo`)는 모델을 쓰는 등급이며, 사람이 답할 질문을 모델이 대신 답하고 사람에게는 절대 격상하지 않는다. 핵심은 그 대응 관계 자체다: 스위치는 옆에 적힌 등급의 동작만 바꾸고, 구현을 끄면 그 등급은 다른 등급으로 몰래 바뀌지 않고 보통의 사람 확인으로 돌아간다. 다섯 등급은 모두 **플러그인 자체**의 profile patch 로 배포되어 설치 직후 피커에 있으며 손으로 고칠 것은 없다(`permissive` 자체는 그대로). 참고로 2개 리비전만 존재했던 per-preset 표(`<preset>=<mode>`)는 사라졌다 — 이 세 스위치와 중복되며, 하나의 자세에 제어기가 두 개면 하나는 반드시 거짓을 말한다.
|
|
29
|
+
- **YOLO 는 얻지 못한 심사자를 칭하지 않는다**: 심사 모델 미설정 또는 `unresolved` 일 때, 등급은 여전히 사람에게 묻지 않고 기계 선별로 처리한다. 다만 기록은 `yolo-allow-no-reviewer` 로 남고 이유에도 그렇게 적힌다 — 라벨 없는 폴백으로는 모델이 없는 순간에만 YOLO 와 기계 등급이 심사 이력에서 구별되지 않기 때문.
|
|
30
|
+
- **모든 등급이 공유하는 하층 기계 심사**: 결정론 판정 (비가역 / 학습 불가 / 해독 불가)이 YOLO·강등 게이트·새 passthrough 세 곳에 손으로 복사되어 있었다. 하나의 `mechanicalJudge`로 합쳐, 등급이 바뀌는 것은 "잔여를 누가 결정하는가"뿐이고 "위험을 무엇으로 보는가"는 바뀌지 않는다. 테스트로 고정: 같은 호출은 YOLO와 passthrough 모두에서 차단되며, 어느 쪽도 모델 호출을 쓰지 않는다.
|
|
31
|
+
- 설정 카드의 불리언 항목은 **낙관적 알약 스위치**가 되었다 (36×20 캡슐, 상태는 `aria-checked`가 단일 원천, 테마 토큰+폴백으로 명암 모두 대응). 무인 확인 각 행은 자기가 제어하는 등급 이름도 함께 찍는다. 모두 클릭 즉시 반전하고, 기록의 확정·거부·미보고 시 표시권을 저장소로 돌려준다.
|
|
32
|
+
- 심사 이력에서 맨 태그로 노출되던 결정 경로를 라벨링: `yolo-allow` / `yolo-block`, `rules-fallback-*`, `safety-net-passthrough-*`, 그리고 이전부터 미번역이던 넷 (`cleanup-safe`, `escalation-auto`, `learned-granted`, `network-ask`).
|
|
33
|
+
- 프로파일 및 보호된 Windows 루트를 **변수나 glob 경유**로 삭제하는 처리에 대한 결정론적 그물(`$HOME`, `~/.*`, `$env:USERPROFILE\.*`, `%WINDIR%`, `$PSHOME` 등): 프로파일 루는 바로 거부하고, 다른 보호 루트는 '지워지지 않는 영원한 ask'가 된다. 9B 검토 모델에서는 지식을 주입한 프롬프트로도 실측으로 놓쳤기에 코드 층에 두었다.
|
|
34
|
+
|
|
35
|
+
### 수정됨
|
|
36
|
+
|
|
37
|
+
- issue #2: 문서형 도구의 본문을 더 이상 동작으로 읽지 않는다. 공유 규칙 `src/scan-text.ts`가 도구 구분으로 읽을 키를 고른다(read / internal / write는 command·url·path·query만. 알 수 없는 도구명은 여전히 실행형으로 전부 읽음). `exit_plan_mode`는 실행할 단계를 솔직히 적을 수 있게 되어, 모델이 계획 문구를 비틀어 게이트를 통과하는 상황을 막는다.
|
|
38
|
+
- 같은 보고의 부수 항목: 따옴표 밖의 줄바꿈과 여백 없이 붙은 `;` `|` `&&` `||`를 문 구분자로 `decomposeShellCommand`가 보게 되어, 다중 행 명령의 두 번째 문이 규칙에 도달한다.혼자 쓰인 `&`는 자르지 않아 `2>&1`과 백그라운드 실행 형태를 지킨다.
|
|
39
|
+
- issue #3: 기본 안전 스크린이 올린 격상은 자기 이유를 직접 밝힌다(`write target outside the workspace (…)` / `command carries a file-write or redirect pattern`). `no rule matched`를 사칭하지 않고, 모델 자신의 문장도 확인·거부 문구에 실린다(개행 제거·각괄호 제거·마스크 처리·180자 상한으로 `[deny-rule:…]` 위조를 방지).
|
|
40
|
+
- issue #4: `=>`와 `->`를 파일 리다이렉트로 오인하지 않는다.
|
|
41
|
+
- `write` / `edit`로 자격증명 스토어를 변경하는 행위(`~/.ssh/authorized_keys`, `.git-credentials`, `.npmrc`, 클라우드 자격증명)를 P0에서 거부한다. 기존에는 삭제만 막혀 있어 자동 허용된 쓰기만으로 접근 권한을 심을 수 있었다.
|
|
42
|
+
- 키 쌍의 공개 쪽(`id_ed25519.pub`)은 인자 전체 자격증명 스크린에 걸리지 않는다(손으로 키를 복원하는 운용에 이의 제기 불가능 계층이 막히고 있었다).
|
|
43
|
+
- `deny-keyword` 감사 문구에서 사용자가 추가한 항목에 대한 "preset" 표현을 없앴다.
|
|
44
|
+
|
|
45
|
+
### 알려진 공백
|
|
46
|
+
|
|
47
|
+
- `pathArgument`는 `file_path` / `path` / `cwd` / `workdir`만 본다. 복수형 필드(`paths`·`files`·`urls`)는 자격증명 경로 기준 밖에 남는다.
|
|
48
|
+
- 넘겨받은 문서 자체를 실행하는 도구(`workflow`·`skill`·`ralph`)의 본문은 평탄화된 스크린으로 읽지 않는다. 위임된 작업은 독립적인 도구 호출로 심사된다.
|
|
49
|
+
|
|
50
|
+
## [5.2.0] - 2026-10-14
|
|
51
|
+
|
|
52
|
+
### 추가됨
|
|
53
|
+
|
|
54
|
+
- `src/preset-rules.ts`: cc-safety-net에서 이식한 51개의 `[deny-rule:*]` 항목(MIT, 출처는 `THIRD_PARTY_NOTICES.md`). `mergePresetIntoRaw()`는 `deny`/`ask` 끝에 추가하고 id 단위로 멱등이며, 사용자가 취소한 행을 다시 넣지 않는다. 새 volatile 키 `presetRulesSeeded`를 활성 시점에 한 번 기록.
|
|
55
|
+
- `argv.pipeline`을 연결 문자열뿐 아니라 개별 단순 명령마다 평가한다(프리셋 적중률이 여기에 의존). 규칙 판정은 `deny-rule:<id>`로 귀속.
|
|
56
|
+
|
|
57
|
+
### 수정됨
|
|
58
|
+
|
|
59
|
+
- 시딩이 `apply`의 동기 본문에서 달려 settings 서비스가 아직 마운트되지 않은 상태였기 때문에, 어떤 호스트에서도 조용히 한 번도 적용되지 않았다. 이제 inject 콜백 안, 각 세대가 네임스페이스를 등록한 뒤에 실행한다(0.1.5에서는 `installSection` 이전 쓰기가 예외를 던진다).
|
|
60
|
+
- 규칙과 멱등 플래그를 두 개의 `update`로 나누면 rc.1+에서 두 번째가 `Plugin entry "dsh-perm-gate" is no longer configurable`로 실패해 플래그가 영원히 서지 않았고, 사용자가 전부 취소한 표가 무한히 재시딩되었다. 이제 한 번의 갱신으로, 규칙 성공 이후에 플래그를 쓴다.
|
|
61
|
+
- `rawEntry()`가 `params` 차원에 **컴파일된** `ParamCondition[]`를 내보냈고, 그래서 시딩된 문서는 다음 부팅에서 이 플러그인 자기 자신의 리더에서 실패해(`permissions.deny[22].params.params must be a mapping`) perm-gate가 활성화되지 못했다. mapping으로 되돌리고 `!glob` 부정 접두어도 복원.
|
|
62
|
+
- 플러그인 자신의 `perm-gate/rules.yml`로 시딩하는 폴백을 폐기(저자 결정 2026-10-14): 손으로 관리하는 규칙 원본에 주입 행 51개를 섞어서는 안 되고, 그 분기는 구세대 호스트에서만 돌아 두 호스트 세대의 동작이 갈렸다. settings 서비스가 없으면 지금은 시딩하지 않으며, 파일 쓰기로 축소하지 않고 명시적으로 보고한다.
|
|
63
|
+
- 세 번째 항목을 잡을 수 있던 관문을 추가했다: `test/preset-rules-roundtrip.spec.ts`가 병합된 문서를 리더와 컴파일러에 다시 통과시킨다. 음성 대조(수정 3을 되돌리면 5개 중 3개 실패)도 확인했다.
|
|
64
|
+
|
|
65
|
+
## [5.1.0] - 2026-10-05
|
|
66
|
+
|
|
67
|
+
### 변경됨
|
|
68
|
+
|
|
69
|
+
- 15-rc 열거 라인 통일: 세 개의 호스트 서브패키지(`client-locale`·`client-ui-renderer`·`client-ui-settings`)의 peer를 전부 열거하고, 내용은 검증 환경에서 확인된 `4.3.0-beta.2`와 같은 트리이며, 버전은 compat 라인의 `5.0.4`를 넘는다.
|
|
70
|
+
|
|
8
71
|
## [2.4.1] - 2026-09-17
|
|
9
72
|
|
|
10
73
|
### 수정됨
|
|
@@ -121,7 +184,7 @@
|
|
|
121
184
|
방패 글리프에 맞추기 위한 것이었고, 0.1.2에서는 `aria-haspopup="menu"` 선택자를 통해 설정 행에도
|
|
122
185
|
적용되었으며, 선택기의 글리프는 내장 값에만 연결되므로 플러그인 티어는 그리지 않습니다.
|
|
123
186
|
|
|
124
|
-
## [
|
|
187
|
+
## [0.2.1-beta.4] - 2026-09-11
|
|
125
188
|
|
|
126
189
|
### 추가
|
|
127
190
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,150 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
|
-
## 统一 15-rc 枚举线:三宿主子包 peer 全量枚举(client-locale/client-ui-renderer/client-ui-settings),内容=保留场验证的 4.3.0-beta.2 同树,版本越过 compat 线 5.0.4。 — 2026-10-05
|
|
5
|
-
|
|
6
|
-
undefined
|
|
7
|
-
|
|
8
4
|
|
|
9
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
10
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
11
7
|
|
|
8
|
+
## [5.3.1] - 2026-10-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Host support: DSH `0.2.1-rc.1`.** The supported-host enumeration (`package.json` engines.dsh,
|
|
13
|
+
`dsh.plugin.json`, every `@deepseek-ai/dsh*` peer and the README managed blocks) now lists
|
|
14
|
+
`0.2.1-rc.1` alongside the fifteen rc releases up the 0.2.0 line — exact per-rc enumeration,
|
|
15
|
+
no ranges. Behaviour is unchanged: this is a declaration-surface release so the host gate
|
|
16
|
+
(which since 0.2.1-alpha.4 reads engines.dsh alone) accepts the plugin on a 0.2.1-rc.1 host.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Pinned `publishConfig.registry` to `https://registry.npmjs.org` (release hygiene: a publish can
|
|
21
|
+
no longer drift to a mirror registry).
|
|
22
|
+
|
|
23
|
+
## [5.3.0] - 2026-10-17
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **YOLO tier** (`yolo`, owning the `permissive-yolo` preset): never raises a human
|
|
28
|
+
confirmation. A dangerous ask — irreversible, unlearnable, an unreadable payload, or a
|
|
29
|
+
hard-risk verdict from the configured reviewer — is blocked and the reason is fed back to the
|
|
30
|
+
main agent as a `工具审核意见` user message; everything else runs. With no reviewer in seat it
|
|
31
|
+
does **not** quietly allow: the mechanical screen settles it and the event is labelled (see the
|
|
32
|
+
`yolo-allow-no-reviewer` entry below).
|
|
33
|
+
- **Degraded review** (`rulesFallback`): when the reviewer is not configured or returns no
|
|
34
|
+
verdict, the deterministic nets decide instead of parking the call on a confirmation nobody
|
|
35
|
+
will answer. Unchanged while a reviewer answers; it applies to the ordinary 自动审查 tiers
|
|
36
|
+
(`permissive`, `permissive-full`) — the three tiers that own an implementation already say who
|
|
37
|
+
answers, so this switch does not degrade them.
|
|
38
|
+
- **Script review** (`scriptReview`, on by default): the body of every script a call runs is read
|
|
39
|
+
(bounded, never executed) and given to the grader, the human card and the deterministic nets —
|
|
40
|
+
a delete that only shows up inside the file is graded on its code instead of its filename. A
|
|
41
|
+
fully-read script also stops being an unreadable payload; switching this off keeps file content
|
|
42
|
+
on the machine at the cost of sending such runs back to the `U` (unknown-target) tier.
|
|
43
|
+
- **User-declared protection**, all additive and all hot-applied: `credentialPaths` (path globs
|
|
44
|
+
held to the same standard as `.ssh` — reading one outside the workspace, or mutating one with a
|
|
45
|
+
file tool, is refused), `denyKeywordsExtra` (appends to the blacklist; the preset list stays
|
|
46
|
+
un-replaceable), and `extraContentArgKeys` / `extraOperationArgKeys` (which argument fields are
|
|
47
|
+
prose and which are operations, on top of the built-in lists).
|
|
48
|
+
- **Three unattended implementations, one switch and one permission preset each**: `safenetAsk`
|
|
49
|
+
(`permissive-snet`) screens with the deterministic nets and **still asks a person**, calling no
|
|
50
|
+
grader at all — the shape the gate takes when no reviewer LLM is connected, or when the tokens
|
|
51
|
+
are not worth spending and a human answer beats an auto-decision. `safenetPass`
|
|
52
|
+
(`permissive-mech`) lets the same screen **take over the ask**: named danger is blocked and fed
|
|
53
|
+
back to the main agent, everything it cannot condemn runs, with no human prompt and no model
|
|
54
|
+
call — the reviewed form of `approval: never`. `yolo` (`permissive-yolo`) is the model-backed
|
|
55
|
+
tier: the grader answers in the person's place and it never escalates. The mapping is the point:
|
|
56
|
+
a switch changes the behaviour of the tier named beside it and of no other, and switching an
|
|
57
|
+
implementation off returns that tier to the ordinary human flow rather than quietly turning it
|
|
58
|
+
into a different one. All five tiers ship in **the plugin's own** profile patch, so they are in
|
|
59
|
+
the permission picker on install with nothing to hand-edit; `permissive` itself is untouched.
|
|
60
|
+
(A per-preset `<preset>=<mode>` table existed for two revisions and is retired — it competed with
|
|
61
|
+
these switches, and two controls for one posture means one of them lies.)
|
|
62
|
+
- **YOLO no longer claims a reviewer it did not get.** With no grader configured, or one that
|
|
63
|
+
returns `unresolved`, the tier still refuses to ask a person and settles on the mechanical
|
|
64
|
+
screen — but the event is recorded as `yolo-allow-no-reviewer` and the reason says so, because
|
|
65
|
+
an unlabelled fallback made YOLO and the mechanical tier indistinguishable in the approvals
|
|
66
|
+
history exactly when the model was missing.
|
|
67
|
+
- **One mechanical floor for every tier**: the deterministic judge (irreversible / unlearnable /
|
|
68
|
+
unreadable) was hand-copied in three places — YOLO, the degraded gate and the new passthrough
|
|
69
|
+
tier. It is now a single `mechanicalJudge`, so a tier can change only *who settles the residual*,
|
|
70
|
+
never *what counts as danger*. Pinned by tests: the same call is blocked under YOLO and under
|
|
71
|
+
passthrough alike, and neither spends a model call on it.
|
|
72
|
+
- The settings card's booleans are now **optimistic pill switches** (36×20 capsule, state keyed off
|
|
73
|
+
`aria-checked`, theme tokens with fallbacks so light and dark both read correctly), and each
|
|
74
|
+
unattended row prints the preset it governs. They flip on click and hand the visual back to the
|
|
75
|
+
store when the write lands, is rejected, or is never reported.
|
|
76
|
+
- The approvals history labels the decision paths that previously showed raw tags: `yolo-allow` /
|
|
77
|
+
`yolo-block`, `rules-fallback-*`, `safety-net-passthrough-*`, plus four older ones that also
|
|
78
|
+
reached the feed untranslated (`cleanup-safe`, `escalation-auto`, `learned-granted`, `network-ask`).
|
|
79
|
+
- A deterministic net for deletions aimed at the profile or a protected Windows root **through a
|
|
80
|
+
variable or a glob** (`$HOME`, `~/.*`, `$env:USERPROFILE\.*`, `%WINDIR%`, `$PSHOME` …): the
|
|
81
|
+
profile root is refused outright, other protected roots become a permanent confirmation that no
|
|
82
|
+
answer can be learned away. Measured: no grading prompt — not one primed with read-only-variable
|
|
83
|
+
knowledge — held this on a 9B reviewer, which is why it lives in code.
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
|
|
87
|
+
- Issue #2: a document tool's prose is no longer read as an operation. One shared rule
|
|
88
|
+
(`src/scan-text.ts`) picks readable keys by tool class — a read/internal/write tool exposes only
|
|
89
|
+
its command, url, path and query fields, while an unfamiliar tool name is still treated as an
|
|
90
|
+
executor. `exit_plan_mode` can now describe a step it intends to ask about; previously the plan
|
|
91
|
+
text hit the destructive blacklist and the model learned to reword plans to get past the gate.
|
|
92
|
+
- The same report's aside: newlines and glued `;` / `|` / `&&` / `||` outside quotes are now
|
|
93
|
+
statement separators for `decomposeShellCommand`, so the second statement of a multi-line
|
|
94
|
+
command is finally seen as a program a rule can match. This was the same root as the cross-line
|
|
95
|
+
delete leak; a lone `&` is left alone so `2>&1` and background jobs keep their shape.
|
|
96
|
+
- Issue #3: an escalation the default safety screen produced reports itself
|
|
97
|
+
(`write target outside the workspace (…)` / `command carries a file-write or redirect pattern`)
|
|
98
|
+
instead of impersonating "no rule matched", and the reviewer's own sentence now reaches the
|
|
99
|
+
confirmation and the block wording — flattened, bracket-stripped, redacted and capped, so a
|
|
100
|
+
model cannot forge a `[deny-rule:…]` tag into the audit trail.
|
|
101
|
+
- Issue #4: the write-pattern pre-screen no longer reads `=>` or `->` as a redirect into a file.
|
|
102
|
+
- Credential stores mutated through `write`/`edit` (`~/.ssh/authorized_keys`, `.git-credentials`,
|
|
103
|
+
`.npmrc`, cloud credential files …) are refused at P0. Only deleting them was covered, so an
|
|
104
|
+
auto-allowed write could install an access backdoor.
|
|
105
|
+
- The public half of a keypair (`id_ed25519.pub`) is no longer caught by the whole-arguments
|
|
106
|
+
credential screen, which had made a hand-carried key restore impossible to appeal.
|
|
107
|
+
- `deny-keyword` audit wording drops "preset" for entries the user appended.
|
|
108
|
+
|
|
109
|
+
### Known gap
|
|
110
|
+
|
|
111
|
+
- `pathArgument` reads `file_path` / `path` / `cwd` / `workdir`; plural fields (`paths`, `files`,
|
|
112
|
+
`urls`) are not held to the credential-path standard.
|
|
113
|
+
- A tool that executes a document it was given (`workflow`, `skill`, `ralph`) is not read from that
|
|
114
|
+
body by the flattened screen; the work it delegates is gated as its own tool call.
|
|
115
|
+
|
|
116
|
+
## [5.2.0] - 2026-10-14
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
|
|
120
|
+
- `src/preset-rules.ts`: 51 `[deny-rule:*]` entries ported from cc-safety-net (MIT; attribution in
|
|
121
|
+
`THIRD_PARTY_NOTICES.md`). `mergePresetIntoRaw()` appends to the tail of `deny`/`ask`, is
|
|
122
|
+
idempotent per id, and never re-adds a row the user revoked. New volatile `presetRulesSeeded`,
|
|
123
|
+
written once on activation.
|
|
124
|
+
- `argv.pipeline` is evaluated per simple command as well as over the joined string — the preset's
|
|
125
|
+
hit rate depends on it — and a rule verdict is attributed by its `deny-rule:<id>`.
|
|
126
|
+
|
|
127
|
+
### Fixed
|
|
128
|
+
|
|
129
|
+
- The seed ran inside `apply`'s synchronous body, where the settings service is not mounted yet, so
|
|
130
|
+
it silently never happened on any host. It now runs in the inject callback, after each host
|
|
131
|
+
generation has registered the namespace (on 0.1.5 a write before `installSection` throws).
|
|
132
|
+
- Rules and the idempotency flag were two separate `update` calls; on rc.1+ the second throws
|
|
133
|
+
`Plugin entry "dsh-perm-gate" is no longer configurable`, so the flag never landed and a full
|
|
134
|
+
user revocation would be re-seeded forever. Now one update, with the flag written only after the
|
|
135
|
+
rules succeeded.
|
|
136
|
+
- `rawEntry()` emitted the *compiled* `ParamCondition[]` for the `params` dimension, so the seeded
|
|
137
|
+
document failed this plugin's own reader on the next boot
|
|
138
|
+
(`permissions.deny[22].params.params must be a mapping`) and perm-gate stopped activating.
|
|
139
|
+
Reverted to a mapping, restoring the `!glob` negation prefix.
|
|
140
|
+
- Dropped the fallback that seeded into the plugin's own `perm-gate/rules.yml`: a hand-maintained
|
|
141
|
+
rule source must not get 51 injected entries mixed into it, and the branch only ran on legacy
|
|
142
|
+
hosts, so the two host generations behaved differently. No settings service now means no seeding,
|
|
143
|
+
reported loudly instead of degrading into a file write.
|
|
144
|
+
- Added the gate that would have caught the third item:
|
|
145
|
+
`test/preset-rules-roundtrip.spec.ts` feeds the merged document back through the reader and the
|
|
146
|
+
compiler, with a negative control (reverting the fix fails 3 of 5 cases).
|
|
147
|
+
|
|
12
148
|
## [5.1.2] - 2026-10-12
|
|
13
149
|
|
|
14
150
|
### Changed
|
|
@@ -113,6 +249,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
113
249
|
- 席位契约测试(test/client-settings-seat.spec.ts)改钉单节形态:
|
|
114
250
|
settings.section 恰一次(order 30 / PermissiveCard),三个退役席位断言缺席。
|
|
115
251
|
|
|
252
|
+
## [5.1.0] - 2026-10-05
|
|
253
|
+
|
|
254
|
+
### Changed
|
|
255
|
+
|
|
256
|
+
- Unified the 15-rc enumeration line: the three host sub-packages (`client-locale`,
|
|
257
|
+
`client-ui-renderer`, `client-ui-settings`) enumerate their peers in full, the content equals the
|
|
258
|
+
verification-farm-confirmed `4.3.0-beta.2` tree, and the version supersedes the compat line's
|
|
259
|
+
`5.0.4`.
|
|
260
|
+
|
|
116
261
|
## [2.6.0] - 2026-09-17
|
|
117
262
|
|
|
118
263
|
### Added
|
package/README.ja.md
CHANGED
|
@@ -63,7 +63,7 @@ fail-closed を徹底します:P0 の判定は、grant・ルール・分類器
|
|
|
63
63
|
上書きされません。
|
|
64
64
|
|
|
65
65
|
<!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->
|
|
66
|
-
- **対応する DSH ホスト:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2`(0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0 の
|
|
66
|
+
- **対応する DSH ホスト:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` `0.2.1-rc.1`(0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0 / 0.2.1 の 16 rc)
|
|
67
67
|
- **ランタイム検証済み:** `0.2.0-rc.2`(証跡は `.compat-results/`)
|
|
68
68
|
<!-- host-compat:end -->
|
|
69
69
|
|
|
@@ -260,7 +260,33 @@ P0–P4 の全チェーンが動作します。ゲートはプリセットの**
|
|
|
260
260
|
alwaysConfirm: false # すべて ask。許可コントロールに拡張ボタン 2 つ
|
|
261
261
|
trustEscalation: true # ゲートが許可済みの呼び出し自身のサンドボックス昇格は確認不要
|
|
262
262
|
llmAssist: false # まず LLM が分類、ask/失敗時は人手へ
|
|
263
|
+
yolo: false # 無人監視:人を確認せず、危険のみ遮断・他は実行
|
|
264
|
+
rulesFallback: false # レビューモデル不在時だけ決定論的ネット単独で裁定
|
|
265
|
+
scriptReview: true # 呼び出しが実行するスクリプト本文をレビューに添付
|
|
266
|
+
credentialPaths: [] # 内蔵一覧にない秘密パスを `.ssh` と同格で保護
|
|
267
|
+
denyKeywordsExtra: [] # ブラックリストへの追記(プリセットを置き換えない)
|
|
268
|
+
extraContentArgKeys: [] # どの引数が文書で、どれが操作か
|
|
269
|
+
extraOperationArgKeys: [] # 実際に実行されるコードである項目(同名時はこちら優先)
|
|
270
|
+
safenetPass: true # permissive-mech ティアの実装が存在(機械が ask を引き取る)
|
|
271
|
+
safenetAsk: false # permissive-snet ティアの実装が存在(機械スクリーニング、人確認は残る)
|
|
263
272
|
```
|
|
273
|
+
スイッチは三つ、それぞれがプラグイン自身ピッカーに出す権限ティア1 個だけを制御します。だから
|
|
274
|
+
あるスイッチの変更は自分のティアにだけ及ぼし、実装をオフにするとそのティアは別のティアに化けず
|
|
275
|
+
通常の人確認へ戻ります。
|
|
276
|
+
|
|
277
|
+
| スイッチ | ティア | ask を決めるのは | 人に聞くか | モデルを呼ぶか |
|
|
278
|
+
| --- | --- | --- | --- | --- |
|
|
279
|
+
| `permissive` | `permissive` / `permissive-full` | 機械スクリーニング + モデル精査、残り人は人 | 聞く | `llmAssist` 次第 |
|
|
280
|
+
| `safenetAsk` | `permissive-snet` | 人に聞く(機械の疑点を併記) | **聞く** | **一度も呼ばない** |
|
|
281
|
+
| `safenetPass` | `permissive-mech` | 機械のみ:名指しは遮断 + 返送、他は実行 | 聞かない | **一度も呼ばない** |
|
|
282
|
+
| `yolo` | `permissive-yolo` | モデルが人の代わりに裁く(risky は遮断 + 返送) | 絶対に聞かない | 毎回 |
|
|
283
|
+
|
|
284
|
+
`safenetPass` は `approval: never` の審査付き版(あちらは誰も判定せずに全部通す)であり、レビューア
|
|
285
|
+
不在時に YOLO が退化する先でもあります。`yolo` は定義上モデル付きのティアです:レビューアが
|
|
286
|
+
いない時も人には聞かず機械で処理し、記録を `yolo-allow-no-reviewer` にして「モデルが答えた」と
|
|
287
|
+
読まれないようにします。五ティアともプラグイン同梱の patch で配布されるため、インストール直後から
|
|
288
|
+
ピッカーにあり手編集は不要。`gatePresets` 外のプリセットはここには現れません。
|
|
289
|
+
|
|
264
290
|
|
|
265
291
|
`trustAutoAllow` は中間ティアのベースラインです(rule-allow は自動通過)。
|
|
266
292
|
`alwaysConfirm` はすべての境界で承認パネルを表示し、その「許可コントロール」に
|
|
@@ -273,6 +299,23 @@ P0–P4 の全チェーンが動作します。ゲートはプリセットの**
|
|
|
273
299
|
常に fail-closed です。`trustEscalation`(ティア有効時に既定オン)はゲートがすでに許可した呼び出し内で
|
|
274
300
|
`sandbox_permissions` 昇格が発生した際にここで回答します。以下参照。`permissive` がオフなら、ゲートの挙動は以前と完全に同じです。
|
|
275
301
|
|
|
302
|
+
### 無人監視ティアと、プリセットが知らない秘密を守るには
|
|
303
|
+
|
|
304
|
+
三つのスイッチは「誰が決めるか」を、七つのキーは「何が見えるか」を変える。すべて volatile で、
|
|
305
|
+
設定カードからの変更は次のツール呼び出しから効く(リロード不要)。
|
|
306
|
+
|
|
307
|
+
- `yolo`(`permissive-yolo` を担当)— 人手確認を一切要求しない。危険な ask(不可逆 / 学習不能 / 解読不能なペイロード / モデルの重リスク判定)は遮断し、理由を `工具审核意见` メッセージでメイン LLM に返す。それ以外は実行する。レビューモデルが不在の時も黙って実行に倒さず、機械スクリーニングで裁定し `yolo-allow-no-reviewer` に記録する — 応答しなかったモデルを応答したと報告できないため。
|
|
308
|
+
- `rulesFallback` — 縮退レビュー。レビューモデルが未設定、または判定を返さなかったときに限り、誰も答えない確認画面で待たず決定論的ネットだけで裁定する。モデルが応答している間は不変。適用先は通常の自動審査ティア(`permissive` / `permissive-full`)で、実装を専有する 3 ティアは答える側を既に明示しているため縮退させない。
|
|
309
|
+
- `scriptReview`(既定オン)— 呼び出しがスクリプトを実行するとき、その本文を読み(有界・絶対実行しない)、レビューモデル・人のカード・決定論的ネットの三者に見せる。ファイル名では見えない削除がコードで判定される。全文を読めれば「解読不能」でもないので U ティアを抜ける。オフにするとファイル内容は本機に残るが、ワークスペース外スクリプトは「読めない=人に聞く」に戻る。
|
|
310
|
+
|
|
311
|
+
「何を秘密とみなすか」の長尾は拡張できるが、いずれの表も**内蔵表への追記のみ**で置き換えはできない。`content` や `plan` を書き漏らすと、この門禁が既に直した bug を静かに再現してしまうからだ。
|
|
312
|
+
|
|
313
|
+
- `credentialPaths` — パス glob(双アスタリスクはディレクトリを横断、単アスタリスクと?は 1 段内。ワイルドカードなしならパス断片として一致、`~/` は home に展開、相対指定は任意の深さでも一致)。列挙したパスは `.ssh` と同格:ワークスペース外からの読み取りも、`write`/`edit` での変更も拒否する。このティアは P0(異議申立て不能、レビューモデルも通過させられない)で、`rules.yaml` ではなく設定項目にしたのはそのせい:読み取り専用ツールは規則鎖より**前**に自動許可されるため、規則はこれらの呼び出しを見られない。
|
|
314
|
+
- `denyKeywordsExtra` — 実際に有効なブラックリスト(プリセットでも自分で置き換えた表でも)に**追記**する。自社 CLI の取消しサブコマンドや自社トークン接頭辞を、50 行のプリセットを profile に写さずに決定論的に遮断できる。
|
|
315
|
+
- `extraContentArgKeys` / `extraOperationArgKeys` — どの引数が文書でどれが操作かの宣言。前者はホストツールの `steps`/`notes` 本文を操作として読ませない(issue #2 はまさにこれで、正直な計画書が `rm -rf` を書いたという理由で拒否された)。後者は `workflowYaml` のように本文が本当に実行されるフィールドを逆方向に開くもので、両方に同名がある場合はこちらが勝つ。本物の文書フィールドを指定すると「計画に `rm -rf` とある」ことが再び拒否理由になるため、既定はオフ。
|
|
316
|
+
|
|
317
|
+
`command` や `file_path` を文書と宣言しても門禁は弱まらない:実際に実行されるコマンドと変更されるパスは別の判別経路で見ており、この表を通らない(テストで固定済み)。
|
|
318
|
+
|
|
276
319
|
### サンドボックス昇格:なぜ `safe` 判定でもプロンプトが出たか
|
|
277
320
|
|
|
278
321
|
ツール呼び出しは**2 つの独立した承認**を引き起こし得ます。ゲートが持つのが第 1 の承認 —
|
package/README.ko.md
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
> `@deepseek-ai/dsh-client-runtime`은 `0.1.2-alpha.1`에서 **제거**되었습니다 —
|
|
38
38
|
> 단순히 이동한 것이 아닙니다. `legacy` 라인은 여전히 이를 통해 `ctx.slots`에
|
|
39
39
|
> 접근합니다. `main`은 `@deepseek-ai/dsh-client-ui-renderer/client`에서 같은
|
|
40
|
-
> 선언을 가져옵니다. 두 버전 민감
|
|
40
|
+
> 선언을 가져옵니다. 두 버전 민감 사항은 버전 체크 대신 기능 프로브로 처리합니다:
|
|
41
41
|
> (1) 설정 등록은 `register`를 사용하며, 두 라인 모두에 존재합니다
|
|
42
42
|
> (`installSection`은 대체가 아닌 추가 사항); (2) `effectivePolicy`는 두 라인
|
|
43
43
|
> 모두에서 user-approval 서비스의 **개인** 메소드이므로 `typeof` 프로브를 통해
|
|
@@ -61,7 +61,7 @@ DeepSeek Harness용 단일·자족적·결정론 우선·fail-closed 권한 게
|
|
|
61
61
|
덮어써지지 않습니다.
|
|
62
62
|
|
|
63
63
|
<!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->
|
|
64
|
-
- **지원하는 DSH 호스트:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` (0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0 라인의
|
|
64
|
+
- **지원하는 DSH 호스트:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` `0.2.1-rc.1` (0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0 / 0.2.1 라인의 16개 rc)
|
|
65
65
|
- **런타임 검증됨:** `0.2.0-rc.2` (증적은 `.compat-results/`)
|
|
66
66
|
<!-- host-compat:end -->
|
|
67
67
|
|
|
@@ -255,7 +255,33 @@ DSH **자신**의 트래픽 —— 내장 네트워크 도구와 LLM 전송 —
|
|
|
255
255
|
alwaysConfirm: false # 매번 ask. 허용 컨트롤에 확장 버튼 2개
|
|
256
256
|
trustEscalation: true # 게이트가 허용한 호출 자체의 샌드박스 승격은 확인 불필요
|
|
257
257
|
llmAssist: false # 먼저 LLM이 분류, ask/실패 시 사람에게
|
|
258
|
+
yolo: false # 무인: 사람에게 묻지 않음, 위험만 차단·나머지 실행
|
|
259
|
+
rulesFallback: false # 검토 모델 없을 때만 결정론 그물만으로 판정
|
|
260
|
+
scriptReview: true # 호출이 실행하는 스크립트 본문을 검토에 첨부
|
|
261
|
+
credentialPaths: [] # 내장 목록 밖의 비밀 경로를 `.ssh`와 같은 기준으로
|
|
262
|
+
denyKeywordsExtra: [] # 블랙리스트에 추가 (프리셋을 대체하지 않음)
|
|
263
|
+
extraContentArgKeys: [] # 어떤 인자가 문서이고 어떤 것이 동작 서술인가
|
|
264
|
+
extraOperationArgKeys: [] # 실제로 실행되는 코드인 항목 (같은 키면 이것 우선)
|
|
265
|
+
safenetPass: true # permissive-mech 등급의 구현 존재 (기계가 ask 를 인계)
|
|
266
|
+
safenetAsk: false # permissive-snet 등급의 구현 존재 (기계 선별, 사람 확인은 남음)
|
|
258
267
|
```
|
|
268
|
+
스위치는 셋이고, 각자가 플러그인 스스로 피커에 올리는 권한 등급 하나만 제어합니다. 따라서 한 스위치
|
|
269
|
+
는 자기 등급의 동작만 바꾸고, 구현을 끄면 그 등급은 다른 등급으로 몰래 바뀌지 않고 보통의 사람 확인으로
|
|
270
|
+
돌아갑니다.
|
|
271
|
+
|
|
272
|
+
| 스위치 | 등급 | ask 를 결정하는 주체 | 사람에게 묻나 | 모델을 부르나 |
|
|
273
|
+
| --- | --- | --- | --- | --- |
|
|
274
|
+
| `permissive` | `permissive` / `permissive-full` | 기계 선별 + 모델 정제, 나머지는 사람 | 묻는다 | `llmAssist` 차례 |
|
|
275
|
+
| `safenetAsk` | `permissive-snet` | 사람에게 묻는다 (기계 의문점 제시) | **묻는다** | **한 번도 안 부름** |
|
|
276
|
+
| `safenetPass` | `permissive-mech` | 기계 단독: 지목은 차단 + 회송, 나머지는 실행 | 묻지 않는다 | **한 번도 안 부름** |
|
|
277
|
+
| `yolo` | `permissive-yolo` | 모델이 사람 대신 판정 (risky 차단 + 회송) | 절대 묻지 않는다 | 잔여마다 |
|
|
278
|
+
|
|
279
|
+
`safenetPass` 는 `approval: never` 의 심사판이고 (저쪽은 판정자 없이 전부 통과), 심사자가 부재할 때
|
|
280
|
+
YOLO 가 열화되는 형태이기도 합니다. `yolo` 는 정의상 모델을 쓰는 등급입니다: 심사자가 없어도 사람에게
|
|
281
|
+
묻지 않고 기계로 처리하며, 기록을 `yolo-allow-no-reviewer` 로 남겨 "모델이 답했다" 로 오독되는 것을
|
|
282
|
+
막습니다. 다섯 등급 모두 플러그인 자체 patch 로 배포되어 설치 직후 피커에 있으며 손으로 고칠 것은
|
|
283
|
+
없습니다. `gatePresets` 밖의 프리셋은 여기까지 오지 않습니다.
|
|
284
|
+
|
|
259
285
|
|
|
260
286
|
`trustAutoAllow`은 중간 티어의 기준선입니다(rule-allow는 자동 통과). `alwaysConfirm`은
|
|
261
287
|
모든 경계에서 승인 패널을 띄우며, 그「허용 컨트롤」에 두 개의 확장 버튼을 추가합니다 —
|
|
@@ -270,6 +296,22 @@ DSH **자신**의 트래픽 —— 내장 네트워크 도구와 LLM 전송 —
|
|
|
270
296
|
`sandbox_permissions` 승격이 발생할 때 여기서 응답합니다. 아래 참조.
|
|
271
297
|
`permissive`가 꺼져 있으면 게이트는 이전과 완전히 동일하게 동작합니다.
|
|
272
298
|
|
|
299
|
+
### 무인 티어와, 프리셋이 모르는 비밀 지키기
|
|
300
|
+
|
|
301
|
+
세 개의 스위치는 “누가 정하는가”를, 일곱 개의 키는 “무엇이 보이는가”를 바꾼다. 모두 volatile이라 설정 카드에서 고치면 다음 도구 호출부터 적용된다(재시작 불요).
|
|
302
|
+
|
|
303
|
+
- `yolo`(`permissive-yolo` 담당) — 사람 확인을 절대 요구하지 않는다. 위험한 ask(되돌릴 수 없음 / 학습 불가 / 해독 불가 하중 / 모델의 하드 위험 판정)는 차단하고 이유를 `工具审核意见` 메시지로 메인 LLM에 되돌려 준다. 나머지는 실행한다. 심사 모델이 부재할 때도 조용히 실행으로 넘기지 않고 기계 선별로 판정해 `yolo-allow-no-reviewer`로 남긴다 — 답하지 않은 모델을 답한 것처럼 보고할 수는 없기 때문이다.
|
|
304
|
+
- `rulesFallback` — 축소 검토. 검토 모델이 없거나 판정을 내리지 못했을 때만, 아무도 답하지 않는 확인 창에 멈추지 않고 결정론 그물만으로 판정한다. 모델이 답하는 동안에는 그대로다. 적용 대상은 보통의 자동 심사 등급(`permissive` / `permissive-full`)이며, 구현을 독점하는 세 등급은 이미 답하는 주체를 명시하므로 강등하지 않는다.
|
|
305
|
+
- `scriptReview`(기본 켬) — 호출이 스크립트를 실행할 때 본문을 읽어(용량 제한·절대 실행 없음) 검토 모델·사람 카드·결정론 그물 셋에 같은 코드를 보여 준다. 파일명으로는 보이지 않는 삭제가 코드로 판정된다. 전부 읽혔다면 ‘해독 불가’가 아니므로 U 티어를 벗어난다. 끄면 파일 내용은 본기에 남지만, 워크스페이스 외부 스크립트는 ‘읽을 수 없음=사람에게 묻기’로 돌아간다.
|
|
306
|
+
|
|
307
|
+
‘무엇을 비밀로 칠 것인가’의 롱테일은 확장할 수 있지만, 모든 표는 **내장 표에 추가만** 가능하고 대체는 불가능하다. `content`나 `plan`을 빼먹으면 이 게이트가 이미 고친 bug를 조용히 되살리게 되기 때문이다.
|
|
308
|
+
|
|
309
|
+
- `credentialPaths` — 경로 glob(이중 별은 디렉터리 횡단, 단별과 ?는 한 단계 안. 와일드카드가 없으면 경로 단편 전체로 일치, `~/`는 home으로 확장, 상대 패턴은 어떤 깊이에서도 일치). 나열한 경로는 `.ssh`와 같은 기준: 워크스페이스 외부 읽기와 `write`/`edit` 변경이 모두 거부된다. 이 등급은 P0(이의 제기 불가, 검토 모델도 통과시킬 수 없음)이며, `rules.yaml` 규칙이 아니라 설정 항목인 이유가 그것이다: 읽기 전용 도구는 규칙 사슬보다 **앞**에서 자동 허용되므로 규칙은 그 호출을 볼 수 없다.
|
|
310
|
+
- `denyKeywordsExtra` — 지금 살아 있는 블랙리스트(프리셋이든 대체한 표든)에 **추가**한다. 사내 CLI의 취소 하위 명령이나 자체 토큰 접두어를, 프리셋 50행을 profile에 베끼지 않고 결정론적으로 차단할 수 있다.
|
|
311
|
+
- `extraContentArgKeys` / `extraOperationArgKeys` — 어떤 인자가 문서이고 어떤 것이 동작인지를 선언한다. 앞자는호스트 도구의 `steps`/`notes` 본문을 동작으로 읽지 못하게 한다(issue #2가 바로 이것: 솔직한 계획서에 `rm -rf`를 적었다는 이유로 거부됐다). 뒷자는 `workflowYaml`처럼 본문이 실제로 실행되는 필드를 반대 방향으로 열며, 두 표에 같은 이름이 있으면이쪽이 이긴다. 진짜 문서 필드를 적으면 “계획서에 `rm -rf`가 보인다”가 다시 거부 이유가 되므로 기본은 꺼짐.
|
|
312
|
+
|
|
313
|
+
`command`나 `file_path`를 문서로 선언해도 게이트는 약해지지 않는다: 실제로 실행되는 명령과 변경되는 경로는 각자의 판별 경로를 통해 보이며, 이 표를 지나지 않는다(테스트로 고정).
|
|
314
|
+
|
|
273
315
|
### 샌드박스 승격: 왜 `safe` 판정에도 프롬프트가 떴나
|
|
274
316
|
|
|
275
317
|
툴 호출은 **두 개의 독립된 승인**을 일으킬 수 있습니다. 게이트가 맡는 것이 첫 번째 —
|
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ A single, self-sufficient, deterministic-first, fail-closed permission gate for
|
|
|
59
59
|
Strictly fail-closed: a P0 decision is never overridden by a grant, a rule, the classifier, or a human.
|
|
60
60
|
|
|
61
61
|
<!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->
|
|
62
|
-
- **Supported DSH hosts:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` (
|
|
62
|
+
- **Supported DSH hosts:** `0.1.0-rc.2` `0.1.0-rc.3` `0.1.0-rc.6` `0.1.0-rc.7` `0.1.0-rc.8` `0.1.1-rc.1` `0.1.1-rc.2` `0.1.2-rc.1` `0.1.5-rc.1` `0.1.5-rc.2` `0.1.5-rc.3` `0.1.7-rc.1` `0.1.7-rc.2` `0.2.0-rc.1` `0.2.0-rc.2` `0.2.1-rc.1` (16 rc releases across lines 0.1.0 / 0.1.1 / 0.1.2 / 0.1.5 / 0.1.7 / 0.2.0 / 0.2.1)
|
|
63
63
|
- **Runtime-verified:** `0.2.0-rc.2` — evidence in `.compat-results/`
|
|
64
64
|
<!-- host-compat:end -->
|
|
65
65
|
|
|
@@ -323,7 +323,35 @@ In `cordis.yml`:
|
|
|
323
323
|
alwaysConfirm: false # every crossing asks; allow-controls add repeat-allow / wl-migrate buttons
|
|
324
324
|
llmAssist: false # LLM classify first, human fallback on ask/failure
|
|
325
325
|
trustEscalation: true # a cleared call's own sandbox escalation needs no prompt
|
|
326
|
+
yolo: false # unattended: never ask a human, block danger, run the rest
|
|
327
|
+
rulesFallback: false # no reviewer available => decide on the rule nets alone
|
|
328
|
+
scriptReview: true # attach the body of a script the call runs to the review
|
|
329
|
+
credentialPaths: [] # long-tail secret paths, held to the `.ssh` standard
|
|
330
|
+
denyKeywordsExtra: [] # appended blacklist words (never replaces the preset)
|
|
331
|
+
extraContentArgKeys: [] # argument fields that are documents, not operations
|
|
332
|
+
extraOperationArgKeys: [] # argument fields that ARE executed code (wins on conflict)
|
|
333
|
+
safenetPass: true # the permissive-mech implementation exists (mechanical takeover)
|
|
334
|
+
safenetAsk: false # the permissive-snet implementation exists (mechanical screen, still asks)
|
|
326
335
|
```
|
|
336
|
+
Three switches, each owning exactly one permission preset the plugin contributes to the picker —
|
|
337
|
+
so a switch changes the behaviour of its own tier and of no other, and switching an implementation
|
|
338
|
+
off returns that tier to the ordinary human flow instead of quietly turning it into a different one.
|
|
339
|
+
|
|
340
|
+
| switch | tier | who settles an ask | asks a person | calls the model |
|
|
341
|
+
| --- | --- | --- | --- | --- |
|
|
342
|
+
| `permissive` | `permissive` / `permissive-full` | machine screen + grader refine, then a person | yes | per `llmAssist` |
|
|
343
|
+
| `safenetAsk` | `permissive-snet` | a person, with the machine screen's doubts listed | **yes** | **never** |
|
|
344
|
+
| `safenetPass` | `permissive-mech` | the machine screen alone: named danger blocked + fed back, rest runs | no | **never** |
|
|
345
|
+
| `yolo` | `permissive-yolo` | the grader answers in the person's place; risky blocks + feeds back | never | every residual |
|
|
346
|
+
|
|
347
|
+
`safenetPass` is the reviewed form of `approval: never` (that preset passes every ask with nothing
|
|
348
|
+
judging it) and what YOLO degrades to with no reviewer. `yolo` is the model-backed tier by
|
|
349
|
+
definition: with no reviewer in seat it still refuses to ask a person, settles on the machine
|
|
350
|
+
screen, and records `yolo-allow-no-reviewer` so the history cannot read as if a model had answered.
|
|
351
|
+
All five tiers ship in the plugin's own profile patch, so they are in the picker on install —
|
|
352
|
+
nothing to hand-edit. Presets outside `gatePresets` never reach any of this: the whole gate
|
|
353
|
+
stands down there, so there is no ask to settle.
|
|
354
|
+
|
|
327
355
|
|
|
328
356
|
`trustAutoAllow` is the baseline middle tier (rule-allow auto-passes). `alwaysConfirm` surfaces
|
|
329
357
|
the approval panel for every crossing; its "allow controls" add two extended buttons —
|
|
@@ -335,6 +363,51 @@ human seam on `ask`/error — always fail-closed. `trustEscalation` (on by defau
|
|
|
335
363
|
is on) answers a `sandbox_permissions` escalation raised from inside a call the gate already
|
|
336
364
|
allowed; see below. When `permissive` is off, the gate behaves exactly as before.
|
|
337
365
|
|
|
366
|
+
### Unattended tiers, and how to protect a secret the preset never heard of
|
|
367
|
+
|
|
368
|
+
Three switches change **who decides**, seven keys change **what is known**. They are all
|
|
369
|
+
`volatile`: an edit in the settings card applies to the next tool call, no reload.
|
|
370
|
+
|
|
371
|
+
- `yolo` (the `permissive-yolo` tier) — never raises a confirmation. A dangerous ask
|
|
372
|
+
(irreversible, unlearnable, an unreadable payload, or a hard-risk verdict from the configured
|
|
373
|
+
reviewer) is blocked and the reason comes back to the agent as a `工具审核意见` message;
|
|
374
|
+
everything else runs. With no reviewer in seat the tier does not quietly allow — the mechanical
|
|
375
|
+
screen settles it and the event is recorded as `yolo-allow-no-reviewer`, because a tier that
|
|
376
|
+
advertises a model must not report one it never got.
|
|
377
|
+
- `rulesFallback` — degraded review. Only when there is **no reviewer** (none configured, or the
|
|
378
|
+
endpoint gave no verdict) the deterministic nets decide instead of parking the call on a popup
|
|
379
|
+
nobody will answer. While a reviewer answers, nothing changes. It governs the ordinary 自动审查
|
|
380
|
+
tiers (`permissive`, `permissive-full`); the three tiers that own an implementation already say
|
|
381
|
+
who answers, so this switch does not degrade them.
|
|
382
|
+
- `scriptReview` (on by default) — when a call runs a script, its body is read (bounded, never
|
|
383
|
+
executed) and shown to the model, the human card, **and** the deterministic nets: a delete that
|
|
384
|
+
only appears inside `clean-home.sh` is now graded on code. A fully-read script also stops being an
|
|
385
|
+
unreadable payload, so it leaves the `U` tier. Switch it off to keep file contents on the machine
|
|
386
|
+
— out-of-workspace script runs then go back to "unknowable, ask a human".
|
|
387
|
+
|
|
388
|
+
The long tail of *what counts as a secret* is yours to extend, and each list only ever adds to the
|
|
389
|
+
built-in one — replacing the preset lists is deliberately not offered, because forgetting `content`
|
|
390
|
+
or `plan` would silently re-create a bug this gate already fixed:
|
|
391
|
+
|
|
392
|
+
- `credentialPaths` — path globs (`**` crosses directories, `*`/`?` stay in one segment; a plain
|
|
393
|
+
entry matches a whole path fragment; `~/` expands to your home; a relative pattern also matches at
|
|
394
|
+
any depth). A listed path is held to the same standard as `.ssh`: reading it outside the workspace
|
|
395
|
+
is refused, mutating it through `write`/`edit` is refused. That tier is P0 — not appealable, not
|
|
396
|
+
clearable by a reviewer — which is why it is a setting and not a `rules.yaml` rule: read-only tools
|
|
397
|
+
are auto-allowed *before* the rule chain runs, so a rule cannot see them.
|
|
398
|
+
- `denyKeywordsExtra` — words appended to whichever blacklist is live (preset or your own
|
|
399
|
+
`denyKeywords`), so a company CLI subcommand or token prefix gets a deterministic block without
|
|
400
|
+
you copying fifty preset entries into your profile.
|
|
401
|
+
- `extraContentArgKeys` / `extraOperationArgKeys` — which argument fields are prose and which are
|
|
402
|
+
operations. The first stops a host tool's `steps`/`notes` field from being read as an act (that
|
|
403
|
+
is how issue #2 happened: an honest plan naming `rm -rf` got refused for describing it). The
|
|
404
|
+
second opens the reverse route for a `workflowYaml` whose body really executes — and it wins if
|
|
405
|
+
both name the same key. Naming a genuine document field there makes "the plan mentions `rm -rf`"
|
|
406
|
+
a refusal reason again, so it is off by default.
|
|
407
|
+
|
|
408
|
+
Declaring `command` or `file_path` as prose cannot weaken the gate: the executed command and the
|
|
409
|
+
mutated path are judged by their own code paths, not by this table (asserted by tests).
|
|
410
|
+
|
|
338
411
|
### Sandbox escalation: why a `safe` verdict still prompted
|
|
339
412
|
|
|
340
413
|
A tool call can raise **two independent approvals**. The gate owns the first — its own `ask`, on
|