Skip to content

Commit 2fc36e4

Browse files
Violet2314claude
andcommitted
feat(safety): ship Tool Script Safety Guard as SDK package
Move the pre-execution scanner into trpc_agent_sdk.safety with import-alias tracking, Session/httpx client detection, pathlib chains, base64|sh / python -c rescans, env-secret sinks, and policy knobs (block_on_review, strict_command_allowlist, strict_policy). Expand samples to 20 with manifest-driven eval, add scripts CLI, mkdocs, and adversarial tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 533028d commit 2fc36e4

48 files changed

Lines changed: 4062 additions & 3287 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/mkdocs/en/tool_safety.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Tool Script Safety Guard
2+
3+
The Tool Script Safety Guard is an **opt-in** pre-execution static scanner for
4+
Tool, Skill, and CodeExecutor payloads. It analyzes Python and Bash content
5+
before execution and returns `allow`, `deny`, or `needs_human_review`.
6+
7+
Package: `trpc_agent_sdk.safety`
8+
9+
## Quick start
10+
11+
```python
12+
from trpc_agent_sdk.safety import PolicyConfig, SafetyScanner, ScanInput
13+
14+
policy = PolicyConfig.from_yaml("examples/tool_safety/tool_safety_policy.yaml")
15+
scanner = SafetyScanner(policy=policy)
16+
report = scanner.scan(ScanInput(script="rm -rf /", language="bash"))
17+
assert report.decision.value == "deny"
18+
```
19+
20+
Attach as a Tool Filter:
21+
22+
```python
23+
from trpc_agent_sdk.safety import ToolSafetyFilter, PolicyConfig
24+
25+
policy = PolicyConfig.from_yaml("examples/tool_safety/tool_safety_policy.yaml")
26+
tool = BashTool(filters=[ToolSafetyFilter(policy=policy, audit_path="audit.jsonl")])
27+
```
28+
29+
## Risk coverage
30+
31+
| Rule | Detects |
32+
|---|---|
33+
| R001 dangerous files | recursive delete, credential paths, system dirs, pathlib chains |
34+
| R002 network egress | non-allowlisted hosts via curl/requests/httpx/Session/socket |
35+
| R003 process/system | subprocess/os.system (with import aliases), getattr, eval, base64\|sh |
36+
| R004 dependency install | pip/npm/apt and subprocess list forms |
37+
| R005 resource abuse | infinite loops, fork bombs, long sleep, large writes |
38+
| R006 secret leak | hardcoded secrets, env secret sinks, credential upload |
39+
40+
## Policy
41+
42+
Edit YAML to change allow-listed domains, forbidden paths, allowed commands,
43+
decision thresholds, `block_on_review`, and `strict_command_allowlist` without
44+
code changes.
45+
46+
## Integration points
47+
48+
- `ToolSafetyFilter` — BaseFilter pre-hook
49+
- `wrap_tool` / `safety_wrapper` — generic wrappers
50+
- `SafetyReviewedSkillRunner` — Skill path
51+
- `SafetyGuardedCodeExecutor` / `safe_code_executor` — CodeExecutor path
52+
- `scripts/tool_safety_check.py` — CLI / CI gate (exit 0/1/2)
53+
54+
## Observability
55+
56+
Every decision can write a JSONL audit record and set OpenTelemetry attributes:
57+
58+
- `tool.safety.decision`
59+
- `tool.safety.risk_level`
60+
- `tool.safety.rule_id`
61+
- `tool.safety.scan_duration_ms`
62+
- `tool.safety.blocked`
63+
64+
## Limits
65+
66+
Static analysis cannot catch every dynamic construction. Use this guard **with**
67+
sandbox isolation (ContainerCodeExecutor / process limits). The guard is the
68+
first line of defense; the sandbox is the last.

docs/mkdocs/zh/tool_safety.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Tool 脚本安全扫描(Tool Script Safety Guard)
2+
3+
Tool Script Safety Guard 是面向 Tool / Skill / CodeExecutor 的**可选**执行前静态扫描器。
4+
它对 Python / Bash 内容做策略判定,输出 `allow` / `deny` / `needs_human_review`
5+
6+
包路径:`trpc_agent_sdk.safety`
7+
8+
## 快速开始
9+
10+
```python
11+
from trpc_agent_sdk.safety import PolicyConfig, SafetyScanner, ScanInput
12+
13+
policy = PolicyConfig.from_yaml("examples/tool_safety/tool_safety_policy.yaml")
14+
scanner = SafetyScanner(policy=policy)
15+
report = scanner.scan(ScanInput(script="rm -rf /", language="bash"))
16+
assert report.decision.value == "deny"
17+
```
18+
19+
作为 Tool Filter 接入:
20+
21+
```python
22+
from trpc_agent_sdk.safety import ToolSafetyFilter, PolicyConfig
23+
24+
policy = PolicyConfig.from_yaml("examples/tool_safety/tool_safety_policy.yaml")
25+
tool = BashTool(filters=[ToolSafetyFilter(policy=policy, audit_path="audit.jsonl")])
26+
```
27+
28+
## 风险覆盖
29+
30+
| 规则 | 检测内容 |
31+
|---|---|
32+
| R001 危险文件 | 递归删除、凭据路径、系统目录、pathlib 链 |
33+
| R002 网络外连 | 非白名单域名(curl/requests/httpx/Session/socket) |
34+
| R003 进程命令 | subprocess/os.system(含 import 别名)、getattr、eval、base64\|sh |
35+
| R004 依赖安装 | pip/npm/apt 及 subprocess list 形态 |
36+
| R005 资源滥用 | 无限循环、fork bomb、长 sleep、大写入 |
37+
| R006 敏感泄漏 | 硬编码密钥、环境变量密钥 sink、凭据上传 |
38+
39+
## 策略配置
40+
41+
通过 YAML 调整白名单域名、禁止路径、允许命令、决策阈值、`block_on_review`
42+
`strict_command_allowlist`,无需改代码。
43+
44+
## 接入方式
45+
46+
- `ToolSafetyFilter` — BaseFilter 前置钩子
47+
- `wrap_tool` / `safety_wrapper` — 通用包装
48+
- `SafetyReviewedSkillRunner` — Skill 路径
49+
- `SafetyGuardedCodeExecutor` / `safe_code_executor` — CodeExecutor 路径
50+
- `scripts/tool_safety_check.py` — CLI / CI(退出码 0/1/2)
51+
52+
## 可观测性
53+
54+
每次决策可写 JSONL 审计,并在启用 OpenTelemetry 时设置:
55+
56+
- `tool.safety.decision`
57+
- `tool.safety.risk_level`
58+
- `tool.safety.rule_id`
59+
- `tool.safety.scan_duration_ms`
60+
- `tool.safety.blocked`
61+
62+
## 限制
63+
64+
静态分析无法覆盖全部动态构造。请与沙箱隔离(ContainerCodeExecutor / 进程限制)
65+
一起使用:本工具是第一道防线,沙箱是最后一道防线。

0 commit comments

Comments
 (0)