第 18 章 · 安全模型与环境变量
本章目标:建立对 pi 威胁模型的正确认知——它"信任本地用户、不信任仓库内容",学会用项目信任机制、容器隔离与环境变量管理把风险压到可接受范围。
18.1 威胁模型:本地信任边界
官方 security 文档开宗明义:pi 以启动它的用户账号的全部权限运行,该用户可写的文件都在同一本地信任边界内。这意味着三类典型风险:
- 提示注入(Prompt Injection)——仓库里的 README、代码注释、构建输出都可能包含"指令",被模型读进上下文后诱导它执行危险操作。官方原话:这是本地 agent 的预期风险,pi 无法可靠阻止;
- 恶意仓库——clone 下来的项目可能带
.pi/settings.json、恶意扩展或技能,在你不知情时改变 pi 行为; - 命令执行——
bash工具以你的身份跑任意命令,没有内置确认弹窗(Philosophy 明确 "No permission popups")。
对应的防线是三层的:项目信任(输入加载闸门)→ 工具开关(行为约束)→ 容器隔离(真正的边界)。上一章讲的工具开关只是第二层,本章讲一三两层。
18.2 项目信任机制(Project Trust)
项目信任决定"pi 是否加载这个项目自带的配置与扩展"。当 pi 在项目里发现以下任一内容时,就认为该项目"含有需要信任的资源":
.pi/settings.json.pi/extensions、.pi/skills、.pi/prompts、.pi/themes.pi/SYSTEM.md或.pi/APPEND_SYSTEM.md- 当前目录或祖先目录的项目级
.agents/skills
裸 .pi 目录不算
只有一个空的 .pi 目录不触发信任确认——判断依据是上面列出的具体资源。
信任决定保存在 ~/.pi/agent/trust.json(按目录记录),最近的祖先目录决定优先于全局默认值。交互模式下会弹出询问;非交互模式(-p/json/rpc)不询问,回退到全局设置 defaultProjectTrust:
| 取值 | 非交互行为 |
|---|---|
"ask"(默认) | 忽略需信任的项目资源 |
"never" | 忽略需信任的项目资源 |
"always" | 信任并加载 |
单次运行可用 -a/--approve 强制信任、-na/--no-approve 强制忽略:
# CI 中信任自家仓库的项目配置(确认仓库可信时)
pi -a -p "运行项目自带的检查"
# 审计陌生仓库:忽略其全部项目资源 + 只读工具
pi -na -t read,grep,find,ls -p "这个项目是干什么的?"关键认知:信任只是输入加载闸门。它防止仓库在你批准前悄悄改掉 pi 的设置和扩展,但不会让不可信代码、提示注入或模型输出变得安全。
18.3 没有内置沙箱:隔离要靠操作系统
pi 故意不提供内置沙箱(Philosophy 与 security 文档双重确认)。理由是:进程内沙箱仍依赖宿主 shell、文件系统、包管理器、凭据和扩展代码,容易被误解为安全边界。真正的隔离必须来自操作系统或虚拟化边界。
对不可信仓库、无人值守任务,官方给出的容器化清单(详见第 19 章):
# 只挂载工作区,不挂载宿主 ~/.pi/agent(避免暴露会话与凭据)
docker run --rm -it \
-e ANTHROPIC_API_KEY \
-v "$PWD:/workspace" \
-v pi-agent-home:/root/.pi/agent \
pi-sandbox要点:只挂载任务需要的路径;传最少的 API key 或用短生命周期凭据;任务不需要网络时限制网络;结果拷回可信环境前先审查 diff。若以读写方式 bind-mount 宿主目录,容器内的写操作仍会落到宿主文件——需要更强保护时用只读挂载或拷入拷出。
18.4 API Key 与敏感凭据的存放
- provider 凭据放环境变量或 pi 的 auth 文件(
/login管理),不要写进 shell 历史或仓库; --api-key参数会出现在进程列表(ps)中,只适合临时调试;- 容器场景:用
-e KEY从宿主注入,或像 OpenShell 那样把原始 key 留在网关上游、容器内只访问https://inference.local推理路由。
18.5 环境变量完整参考
pi 的环境变量分三类(官方 environment-variables.md):
① pi 自身配置
| 变量 | 作用 |
|---|---|
PI_CODING_AGENT_DIR | 覆盖配置目录(默认 ~/.pi/agent) |
PI_CODING_AGENT_SESSION_DIR | 覆盖会话存储目录(--session-dir 优先) |
PI_PACKAGE_DIR | 覆盖包目录(Nix/Guix 场景) |
PI_OFFLINE | 关闭启动期网络操作(更新检查、遥测) |
PI_SKIP_VERSION_CHECK | 跳过 pi.dev 版本检查 |
PI_TELEMETRY | 0/false/no 关闭安装/更新遥测 |
PI_CACHE_RETENTION | 设为 long 启用扩展提示缓存(Anthropic 1h / OpenAI 24h) |
HTTP_PROXY / HTTPS_PROXY | 出站代理 |
② 进程标记(CLI 与 RPC 入口自动设置,供子进程识别)
| 变量 | 作用 |
|---|---|
AI_AGENT=pi | 通用标记 |
PI_CODING_AGENT=true | pi 专属标记 |
③ bash 工具会话环境(注入给模型调用的 bash 命令;注意 !/!! 用户命令不会注入)
| 变量 | 作用 |
|---|---|
PI_SESSION_ID | 当前会话 ID |
PI_SESSION_FILE | 当前会话 JSONL 绝对路径(临时会话未设置) |
PI_PROVIDER / PI_MODEL | 当前模型提供方/ID |
PI_REASONING_LEVEL | 当前思考级别 |
# 模型自己就能这样自检,而不是靠猜系统提示词
printf '%s/%s\n' "$PI_PROVIDER" "$PI_MODEL"自定义 bash 工具可通过 createBashTool() 的 exposeSessionEnvironment: false 关闭注入,避免嵌套 pi 进程拿到过期的父会话信息。
18.6 本章小结
- 威胁模型:信任本地用户、不信任仓库内容,提示注入是预期的本地风险;
- 项目信任只管"要不要加载项目资源",判定物是
.pi/下具体资源与项目级.agents/skills; - 非交互模式靠
defaultProjectTrust或-a/-na单次覆盖; - 无内置沙箱是设计决定:真隔离用容器/微 VM,只挂工作区、最小凭据、按需限网;
- 环境变量三类:pi 配置(
PI_OFFLINE等)、进程标记(AI_AGENT)、bash 会话环境(PI_SESSION_ID等)。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 下列哪一项不会触发项目信任确认?
2. 非交互模式下 defaultProjectTrust 取默认值 "ask" 时,项目资源会被?
3. 为什么官方不建议用进程内沙箱替代容器隔离?
4. 关于 bash 工具的会话环境变量,下列说法正确的是?
🛠️ 动手实践
- 在一个测试仓库里创建
.pi/SYSTEM.md,分别在交互模式、-p模式、-na -p模式下启动 pi,观察三种模式下该文件是否被加载。 - 用 Docker 把 pi 跑进容器:只挂载工作区、使用命名卷存
~/.pi/agent,验证容器内无法读到宿主会话。 - 写一个脚本打印 bash 工具会话环境:让 pi 执行
env | grep ^PI_,对照文档核对每个变量的值与含义。