rustinel
[](https://github.com/kosiorkosa47/rustinel/actions/workflows/ci.yml)
[](https://crates.io/crates/cargo-rustinel)
[](https://docs.rs/rustinel-core)


**为 Rust 项目提供防御性的供应链风险差异分析。**
*一个用于 Cargo 依赖项的 pull request 防火墙。*
`cargo audit` 只能告诉你*是否*存在漏洞。
**`rustinel` 则会告诉你某个 pull request 是如何改变你的供应链风险的 —— 以及为什么。**
它能在 **任何 CVE 出现之前** 捕捉到咨询扫描器遗漏的内容:**新维护者**接管了受信任的依赖项(xz / event-stream 攻击向量)、**刚发布**的版本、**typosquat**(拼写抢注)、**回传 build script** 以及**窃取密钥的依赖项** —— 这正是 2025 年 9 月 `faster_log`/`async_println` 加密货币窃取程序的确切类型。它是静态的、优先离线的,并能输出合规级别的 **SBOM + VEX**。
→ **[`cargo audit` 在结构上无法看到的内容](docs/PROACTIVE-DETECTION.md)**
▶ 观看完整录像 (MP4) — 一次真实的扫描,并与 cargo audit 进行了实时交叉核对
```
Project risk: 67/100 HIGH
[█████████████░░░░░░░]
Decision: REVIEW_REQUIRED
Top findings:
[HIGH] openssl-sys@0.9.99: native FFI dependency detected
↳ pulled in via: my-app → reqwest → native-tls → openssl-sys
```
……以及它发布的 PR 评论(参见 `examples/reports/sample_pr_comment.md`):
```
## rustinel — 供应链风险
▃ **0 → 24 (+24)** · MEDIUM · Decision: [review] **review required**
`[████░░░░░░░░░░░░░░░░]` · policy: **balanced** · 5 packages
```
rustinel 执行**纯静态、仅基于元数据**的分析。它从不执行其所分析的依赖项中的代码 —— 参见 [安全模型](#security-model)。
**对比分析** cargo-audit / cargo-deny / cargo-vet / cargo-geiger 及其他工具:参见 [`docs/COMPARISON.md`](docs/COMPARISON.md)。简而言之:rustinel 填补了尚未被满足的、**以 PR 为中心的风险差异**利基市场,并与其它工具相辅相成。
**经过精确验证。** 启发式扫描器只有在不产生误报时才有用。在 **966 个真实的 crate**(真实的依赖闭包 + 刚上传至 crates.io 的包)上进行的基准测试表明:来自*判定为恶意*的信号实现了**零误报** —— 同时仍能捕捉到真实的攻击形态,并准确地标记出三个在构建时通过 `build.rs` 下载代码的 crate。(名称相似度*审查触发器*的表现符合预期设计。)完整的方法论和可复现的脚本:[`docs/DATA-STUDY.md`](docs/DATA-STUDY.md)。
## 安装说明
**MSRV: Rust 1.86**(由依赖树设定;无网络的 `--no-default-features` 构建所需版本更低)。
```
# 来自 crates.io — 安装 `cargo-rustinel` 二进制文件,可用作 `cargo rustinel ...`
cargo install cargo-rustinel
# 或者通过 cargo-binstall 使用预编译的二进制文件(无需编译):
cargo binstall cargo-rustinel
# 零网络依赖(无 HTTPS 客户端)的安全极简构建。
# `--online-metadata` 变为 no-op;其他一切保持不变。
cargo install cargo-rustinel --no-default-features
```
## 使用说明
```
# 分析一个 lockfile
cargo rustinel check --lockfile Cargo.lock --format human
cargo rustinel check --lockfile Cargo.lock --format json
# 此 PR 如何改变风险?
cargo rustinel diff \
--base-lockfile base/Cargo.lock \
--head-lockfile head/Cargo.lock \
--format markdown
# 启动画面 / 版本
cargo rustinel demo
# 创建一个初始 policy
cargo rustinel policy init --profile balanced > rustinel.toml
# 同步 RustSec advisory 数据库(git clone/pull 到 ~/.cargo/advisory-db)
cargo rustinel advisory update
cargo rustinel advisory status
# 导出基于标准的 artifacts(SBOM / vuln interchange)
cargo rustinel export --format cyclonedx --lockfile Cargo.lock # CycloneDX 1.5 SBOM
cargo rustinel export --format spdx --lockfile Cargo.lock # SPDX 2.3 SBOM
cargo rustinel export --format osv --lockfile Cargo.lock # OSV records
cargo rustinel export --format openvex --lockfile Cargo.lock # OpenVEX document
```
### 格式
| `--format` | 用途 |
|-------------|-----|
| `human` | 终端摘要(默认) |
| `json` | 机器可读报告(参见 `schemas/rustinel-report.schema.json`) |
| `markdown` | PR 评论(HTML/Markdown 转义) |
| `sarif` | 用于代码扫描仪表板的 SARIF 2.1.0 |
### 常用标志
- `--policy
` — 应用 `rustinel.toml` 策略(配置文件:`strict`、`balanced`、`permissive`)。
- `--offline` — 永不连接网络;仅使用缓存的咨询数据。
- `--source-path ` — 用于静态信号的解包 crate 源码目录(只读)。
- `--advisory-db ` — 用于咨询匹配的 RustSec advisory-db 检出。
- `--online-metadata` — 查询 crates.io **sparse index** 以获取被撤回的版本(固定主机、无重定向、经过验证的名称 —— SSRF 安全)。默认关闭。
- `--no-timestamp` — 确定性的、逐字节相同的输出。
- `--fail-on-review-required` — 将 `review_required` 视为 CI 失败。
退出码仅由**策略**驱动(与输出格式无关):`fail` → 退出码 1。
## 检测内容
- **已知咨询** — 真实的 RustSec advisory-db(v4 `.md` + `.toml`),通过 `advisory update` 同步,按 semver 匹配。对离线缓存友好。
- **存在 `build.rs`**(检测到文件 — *绝不执行*)。
- **可疑的 `build.rs` 意图** — 静态扫描,标记那些访问**网络**(`reqwest`/`ureq`/`TcpStream`/…)或解包**不透明 payload**(`include_bytes!`/base64/`libloading`)的构建脚本。这正是近期恶意 crate 使用的确切向量;合法的 `cc` 风格原生构建*不会*被标记。
- **原生 / FFI** 依赖(`-sys` 命名 + 清单 `links`)。
- **`unsafe`** 使用(静态计数;仅供参考,其本身不构成漏洞)。
- **Typosquatting(拼写抢注)** — 依赖项名称与热门 crate 仅有一处编辑差异(Damerau-Levenshtein)(`reqwset`→`reqwest`,`tokoi`→`tokio`),这是近期恶意 crate 背后的冒充向量。
- **窃取密钥的恶意软件指纹** — 运行时扫描项目自身的 `.rs` 文件**并且**访问网络 / 处理钱包密钥的源码:这正是 2025 年 9 月 `faster_log`/`async_println` 加密货币窃取程序的确切模式(rustinel 通过此检测**和** typosquatting 同时标记了这两者)。
- **嵌入的编码 payload** — 解码大型 base64/hex 数据块**并且**将结果提供给进程生成或动态库加载的源码:这是一种*打包在* crate 内部的自包含隐藏 payload(无需网络,因此能逃避基于下载的检测)。如果解码后的数据块是*数据*(如证书、密钥、测试夹具),则**不会**被标记;执行接收器(execution sink)是区分标准。
- 同一 crate 的**多个版本**。
- **许可证(License)**检测 / 未知许可证 / 拒绝许可证策略。
- 两个 lockfile 之间的**风险增量**(添加 / 移除 / 更改的包)。
每项发现都带有 `evidence`(证据)、`confidence`(置信度)得分,并且 —— 对于间接依赖项 —— 还包含将其引入的**依赖路径**(`pulled in via: demo → reqwest → native-tls → openssl-sys`),让你知道一个 crate *为什么*会出现在你的依赖树中。
## 风险评分
咨询全分累加;启发式信号在**每个类别中会产生边际递减效应**(因此 30 个 `-sys` crate 不会主导评分),最终计入上限为 0–100 的项目得分(`low` 0–19,`medium` 20–49,`high` 50–79,`critical` 80–100)。严重咨询会将得分锁定为 100。使用 **`--explain`** 运行以查看实时明细。完整的方法论和信号目录:[`docs/DESIGN.md`](docs/DESIGN.md)。
## 策略
```
version = 1
[profile]
name = "balanced"
[risk]
max_project_score = 70
fail_on_delta_above = 35
[advisories]
fail_on = ["critical", "high"]
[licenses]
deny = ["GPL-3.0", "AGPL-3.0"]
```
完整 schema 及三个内置配置文件请参见 `POLICY_SPEC.md` 和 `examples/policies/`。
## GitHub Action
发布带有风险差异的**固定 PR 评论**(创建一次,每次推送时就地更新),在违反策略时使检查失败,并可选择将发现结果作为代码扫描警报上传到仓库的 **Security 选项卡**:
```
permissions:
contents: read
pull-requests: write
# security-events: write # only needed for code-scanning: "true"
jobs:
supply-chain:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: dtolnay/rust-toolchain@stable
- run: git show "origin/${{ github.base_ref }}:Cargo.lock" > base.Cargo.lock || cp Cargo.lock base.Cargo.lock
- uses: kosiorkosa47/rustinel@v0
with:
command: diff
base-lockfile: base.Cargo.lock
head-lockfile: Cargo.lock
policy: rustinel.toml
online-metadata: "true"
# code-scanning: "true" # also upload findings to the Security tab
```
参见 `action.yml` 和 `examples/github-action.yml`。
## 标准与交互
`cargo rustinel export` 直接根据你的 lockfile + 咨询匹配项输出合规级别的工件:
| `--format` | 标准 | 用途 |
|------------|----------|-----|
| `cyclonedx` | CycloneDX 1.5 (JSON) | 包含漏洞及 SHA-256 组件哈希的 SBOM — EU CRA / US EO 14028 |
| `spdx` | SPDX 2.3 (JSON) | SBOM(包 + 关系) |
| `osv` | osv.dev schema | 漏洞记录,与 OSV 工具互操作 |
| `openvex` | OpenVEX v0.2.0 | 机器可读的可利用性声明 |
输出是确定性的(使用 `--no-timestamp`)且采用 JSON 编码(无注入风险)。
## 安全模型
所有分析都是静态的(源码审查)或基于元数据的(lockfile、manifest、咨询数据)。网络功能是可选的,且仅限于咨询元数据;`--offline` 会禁用网络,缺少缓存数据库并非致命错误。不受信任的字符串在输出 Markdown/SARIF 之前会被转义。完整的威胁模型和报告流程请参见 `SECURITY.md`。
## Workspace 布局
```
crates/rustinel-core/ # analysis library (lockfile, signals, risk, policy, advisory, reporters)
crates/rustinel-cli/ # `cargo-rustinel` binary
action.yml # GitHub Action (repo root, for Marketplace)
fixtures/ # offline test fixtures
schemas/ # JSON schemas for report & policy
examples/ # policies + sample reports
```
## 开发
```
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
```
测试完全离线且具有确定性。快照测试(`crates/rustinel-core/tests/snapshots/`)锁定了准确的报告器输出。
## 许可证
根据你的选择,受 [Apache License, Version 2.0](LICENSE-APACHE) 或 [MIT license](LICENSE-MIT) 的许可。除非你明确声明,否则根据 Apache-2.0 许可证的界定,任何有意提交以包含在此 crate 中的贡献均应按上述方式获得双重许可,不附加任何额外条款或条件。