kahramanemir/Vallum
GitHub: kahramanemir/Vallum
Vallum 是一个 Rust 编写的 CLI 安全代理,在 AI 编程代理与 shell 之间拦截命令输出,自动完成密钥脱敏、Prompt 注入中和、不可信输出包装与命令审计。
Stars: 3 | Forks: 0
# Vallum — AI 编程代理与你的 shell 之间的安全边界
*为 AI 编程代理提供 Prompt 注入防御、密钥脱敏、不可信输出净化和命令审计 —— 这是一个作为你终端上 LLM 安全护栏的单一 Rust CLI 代理。`vallum run` 兼容任何运行 shell 命令的代理(Claude Code、Cursor、Codex、Gemini CLI 或你自己的代理);目前已针对 Claude Code 实现了自动零配置拦截。*
[](https://github.com/kahramanemir/Vallum/actions/workflows/ci.yml)
[](https://github.com/kahramanemir/Vallum/actions/workflows/audit.yml)
[](https://crates.io/crates/vallum)
[](https://docs.rs/vallum)
[](https://www.npmjs.com/package/vallum)
[](https://github.com/kahramanemir/Vallum/blob/main/Cargo.toml)
[](#license)
一个作为**安全边界**驻留在 AI 代理和你的 shell 之间的 Rust CLI 代理。当代理运行命令时,Vallum 会对密钥进行脱敏,中和 Prompt 注入企图,将结果包装为不可信数据,保留子进程退出码,并对所有操作进行审计 —— 从而确保传达给模型的内容完全是你希望其看到的。作为附带收益,它还会剔除 ANSI 干扰信息并压缩冗长的输出,这同时也能节省 token。
## 为什么需要
当 AI 代理代表你运行 shell 命令时,命令的输出会直接流入模型的上下文中。该输出属于**不可信输入**,并会引发三个问题:
- 它可能包含**密钥** —— API key、token、凭据 —— 并会被转发给模型(且极可能被其记录在日志中)。
- 它可能包含**对抗性文本** —— 日志行、抓取的网页内容,或是旨在劫持代理的精心构造的错误信息(“忽略之前的指令……”)。
- 它是**非结构化且嘈杂的**,掩盖了相关的有效信号并增加了 token 用量。
Vallum 是一个单一的二进制程序,在该输出与模型之间建立起一道受控的边界。
## Pipeline
```
flowchart LR
A[AI Agent] -->|vallum run cmd| B[Executor]
B --> C[ANSI strip]
C --> D{Output small?}
D -->|yes| W[Whitespace collapse]
D -->|no| E{Known command?}
E -->|yes| F[Optimizer]
E -->|no| G[Whitespace collapse + Truncate]
F --> G
W --> H[Scrubber]
G --> H
H --> I[AI Agent]
B -. raw, opt-in .-> J[(~/.vallum/logs/raw.local.log)]
H -. sanitized .-> K[(~/.vallum/logs/sanitized.ai.log)]
B -.->|tokens_before| L[(~/.vallum/stats.jsonl)]
H -.->|tokens_after| L
```
每个命令都会流经以下阶段:
1. **执行** —— `stdout` 和 `stderr` 会被并发捕获,并按到达顺序合并。捕获过程受字节上限和超时限制(参见“配置”)。`stdin` 会被继承,从而确保交互式命令可正常运行。
2. **ANSI 剔除** —— 移除颜色和光标控制转义字符。
3. **短路机制** —— 如果输出低于 `min_optimize_tokens`,将跳过优化和截断阶段(没必要对寥寥几行进行总结)。下方的安全阶段始终会执行。
4. **优化** —— 如果已注册的 `CommandOptimizer` 匹配成功(例如 `git status`、`cargo test`、`pytest`、`npm test`),它将生成一个压缩视图;否则输入将原样透传。
5. **空白折叠** —— 三个或更多的连续空行折叠为一行;尾部空格被剔除。
6. **截断** —— 保留首尾窗口;重要行(错误、Panic、失败)连同其**上下文被保留在原处**,而常规的长篇大论则会被省略。
7. **清洗** —— API token(OpenAI、Anthropic、GitHub、GitLab、Slack、AWS、Google、Stripe、SendGrid、Twilio、npm、PyPI、Hugging Face)、Bearer/裸 JWT、连接字符串密码以及 PEM 私钥均会被脱敏;已知的注入短语会被中和。
8. **包装** —— 输出被包含在 `[UNTRUSTED TERMINAL OUTPUT]` 标记中;内容中任何伪造的标记都会被失效处理,从而确保输出无法突破包装层。
9. **审计与指标** —— 经过净化的输出会被写入 `~/.vallum/logs/`(原始日志记录需自行开启),同时将每个命令的统计记录追加到 `~/.vallum/stats.jsonl`。
## 安全模型
Vallum 按顺序对每个命令应用四类机制:
Prompt 注入中和(多语言支持,包含不可见/双向字符
剔除以及同形字折叠的检测影子;可选的 `--strict`
故障关闭模式),密钥脱敏(已知格式模式加上上下文控制的
熵检测),带有标记失效处理的不可信输出包装,以及
默认保护隐私的日志记录(可选开启原始日志,`0600` 权限)。
在上述四种针对输出的机制之前,一个可选择性退出的**护栏**
会在命令运行*之前*对其进行评估,并可以提示(`Ask`)或拦截
(`Deny`)一小部分危险操作 —— 参见下方的
[护栏 / 策略](#guardrail--policy)。
**完整的威胁模型:** 参见 [SECURITY.md](SECURITY.md) —— 了解受保护的对象、
采用的机制、强度,以及明确**不**受保证的内容。
## 护栏 / 策略
Vallum 会在每条命令*执行之前*对其进行评估,并返回以下三种
裁定之一:
- **Allow** —— 正常运行(未匹配到任何规则的默认行为)。
- **Ask** —— 在运行前暂停,要求进行明确的确认。
- **Deny** —— 拒绝运行该命令。
护栏**默认开启**,并且每一条内置规则均为 `Ask` —— 一个
真正危险的命令会提示确认,而不是在后台静默运行,
但绝不会发生静默拦截的情况。内置模式经过
严格限定,因此绝不会干扰普通命令(一项承诺的
良性命令精准度把关机制,可防止在执行合法命令时出现打扰)。
内置规则(全部默认为 `Ask`):
| 规则 | 捕获内容 |
|---|---|
| `rm_rf_root` | 针对根路径或家目录路径的递归强制删除 |
| `curl_pipe_shell` | 将下载的内容直接管道传输给 shell(`curl … \| sh`) |
| `shell_download_exec` | 通过进程替换或 `eval` 执行远程获取的内容 |
| `dd_to_device` | 使用 `dd` 直接向块设备写入数据 |
| `redirect_to_device` | 将输出重定向到裸块设备 |
| `mkfs_device` | 在设备上创建文件系统(会破坏现有数据) |
| `fork_bomb` | 经典的 `:(){ :\|:& };:` Fork bomb |
| `chmod_777_recursive` | 递归授予全局可写权限 |
| `read_sensitive_creds` | 读取私钥、凭据文件或 `/etc/shadow` |
| `git_push_force` | 可能覆盖远程历史记录的强制推送 |
**`Ask` 的表现方式:**
- **Hook 模式**(Claude Code):裁定会映射到 Claude Code 的原生
审批 UI —— `Ask` 会在代理中提示你,`Deny` 会拦截该工具调用。
- **直接运行 `vallum run`:** `Ask` 会在 `/dev/tty` 上提示;当没有
终端时(管道传输、CI、`--json`),它将会**故障关闭**(被拦截),除非你
设置了 `security.assume_yes = true` 或 `VALLUM_ASSUME_YES=1`。`Deny`
裁定会退出并返回状态码 **`125`**。
在 `[security]` 和 `[policy]` 下进行配置:
```
[security]
guardrail = true # pre-exec policy layer — default true; set false to bypass entirely
assume_yes = false # auto-approve direct-mode `ask` verdicts (for scripts/CI)
[policy]
disabled = [] # built-in rule names to turn off (e.g. ["git_push_force"])
# 添加你自己的规则。`action` 为 "ask" 或 "deny"(绝不能是 "allow")。
[[policy.rules]]
pattern = '^\s*sudo\b'
action = "ask"
reason = "Elevated privileges"
```
将 `guardrail` 设置为 `false` 会使 Vallum 的行为与该层级引入之前
完全一致。用户规则采用与内置规则相同的“最严重的裁定优先”原则
(`Deny` > `Ask` > `Allow`)进行匹配,并且每一个非 Allow 的
裁定都会被记录(已脱敏)到 `policy.log` 中。
**坦诚说明范围:** 护栏是针对命令文本进行模式匹配的 ——
它是一道减速带 / 纵深防御层,而不是一个沙盒。命令在
匹配前会进行轻度规范化(剔除空的引号对和身份转义的反斜杠,
因此 `r''m -rf /` 或 `\rm -rf /` 依然会被触发),但坚定的
攻击者总能通过变量或 `eval` 的间接方式绕过文本匹配。
输出端的防护措施 —— 密钥清洗和注入化解 —— 并不
依赖于护栏,并始终作为最后一道防线发挥作用。
如果配置文件损坏(TOML 或 regex 错误),Hook 模式会向
stderr 记录一条警告,并继续使用**内置**规则进行拦截;
你的自定义规则将被忽略,直到配置文件被修复
(`vallum doctor` 可以精准定位错误)。
直接运行 `vallum run` 在配置损坏时会完全拒绝运行(退出码 `125`)。
## 度量检测
清洗器会针对 `evals/corpus/` 中一个已提交且带标签的语料库进行评估
(包含 85 个注入负载、54 个高难度良性负样本,以及跨多种语言的
密钥样本)。以下是最近一次运行的概要数据
(完整报告见:[`evals/report.md`](evals/report.md)):
- 注入召回率:**0.812** · 精准度:**1.000** · 良性误报率:**0.000**
- 已知格式密钥召回率:**1.000** · 熵密钥召回率:**1.000**
这些数据是在一个固定的语料库上测得的,是**证据,而非保证** ——
请参阅报告中坦诚的“已知漏报”列表。使用
`cargo run --example eval -- --write` 重新生成;如果低于已提交的
最低标准,CI 将会报错失败。
## 内置优化器
- `git status`:在保留分支状态和代表性文件条目的同时,精简庞大的工作树部分
- `git diff` / `git log`:折叠大量未更改的上下文代码块 / 冗长的提交正文,同时保留头部、差异块和已更改的行
- `cargo build|test|check|clippy|run`:折叠编译/下载干扰信息,保留摘要、失败详情和诊断信息
- `pytest` 和 `python -m pytest`:隐藏进度点刷屏现象,保留收集、失败和摘要部分
- `npm test|install|ci|run`:折叠重复的 `PASS` 和警告行,同时保留结果摘要
- `docker build|compose`:折叠层/步骤进度,同时保留步骤头、错误和最终结果
- `go test`:隐藏 `=== RUN`/`--- PASS` 刷屏信息,同时保留失败详情和摘要
- `make`:突显错误/警告,同时折叠普通的构建干扰信息
- `kubectl get`:折叠连续的健康(`Running`/`Completed`)资源行,同时保留头部以及任何处于异常状态(`CrashLoopBackOff`、`Pending`、`Evicted` 等)的 Pod
- `terraform plan|apply`:折叠状态刷新的冗余信息和属性差异主体,同时保留资源操作头、`Plan:`/`Apply complete!` 摘要以及错误信息
- `rg` / `grep`(也包括 `egrep`/`fgrep`):按文件对匹配项进行分组,保留每个文件的前几项,并用每个文件和总计的计数来汇总其余的内容
- `ls` / `find` / `fd` / `tree`:保留前几项条目并汇总其余内容(针对路径列表提供顶级目录的细分);错误行始终会被保留
## 配置
Vallum 默认查找 `~/.vallum/config.toml`。为了进行测试或实现基于项目的覆盖,可通过 `VALLUM_CONFIG` 指向不同的文件。
```
[audit]
log_dir = "/tmp/vallum-logs"
raw_enabled = false # raw, unredacted logging is opt-in
sanitized_enabled = true
[pipeline]
head_lines = 20
tail_lines = 20
min_optimize_tokens = 50 # skip optimize/truncate below this token estimate
max_output_bytes = 10485760 # 10 MiB capture cap; excess is dropped with a marker
timeout_secs = 300 # kill the child after N seconds (0 = disabled)
max_line_length = 2000 # truncate single lines longer than this (0 disables)
[optimizer]
disabled = [] # optimizer names to turn off; all on by default
[scrubber]
entropy = true # context-gated entropy redaction of credential-ish values
normalize = true # strip invisible/bidi chars; fold homoglyphs for injection matching
extra_secret_patterns = [
{ pattern = "token-[0-9]+", replacement = "token-***" }
]
[security]
strict = false # block the entire output when a prompt injection is detected
guardrail = true # pre-exec policy layer (Allow/Ask/Deny) — default true
assume_yes = false # auto-approve direct-mode `ask` verdicts (scripts/CI)
[policy]
disabled = [] # built-in rule names to disable; all on by default
# [[policy.rules]] # 可选的用户规则;action = "ask" | "deny"
# pattern = '^\s*sudo\b'
# action = "ask"
# reason = "Elevated privileges"
```
支持的设置:
- `audit.log_dir`:审计日志目录覆盖路径
- `audit.raw_enabled`:启用原始(未脱敏的)终端日志 —— **默认 `false`**
- `audit.sanitized_enabled`:启用或禁用净化后的日志记录
- `pipeline.head_lines` / `pipeline.tail_lines`:截断窗口
- `pipeline.min_optimize_tokens`:低于此估算值的输出将跳过 optimize/truncate
- `pipeline.max_output_bytes`:从单个命令捕获的最大字节数(默认 10 MiB)
- `pipeline.timeout_secs`:命令超时时间(秒);`0` 表示禁用(默认 300)
- `optimizer.disabled`:要禁用的优化器名称列表(git_status, git_diff, git_log, cargo, pytest, npm, docker, go_test, make, kubectl, terraform, grep, file_list)—— 默认为空
- `pipeline.max_line_length`:限制单行最大长度;超出的行会在行内被断并附带省略标记 —— 默认 2000,`0` 表示禁用
- `scrubber.extra_secret_patterns`:基于额外正则表达式的脱敏规则
- `scrubber.entropy`:针对具备凭据特征的赋值语句,进行上下文控制的熵值脱敏 —— **默认 `true`**
- `scrubber.normalize`:剔除不可见/双向字符,并折叠同形字以进行注入匹配 —— **默认 `true`**
- `security.strict`:设为 `true`(或使用 `--strict`)时,如果检测到任何注入,输出将被替换为 `[OUTPUT BLOCKED: prompt injection detected]` —— **默认 `false`**
- `security.guardrail`:启用在执行前拦截危险命令的策略层(Allow/Ask/Deny)—— **默认 `true`**;设为 `false` 可完全绕过
- `security.assume_yes`:自动批准直接模式下的 `ask` 裁定(也可通过 `VALLUM_ASSUME_YES=1` 实现)—— **默认 `false`**
- `policy.rules`:用户策略规则 —— 每一项都包含 `pattern`、`action`(`ask` 或 `deny`;`allow` 会被拒绝)和 `reason`
- `policy.disabled`:要禁用的内置规则名称(rm_rf_root, curl_pipe_shell, shell_download_exec, dd_to_device, redirect_to_device, mkfs_device, fork_bomb, chmod_777_recursive, read_sensitive_creds, git_push_force)—— 默认为空
## 安装
**Shell (macOS + Linux):**
```
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/kahramanemir/Vallum/releases/latest/download/vallum-installer.sh | sh
```
**Homebrew:**
```
brew install kahramanemir/homebrew-tap/vallum
```
**Cargo:**
```
cargo install vallum # heuristic token counts (default)
cargo install vallum --features bpe # exact BPE token counts (adds tiktoken-rs)
```
**npm:**
```
npm install -g vallum
```
针对 macOS(Intel + ARM)和 Linux(x86_64 + aarch64)的**预编译二进制文件**会
附加在每一次的 [GitHub Release](https://github.com/kahramanemir/Vallum/releases) 中,
并附带 SHA-256 校验和与构建来源证明。可通过以下方式验证下载的文件:
```
gh attestation verify ./vallum --repo kahramanemir/Vallum
```
### 从源码构建
```
cargo build --release # default: dependency-free heuristic token counts
cargo build --release --features bpe # exact BPE token counts (adds tiktoken-rs)
```
二进制文件将位于 `target/release/vallum`。
## 用法
```
vallum run [args...] # run a command through the proxy
vallum run --json ... # emit structured JSON
vallum run --strict ... # block output if a prompt injection is detected
vallum run --tee ... # also append raw output to ~/.vallum/live.log
vallum stats # show cumulative token savings
vallum stats --reset # delete collected stats
# Integration & UX
vallum install-hook # register vallum in ~/.claude/settings.json
vallum install-hook --project # register in /.claude/settings.json
vallum uninstall-hook # remove the vallum hook entry
vallum hook # internal: invoked by Claude Code (don't run directly)
vallum config show # print effective merged config as TOML
vallum config init [--force] # scaffold ~/.vallum/config.toml
vallum doctor # self-check: config, hook, guardrail, PATH, log dir
vallum completions > completions/_vallum
```
示例:
```
vallum run ls -la
vallum run cargo test
vallum run git status
vallum run pytest
vallum run npm test
vallum run sh -- -c 'exit 7' # preserves the child exit code
vallum run --json printf "hello\n"
```
JSON 输出示例:
```
{
"command": "printf",
"args": ["hello\\n"],
"exit_code": 0,
"optimizer": null,
"tokens_before": 1,
"tokens_after": 18,
"sanitized_output": "[UNTRUSTED TERMINAL OUTPUT START]\nhello\n[UNTRUSTED TERMINAL OUTPUT END]\n"
}
```
请注意,一小段输出在包装后为何会变得*更大*:安全包装本身具有固定的开销,在短命令上这种开销占主导地位。Token 的节省主要体现在庞大、嘈杂的输出上(构建过程、测试运行、巨大的 diff)—— 参见下文。
### 退出码
- 成功时,子进程自身的退出码将作为 Vallum 的退出码进行传递。
- Vallum 层级的失败(配置错误、执行器生成错误、JSON 序列化错误)会退出并返回 **`125`** —— 借鉴了 `env(1)` 的“命令未被调用”惯例 —— 从而使其能够与子进程真正的退出码 1 区分开来。
- 护栏的 **`Deny`** 裁定(或在非交互式会话中被拒绝/执行故障关闭的 `Ask`)也会退出并返回 **`125`** —— 命令绝对不会被执行。`Ask` 会在 `/dev/tty` 上提示;请在脚本中设置 `security.assume_yes` / `VALLUM_ASSUME_YES=1` 以自动批准。
## Claude Code 集成
`vallum install-hook` 会在 `~/.claude/settings.json`(默认,用户级别)或 `/.claude/settings.json`(`--project`)中写入一个 `PreToolUse` 条目。在进行任何修改之前,都会写入一个带有时间戳的 `.bak-` 设置文件备份。该命令是幂等的 —— 如果条目已存在,在没有 `--force` 的情况下重新运行它不会产生任何操作;`--force` 会替换现有条目。其他代理(Cursor、Codex、Gemini CLI)仍然可以通过直接调用 `vallum run` 让命令经过 Vallum 路由;针对它们的零配置 Hook 已在规划中。
安装后,Claude Code 会在每次调用 Bash 工具之前调用 `vallum hook`。该 Hook 会将命令重写为 `vallum run -- bash -c ''`,从而确保在每次调用 shell 时都会运行完整的 Vallum pipeline(捕获、ANSI 剔除、优化、清洗、包装),而无需改变你或代理编写命令的方式。由于该 Hook 会将命令包装为 `bash -c ''`,Vallum 会在匹配优化器之前解开简单的脚本(没有管道、重定向、引号或其他 shell 元字符),因此 `bash -c 'git status'` 依然能够触发 `git_status` 优化器;复杂的脚本则会回退到常规的压缩处理。已知的 TUI 程序(`vim`、`vi`、`nano`、`less`、`more`、`top`、`htop`、`tmux`、`screen`)会被跳过,因为 Vallum 捕获 stdout 会破坏它们对 TTY 的要求。出于幂等性考虑,已经以 `vallum` 开头的命令也会被跳过。
要移除该 Hook,请运行 `vallum uninstall-hook` —— 它仅会移除 Vallum 的条目,而保持设置文件中的其他部分原封不动。
**实时进度。** `vallum run --tee` 会将子进程原始的 stdout/stderr 随着行到来的速度追加到 `~/.vallum/live.log` 中。可以在旁边的终端中使用 `tail -f ~/.vallum/live.log` 进行观察。该 tee 的目标是一个私有文件(`0600`),而不是代理可以读取的流 —— 代理的输入依然是经过包装和清洗的、位于 stdout 上的 pipeline 输出。Tee 会尽最大努力运行:如果文件无法打开或写入,命令仍会正常运行,但不再进行记录。
## 衡量节省效果
每次 `vallum run` 都会将一条包含原始和净化后 token 估算的 JSON 记录追加到 `~/.vallum/stats.jsonl` 中。计数过程会通过一个可插拔的 `TokenEstimator` 完成;默认的是一个无依赖的启发式算法(词组 + 符号),在追踪 BPE 方面比简单的 chars/4 比例表现更好。`vallum stats` 会汇总该文件。使用 `--features bpe` 构建可以通过精确的 `tiktoken`(o200k_base)分词器进行 token 计数,以替代默认的无依赖启发式算法;这是针对 Claude 分词器的 OpenAI 系列近似实现。
```
Vallum — Token savings report
─────────────────────────────────────────
Commands run: 142
Tokens (raw): 58,420
Tokens (sanitized): 11,205
Saved: 47,215 (80.8%)
Top savings by command
─────────────────────────────────────────
cargo build 18,940 saved (94%)
git status 12,103 saved (88%)
npm install 8,442 saved (76%)
```
### 复现节省效果
运行 `cargo bench` 可以针对七个已提交的固定测试用例(`git status`、`cargo build`、`pytest`、`npm install`、一个压缩的数据块、一个 `rg` 匹配列表、一个 `find` 文件列表)为完整的 pipeline 计时,并打印出原始与净化后的 token 对照表。这些测试用例存放在 `benches/fixtures/` 中,并随仓库进行版本控制,因此节省的数据可以通过干净的检出环境复现。在所有 criterion 度量完成后,基准测试还会向 stderr 打印一份摘要表,显示每个测试用例在处理前后的 token 计数。
## 测试
**属性测试。** 清洗器、截断器、ansi、空白符和优化器模块在正常的 `cargo test` 下,都带有行内的 `proptest` 不变量(无 Panic、结构边界、幂等性)以供运行。
## 模块
| 文件 | 职责 |
| ----------------------------- | ---------------------------------------------------- |
| `src/cli.rs` | 参数解析(`run`、`stats`、`hook`、`install-hook`/`uninstall-hook`、`config`、`completions`) |
| `src/config.rs` | 配置加载、默认值与验证 |
| `src/executor.rs` | 带有字节上限、超时、stdin 的并发捕获;可选的 tee 到 `~/.vallum/live.log` |
| `src/ansi.rs` | 剔除 ANSI 转义序列 |
| `src/whitespace.rs` | 折叠连续的空行,剔除尾部空格 |
| `src/optimizer/mod.rs` | `CommandOptimizer` trait + 派发注册表 |
| `src/optimizer/cargo.rs` | 用于嘈杂 `cargo` 输出的摘要优化器 |
| `src/optimizer/docker.rs` | 用于 `docker build`/`compose` 输出的摘要优化器 |
| `src/optimizer/file_list.rs` | 用于 `ls`/`find`/`fd`/`tree` 的条目上限优化器 |
| `src/optimizer/git_diff.rs` | 用于 `git diff` 输出的摘要优化器 |
| `src/optimizer/git_log.rs` | 用于 `git log` 输出的摘要优化器 |
| `src/optimizer/git_status.rs` | 用于 `git status` 输出的摘要优化器 |
| `src/optimizer/go_test.rs` | 用于 `go test` 输出的摘要优化器 |
| `src/optimizer/grep.rs` | 用于 `rg`/`grep` 输出的匹配分组优化器 |
| `src/optimizer/kubectl.rs` | 用于 `kubectl get` 输出的健康行折叠优化器 |
| `src/optimizer/make.rs` | 用于 `make` 输出的摘要优化器 |
| `src/optimizer/npm.rs` | 用于嘈杂 `npm` 输出的摘要优化器 |
| `src/optimizer/pytest.rs` | 用于嘈杂 `pytest` 输出的摘要优化器 |
| `src/optimizer/terraform.rs` | 用于 `terraform plan`/`apply` 输出的摘要优化器 |
| `src/truncator.rs` | 保留上下文的首尾截断 |
| `src/scrubber/mod.rs` | 清洗 pipeline:`sanitize`/`redact` 编排 + 包装器 |
| `src/scrubber/secrets.rs` | 已知格式的密钥脱敏模式 |
| `src/scrubber/entropy.rs` | 上下文控制的熵密钥检测 |
| `src/scrubber/injection.rs` | Prompt 注入中和 |
| `src/scrubber/normalize.rs` | 不可见字符剔除 + 同形字检测影子 |
| `src/scrubber/markers.rs` | 不可信输出标记失效处理 |
| `src/tokenizer.rs` | 可插拔的 `TokenEstimator` + 启发式默认实现 |
| `src/fsutil.rs` | 私有 (0600) 追加文件辅助工具 |
| `src/audit.rs` | 仅追加的日志写入器 |
| `src/metrics.rs` | Token 估算 + JSONL 统计数据写入器 |
| `src/stats.rs` | `vallum stats` 聚合与报告 |
| `src/hook.rs` | Claude Code PreToolUse 处理程序:将 Bash 调用重写为 `vallum run` |
| `src/install_hook.rs` | `install-hook`/`uninstall-hook`:对 Claude Code settings.json 进行读取-修改-写入操作 |
| `src/doctor.rs` | `vallum doctor`:安装/健康状况自检(配置、Hook、PATH、日志目录) |
| `src/main.rs` | Pipeline 线路连接 |
| `src/lib.rs` | 库接口 —— 重新导出模块,以便集成测试可以检验内部逻辑 |
## Roadmap
- [x] v0.1 —— MVP:执行、截断、清洗、审计
- [x] v0.2 —— ANSI 剔除、空白折叠、token 指标、每命令优化器框架、`vallum stats`
- [x] Post-v0.2 强化 —— 退出码传递、结构化 JSON 输出、可配置 pipeline、cargo/pytest/npm 优化器
- [x] 安全扫荡 —— 并发有界捕获(上限 + 超时 + stdin)、保留上下文的截断、更广泛的注入中和、标记防伪造、默认关闭原始日志并配备 `0600` 权限、小输出短路机制、可插拔 token 估算器
- [x] 子项目 B —— 更广泛的命令覆盖(git diff、git log、docker、go test、make)、优化器开关(`[optimizer] disabled`)、长行截断(`pipeline.max_line_length`)、可选的 BPE token 计数(`--features bpe`)
- [x] 子项目 C —— 集成/UX:`install-hook`/`uninstall-hook`(Claude Code PreToolUse)、`vallum hook` 处理程序、`config show`/`config init`、`vallum completions `、exit-125 约定
- [x] 子项目 D ——实时 tee(`vallum run --tee`、`~/.vallum/live.log`);因为 Hook 跳过列表(子项目 C)降低了紧迫性,PTY/流式传输功能被正式移出范围
- [x] 子项目 E —— 成熟度:在 scrubber/truncator/ansi/whitespace/optimizer 模块中引入 `proptest` 不变量;配备五个版本化固定测试用例(`benches/fixtures/`)的 `criterion` 基准测试套件;节省数据可通过干净的检出复现
- [x] grep/file_list 优化器 + Hook 模式派发修复 —— `bash -c` 解包确保优化器能通过 Claude Code Hook 触发;`rg`/`grep` 匹配分组;`ls`/`find`/`fd`/`tree` 条目限制;两个新的基准测试用例(共计七个)
- [x] 上下文控制的熵密钥检测 —— 对具有高 Shannon 熵且带有凭据特征的赋值值进行掩码处理;裸 token(提交 SHA、UUID)在结构上获得豁免;`[scrubber] entropy` 标志(默认开启)
- [x] 注入精准度调优 —— reveal-family 要求在所有五种语言中具备所有格或指向系统的对象;`System:`/`Assistant:` 轮次行加入了自然语言否决机制,从而让日志行通过;熵分词器可捕获分隔符组合(`key== ""`);安全语料库扩充至 20 个注入 / 18 个良性样本
- [x] 子项目 I —— 注入输入规范化(剔除不可见/双向字符;NFKC + 容易混淆的折叠检测影子;no-space ignore-family;`scrubber.normalize` 标志)
- [x] 子项目 J —— 清洗阶段强化:在密钥掩码之前进行注入扫描(填补了密钥吞噬触发的漏洞)、五种语言中的 reveal-family 无空格检测、配置中额外模式的单次编译(`CompiledRule`)
- [x] 子项目 K —— 更广泛的基础设施/优化器覆盖:`kubectl get`(折叠健康资源行,保留异常状态的 Pod)和 `terraform plan|apply`(折叠刷新冗余信息 + 属性差异,保留操作头/摘要/错误);扩大密钥格式覆盖范围(GitLab、SendGrid、Twilio、npm、PyPI、Hugging Face、OpenAI 项目密钥、裸 JWT)
- [x] 子项目 L —— `vallum doctor` 安装/健康状况自检:验证配置文件,标记未知的 `[optimizer] disabled` 名称,报告 Hook 安装情况,检查二进制文件是否在 `PATH` 中,并探测日志目录的可写性(仅在遭遇严重错误时以非零状态码退出)
- [x] 子项目 M —— 发行:基于 `dist` 的标签发行流水线,生成针对 macOS(Intel + ARM)和 Linux(x86_64 + aarch64,musl 静态)的预编译二进制文件,并提供 shell/Homebrew/`cargo install`/npm 安装程序、SHA-256 校验和与 GitHub 构建来源证明;最终标签发布至 crates.io;MSRV 提升至 1.85,并使用 `--locked` 固定 MSRV CI 检查
- [ ] 推迟 —— 中文注入、`cargo-fuzz`/libFuzzer 套件、性能衰退门控、Windows 支持(由 `0600`/超时支持的保证机制需要先具备 Windows 的等效实现)
## 名字含义
**Vallum** —— 拉丁语,指罗马边境防御工事沿线的防护土垒。它伫立在内部与外部之间。
## 许可证
根据以下任一许可证授权:
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) 或 )
- MIT license ([LICENSE-MIT](LICENSE-MIT) 或 )
由你任选其一。
### 贡献
有关本地工作流(fmt/clippy/test
门控、MSRV、如何添加优化器或密钥模式),请参阅 [CONTRIBUTING.md](CONTRIBUTING.md),发布历史请参阅 [CHANGELOG.md](CHANGELOG.md)。
除非你明确声明,否则任何由你有意提交以包含在本作品中的贡献,根据 Apache-2.0 许可证的定义,均应按上述方式获得双重许可,不附加任何额外的条款或条件。
标签:AI代码助手, Python安全, Rust, 可视化界面, 命令行代理, 大语言模型安全, 密钥脱敏, 提示词注入防御, 文档结构分析, 暗色界面, 机密管理, 网络流量审计, 通知系统