pi-ast-guard
基于 AST 的 Pi 代理安全防护扩展 — 解析 Bash 命令,拦截危险操作(继承自 pi-damage-control)
Package details
Install pi-ast-guard from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-ast-guard- Package
pi-ast-guard- Version
1.0.4- Published
- Aug 4, 2026
- Downloads
- 513/mo · 513/wk
- Author
- rainmanhhh
- License
- MIT
- Types
- extension
- Size
- 233.2 KB
- Dependencies
- 4 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-ast-guard
简介
pi-ast-guard(原名 pi-damage-control)是一款基于 AST 的代理安全防护扩展,专为 Pi 编码代理设计。
它能够在破坏性 shell 命令或文件操作执行之前进行拦截,同时避免因普通文本、markdown、heredoc 和任务描述中的内容而产生误报。
继承说明:本项目继承自
pi-damage-control(原作者 Baishampayan Ghose,原仓库已删除), 在保留原有 AST 解析方案与策略引擎的基础上继续维护与改进。
安装
pi install npm:pi-ast-guard
# 或者
# pi install git:github.com/rainmanhhh/pi-ast-guard
DNA 模式(Do Not Ask)
不想每次操作都弹窗确认?/ag:dna 一键进入 DNA 模式:遇到 ask 不再询问,而是按策略自动审批或拒绝;block 规则照常拦截,安全底线不丢。
自动回答由 4 个参数决定(工作区内/外 × 读/写),外加工具黑白名单与累计违反上限,可在 settings.dna 中配置:
| 参数 | 默认 | 含义 |
|---|---|---|
dna.readInside |
allow |
工作区内读取 |
dna.readOutside |
allow |
工作区外读取(仅读取,风险低) |
dna.writeInside |
allow |
工作区内写/删/移动 |
dna.writeOutside |
block |
工作区外写/删/移动(高风险,默认拒绝) |
dna.maxViolations |
3 |
本次 DNA 模式下累计自动拒绝的总上限(所有规则含工具黑白名单),达到后强制中断会话并清零(对话结束也清零) |
dna.allowTools |
[] |
工具白名单(非空时启用白名单模式,仅允许名单中的工具调用) |
dna.blockTools |
[] |
工具黑名单(白名单为空时启用黑名单模式,禁止名单中的工具调用) |
工作区 = cwd +
settings.extraDirs。命令类ask(如发布命令)在 DNA 模式下默认放行;自动拒绝会拦截操作并引导 AI 评估替代方案(勿绕过规则),本次模式内累计违反达到上限(dna.maxViolations,默认 3)才强制中断。
工作原理
- 使用
just-bash解析 Bash 命令 AST,无需正则表达式回退 - 根据
config/default-policy.yaml中的语义化命令规则进行评估 - 从 Bash 命令和 Pi 文件工具中提取文件操作意图
- 对零访问(zero-access)、只读(read-only)、禁止删除(no-delete)和工作区外写入路径应用路径策略
- 当策略动作为
ask时弹出四选对话框(同意一次 / 本会话允许 / 本会话拒绝 / 拒绝一次);当 UI 不可用时自动拒绝(fail-closed)
配置方式
创建项目级策略文件:
.pi/ast-guard.yml
或全局策略文件:
~/.pi/agent/ast-guard.yml
策略分层加载:全局策略(~/.pi/agent/ast-guard.yml)为基础层(缺失时用内置默认策略),项目策略(.pi/ast-guard.yml)存在时在其上合并——settings 字段级覆盖,rules 按 id 覆盖(同 id 项目优先),不同 id 的规则全部保留。
内置默认策略文件:config/default-policy.yaml
策略语言
顶层策略结构:
settings:
language: auto
parseFailure: ask
showStatus: true
# 额外工作区目录:与 cwd 共同构成「完整的工作区」,outsideWorkdir: true 的语义变为「在工作区目录列表之外」
extraDirs: []
# DNA 模式(Do Not Ask)下 ask 的自动回答
dna:
readInside: allow
readOutside: allow
writeInside: allow
writeOutside: block
maxViolations: 3
rules: []
settings.language 控制扩展 UI 提示的语言(zh 中文 / en 英文 / auto 跟随系统,默认 auto),包括通知、拦截/确认对话框、命令描述与默认策略规则文案;auto 通过系统区域设置探测(Windows 取系统区域,Unix-like 取 LANG/LC_ALL,无则英文)。跟随项目策略,/ag:status(已合并 reload)后生效。
路径规则
路径规则与命令规则同属顶层的 rules 列表。其 type 字段编码了路径策略的子类型:
path:zeroAccess— 禁止读、写、删除和移动操作path:readOnly— 仅禁止写、删除和移动操作,读取允许path:noDelete— 仅禁止删除和移动操作
每条路径规则示例:
- id: path-secrets-env
type: path:zeroAccess
action: block
reason: 环境文件可能包含密钥信息
match:
path:
any: .env*
except: [.env.example]
match.path.any 可以是字符串或字符串列表:
match:
path:
any: [LICENSE, LICENSE.*, COPYING, COPYING.*]
支持的路径模式(glob 语义,* 按段匹配不跨 /,** 匹配任意深度):
- 精确匹配/文件名:
README.md、.env(无斜杠模式匹配任意位置的同名文件,如ast-guard.yml可命中~/.pi/ast-guard.yml) - 目录:
.git/、node_modules/(含目录本身及其下所有内容) - 通配符:
*.pem、docker-compose.*.yml、dist/**、**/secrets/**(**段感知,**/secrets/**命中任意深度含secrets段的路径) - 前缀:
build-*(/段结尾) - 当前工作目录宏:
$CWD、$CWD/…(工作区外用outsideWorkdir: true) - 相对模式解析到工作区根(cwd),
~解析到 HOME
工作区外写入确认示例:
- id: path-outside-project-write
type: path:readOnly
reason: 工作区外写入需要确认
match:
path:
outsideWorkdir: true
except: [/tmp/, /dev/null]
命令规则
命令规则使用 type: command:
- id: git-reset-hard
type: command
action: block
reason: git reset --hard 会丢弃工作区变更
match:
command: git
subcommand: reset
flags:
any: [--hard]
常用匹配字段:
command:精确的命令名称commandAny:多个命令名称之一subcommand:第一个非选项命令操作数subcommandAny:多个子命令之一argsAny:参数列表中任意一个匹配即可argsAll:参数列表中全部必须匹配argsNone:参数列表中不得出现任何匹配项argsContainAny/argsContainAll:参数子串匹配flags.any/flags.all/flags.none:语义化标志匹配optionsBeforeSubcommand.value:子命令检测前的全局选项值,适用于git -C repo ...visibleTextAny/visibleTextAll/visibleTextNone:匹配可见静态文本,适用于 SQL 执行器
规则默认启用。审批对话框中的「本会话允许」会在当前会话内临时解除被触发规则的检查。
规则可配 priority(默认 0,值越大越优先):命中多条规则时只保留最高优先级的一组再按动作强度判定(block > ask > allow),因此高优先级 allow 规则可豁免低优先级 ask/block。来源偏移:项目 0 / home -0.3 / 内置默认 -0.6。
动作选项:
allow— 放行ask— 请求确认block— 直接阻止
action 字段可选,省略时默认为 ask。
- id: git-commit
type: command
action: ask
reason: git commit 需要确认
match:
command: git
subcommand: commit
完整示例:
settings:
parseFailure: ask
showStatus: true
rules:
- id: path-secrets-env
type: path:zeroAccess
action: block
reason: 环境文件可能包含密钥信息
match:
path:
any: .env*
except: [.env.example]
- id: path-outside-project-write
type: path:readOnly
reason: 工作区外写入需要确认
match:
path:
outsideWorkdir: true
except: [/tmp/, /dev/null]
- id: git-commit
type: command
action: ask
reason: git commit 需要确认
match:
command: git
subcommand: commit
审批对话框
当规则动作评估为 ask 时,弹出四选对话框(30 秒超时,超时即拒绝):
- 同意一次 — 只放行当前这一次工具调用(单次生效,不影响下次)
- 本会话允许 — 记录为会话级决策(决策层),当前会话内该规则在作用域内不再询问
- 本会话拒绝 — 记录为会话级决策(决策层),当前会话内该规则在作用域内直接拦截、不再弹窗
- 拒绝一次 — 拦截本次调用(单次生效,不影响下次)
会话级决策 = 规则匹配之上叠加的一层精确路径匹配:每条决策是 (规则, 作用域路径),查询时 deny 优先于 allow(无论新旧);同一 (规则, 作用域) 的新决策覆盖旧决策,不同作用域累积生效。
拒绝(含本会话拒绝、拒绝一次)、对话框取消/超时未应答,以及无 UI 自动拒绝,都会在拦截的同时中止当前轮(agent 停止执行,回到等待用户输入的状态);拦截消息仍作为工具结果发给 AI。
对话框被取消或超时均视为拒绝并拦截。无 UI 环境(print/JSON 模式)下,ask 决策自动拦截(fail-closed)。
作用域输入(粗粒度规则)
规则匹配域超出「工作区锚定的局部区域」(粗粒度)时,选中「本会话允许/拒绝」后额外弹一次输入框确定作用域:
| 输入 | 作用域 |
|---|---|
| (空) | 仅本次触发的目标文件(父目录存在即可,容忍尚未创建的文件) |
. |
目标文件所在目录 |
../.. |
从目标文件的上两级目录起(相对输入均相对目标文件目录解析) |
| 绝对路径 | 直接以该路径为作用域 |
输入会校验:不得含通配符;作用域必须与规则的匹配域相交(如 outsideWorkdir 规则不接受工作区内的绝对路径,/etc/** 规则不接受 /var);目录作用域必须真实存在;不通过则提示并重新输入。取消输入等同取消对话框(fail-closed,中止当前轮)。
粗粒度判定(任一命中即弹输入):
outsideWorkdir: true- 根锚定绝对路径且解析后字面深度 ≤ 2(如
/etc/**、/var/log/;/home/user/data/**深度 ≥ 3 视为细粒度) - 首段为通配符或覆盖工作区及以上(
**/…、*/…、.、./**、..、../**)
无斜杠模式(ast-guard.yml、*.log)不弹输入:选中后自动把作用域限定为本次触发的目标文件(同名其他位置下次仍会询问)。命令面规则(无路径可锚定)与细粒度路径规则保持规则级决策(覆盖该规则所有路径)。
最近决策与按序号清除
会话级决策记录到 /ag:status 面板的「最近决策」(保留最近 10 条),每行带序号(最新在前 = 1):
最近决策
1. 14:32 本会话允许 → outside-ask → C:/tmp/x.log (touch C:/tmp/x.log)
2. 14:31 本会话拒绝 → git-commit (git commit)
单次生效的同意/拒绝不影响下次 ask,不在面板展示。执行 /ag:forget 1,3 按序号清除单条决策(逗号分隔多个);清除后序号重排,新决策到达也会使序号位移,忘记前可先执行 /ag:status 查看最新序号。
可用命令
| 命令 | 说明 |
|---|---|
/ag:forget <序号...> |
按序号清除会话决策(逗号分隔多个,如 1,3),清除后序号重排 |
/ag:dna |
开启/关闭 Do Not Ask 模式 |
/ag:status |
重新加载策略并显示状态面板(含带序号的「最近决策」);再次执行刷新 |
开发
使用 Bun 作为包管理器:
bun install
bun run test # 运行单元测试(Vitest)
bun run test:watch # 监听模式
bun run typecheck # TypeScript 类型检查
bun run check # 完整检查(lint + 测试 + 类型)
bun run bench # 性能基准(mitata)
测试位于 tests/ 目录,按模块组织(bash/、rules/、policy/、engine/、extension/、intents/)。
已知问题与待优化项见 docs/known-issues.md。
本地开发与验证
在 ~/.pi/agent/settings.json 中直接指向源码(改代码即时生效):
{
"extensions": ["E:/workspace/pi-ast-guard/src/index.ts"]
}
然后进入任意测试项目运行 pi,状态栏出现 🛡 图标即加载成功。仓库内 bun run check 通过后提交(pre-commit hook 会自动运行 bun run lint)。
也可在 ast-guard-demo 测试沙箱(含 .env、dist/、自定义策略与完整验证清单)中手动验证。
鸣谢
本项目继承自 pi-damage-control(原作者 Baishampayan Ghose,原仓库已删除)。 灵感来源于 claude-code-damage-control。
许可证
MIT © rainmanhhh