phocinae-guard 0.1.0__tar.gz
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.
- phocinae_guard-0.1.0/LICENSE +201 -0
- phocinae_guard-0.1.0/PKG-INFO +260 -0
- phocinae_guard-0.1.0/README.md +250 -0
- phocinae_guard-0.1.0/phocinae_guard/__init__.py +3 -0
- phocinae_guard-0.1.0/phocinae_guard/guard.py +508 -0
- phocinae_guard-0.1.0/phocinae_guard/l0_table.json +200 -0
- phocinae_guard-0.1.0/phocinae_guard.egg-info/PKG-INFO +260 -0
- phocinae_guard-0.1.0/phocinae_guard.egg-info/SOURCES.txt +11 -0
- phocinae_guard-0.1.0/phocinae_guard.egg-info/dependency_links.txt +1 -0
- phocinae_guard-0.1.0/phocinae_guard.egg-info/entry_points.txt +2 -0
- phocinae_guard-0.1.0/phocinae_guard.egg-info/top_level.txt +1 -0
- phocinae_guard-0.1.0/pyproject.toml +21 -0
- phocinae_guard-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 phocinae-guard authors (Nous Research)
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: phocinae-guard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Phocinae command approval gate for AI harnesses (L0 whitelist/blacklist)
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Dynamic: license-file
|
|
10
|
+
|
|
11
|
+
# phocinae-guard · L0 内核
|
|
12
|
+
|
|
13
|
+
**斑海豹(phocinae)命令行审批门 L0 内核**:一条 shell 命令进来,判定出去
|
|
14
|
+
(`allow` / `deny` / `ask` + exit code)。面向 Claude Code / Cline / Codex CLI /
|
|
15
|
+
Crush / dsh / Gemini CLI / Qwen Code / Kimi Code / OpenHands / Hermes 的 hook /
|
|
16
|
+
包装通用形态;本次交付为通用 CLI 形态(stdin 或 `--command`)。
|
|
17
|
+
|
|
18
|
+
## 定位
|
|
19
|
+
|
|
20
|
+
- 审批门而非沙箱:只做「放行 / 拒绝 / 需人工确认」判定,不承诺隔离执行环境。
|
|
21
|
+
- 单文件 `guard.py`,Python ≥ 3.8,**零第三方依赖**(纯标准库),可直接塞进任何 hook 管道。
|
|
22
|
+
- L0 确定性表独立存活:服务器挂了也能守住黑白名单底线。
|
|
23
|
+
|
|
24
|
+
## 架构(三层)
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
命令 → 归一化
|
|
28
|
+
├─ L0 确定性表(纯离线):白名单精确/前缀 → allow
|
|
29
|
+
│ 黑名单危险正则 → deny(先于白名单判定)
|
|
30
|
+
├─ L1 /v1/systemone 两问:noul「是否放行」+ score「风险层 2–10」(默认关闭,见下)
|
|
31
|
+
│ 阈值映射(通道合成取最严格):
|
|
32
|
+
│ risk≥7 或 noul=false(≤0.35) → deny
|
|
33
|
+
│ risk 4–6 或 noul 摇摆 → ask(hook 阻塞态,可 --confirm)
|
|
34
|
+
│ 其余(risk<4 且 noul=true) → allow
|
|
35
|
+
└─ 服务器不可用 → fail-closed:除白名单外一律 deny/ask(默认 deny,可配 ask)
|
|
36
|
+
|
|
37
|
+
不变式:只有 allow 类能过门(exit 0);deny/ask 均非零退出;
|
|
38
|
+
--confirm 只能把 ask 升级为 allow,永远不能覆盖 deny。
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
判定矩阵(noul 阈值 0.65 / ask≥4 / deny≥7,均可配):
|
|
42
|
+
|
|
43
|
+
| risk | noul=false | noul 摇摆 | noul=true |
|
|
44
|
+
|------|-----------|----------|-----------|
|
|
45
|
+
| ≥7 | deny | deny | deny |
|
|
46
|
+
| 4–6 | deny | ask | ask |
|
|
47
|
+
| <4 | deny | ask | allow |
|
|
48
|
+
|
|
49
|
+
## L0 表内容概要(`l0_table.json`,24 条黑名单正则)
|
|
50
|
+
|
|
51
|
+
| 类 | 覆盖 |
|
|
52
|
+
|----|------|
|
|
53
|
+
| 危险删除 | `rm -rf /`、`/*`、`~`、`$HOME`、`/etc` `/usr` `/var` `/boot` `/bin` `/sbin` `/lib` `/opt` `/root`、`rm -rf .`/`..` |
|
|
54
|
+
| sudo 破坏 | `sudo rm/dd/mkfs/fdisk/sfdisk/parted/wipefs/shutdown/reboot/poweroff/halt` |
|
|
55
|
+
| 下载即执行 | `curl\|sh`、`wget\|bash`、任意管道喂 shell、`sh -c 'curl…'`、`eval $(curl)`、`source <(curl)` |
|
|
56
|
+
| git 破坏 | `push --force`/`-f`、`push --delete`(`--force-with-lease` 有意放行到 L1 由模型裁决) |
|
|
57
|
+
| find/xargs 删除 | `find / -delete`、`find /usr… -delete`、`find -exec rm`、`xargs rm` |
|
|
58
|
+
| 块设备 | `dd of=/dev/sd*/hd*/vd*/nvme*/mmcblk*/dm-*/md*/loop*/disk`、`mkfs.*` |
|
|
59
|
+
| 权限/属主 | `chmod [-R] 777`、`chown … /系统路径` |
|
|
60
|
+
| 其他 | fork bomb(`:(){ :\|:& };:`、`%0\|%0`)、`shutdown/reboot/poweroff/halt`、`crontab -r`、`> /etc…` 重定向覆写、`mv` 进系统路径 |
|
|
61
|
+
|
|
62
|
+
白名单:`ls`/`pwd`/`git status|diff|log|show|fetch|branch|tag` 等只读命令(精确+前缀两档),
|
|
63
|
+
服务器不可用时这些命令仍可离线放行。
|
|
64
|
+
|
|
65
|
+
## 目录结构
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
phocinae-guard/
|
|
69
|
+
├── guard.py # 单文件审批门(纯标准库)
|
|
70
|
+
├── l0_table.json # L0 确定性表(白名单+黑名单正则)
|
|
71
|
+
├── guard.conf.example.json# 配置文件示例
|
|
72
|
+
├── mock_server.py # 本地测试 mock(POST /v1/systemone 固定 noul/score)
|
|
73
|
+
├── mock_rules.json # mock 按命令区分的规则(灰带命令用)
|
|
74
|
+
├── test_guard.py # 验收测试(replay battery + 全链路)
|
|
75
|
+
├── .claude-plugin/ # Claude Code 插件(本地成品;市场提交为后续迭代)
|
|
76
|
+
│ ├── plugin.json # 插件 manifest(name/version/description/author/hooks 声明)
|
|
77
|
+
│ ├── hooks/
|
|
78
|
+
│ │ ├── hooks.json # PreToolUse(Bash) command 型 hook 配置
|
|
79
|
+
│ │ └── guard_hook.py # hook 本体:Claude Code JSON 协议 ↔ guard.py 裁决
|
|
80
|
+
│ ├── skills/
|
|
81
|
+
│ │ └── phocinae-guard/SKILL.md # 「审批门」技能说明(应对守则+自查清单)
|
|
82
|
+
│ └── scripts/
|
|
83
|
+
│ └── self_test.sh # 插件自测(hook 链路 + exit code 断言)
|
|
84
|
+
├── README.md
|
|
85
|
+
└── LICENSE # Apache-2.0
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 安装
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
mkdir -p /opt/phocinae-guard
|
|
92
|
+
cp guard.py l0_table.json /opt/phocinae-guard/
|
|
93
|
+
# 可选:全局配置文件(路径、阈值、L0 表路径都在这里改)
|
|
94
|
+
cp guard.conf.example.json /etc/phocinae-guard.conf.json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
依赖:仅 Python ≥ 3.8。L1 判定需要一个 `/v1/systemone` 服务(phocinae-server P0
|
|
98
|
+
扁平协议,或测试用 mock_server.py)。**P0 口径:L1 默认关闭(`l1_enabled=false`)**——
|
|
99
|
+
当前 150M 权重未经命令审批域校准(2026-10-08 联合实测:对灰区命令的 noul/score
|
|
100
|
+
信号≈噪声),灰区命令走 fail-closed(deny/ask)。领域微调 + 标定电池完成后(P1)
|
|
101
|
+
再开 `PHOCINAE_GUARD_L1_ENABLED=1`。不装服务也可用——L1 关闭时灰区自动进入
|
|
102
|
+
fail-closed。
|
|
103
|
+
|
|
104
|
+
## 用法
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# stdin 收命令
|
|
108
|
+
echo "rm -rf /" | guard.py # exit 1,deny
|
|
109
|
+
# 或显式传
|
|
110
|
+
guard.py --command "git status" # exit 0,allow
|
|
111
|
+
guard.py --command "npm install -g x" # exit 2,ask(需人工确认)
|
|
112
|
+
guard.py --command "npm install -g x" --confirm # 人工确认后 exit 0
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
exit code:`0`=allow(可执行)· `1`=deny(拒绝)· `2`=ask(阻塞待人工,hook 输出阻塞态)·
|
|
116
|
+
`3`=用法/配置错误。stdout 默认一行 JSON(含 `decision`/`layer`/`reason`/`noul`/`score`/
|
|
117
|
+
`thresholds`/`exit`),`--text` 换人读格式。审计 JSONL(ts+command+cwd+decision+依据层+原因)
|
|
118
|
+
默认追加到 `./phocinae-guard.audit.jsonl`,`--audit off` 或 env 置 `off` 可禁用。
|
|
119
|
+
|
|
120
|
+
## 集成示例
|
|
121
|
+
|
|
122
|
+
**通用 bash 包装**(Claude Code / Cline / Crush / dsh 等都可用):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
#!/usr/bin/env bash
|
|
126
|
+
# guard-wrap.sh:先过门再执行
|
|
127
|
+
out=$(/opt/phocinae-guard/guard.py --command "$1")
|
|
128
|
+
case $? in
|
|
129
|
+
0) shift; exec "$@" ;; # allow → 执行
|
|
130
|
+
1) echo "[guard] DENY: $out" >&2; exit 1 ;; # deny → 拦截
|
|
131
|
+
2) echo "[guard] ASK: $out" >&2; exit 2 ;; # ask → 阻塞待人工
|
|
132
|
+
*) echo "[guard] ERROR" >&2; exit 3 ;;
|
|
133
|
+
esac
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Claude Code PreToolUse hook**(`settings.json`):
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{"hooks": {"PreToolUse": [{"matcher": "Bash", "hooks": [
|
|
140
|
+
{"type": "command",
|
|
141
|
+
"command": "jq -r .tool_input.command | /opt/phocinae-guard/guard.py"}]}]}}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
hook 收到的 stdin JSON 里取命令后喂给 guard:exit 0 放行;exit 2 输出
|
|
145
|
+
`decision=ask` 给前端做人工确认(确认后带 `--confirm` 重跑);exit 1 直接阻断。
|
|
146
|
+
其余工具同理:Codex CLI / Gemini CLI 用 `sandbox_command_wrapper`/`command wrapper`,
|
|
147
|
+
OpenHands / Hermes 用 PreToolUse 类 hook——凡是能「拦命令、看 exit code」的位置都能挂。
|
|
148
|
+
|
|
149
|
+
## Claude Code 插件(.claude-plugin/)
|
|
150
|
+
|
|
151
|
+
本地成品形态:一个 Claude Code 插件目录——`PreToolUse(Bash)` 拦截每一次 shell
|
|
152
|
+
命令,交给 guard.py 裁决,再把结果翻译成 Claude Code hook JSON 协议
|
|
153
|
+
(`permissionDecision: allow/deny/ask` + 可执行理由)。**本次仅本地成品,不发布;
|
|
154
|
+
claude-community 市场提交为后续迭代。**
|
|
155
|
+
|
|
156
|
+
### 插件结构
|
|
157
|
+
|
|
158
|
+
- `.claude-plugin/plugin.json`:manifest(name/version/description/author +
|
|
159
|
+
`hooks`/`skills` 组件声明,Apache-2.0);
|
|
160
|
+
- `.claude-plugin/hooks/hooks.json`:`PreToolUse` → matcher `Bash` → command 型
|
|
161
|
+
hook `python3 "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/hooks/guard_hook.py"`
|
|
162
|
+
(timeout 30s,远低于默认 60s 上限);
|
|
163
|
+
- `.claude-plugin/hooks/guard_hook.py`:协议适配器(纯标准库)——stdin 收
|
|
164
|
+
PreToolUse 事件 JSON,取 `tool_input.command` 调 guard.py,按 exit code 映射:
|
|
165
|
+
`0/allow → hook exit 0 + allow`(跳过权限弹窗)、`1/deny → hook exit 2 + deny`、
|
|
166
|
+
`2/ask → hook exit 2 + ask`(auto 模式下 ask 也强制弹窗);guard.py 出错/超时 →
|
|
167
|
+
无输出、exit 0,落入正常权限流(fail-closed,**绝不自动 allow**)。
|
|
168
|
+
**传参逐项对齐**:只显式传 `--command` / `--cwd`,不覆盖服务地址参数,沿用
|
|
169
|
+
guard.py 内置默认 `http://127.0.0.1:8155`;阈值/fail-closed/L1 开关/审计路径
|
|
170
|
+
等经环境变量透传(见「配置」节)。审计默认落 `~/.phocinae-guard/audit.jsonl`
|
|
171
|
+
(避免散落到各项目目录),`PHOCINAE_GUARD_AUDIT=off` 禁用;
|
|
172
|
+
- `.claude-plugin/skills/phocinae-guard/SKILL.md`:教 Claude 理解裁决、被 deny 后
|
|
173
|
+
改方案而非原样重试、危险命令自查清单。
|
|
174
|
+
|
|
175
|
+
### 安装
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# 本地开发/验证:claude --plugin-dir 直接挂本仓(团队分发走插件市场,后续迭代)
|
|
179
|
+
claude --plugin-dir /home/hermes/dev/phocinae-guard
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
依赖:`python3` ≥ 3.8 在 PATH(hook 与 guard.py 均零第三方包)。不装插件时,可把
|
|
183
|
+
上文「集成示例」里的 settings.json hook 片段直接贴进 `.claude/settings.json`,
|
|
184
|
+
效果等同(插件只是把这个片段打包成一键安装)。
|
|
185
|
+
|
|
186
|
+
### 自测
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
bash .claude-plugin/scripts/self_test.sh
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
纯本地、纯 CPU(不起真实模型服务):两份 JSON 可解析+结构断言 → 服务地址对齐
|
|
193
|
+
断言(guard 内置默认 127.0.0.1:8155、hook 不覆盖)→ guard 直连(良性 exit 0 /
|
|
194
|
+
危险 exit 1 / 灰区 fail-closed)→ hook 链路(良性 exit 0+allow、危险 exit 2+deny、
|
|
195
|
+
灰区 exit 2+deny)→ L1 端到端(本地 mock 起在 8155 验证默认 server 对齐与阈值
|
|
196
|
+
映射,8155 被占则 SKIP)→ 审计 JSONL 校验。退出码 0 = 全绿。
|
|
197
|
+
|
|
198
|
+
### 行为要点
|
|
199
|
+
|
|
200
|
+
- 默认只有 L0 表在跑(`l1_enabled=false`):白名单放行、黑名单 deny、其余灰区
|
|
201
|
+
fail-closed=deny——**装上即最严格**。体验过严时设 `PHOCINAE_GUARD_FAIL_CLOSED=ask`
|
|
202
|
+
放宽为人工确认档;L1 模型经命令审批域校准后再开 `PHOCINAE_GUARD_L1_ENABLED=1`。
|
|
203
|
+
- deny 在任何权限模式下都生效(含 bypass/yolo 模式),`--confirm` 也无法覆盖;
|
|
204
|
+
被 deny 后 Claude 应依据理由改方案而不是重试同款。
|
|
205
|
+
- 门只管 Bash 工具调用;Write/Edit/MCP 工具不受此 hook 约束(后续迭代可扩 matcher)。
|
|
206
|
+
|
|
207
|
+
## 配置
|
|
208
|
+
|
|
209
|
+
优先级:命令行 > 环境变量 > 配置文件 > 内置默认。
|
|
210
|
+
|
|
211
|
+
| env | 默认 | 说明 |
|
|
212
|
+
|-----|------|------|
|
|
213
|
+
| `PHOCINAE_GUARD_SERVER` | `http://127.0.0.1:8155` | L1 服务基地址(自动拼 `/v1/systemone`) |
|
|
214
|
+
| `PHOCINAE_GUARD_TIMEOUT` | `2.0` | L1 请求超时(秒) |
|
|
215
|
+
| `PHOCINAE_GUARD_NOUL_THRESHOLD` | `0.65` | noul 放行阈值 |
|
|
216
|
+
| `PHOCINAE_GUARD_DENY_AT` | `7.0` | score ≥ 此值 → deny |
|
|
217
|
+
| `PHOCINAE_GUARD_ASK_AT` | `4.0` | score ≥ 此值且 < deny → ask |
|
|
218
|
+
| `PHOCINAE_GUARD_TABLE` | 同目录 `l0_table.json` | L0 表路径 |
|
|
219
|
+
| `PHOCINAE_GUARD_AUDIT` | `./phocinae-guard.audit.jsonl` | 审计路径(`off` 禁用) |
|
|
220
|
+
| `PHOCINAE_GUARD_FAIL_CLOSED` | `deny` | 服务器不可用兜底:`deny`/`ask` |
|
|
221
|
+
| `PHOCINAE_GUARD_CONFIG` | 无 | 配置文件路径(JSON,见 `guard.conf.example.json`) |
|
|
222
|
+
|
|
223
|
+
对应命令行参数:`--server/--timeout/--noul-threshold/--deny-at/--ask-at/--table/--audit/--fail-closed/--config`。
|
|
224
|
+
L0 表自定义:JSON 的 `whitelist`/`whitelist_prefix`/`blacklist` 三节各自覆盖内置默认节;
|
|
225
|
+
`blacklist` 条目形如 `[名称, 正则, 说明]`。
|
|
226
|
+
|
|
227
|
+
## 测试与验收
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
python3 mock_server.py --port 8155 --rules mock_rules.json & # 本地 mock
|
|
231
|
+
python3 test_guard.py -v # 验收套件
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
replay battery:**15 条良性**(ls/git status/pytest/npm test/echo/…)、**24 条危险**
|
|
235
|
+
(rm -rf /、curl|sh、sudo rm、git push --force、find -delete、dd、mkfs、fork bomb、
|
|
236
|
+
chmod -R 777、shutdown、crontab -r、重定向覆写 /etc 等)、**4 条灰带**
|
|
237
|
+
(npm install -g→ask、pip install→allow、curl 仅下载→allow、push --force-with-lease→ask)。
|
|
238
|
+
|
|
239
|
+
验收实测(2026-10-08):危险误放行 **0/24**,良性误拒 **0/15**(门槛 ≤1),
|
|
240
|
+
L1 阈值映射 8 档全过(含边界 noul=0.65、score=4.0),服务器不可用 → fail-closed
|
|
241
|
+
行为正确(白名单离线放行、黑名单离线 deny、灰区 deny/ask 可配),审计 JSONL 落盘齐全,
|
|
242
|
+
自定义 L0 表与阈值 env 覆盖生效。测试全程只用本地 mock,不触碰任何真实服务。
|
|
243
|
+
|
|
244
|
+
## 安全声明
|
|
245
|
+
|
|
246
|
+
- **L0 正则表是确定性启发式,不是完备防护**:换行/字符串拼接/多阶段下载再执行/base64
|
|
247
|
+
混淆等手法可绕过正则;它负责「宁严勿松」的第一道确定性拦截,不是安全的全部。
|
|
248
|
+
- **L1 判定依赖服务与模型质量**:noul/score 是模型输出,阈值映射只是把模型意见翻译成
|
|
249
|
+
门禁动作;服务不可用默认 fail-closed=deny(最严),可用 `PHOCINAE_GUARD_FAIL_CLOSED=ask`
|
|
250
|
+
放宽为人工确认档。
|
|
251
|
+
- **不变式**:只有 allow 类能过门;`--confirm` 只升级 ask,deny 永不可覆盖。
|
|
252
|
+
- **审计是事后追责材料**:JSONL 记录了时间戳+命令+cwd+判定+依据层,请定期复核;
|
|
253
|
+
审计写失败不阻断判定(宁可漏记不误杀),但会向 stderr 报错。
|
|
254
|
+
- **生产建议**:关键路径配容器/权限/网络隔离;guard 是审批门,不是沙箱。
|
|
255
|
+
- 已知局限:多行脚本整体喂入时判定按整段文本归一匹配;`--force-with-lease`、
|
|
256
|
+
普通 `find -delete`(非根/系统路径)等有意留给 L1 裁决,L0 不覆盖所有变体。
|
|
257
|
+
|
|
258
|
+
## License
|
|
259
|
+
|
|
260
|
+
Apache License 2.0 —— 见 `LICENSE`。版权 2026 phocinae-guard 作者(Nous Research)。
|