dsh-perm-gate 2.1.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.ja.md +82 -0
- package/CHANGELOG.ko.md +80 -0
- package/CHANGELOG.md +210 -0
- package/INSTALL.ja.md +14 -8
- package/INSTALL.ko.md +15 -9
- package/INSTALL.md +16 -8
- package/INSTALL.zh.md +12 -7
- package/README.ja.md +19 -6
- package/README.ko.md +20 -7
- package/README.md +35 -4
- package/README.zh.md +13 -4
- 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 +1 -1
- package/examples/permissions.example.yaml +16 -1
- package/lib/allowlist.d.ts +27 -0
- package/lib/allowlist.js +103 -1
- package/lib/cli.js +11 -14
- package/lib/client.js +484 -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 +11 -0
- package/lib/compiler.js +16 -0
- package/lib/config.d.ts +73 -12
- package/lib/config.js +56 -14
- package/lib/dry-run.d.ts +87 -0
- package/lib/dry-run.js +110 -0
- package/lib/engine.js +52 -2
- package/lib/evaluate.js +76 -2
- package/lib/events.d.ts +56 -2
- package/lib/events.js +92 -0
- package/lib/index.js +106 -26
- 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/risk.d.ts +17 -3
- package/lib/risk.js +17 -3
- package/lib/rule-chain.js +13 -22
- package/lib/rule-dims.d.ts +35 -0
- package/lib/rule-dims.js +36 -0
- package/lib/rule.d.ts +36 -1
- package/lib/rule.js +56 -8
- package/lib/rules-view.d.ts +52 -0
- package/lib/rules-view.js +126 -0
- package/lib/runtime.d.ts +121 -7
- package/lib/runtime.js +204 -25
- package/lib/shell.d.ts +14 -0
- package/lib/shell.js +17 -0
- package/package.json +8 -1
package/CHANGELOG.ja.md
CHANGED
|
@@ -5,6 +5,88 @@
|
|
|
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] - 2026-09-17
|
|
9
|
+
|
|
10
|
+
### 修正
|
|
11
|
+
|
|
12
|
+
- 承認履歴が、フラグ付きの呼び出しがなぜレビューされずに実行されたのかを説明する唯一のイベントについて、生の `preset-passthrough` 文字列を表示していました(ティアは `approval: ask` を宣言しているのに、セッションが `never` で上書きされ、ゲートの ask がパススルーに降格したためです)。他の判定と同じく読みやすいラベルで表示されるようになりました。
|
|
13
|
+
|
|
14
|
+
## [2.4.0] - 2026-09-17
|
|
15
|
+
|
|
16
|
+
### 変更
|
|
17
|
+
|
|
18
|
+
- **P3 LLM 分類器はエスカレート専用になり、拒否できなくなりました。** ハードカテゴリ
|
|
19
|
+
(`deletion` / `credential` / `remote` / `system` / `bulk`) の `risky` 判定はこれまでパネルなしで
|
|
20
|
+
**自動拒否**していましたが、現在は**人間への確認(ask)を維持**します。拒否は決定論的レイヤー
|
|
21
|
+
(P0 ハード拒否、拒否キーワードのブラックリスト、明示的な `deny:` ルール)だけに属します。
|
|
22
|
+
確率的な判定が、異議を唱えられないブロックを下してはならないからです。実測: グレーダーは無害な
|
|
23
|
+
`git commit -F …` を **`remote`** と判定し、自動拒否は承認するパネルも再試行する grant も残しませんでした
|
|
24
|
+
(たまたま `safe` と判定された手動リトライだけが通りました)。これは「高リスク操作は**決定論的に**
|
|
25
|
+
遮断し、LLM の判断には委ねない」というプロジェクト自身のルールとも整合します。
|
|
26
|
+
|
|
27
|
+
### 追加
|
|
28
|
+
|
|
29
|
+
- ハードリスクカテゴリは `neutral` との重要な違いを一つだけ保ちます: **決して学習されません**。
|
|
30
|
+
人間の承認を繰り返しても `deletion`/`credential`/`remote`/`system`/`bulk` の判定が自動許可に
|
|
31
|
+
沈殿することはありません(従来は自動拒否の副作用としてのみ成立していましたが、現在は明示的な性質です)。
|
|
32
|
+
|
|
33
|
+
### 動作上の注意
|
|
34
|
+
|
|
35
|
+
- `approval: never` では、ゲートが配信できない ask は従来どおりパススルーに降格するため、分類器が
|
|
36
|
+
フラグを立てた呼び出しは**実行されます**(以前は自動拒否でした)。これは「決定論的に危険なものだけを
|
|
37
|
+
拒否し、それ以外は交渉する」の直接の帰結です —— 交渉には人間が必要で、`never` は人間がいないことを
|
|
38
|
+
意味します。フラグを実際に受け取りたい場合は `approval` が `ask` のティアで運用してください。
|
|
39
|
+
|
|
40
|
+
## [2.3.0] - 2026-09-17
|
|
41
|
+
|
|
42
|
+
### 追加
|
|
43
|
+
|
|
44
|
+
- **ゲートの停止はもはや沈黙しません。** セッションの権限プリセットが `gatePresets` の外にあるとき、
|
|
45
|
+
ゲートは停止して何も記録しませんでした —— そのためツール呼び出しは、ゲートが検査して許可した
|
|
46
|
+
呼び出しと見分けがつきませんでした。現在は (session, preset) の遷移ごとに **1 件だけ**
|
|
47
|
+
`stand-down` 通知を記録し(呼び出しごとではありません)、プリセット・スコープ・P0 ハード拒否が
|
|
48
|
+
無効である事実を明示します。ブラウザは入力欄の上に常駐の **GATE OFF** ストリップとして表示し、
|
|
49
|
+
承認履歴には `ゲート停止` タグが出ます。
|
|
50
|
+
- 自动审查 設定カードがゲート自身のプリセットスコープ(`gatePresets`、既定は
|
|
51
|
+
`permissive` / `permissive-full`)とその外側で何が起きるかを明示するため、スコープはティアを
|
|
52
|
+
設定する場所で確認できます。
|
|
53
|
+
|
|
54
|
+
### 変更
|
|
55
|
+
|
|
56
|
+
- **P0 の文書上の位置づけはグローバルではなくスコープ付きです。** P0 ハード拒否は*ゲートのプリセット
|
|
57
|
+
スコープ内*で単調かつ交渉不能です。プリセットをまたぐとゲートは P0 を含めて完全に停止します ——
|
|
58
|
+
選択されたティア自身のポリシーがそのセッションを所有するためです。コードは常にこう動作していましたが、
|
|
59
|
+
`AGENTS.md` と 4 つの README は逆を主張しており、`danger-full-access` が「P0 は依然適用される」と
|
|
60
|
+
読めてしまいました。`gatePresets: ['*']` を設定すると P0 は再びグローバルになります。
|
|
61
|
+
|
|
62
|
+
### 修正
|
|
63
|
+
|
|
64
|
+
- `DEFAULT_GATE_PRESETS` / `resolveGatePresets` を `config.ts`(schemastery を import しています)から
|
|
65
|
+
依存のない `preset.ts` へ移し、ブラウザ側が node 専用依存をクライアントバンドルに引き込まずに
|
|
66
|
+
スコープを描画できるようにしました。`config.ts` は両方を再エクスポートするため、既存の import は
|
|
67
|
+
変更ありません。
|
|
68
|
+
|
|
69
|
+
## [2.2.0] - 2026-09-17
|
|
70
|
+
|
|
71
|
+
### 修正
|
|
72
|
+
|
|
73
|
+
- **P0 ハード拒否が、4 つのシェルツール以外をすべて素通りさせていました。** `hardDenyReason` はシェル検査をローカルの正規表現 `/^(?:bash|pwsh|sh|cmd)$/` で門番していましたが、これは `shell` / `terminal` / `powershell` に**一致しません**。`shell` は DSH の主要シェルツールであるため、P0 のシェル検査(保護パスへのリダイレクト)は**最も一般的な呼び出し形に対して無効**でした。実測、同一コマンド `echo x > /etc/passwd`:`bash` 経由は遮断、`shell` 経由は**通過**。`engine.ts` は `evaluate.ts` から `SHELL_TOOLS` を取り込むよう変更しました——同じ事実の複製が 3 か所にあり、完全だったのは 1 つだけでした。
|
|
74
|
+
- **`git push --delete` が通常の push として解析されていました。** `hasDelete` は `analyzeSubcommand` で計算されながら `branch` ケースでしか読まれず、`git push --delete origin main` は通常 push 分岐(`destructiveness: 4`)に落ちていました。`DESTRUCTIVENESS_MAP` の `'push-delete': 5` は死んだデータでした。
|
|
75
|
+
- **保護ブランチ判定が、スラッシュを含む名前に誤反応していました。** 述語は最後の `/` より前を落としていたため、`backup/main` や `feat/release` が保護扱いになっていました。既知の ref 接頭辞(`refs/heads/`、`refs/tags/`、`refs/remotes/<remote>/`)のみを剥がすよう変更しました。方向が重要です——この述語は**取り消し不能な** P0 に供給され、見逃しにはキーワード/ルール/LLM 層という受け皿がありますが、誤検出は正当なワークフローを出口なく塞いでしまいます。
|
|
76
|
+
|
|
77
|
+
### 追加
|
|
78
|
+
|
|
79
|
+
- **保護ブランチに対するリモート履歴改変の P0 ハード拒否。** `main` / `master` / `production` / `release` / `stable` を強制上書きまたは削除する `git push` を、LLM 呼び出しより前に決定的に拒否します。従来の保護は、フラットでブランチを見ず、名前空間で上書き可能なキーワード `'push --force'` でした。これはその下に敷く交渉不能な床です。
|
|
80
|
+
- **「エスカレーションのみ」は慣習ではなく構造です**: ヘルパーは `string | undefined` を返し、呼び出し側はそれを deny / 未決定として読みます。allow を表現する手段がないため、P0 に配線してもゲートが許可する範囲を広げることはできません。
|
|
81
|
+
- 意図的に**対象外**(引き続きキーワード/ルール/LLM 層が担当): 非保護ブランチへの force push、ブランチ名を書かない `git push --force`、通常の push。
|
|
82
|
+
- コマンドパーサ(`command-dispatcher` / `command-semantics` / `parsers/git` / `parsers/shell-cmds`)の初の本番利用です。これまで自身のテストファイルからしか参照されていませんでした。
|
|
83
|
+
|
|
84
|
+
### テスト
|
|
85
|
+
|
|
86
|
+
- 新規 `test/git-protected-push.spec.ts`(13 件)。
|
|
87
|
+
- **反証**: 3 つの修正をそれぞれ戻すと、それを守るケースだけが赤くなります(計 7 件)。意図的に許可するケースは緑のままです。
|
|
88
|
+
- 全量 **40 ファイル / 459 件**、`typecheck` クリーン。
|
|
89
|
+
|
|
8
90
|
## [2.0.0] - 2026-09-11
|
|
9
91
|
|
|
10
92
|
### 修正
|
package/CHANGELOG.ko.md
CHANGED
|
@@ -5,6 +5,86 @@
|
|
|
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] - 2026-09-17
|
|
9
|
+
|
|
10
|
+
### 수정됨
|
|
11
|
+
|
|
12
|
+
- 승인 이력이, 플래그된 호출이 왜 검토 없이 실행되었는지 설명하는 유일한 이벤트에 대해 원시 `preset-passthrough` 문자열을 표시했습니다(티어는 `approval: ask`를 선언했지만 세션이 `never`로 재정의되어 게이트의 ask가 패스스루로 강등된 경우입니다). 이제 다른 판정과 마찬가지로 읽기 쉬운 라벨로 표시됩니다.
|
|
13
|
+
|
|
14
|
+
## [2.4.0] - 2026-09-17
|
|
15
|
+
|
|
16
|
+
### 변경됨
|
|
17
|
+
|
|
18
|
+
- **P3 LLM 분류기는 에스컬레이션 전용이 되어 더 이상 거부할 수 없습니다.** 하드 카테고리
|
|
19
|
+
(`deletion` / `credential` / `remote` / `system` / `bulk`)의 `risky` 판정은 이전에는 패널 없이
|
|
20
|
+
**자동 거부**했지만, 이제는 **사람 확인(ask)을 유지**합니다. 거부는 결정론적 계층(P0 하드 거부,
|
|
21
|
+
거부 키워드 블랙리스트, 명시적 `deny:` 규칙)에만 속합니다. 확률적 판정이 이의를 제기할 수 없는
|
|
22
|
+
차단을 내려서는 안 되기 때문입니다. 실측: 그레이더가 무해한 `git commit -F …`를 **`remote`**로
|
|
23
|
+
판정했고, 자동 거부는 승인할 패널도 재시도할 grant도 남기지 않았습니다(우연히 `safe`로 판정된
|
|
24
|
+
수동 재시도만 통과했습니다). 이는 "고위험 작업은 **결정론적으로** 차단하고 LLM 판단에 맡기지
|
|
25
|
+
않는다"는 프로젝트 자체 규칙과도 일치합니다.
|
|
26
|
+
|
|
27
|
+
### 추가됨
|
|
28
|
+
|
|
29
|
+
- 하드 위험 카테고리는 `neutral`과의 중요한 차이를 하나만 유지합니다: **결코 학습되지 않습니다**.
|
|
30
|
+
사람의 승인을 반복해도 `deletion`/`credential`/`remote`/`system`/`bulk` 판정이 자동 허용으로
|
|
31
|
+
침전되지 않습니다(이전에는 자동 거부의 부수 효과로만 성립했지만, 이제는 명시적 속성입니다).
|
|
32
|
+
|
|
33
|
+
### 동작 주의
|
|
34
|
+
|
|
35
|
+
- `approval: never`에서는 게이트가 전달할 수 없는 ask가 여전히 패스스루로 강등되므로, 분류기가
|
|
36
|
+
플래그한 호출은 이제 **실행됩니다**(이전에는 자동 거부였습니다). 이는 "결정론적으로 위험한 것만
|
|
37
|
+
거부하고 나머지는 협상한다"의 직접적 귀결입니다 —— 협상에는 사람이 필요하고, `never`는 사람이
|
|
38
|
+
없다는 뜻입니다. 플래그를 실제로 받으려면 `approval`이 `ask`인 티어에서 운용하십시오.
|
|
39
|
+
|
|
40
|
+
## [2.3.0] - 2026-09-17
|
|
41
|
+
|
|
42
|
+
### 추가됨
|
|
43
|
+
|
|
44
|
+
- **게이트 정지는 더 이상 침묵하지 않습니다.** 세션 권한 프리셋이 `gatePresets` 밖에 있을 때 게이트는
|
|
45
|
+
정지하고 아무것도 기록하지 않았습니다 —— 그래서 그 도구 호출은 게이트가 검사하고 허용한 호출과
|
|
46
|
+
구별되지 않았습니다. 이제 (session, preset) 전환마다 **1건만** `stand-down` 알림을 기록하고
|
|
47
|
+
(호출마다가 아닙니다), 프리셋·범위·P0 하드 거부가 비활성이라는 사실을 명시합니다. 브라우저는
|
|
48
|
+
입력창 위에 상시 **GATE OFF** 표시줄로 렌더링하고, 승인 이력에는 `게이트 정지` 태그가 표시됩니다.
|
|
49
|
+
- 自动审查 설정 카드가 게이트 자체의 프리셋 범위(`gatePresets`, 기본값
|
|
50
|
+
`permissive` / `permissive-full`)와 그 밖에서 벌어지는 일을 명시하므로, 범위를 티어를 설정하는
|
|
51
|
+
곳에서 확인할 수 있습니다.
|
|
52
|
+
|
|
53
|
+
### 변경됨
|
|
54
|
+
|
|
55
|
+
- **P0의 문서상 위치는 전역이 아니라 범위 한정입니다.** P0 하드 거부는 *게이트의 프리셋 범위 안에서*
|
|
56
|
+
단조롭고 협상 불가능합니다. 프리셋을 넘어가면 게이트는 P0를 포함해 완전히 정지합니다 —— 선택된
|
|
57
|
+
티어 자체의 정책이 그 세션을 소유하기 때문입니다. 코드는 항상 이렇게 동작했지만 `AGENTS.md`와
|
|
58
|
+
4개 README는 반대로 주장해, `danger-full-access`가 "P0는 여전히 적용된다"로 읽혔습니다.
|
|
59
|
+
`gatePresets: ['*']`로 설정하면 P0는 다시 전역이 됩니다.
|
|
60
|
+
|
|
61
|
+
### 수정됨
|
|
62
|
+
|
|
63
|
+
- `DEFAULT_GATE_PRESETS` / `resolveGatePresets`를 `config.ts`(schemastery를 import합니다)에서
|
|
64
|
+
의존성 없는 `preset.ts`로 옮겨, 브라우저 쪽이 node 전용 의존성을 클라이언트 번들로 끌어오지 않고
|
|
65
|
+
범위를 렌더링할 수 있게 했습니다. `config.ts`는 둘 다 재수출하므로 기존 import는 변경이 없습니다.
|
|
66
|
+
|
|
67
|
+
## [2.2.0] - 2026-09-17
|
|
68
|
+
|
|
69
|
+
### 수정
|
|
70
|
+
|
|
71
|
+
- **P0 하드 거부가 4개의 셸 도구를 제외한 나머지를 모두 통과시키고 있었습니다.** `hardDenyReason`은 셸 검사를 로컬 정규식 `/^(?:bash|pwsh|sh|cmd)$/`로 막고 있었는데, 이는 `shell` / `terminal` / `powershell`에 **일치하지 않습니다**. `shell`은 DSH의 주 셸 도구이므로, P0의 셸 검사(보호 경로로의 리다이렉트)는 **가장 흔한 호출 형태에 대해 무력**했습니다. 실측, 동일 명령 `echo x > /etc/passwd`: `bash` 경유는 차단, `shell` 경유는 **통과**. `engine.ts`가 이제 `evaluate.ts`에서 `SHELL_TOOLS`를 가져옵니다——같은 사실의 사본이 세 곳에 있었고, 완전한 것은 하나뿐이었습니다.
|
|
72
|
+
- **`git push --delete`가 일반 push로 파싱되고 있었습니다.** `hasDelete`는 `analyzeSubcommand`에서 계산되지만 `branch` 케이스에서만 읽혔고, 그 결과 `git push --delete origin main`은 일반 push 분기(`destructiveness: 4`)로 떨어졌습니다. `DESTRUCTIVENESS_MAP`의 `'push-delete': 5`는 죽은 데이터였습니다.
|
|
73
|
+
- **보호 브랜치 판정이 슬래시를 포함한 이름에 오작동하고 있었습니다.** 술어가 마지막 `/` 앞부분을 잘라내어 `backup/main`과 `feat/release`가 보호 대상으로 읽혔습니다. 이제 알려진 ref 접두사(`refs/heads/`, `refs/tags/`, `refs/remotes/<remote>/`)만 제거합니다. 방향이 중요합니다——이 술어는 **되돌릴 수 없는** P0에 공급되며, 놓침에는 키워드/규칙/LLM 계층이라는 안전망이 있지만 오탐은 정당한 워크플로를 출구 없이 막습니다.
|
|
74
|
+
|
|
75
|
+
### 추가
|
|
76
|
+
|
|
77
|
+
- **보호 브랜치에 대한 원격 이력 재작성의 P0 하드 거부.** `main` / `master` / `production` / `release` / `stable`을 강제 덮어쓰기하거나 삭제하는 `git push`를 LLM 호출 이전에 결정론적으로 거부합니다. 기존 보호는 평면적이고 브랜치를 보지 않으며 네임스페이스로 덮어쓸 수 있는 키워드 `'push --force'`였습니다. 이것은 그 아래에 깔리는 협상 불가능한 바닥입니다.
|
|
78
|
+
- **"에스컬레이션 전용"은 관례가 아니라 구조입니다**: 헬퍼는 `string | undefined`를 반환하고 호출자는 이를 deny / 미결로 읽습니다. allow를 표현할 수단이 없으므로 P0에 배선해도 게이트가 허용하는 범위를 넓힐 수 없습니다.
|
|
79
|
+
- 의도적으로 **대상에서 제외**(키워드/규칙/LLM 계층이 계속 담당): 비보호 브랜치로의 force push, 브랜치명을 쓰지 않은 `git push --force`, 일반 push.
|
|
80
|
+
- 커맨드 파서(`command-dispatcher` / `command-semantics` / `parsers/git` / `parsers/shell-cmds`)의 첫 프로덕션 사용입니다. 지금까지는 자체 테스트 파일에서만 참조되고 있었습니다.
|
|
81
|
+
|
|
82
|
+
### 테스트
|
|
83
|
+
|
|
84
|
+
- 신규 `test/git-protected-push.spec.ts`(13건).
|
|
85
|
+
- **반증**: 세 수정을 각각 되돌리면 그것을 지키는 케이스만 빨개집니다(총 7건). 의도적으로 허용하는 케이스는 초록으로 남습니다.
|
|
86
|
+
- 전체 **40 파일 / 459건**, `typecheck` 클린.
|
|
87
|
+
|
|
8
88
|
## [2.0.0] - 2026-09-11
|
|
9
89
|
|
|
10
90
|
### 수정
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,216 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.6.0] - 2026-09-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Rule test (dry-run) in the settings card.** A new panel evaluates one would-be tool call
|
|
13
|
+
against the ruleset the gate currently has loaded and shows the verdict, the matched rule (index
|
|
14
|
+
and action), the dimensions that rule constrains, and the reason. Written for the question the
|
|
15
|
+
YAML cannot answer by inspection: *what will this actually do?* — `args` is an OR over tokens, an
|
|
16
|
+
empty dimension constrains nothing, and `command` matches the decomposed command **word** only, so
|
|
17
|
+
a plausible-looking rule can be dead on arrival.
|
|
18
|
+
|
|
19
|
+
The report keeps two answers apart on purpose. **`verdict`** is the policy result of the whole
|
|
20
|
+
chain (P0 hard-deny → deny-keyword → P1 grant → P2 rules → P4 ask → permissive).
|
|
21
|
+
**`ruleLayer`** is what the `permissions` chain decides on its own, and only that layer can name a
|
|
22
|
+
rule index: a P0 hard-deny or a preset deny-keyword fires *before* it and leaves no rule behind, so
|
|
23
|
+
the panel says so instead of attributing an unrelated rule. `matchedDimensions` likewise lists the
|
|
24
|
+
dimensions the matched rule *constrains* rather than the one that "caused" the match — dimensions
|
|
25
|
+
are ANDed, so a single cause cannot honestly be named. A `ruleCount` of 0 is surfaced as "0 rules
|
|
26
|
+
loaded, check the rulesFile path" rather than as "nothing matched".
|
|
27
|
+
|
|
28
|
+
- **`POST /api/dsh-perm-gate/dry-run`** — the panel's endpoint. **Read-only by construction**: it
|
|
29
|
+
has no write form, unknown body keys are dropped rather than forwarded, and it never touches
|
|
30
|
+
rules, grants, learning state or the settings namespace. Testing a rule must not be able to change
|
|
31
|
+
it. It evaluates against the **live** runtime rather than a fresh one, so the panel tests the rules
|
|
32
|
+
in force — a fresh runtime would re-resolve the chain from a different root and could silently
|
|
33
|
+
answer about a different file.
|
|
34
|
+
|
|
35
|
+
- **`src/dry-run.ts`** — `runDryRun` / `createDryRunRuntime`, the shared evaluator for the CLI and
|
|
36
|
+
the route, plus `PermGateRuntime.explainRules` (read-only rule-layer report) and
|
|
37
|
+
`PermGateRuntime.explainCall` (pure policy evaluation). `src/cli.ts` is now a thin wrapper over it;
|
|
38
|
+
its output is unchanged across nine replayed invocations, verified byte for byte (including the
|
|
39
|
+
`--list`, no-tool, bad-JSON and write-path cases).
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **The rule-test panel reported `allow` for calls the rules send to a human.** The first version
|
|
44
|
+
evaluated through the host-facing path, which applies the session layers — the preset stand-down
|
|
45
|
+
and the `approval: never` ask degradation. A session-less dry-run has no session, so the policy
|
|
46
|
+
reader answered "never", every `ask` degraded to a passthrough, and the panel showed **allow** for
|
|
47
|
+
exactly the rules someone opens it to review. Measured on the live host: `shell ls -la` showed
|
|
48
|
+
`allow` while the rule layer on the same card said `ask`.
|
|
49
|
+
|
|
50
|
+
`runDryRun` now reports the **pure policy** verdict from `explainCall`: the same
|
|
51
|
+
P0 → deny-keyword → P1 → P2 → P4 chain with the session-state layers excluded rather than guessed,
|
|
52
|
+
and with `reason` never collapsed to a bare `(default/passthrough)`. The host-facing view remains
|
|
53
|
+
available under `input.hostView`; the CLI asks for it, so its historic output stays byte for byte
|
|
54
|
+
identical (re-verified: 9/9 cases, SHA256 per case).
|
|
55
|
+
|
|
56
|
+
- **The "read-only" route was not read-only.** It ran the host-facing decision path against the live
|
|
57
|
+
runtime, which appends audit entries and records decision events — opening the rule-test panel
|
|
58
|
+
wrote to the live decision feed. The pure path appends nothing, and `test/dry-run.spec.ts` now
|
|
59
|
+
asserts that a call the host path *would* record leaves the audit mirror at zero.
|
|
60
|
+
|
|
61
|
+
## [2.5.0] - 2026-09-17
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
|
|
65
|
+
- **`branch` rule dimension** — git branch / remote / protected-branch matching, so a rule can
|
|
66
|
+
finally say "no push to a protected branch" without catching unrelated commands. The decisive
|
|
67
|
+
case is the one `args` can never express: `git push --force origin main` (dangerous) and
|
|
68
|
+
`git checkout --force main` (routine) carry the *same tokens*, and only the branch dimension
|
|
69
|
+
tells them apart. Sub-fields: `target` (branch-name glob, `*` crosses `/`), `remote`
|
|
70
|
+
(remote-name glob) and `shared` (require a protected branch). Candidates come from the shared
|
|
71
|
+
command dispatcher, so `refspec` forms (`HEAD:main`) are already split and a remote name is
|
|
72
|
+
never mistaken for a branch name. Documented in `docs/rules-format.md` §4.11.
|
|
73
|
+
|
|
74
|
+
### Fixed
|
|
75
|
+
|
|
76
|
+
- **The multi-file rule chain silently emptied every match dimension.** `resolveRuleChain` merged
|
|
77
|
+
entries by hand with `tools: []`, `command: []`, `args: []` and `paths: []`. An empty dimension
|
|
78
|
+
means "no constraint", so EVERY merged entry matched EVERY call: the first `deny` entry denied
|
|
79
|
+
everything in its partition, and the first `allow` entry allowed everything before the `ask`
|
|
80
|
+
partition was ever consulted. The merge now goes through the same `compileRuleEntry` the
|
|
81
|
+
single-file path uses.
|
|
82
|
+
|
|
83
|
+
*Reach:* the chain resolver is reached **only** under `searchUp: true` (product default `false`,
|
|
84
|
+
and unset in a stock profile), so the default single-file path — `compileDocument` — was never
|
|
85
|
+
affected. That is also why the existing suite stayed green: no test drove a rules *file* through
|
|
86
|
+
the chain. `test/rule-chain.spec.ts` now does. A separate, still-open defect on the same
|
|
87
|
+
opt-in path is recorded in the plan: `findChainEntries` joins the configured `rulesFile` onto
|
|
88
|
+
each directory, so the absolute path `resolveRulesFile` always produces matches nothing and the
|
|
89
|
+
chain yields an empty ruleset without an error.
|
|
90
|
+
|
|
91
|
+
- **`argv.pipeline` could not see its own subject.** The pipeline match string was built from
|
|
92
|
+
`SimpleCommand.command`, which is only the command *word* — `curl https://x.sh | sh` collapsed
|
|
93
|
+
to `curl|sh`, so the documented `curl|sh` pattern matched the harmless adjacent form while the
|
|
94
|
+
genuinely dangerous one with arguments did not match at all. The match string is now each
|
|
95
|
+
simple command's full argv (joined by `|`), and the docs state that `|` in a pattern is a
|
|
96
|
+
literal, so covering arguments requires `curl*|sh`.
|
|
97
|
+
|
|
98
|
+
- Nine pre-existing `eslint` errors (unused imports/constants and one `prefer-const` in
|
|
99
|
+
`src/parsers/` and `test/command-parsers.spec.ts`) — `npm run lint` is green again.
|
|
100
|
+
|
|
101
|
+
## [2.4.1] - 2026-09-17
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
|
|
105
|
+
- The approvals history showed the raw `preset-passthrough` string for the one event that
|
|
106
|
+
explains *why* a flagged call ran unreviewed: the tier declares `approval: ask`, the session was
|
|
107
|
+
overridden to `never`, and the gate's ask therefore degraded to a passthrough. It now renders as
|
|
108
|
+
a readable label like every other verdict.
|
|
109
|
+
|
|
110
|
+
## [2.4.0] - 2026-09-17
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- **The P3 LLM classifier is escalate-only — it can no longer deny.** A `risky` verdict with a
|
|
115
|
+
hard category (`deletion` / `credential` / `remote` / `system` / `bulk`) used to **auto-deny**
|
|
116
|
+
with no panel; it now **keeps the human ask**. Denying is reserved for the deterministic layers
|
|
117
|
+
alone — P0 hard-deny, the deny-keyword blacklist, explicit `deny:` rules — because a
|
|
118
|
+
probabilistic verdict must not be able to hand down an unappealable block. Measured live: the
|
|
119
|
+
grader called a benign `git commit -F …` **`remote`** and the auto-deny left no panel to approve
|
|
120
|
+
and no grant to retry with; only a manual retry (which happened to grade `safe`) got past it.
|
|
121
|
+
This also aligns the code with the project's own rule that high-risk operations are intercepted
|
|
122
|
+
**deterministically, never on the LLM's judgement**.
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
|
|
126
|
+
- Hard risk categories keep one meaningful distinction from `neutral`: they are **never
|
|
127
|
+
learnable**. Repeated human approvals cannot sediment a `deletion`/`credential`/`remote`/
|
|
128
|
+
`system`/`bulk` verdict into an auto-allow (previously this was true only as a side effect of
|
|
129
|
+
the auto-deny; it is now an explicit property).
|
|
130
|
+
|
|
131
|
+
### Behaviour notes
|
|
132
|
+
|
|
133
|
+
- Under `approval: never` an ask the gate cannot deliver still degrades to passthrough, so a
|
|
134
|
+
classifier-flagged call now **runs** where it used to be auto-denied. That is the direct
|
|
135
|
+
consequence of "deny only what is deterministically dangerous, negotiate everything else": a
|
|
136
|
+
negotiation needs a human, and `never` means there is none. Run the gate in a tier whose
|
|
137
|
+
`approval` is `ask` for the flags to reach you.
|
|
138
|
+
|
|
139
|
+
## [2.3.0] - 2026-09-17
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
- **A stand-down is no longer silent.** When the session's permission preset is outside
|
|
144
|
+
`gatePresets`, the gate used to stand down and record nothing — so the tool call looked
|
|
145
|
+
exactly like one the gate had inspected and allowed. It now records **one** `stand-down`
|
|
146
|
+
notice per (session, preset) transition (never per call), naming the preset, the scope and
|
|
147
|
+
the fact that P0 hard-deny is inactive. The browser renders it as a sticky **GATE OFF**
|
|
148
|
+
strip above the input, and the approvals history shows a `Gate off` tag.
|
|
149
|
+
- The 自动审查 settings card states the gate's own preset scope (`gatePresets`, default
|
|
150
|
+
`permissive` / `permissive-full`) and what happens outside it, so the scope is visible
|
|
151
|
+
where the tier is configured.
|
|
152
|
+
|
|
153
|
+
### Changed
|
|
154
|
+
|
|
155
|
+
- **P0's documented positioning is scoped, not global.** P0 hard-deny is monotonic and
|
|
156
|
+
non-negotiable *within the gate's preset scope*; across presets the gate stands down
|
|
157
|
+
entirely — P0 included — because the selected tier's own policy owns that session. The
|
|
158
|
+
code always behaved this way; `AGENTS.md` and the four READMEs claimed otherwise, which
|
|
159
|
+
made `danger-full-access` read as "P0 still applies". Set `gatePresets: ['*']` to make P0
|
|
160
|
+
global again.
|
|
161
|
+
|
|
162
|
+
### Fixed
|
|
163
|
+
|
|
164
|
+
- `DEFAULT_GATE_PRESETS` / `resolveGatePresets` moved from `config.ts` (which imports
|
|
165
|
+
schemastery) into the dependency-free `preset.ts`, so the browser half can render the scope
|
|
166
|
+
without pulling a node-only dependency into the client bundle. `config.ts` re-exports both,
|
|
167
|
+
so existing imports are unchanged.
|
|
168
|
+
|
|
169
|
+
## [2.2.0] - 2026-09-17
|
|
170
|
+
|
|
171
|
+
### Fixed
|
|
172
|
+
|
|
173
|
+
- **P0 hard-deny skipped every shell tool but four.** `hardDenyReason` gated its shell
|
|
174
|
+
inspection on a locally defined regex, `/^(?:bash|pwsh|sh|cmd)$/`, which does **not**
|
|
175
|
+
match `shell`, `terminal` or `powershell`. `shell` is DSH's primary shell tool, so the
|
|
176
|
+
whole P0 shell check — the protected-path redirect guard — was **inert for the most
|
|
177
|
+
common call shape**. Measured, same command `echo x > /etc/passwd`: blocked via `bash`,
|
|
178
|
+
**allowed** via `shell`. `engine.ts` now imports `SHELL_TOOLS` from `evaluate.ts`; the
|
|
179
|
+
gate held three copies of that one fact and only one of them was complete.
|
|
180
|
+
- **`git push --delete` was parsed as an ordinary push.** `hasDelete` was computed in
|
|
181
|
+
`analyzeSubcommand` but only ever read in the `branch` case, so `git push --delete
|
|
182
|
+
origin main` fell through to the plain-push branch (`destructiveness: 4`) and the
|
|
183
|
+
`DESTRUCTIVENESS_MAP` entry `'push-delete': 5` was dead data.
|
|
184
|
+
- **Protected-branch detection mis-fired on any name containing a slash.** The predicate
|
|
185
|
+
stripped everything before the last `/`, so `backup/main` and `feat/release` were read
|
|
186
|
+
as protected. It now strips only known ref prefixes (`refs/heads/`, `refs/tags/`,
|
|
187
|
+
`refs/remotes/<remote>/`). The direction matters: this predicate feeds an **unremovable**
|
|
188
|
+
P0, where a miss still has the keyword / rule / LLM layers behind it, while a false
|
|
189
|
+
positive blocks a legitimate workflow with no recourse.
|
|
190
|
+
|
|
191
|
+
### Added
|
|
192
|
+
|
|
193
|
+
- **P0 hard-deny for remote-history rewrite on a protected branch.** A `git push` that
|
|
194
|
+
force-overwrites or deletes `main` / `master` / `production` / `release` / `stable` is
|
|
195
|
+
rejected deterministically, before any LLM call. The pre-existing protection was the
|
|
196
|
+
flat, branch-blind, namespace-overridable keyword `'push --force'`; this is the
|
|
197
|
+
non-negotiable floor beneath it.
|
|
198
|
+
- **Escalate-only by construction, not by convention**: the helper returns
|
|
199
|
+
`string | undefined`, which the caller reads as deny / undecided. It has no way to
|
|
200
|
+
express allow, so wiring it into P0 cannot widen what the gate permits.
|
|
201
|
+
- Deliberately **not** covered (still left to the keyword / rule / LLM layers):
|
|
202
|
+
force-push to a non-protected branch, `git push --force` with no branch named, and
|
|
203
|
+
ordinary pushes.
|
|
204
|
+
- First production use of the command parser (`command-dispatcher`, `command-semantics`,
|
|
205
|
+
`parsers/git`, `parsers/shell-cmds`), which until now was referenced only by its own
|
|
206
|
+
test file.
|
|
207
|
+
|
|
208
|
+
### Tests
|
|
209
|
+
|
|
210
|
+
- New suite `test/git-protected-push.spec.ts` (13 cases): parser variants, the
|
|
211
|
+
protected-branch predicate in both directions, full `SHELL_TOOLS` coverage, the four
|
|
212
|
+
deliberately-allowed shapes, and compound-command segmentation
|
|
213
|
+
(`git status && git push --force origin main`).
|
|
214
|
+
- **Falsified**: reverting each of the three fixes turns exactly the cases guarding it red
|
|
215
|
+
(7 failures in total), while the deliberate-allow cases stay green.
|
|
216
|
+
- Full suite **40 files / 459 cases**; `typecheck` clean.
|
|
217
|
+
|
|
8
218
|
## [2.1.2] - 2026-09-15
|
|
9
219
|
|
|
10
220
|
### Added
|
package/INSTALL.ja.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
13
13
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
14
14
|
|
|
15
|
-
`dsh-perm-gate` バージョン **2.
|
|
15
|
+
`dsh-perm-gate` バージョン **2.6.0**。判定チェーン、ルールファイル形式、自动审查
|
|
16
16
|
ティアについては [日本語 README](./README.ja.md) を参照してください。
|
|
17
17
|
|
|
18
18
|
## 必要条件
|
|
@@ -23,19 +23,20 @@
|
|
|
23
23
|
- インストール先の profile。ブラウザ側は `web` profile 向けにのみビルドされます
|
|
24
24
|
(`package.json` の `dsh.client.platform = "web"`)。
|
|
25
25
|
|
|
26
|
-
## DSH
|
|
26
|
+
## DSH のバージョンに合うラインを選ぶ
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
2 つの長期ブランチが 2 つの DSH ラインを担当します:`main`(2.x)と
|
|
29
|
+
`sync/0.1.5-from-main`(3.x、DSH 0.1.5 のパッケージング変体 —— `compat/0.1.5` は
|
|
30
|
+
同じコードツリーを指します)。
|
|
31
31
|
|
|
32
32
|
| DSH のバージョン | インストール方法 |
|
|
33
33
|
|-----------------|-----------------|
|
|
34
|
-
| `0.1.2-alpha.1`
|
|
34
|
+
| `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate`(tag `latest`、2.x ライン) |
|
|
35
|
+
| `0.1.5-rc.1` 以上 | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main`(3.x ライン;npm の dist-tag は未公開 —— `@latest` は同じコードの 2.x パッケージングをインストールします) |
|
|
35
36
|
| `0.1.1-rc.2` まで | `dsh plugin --profile web add dsh-perm-gate@legacy` |
|
|
36
37
|
|
|
37
|
-
DSH は `engines.dsh` を強制しないため、tag
|
|
38
|
-
|
|
38
|
+
DSH は `engines.dsh` を強制しないため、tag と ref は選択メカニズムであり、互換性
|
|
39
|
+
ゲートそのものではありません。ラインと tag の公開レイアウトについては
|
|
39
40
|
[RELEASING.md](./RELEASING.md) を参照してください。
|
|
40
41
|
|
|
41
42
|
## 公式 CLI でインストール
|
|
@@ -72,6 +73,11 @@ profile の `cordis.yml` にプラグインを追加します:
|
|
|
72
73
|
defaultAction: ask # allow | ask | deny
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
2.6.0 から、ルール本体は `dsh-perm-gate-rules` settings 名前空間に保存され、変更の
|
|
77
|
+
たびにゲートがその場で再コンパイルされます。上記の YAML ファイルは任意になりました。
|
|
78
|
+
名前空間が未設定の間だけ読み込まれ、プラグインが最初にルールを書き込む際(許可リスト
|
|
79
|
+
の承認、または設定 UI での編集)にファイルのルールが自動的に取り込まれます。
|
|
80
|
+
|
|
75
81
|
まずは [examples/permissions.example.yaml](./examples/permissions.example.yaml)
|
|
76
82
|
から始め、profile を再読込してください。
|
|
77
83
|
|
package/INSTALL.ko.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
13
13
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
14
14
|
|
|
15
|
-
`dsh-perm-gate` 버전 **2.
|
|
15
|
+
`dsh-perm-gate` 버전 **2.6.0**. 결정 체인, 규칙 파일 형식, 自动审查 티어는
|
|
16
16
|
[한국어 README](./README.ko.md)를 참고하세요.
|
|
17
17
|
|
|
18
18
|
## 요구 사항
|
|
@@ -23,20 +23,21 @@
|
|
|
23
23
|
- 설치할 profile. 브라우저 절반은 `web` profile용으로만 빌드됩니다
|
|
24
24
|
(`package.json`의 `dsh.client.platform = "web"`).
|
|
25
25
|
|
|
26
|
-
## DSH 버전에 맞는
|
|
26
|
+
## DSH 버전에 맞는 라인 선택
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
두 개의 장기 브랜치가 두 DSH 라인을 담당합니다: `main`(2.x)과
|
|
29
|
+
`sync/0.1.5-from-main`(3.x, DSH 0.1.5 패키징 변형 —— `compat/0.1.5`는 같은 코드
|
|
30
|
+
트리를 가리킵니다).
|
|
31
31
|
|
|
32
32
|
| DSH 버전 | 설치 방법 |
|
|
33
33
|
|----------|-----------|
|
|
34
|
-
| `0.1.2-alpha.1`
|
|
34
|
+
| `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate` (tag `latest`, 2.x 라인) |
|
|
35
|
+
| `0.1.5-rc.1` 이상 | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main` (3.x 라인; npm dist-tag 미게시 —— `@latest`는 동일 코드의 2.x 패키징을 설치) |
|
|
35
36
|
| `0.1.1-rc.2` 이하 | `dsh plugin --profile web add dsh-perm-gate@legacy` |
|
|
36
37
|
|
|
37
|
-
DSH는 `engines.dsh`를 강제하지 않으므로, tag
|
|
38
|
-
아닙니다.
|
|
39
|
-
|
|
38
|
+
DSH는 `engines.dsh`를 강제하지 않으므로, tag과 ref은 선택 메커니즘이지 호환성
|
|
39
|
+
게이트가 아닙니다. 라인과 tag 게시 레이아웃은 [RELEASING.md](./RELEASING.md)를
|
|
40
|
+
참고하세요.
|
|
40
41
|
|
|
41
42
|
## 공식 CLI로 설치
|
|
42
43
|
|
|
@@ -73,6 +74,11 @@ profile의 `cordis.yml`에 플러그인을 추가합니다:
|
|
|
73
74
|
defaultAction: ask # allow | ask | deny
|
|
74
75
|
```
|
|
75
76
|
|
|
77
|
+
2.6.0부터 규칙 본체는 `dsh-perm-gate-rules` settings 네임스페이스에 저장되며, 변경 시
|
|
78
|
+
마다 게이트가 그 자리에서 다시 컴파일됩니다. 위의 YAML 파일은 선택 사항이 되었습니다.
|
|
79
|
+
네임스페이스가 설정되지 않은 동안에만 읽히며, 플러그인이 처음으로 규칙을 쓸 때(허용
|
|
80
|
+
목록 승인 또는 설정 UI에서의 편집) 파일의 규칙이 자동으로 흡수됩니다.
|
|
81
|
+
|
|
76
82
|
[examples/permissions.example.yaml](./examples/permissions.example.yaml)에서 시작한 뒤
|
|
77
83
|
profile을 다시 불러오세요.
|
|
78
84
|
|
package/INSTALL.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
13
13
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
14
14
|
|
|
15
|
-
`dsh-perm-gate` version **2.
|
|
15
|
+
`dsh-perm-gate` version **2.6.0**. Continue with the [README](./README.md) for the
|
|
16
16
|
decision chain, the rules file format and the 自动审查 tier.
|
|
17
17
|
|
|
18
18
|
## Requirements
|
|
@@ -23,19 +23,21 @@ decision chain, the rules file format and the 自动审查 tier.
|
|
|
23
23
|
- A profile to install into — the browser half only ships for the `web` profile
|
|
24
24
|
(`dsh.client.platform = "web"` in `package.json`).
|
|
25
25
|
|
|
26
|
-
## Pick the
|
|
26
|
+
## Pick the line for your DSH version
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
Two long-lived branches serve two DSH lines: `main` (2.x) and
|
|
29
|
+
`sync/0.1.5-from-main` (3.x, the DSH 0.1.5 packaging variant — `compat/0.1.5`
|
|
30
|
+
points at the same tree).
|
|
30
31
|
|
|
31
32
|
| Your DSH | Install |
|
|
32
33
|
|----------|---------|
|
|
33
|
-
| `0.1.2-alpha.1`
|
|
34
|
+
| `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate` (tag `latest`, the 2.x line) |
|
|
35
|
+
| `0.1.5-rc.1` or newer | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main` (the 3.x line; no npm dist-tag yet — `@latest` installs the same code with 2.x packaging) |
|
|
34
36
|
| up to `0.1.1-rc.2` | `dsh plugin --profile web add dsh-perm-gate@legacy` |
|
|
35
37
|
|
|
36
|
-
DSH does not enforce `engines.dsh`, so
|
|
37
|
-
than a compatibility gate. See [RELEASING.md](./RELEASING.md) for
|
|
38
|
-
|
|
38
|
+
DSH does not enforce `engines.dsh`, so tags and refs are the selection mechanism
|
|
39
|
+
rather than a compatibility gate. See [RELEASING.md](./RELEASING.md) for how the
|
|
40
|
+
lines and tags are laid out.
|
|
39
41
|
|
|
40
42
|
## Install with the official CLI
|
|
41
43
|
|
|
@@ -73,6 +75,12 @@ Add the plugin to your profile's `cordis.yml`:
|
|
|
73
75
|
gatePresets: [permissive] # tiers where the gate is active at all (default)
|
|
74
76
|
```
|
|
75
77
|
|
|
78
|
+
Since 2.6.0 the rules themselves are stored in the `dsh-perm-gate-rules` settings
|
|
79
|
+
namespace, and every change recompiles the gate in place. The YAML file above is
|
|
80
|
+
optional: it is only read while the namespace is untouched, and the first rules
|
|
81
|
+
write from the plugin (an allowlist approval, or an edit in the settings UI)
|
|
82
|
+
absorbs the file's rules automatically.
|
|
83
|
+
|
|
76
84
|
Start from [examples/permissions.example.yaml](./examples/permissions.example.yaml),
|
|
77
85
|
then reload the profile.
|
|
78
86
|
|
package/INSTALL.zh.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
13
13
|
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
14
14
|
|
|
15
|
-
`dsh-perm-gate` 版本 **2.
|
|
15
|
+
`dsh-perm-gate` 版本 **2.6.0**。裁决链、规则文件格式与自动审查档位请见
|
|
16
16
|
[中文 README](./README.zh.md)。
|
|
17
17
|
|
|
18
18
|
## 前置条件
|
|
@@ -23,18 +23,19 @@
|
|
|
23
23
|
- 需要一个目标 profile —— 浏览器端只为 `web` profile 构建(`package.json`
|
|
24
24
|
里 `dsh.client.platform = "web"`)。
|
|
25
25
|
|
|
26
|
-
## 按你的 DSH
|
|
26
|
+
## 按你的 DSH 版本选择安装线
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
两条长期分支分别服务两条 DSH 线:`main`(2.x)与 `sync/0.1.5-from-main`
|
|
29
|
+
(3.x,DSH 0.1.5 打包变体 —— `compat/0.1.5` 指向同一棵代码树)。
|
|
30
30
|
|
|
31
31
|
| 你的 DSH | 安装方式 |
|
|
32
32
|
|----------|----------|
|
|
33
|
-
| `0.1.2-alpha.1`
|
|
33
|
+
| `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate`(tag `latest`,2.x 线) |
|
|
34
|
+
| `0.1.5-rc.1` 或更高 | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main`(3.x 线;npm 尚无对应 dist-tag —— `@latest` 安装的是相同代码的 2.x 打包) |
|
|
34
35
|
| 不高于 `0.1.1-rc.2` | `dsh plugin --profile web add dsh-perm-gate@legacy` |
|
|
35
36
|
|
|
36
|
-
DSH 不强制 `engines.dsh`,因此 tag 是选择机制而非兼容性关卡。
|
|
37
|
-
|
|
37
|
+
DSH 不强制 `engines.dsh`,因此 tag 与 ref 是选择机制而非兼容性关卡。
|
|
38
|
+
各线与 tag 的发布布局详见 [RELEASING.md](./RELEASING.md)。
|
|
38
39
|
|
|
39
40
|
## 用官方 CLI 安装
|
|
40
41
|
|
|
@@ -70,6 +71,10 @@ dsh plugin --profile web add .
|
|
|
70
71
|
defaultAction: ask # allow | ask | deny
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
自 2.6.0 起,规则本体存储在 `dsh-perm-gate-rules` settings 命名空间中,每次变更都会
|
|
75
|
+
就地重编译闸门。上面的 YAML 文件变为可选:只有命名空间未被配置时才会读取它,插件
|
|
76
|
+
发起的首次规则写入(白名单批准或设置界面编辑)会自动收编文件中的规则。
|
|
77
|
+
|
|
73
78
|
可从 [examples/permissions.example.yaml](./examples/permissions.example.yaml) 起步,
|
|
74
79
|
然后重载 profile。
|
|
75
80
|
|