tess-fun/fleetreach
GitHub: tess-fun/fleetreach
FleetReach 是一款 Rust 编写的群体级依赖安全审计 CLI,一次性扫描多个仓库并对已知漏洞进行去重、排序、爆炸半径分析和批量修复编排。
Stars: 0 | Forks: 0
# fleetreach
[](https://crates.io/crates/fleetreach-cli)
[](https://github.com/tess-fun/fleetreach/actions/workflows/ci.yml)
[](#msrv)
[](#license)
**一个面向群体的依赖安全审计工具。** 将它一次性指向多个代码仓库,
即可获得一个去重、排序且适配 CI pipeline 的全局视图,了解整个群体中哪些依赖
存在已知的安全公告(以及供应链警告:
未维护、不可靠、通知;甚至包括针对 Rust 工具链
本身的安全公告)。在此之上,你还可以获得爆炸半径分析(即哪一次单独的修复可以清除
最多的仓库,区分直接依赖与间接依赖),一个批量修复队列,
覆盖整个群体的 `--why` 来源追踪、扫描间的漂移追踪,以及 SARIF /
JSON / OpenVEX 输出。单一二进制文件:无需运行服务器,无需配置 SBOM pipeline。
它覆盖 12 个生态系统(Rust、Go、npm、PyPI、RubyGems、Packagist、NuGet、Julia、
Swift、Hex、Maven、GitHub Actions),并且对于 Rust,它增加了一种可靠的基于 MIR 的
可达性分析,可以证明存在漏洞的函数是否真正可被调用。
它 **不是** 一个扫描器或安全公告数据库。它是一个基于已审计数据源的编排和
关联层:用于 Rust 的
[`rustsec`](https://crates.io/crates/rustsec) 引擎(与 `cargo-audit` 基于
相同的库构建)以及用于其他所有
生态系统的 [OSV](https://osv.dev) 数据库。其信任边界是“结构化的安全公告数据加上你自己的
配置”,绝不依赖原始 HTML,并且它采用失败即关闭原则:它无法扫描的缺口绝不会
被报告为安全。
## 横向对比
`fleetreach` 刻意占据了主流扫描器留下的空白领域:
轻量级、CLI 原生、**群体级别** 的审计。
- **对比 `osv-scanner` (Google)、Trivy、Grype。** 这些工具一次扫描一个项目,
并回答“*这个项目* 有漏洞吗?”。`fleetreach` 在一次扫描中处理多个仓库,
并回答群体级别的问题:*哪一次单独的修复可以清除最多的仓库,我该如何安排工作顺序?*
(即 `impact` / `blast` / `packages` / `remediation` 视图)。它刻意保持了较小的功能表面积:没有容器或 OS
扫描(请使用 Trivy/Grype 进行此类扫描),也没有自带的安全公告数据库。
- **对比 OWASP Dependency-Track。** 它是资产组合管理领域的传统强者,但它是
一个*需要你自行运维的服务器*:需要搭建平台、导入 CycloneDX SBOM、托管
数据库和 Web UI。`fleetreach` 是一个单一的二进制程序,你可以直接在 CI 或
shell 中针对 `fleet.toml` 运行它。无需服务器,无需 SBOM pipeline,无需托管状态。
- **特别是对于 Rust。** 它增加了一种*可靠的*静态可达性模式(带有见证链的 MIR
调用图分析),这是大多数开源扫描器所缺乏的,并建立在失败即关闭的 CI 契约之上,在此契约下,错误的“安全报告”被视为
最糟糕的输出结果。
如果你需要容器扫描、托管仪表板或单仓库 CI 检查,上述
工具更合适。如果你想要一条命令来回答“我的*群体* 的
依赖风险是什么,我首先该修复什么”,这正是它的用武之地。
## 安装
```
cargo install fleetreach-cli --features network # the `fleetreach` binary, with DB fetch + enrichment
```
默认构建版本是 **纯 Rust**(没有内置的 C 语言 TLS 栈):它不支持网络
功能,需要通过 `--db ` 使用本地的 advisory-db 克隆。可选开启的
`network` feature 增加了 advisory-DB 获取和 KEV/EPSS/NVD 数据丰富化功能(引入
`rustls` TLS 栈)。使用 `--features network` 安装可获得通常的运行时拉取
行为;省略它则获得最精简、依赖少、纯离线(`--db`)的构建。
或者从源码构建:
```
git clone https://github.com/tess-fun/fleetreach
cargo install --path crates/cli --features network # omit --features network for the pure-Rust offline build
```
## 使用方法
```
fleetreach scan -c fleet.toml # human table (default)
fleetreach scan -c fleet.toml -f json # machine payload on stdout, clean for | jq
fleetreach scan -c fleet.toml -f sarif # SARIF 2.1.0 for GitHub code scanning
fleetreach scan -c fleet.toml -f impact # advisories ranked by repos affected
fleetreach scan -c fleet.toml -f blast # blast radius split direct vs transitive
fleetreach scan -c fleet.toml -f packages # dependencies ranked by fleet reach
fleetreach scan -c fleet.toml -f fix-first # advisories ranked by what to patch first
fleetreach scan -c fleet.toml -f remediation # the fix queue: what to bump, batched
fleetreach scan -c fleet.toml -f packages-json # the packages rollup as JSON
fleetreach scan -c fleet.toml -f remediation-json # the fix queue as JSON
fleetreach scan --why serde # how does `serde` get into the tree?
fleetreach scan -c fleet.toml --npm-vuln-db file://./npm-osv # also audit npm repos
fleetreach scan -c fleet.toml --pypi-vuln-db file://./pypi-osv # also audit Python repos
fleetreach scan -c fleet.toml --packagist-vuln-db file://./packagist-osv # also audit PHP/Composer repos
fleetreach scan -c fleet.toml --rubygems-vuln-db file://./rubygems-osv # also audit Ruby repos
fleetreach scan -c fleet.toml --nuget-vuln-db file://./nuget-osv # also audit .NET/NuGet repos
fleetreach scan -c fleet.toml --julia-vuln-db file://./julia-osv # also audit Julia repos
fleetreach scan -c fleet.toml --swift-vuln-db file://./swift-osv # also audit Swift repos
fleetreach scan -c fleet.toml --hex-vuln-db file://./hex-osv # also audit Elixir/Hex repos
fleetreach scan -c fleet.toml --ghactions-vuln-db file://./gha-osv # also audit GitHub Actions pins
fleetreach scan -c fleet.toml --maven-vuln-db file://./maven-osv # also audit Java (gradle.lockfile/pom.xml)
fleetreach diff old.json new.json # what changed between two scans
```
`impact` 视图通过评估安全公告影响的 crate 数量来排序,回答了群体级别的
问题(*哪一次修复可以清除最多的仓库?*)。以下示例
来自一个包含十个仓库的演示群体(参见
[`examples/demo-fleet.toml`](examples/demo-fleet.toml)):
```
Repos Severity Advisory Affected Title
2 medium 6.2 RUSTSEC-2020-0071 payments-api, scheduler Potential segfault in time
1 critical 9.8 RUSTSEC-2021-0003 ingest-worker SmallVec::insert_many overflow
1 critical 9.8 RUSTSEC-2021-0097 ls-replacement SM2 decryption buffer overflow
1 high 8.6 RUSTSEC-2024-0013 ls-replacement libgit2 memory corruption
1 high 7.5 RUSTSEC-2022-0013 search-svc regex repetition DoS
```
首行是一个*中等* 级别,而不是严重级别:`time` 段错误是唯一
存在于两个仓库中的安全公告,因此一次升级即可同时修复 `payments-api` 和
`scheduler`。这种排序正是单仓库工具无法回答的问题。
`blast` 视图保持了相同的排序,但将每个安全公告的影响范围拆分为
**直接** 和 **间接** 仓库,并添加了修复路径提示,因为 *如何*
修复取决于这种划分:如果一个公告主要间接影响其所在的仓库,则无法
通过编辑这些仓库的 manifest 来修复(你需要上游升级或依赖
覆盖 → `upstream`),而直接的则可以(`manifest`)。一项针对
真实 Go 生态系统的语料库研究发现,约 3/4 的易受攻击依赖暴露是间接的,因此
单纯受影响仓库的计数会掩盖修复策略。
```
Repos Direct Transitive Fix Severity Advisory Title
2 1 1 mixed unknown RUSTSEC-2025-0004 ssl select_next_proto UAF
1 1 0 manifest critical 9.8 RUSTSEC-2021-0003 SmallVec::insert_many overflow
1 0 1 upstream medium 6.2 RUSTSEC-2020-0071 Potential segfault in time
```
`packages` 视图将这些行向上汇总了一级 —— 汇总到 *依赖* 本身。一个包通常
在多个仓库中存在许多安全公告,而一次升级即可解决所有问题,因此
这回答了“哪个依赖是我群体中最大的负债?”。它按群体影响范围对易受攻击的
依赖进行排序,带有同样的直接/间接划分,并显示一次升级可以
解决的安全公告数量:
```
Repos Direct Transitive Advisories Severity Fix Package
3 0 3 2 medium upstream time
2 1 1 7 unknown mixed openssl
1 1 0 1 critical manifest smallvec
```
在这里,一次 `openssl` 升级即可解决七个安全公告 —— 这是按安全公告
划分的视图无法展示的汇总信息。(`-f json` 会在每次出现时携带 `dependency_kind`,并且 SARIF
结果会增加一个 `dependencyKind` 属性,因此 CI 消费者可以获得相同的信号。)
`fix-first` 视图回答了互补的问题(*我首先该修复
什么?*)。它以严重性为主导:活跃被利用(KEV)的发现排在最前,然后是
严格的严重性等级,只有在 *同一等级内*,爆炸半径才会打破平局。
这确保了一个仓库中的严重 CVE 排名高于一个影响数千个仓库但级别较低的不可靠
代码检查 —— 这与 `impact` 的权衡恰恰相反,后者会将
范围广但仅作为信息提示的警告置于顶部。
`remediation` 视图更进一步。`fix-first` 对 *是哪个安全公告* 进行排序,而此视图
输出 *该采取什么措施*:具体的依赖升级。每一
行都是 **批量处理** 的,因此一个单独的 `bump tokio 1.0 → 1.38` 行即可解决
每一次升级在所有仓库中能够解决的所有安全公告,并且破坏性(semver-major)的跨版本升级会被
标记出来,以便优先处理影响小的修复。没有发布修复补丁的安全公告会被
如实标注(`no fix: …`),而不是粉饰为升级。当静态
可达性分析运行后(`--reachability=static`),*被证明* 不可达的安全公告会降至
信息性尾部(会显示,但绝不会排入修复队列中),因此
死代码发现永远不会挤占真正重要的升级操作。
### 追踪随时间的漂移
`fleetreach diff ` 比较两份保存的报告(每份
均来自 `scan -f json`),并将发现结果分为 **新增**、**已修复** 和
**仍然存在** —— 这是单次扫描无法回答的问题:*这个分支使群体变得更好还是更糟?*
新增的安全公告是倒退;已修复的是进步;一个
仍然存在但仓库影响范围缩小或扩大的公告会显示 `±` 爆炸半径
漂移。它是纯粹的(无需扫描、数据库或网络 —— 仅需两个 JSON 文件),因此可以直接
作为轻量级检测关卡加入到 CI 中:
```
1 new, 1 fixed, 1 still open.
New (1):
critical RUSTSEC-2026-9999 2 (+2) brand new critical
```
退出代码与 `scan` 一致:`0` 安全,`1` 表示 *新增* 的发现触发了关卡,`2` 表示
无法读取文件。`--fail-on ` 设置了新增漏洞必须
达到才能触发关卡的最低门槛(默认为 `low`;Unknown 总是计入,失败即关闭),`--fail-on-warnings`
也会在新引入的警告处触发关卡,而 `--exit-zero` 使其仅作报告而不拦截。
`-f json` 输出完整的结构化差异以供自动化使用。
### GitHub Action
使用内置的组合 Action 将发现结果放入 Security(安全)标签页并添加 PR 注释
(参见 [`.github/workflows/audit-example.yml`](.github/workflows/audit-example.yml)):
```
- uses: tess-fun/fleetreach@v1
with:
args: "--enrich --resolve-features"
```
`fleet.toml` 列出了要扫描的仓库:
```
[[repo]]
id = "core-lib"
path = "../core-lib" # repo root; Cargo.lock located within
[[repo]]
id = "services"
path = "../services"
glob = true # discover **/Cargo.lock under the tree
glob_max_depth = 4 # bounded; default 3
[[repo]]
id = "billing-api"
path = "../billing-api" # a go.mod repo; scanned via govulncheck
ecosystem = "go" # optional; auto-detected from the manifests
[[repo]]
id = "web-frontend"
path = "../web-frontend" # a package-lock.json repo; toolchain-free OSV match
ecosystem = "npm" # optional; auto-detected from the manifests
[[repo]]
id = "ml-service"
path = "../ml-service" # a uv.lock/poetry.lock/Pipfile.lock repo; toolchain-free
ecosystem = "pypi" # optional; auto-detected from the manifests
[[repo]]
id = "storefront"
path = "../storefront" # a composer.lock repo; toolchain-free OSV match
ecosystem = "packagist" # optional; auto-detected from the manifests
[[repo]]
id = "payments-dotnet"
path = "../payments-dotnet" # a packages.lock.json repo; toolchain-free OSV match
ecosystem = "nuget" # optional; auto-detected from the manifests
[[repo]]
id = "sim-pipeline"
path = "../sim-pipeline" # a Manifest.toml repo; toolchain-free OSV match
ecosystem = "julia" # optional; auto-detected from the manifests
[[repo]]
id = "ios-client"
path = "../ios-client" # a Package.resolved repo; toolchain-free OSV match
ecosystem = "swift" # optional; auto-detected from the manifests
[[repo]]
id = "billing-api"
path = "../billing-api" # a Gemfile.lock repo; toolchain-free OSV match
ecosystem = "rubygems" # optional; auto-detected from the manifests
[[repo]]
id = "chat-service"
path = "../chat-service" # a mix.lock repo; toolchain-free OSV match
ecosystem = "hex" # optional; auto-detected from the manifests
[[repo]]
id = "analytics-jvm"
path = "../analytics-jvm" # a gradle.lockfile/pom.xml repo; toolchain-free OSV match
ecosystem = "maven" # optional; auto-detected from the manifests
[[repo]]
id = "ci-config"
path = "../ci-config" # a .github/workflows repo; scans pinned `uses:` actions
ecosystem = "githubactions" # set explicitly to scan a package repo's workflows too
[[settings.ignore]]
id = "RUSTSEC-2020-0071"
reason = "dev-dependency only, not in any shipped path" # REQUIRED, non-empty
```
包含 `go.mod`(且没有 `Cargo.lock`)的仓库会被 `govulncheck` 扫描,并
汇入同一份群体报告中,因此一个混合了 Rust 和 Go 的群体会产生一个统一的、具备爆炸半径
和可达性感知的修复队列。由于 govulncheck 需要编译 module,Go
扫描需要 `--allow-untrusted-builds` 以及一个 `govulncheck` 二进制文件(通过 `--govulncheck` 指定,
或者在 `PATH`/`$GOPATH/bin` 中);如果没有这些,Go 仓库会被报告为错误缺口,
而不是被静默跳过。确认的 Go 调用点会被标记为 `reachable`(该
分析是可靠阳性的),而存在但未被调用的保持为 `unknown`,绝不会出现错误的“不可达”。
没有 Go 工具链?一种降级的 **module 级别** 模式会读取 `go.mod` 并
将每个依赖与 vuln.go.dev 镜像进行匹配(`--go-vuln-db=file://`)—— 它不编译
任何东西,因此不需要 `--allow-untrusted-builds`。它仅限于 module 级别(发现结果的
可达性为 `unknown`,没有符号分析),并且无法看到 Go stdlib 公告,但
其匹配机制已经过与 govulncheck 在真实 module 上的差异性验证,保证
**零误报安全**。
其他每个生态系统都以同样 **无需工具链** 的方式进行扫描:`fleetreach` 读取
lockfile(完整的传递依赖树,已固定到确切版本),并将每个
包与通过 `---vuln-db=file://` 传入的 **OSV 镜像** 进行匹配,指向
osv.dev 导出的 `all.zip`(每个生态系统位于
`https://osv-vulnerabilities.storage.googleapis.com//all.zip`,可直接读取
无需解压)或一个包含解压记录的目录。它不运行任何包管理器,也没有
安装或构建脚本,因此与 Go 的 module 级别模式一样,它在构建上是安全的,并且
不需要 `--allow-untrusted-builds`;如果没有镜像,该仓库就是一个如实的错误缺口,
绝不静默跳过。严重性来自 GHSA 等级或 CVSS 向量,直接与
间接的区分来自 lockfile,除非运行了可达性
模式,否则发现结果的可达性均为 `unknown`。
| 生态系统 | Lockfile | 标志 | 版本语义 |
|-----------|-------------|------|-------------------|
| npm | `package-lock.json` | `--npm-vuln-db` | SemVer |
| PyPI | `uv.lock` / `poetry.lock` / `Pipfile.lock` | `--pypi-vuln-db` | PEP 440 (PEP 503 名称) |
| RubyGems | `Gemfile.lock` | `--rubygems-vuln-db` | `Gem::Version` |
| Packagist | `composer.lock` | `--packagist-vuln-db` | Composer `version_compare` |
| NuGet | `packages.lock.json` | `--nuget-vuln-db` | 四段式 `NuGetVersion` |
| Julia | `Manifest.toml` | `--julia-vuln-db` | `VersionNumber` |
| Swift | `Package.resolved` | `--swift-vuln-db` | URL 标识的 SemVer |
| Hex | `mix.lock` | `--hex-vuln-db` | SemVer |
| Maven | `gradle.lockfile` / `pom.xml` | `--maven-vuln-db` | `ComparableVersion` |
| GitHub Actions | `.github/workflows/*.yml` | `--ghactions-vuln-db` | tag SemVer |
有一些细节无法填入表格。当公告列举的是受影响的版本而非
范围时(特别是恶意软件 `MAL-` 记),匹配器会同时查阅这两个列表。PyPI
根据 PEP 503 规范化名称,因此 `Flask` 和 `flask` 能匹配上。对于 GitHub Actions,仅
匹配固定了版本的 `uses:` 引用(例如 `tj-actions/changed-files`
供应链公告),而 SHA 和分支固定会被作为如实的缺口跳过。每个定制
比较器都与现有的真实上游库进行了差异性验证:Maven
比较器与 Apache Maven 自带的 `ComparableVersion` 在超过 710,000 个版本
对上保持一致,而 npm/PyPI/RubyGems 的匹配在针对 OSV 导出数据验证时
达到了 100% 的召回率和零误报安全。
一个混合生态系统的群体 —— Rust、Go 以及任何无需工具链的输入源 —— 都能汇入一个
统一的、按爆炸半径排序的修复队列。
核心标志:`--db ` (使用本地 advisory-db 克隆), `--offline`,
`--max-db-age 7d`, `--min-severity high`, `--fail-on critical`,
`--fail-on-warnings`。详见 `fleetreach scan --help`。
### 根据真实世界风险确定优先级
`--enrich` 使用 **CISA KEV**(在野被积极利用)和
**FIRST EPSS**(漏洞利用概率)对每个发现进行注释,将它们重新排序为一个行动
队列,并添加一个 `Risk` 列:
```
Severity Risk Advisory Fix Title
critical 9.8 epss 88% RUSTSEC-2021-0097 openssl-src → 111.16.0 SM2 decryption buffer overflow
high 7.5 epss 71% RUSTSEC-2022-0014 openssl-src → 111.18.0 infinite loop in BN_mod_sqrt
high 7.4 epss 50% RUSTSEC-2021-0098 openssl-src → 111.16.0 ASN.1 read buffer overruns
high 7.5 epss 14% RUSTSEC-2022-0013 regex 1.5.4 → 1.5.5 regex repetition DoS
critical 9.8 epss 2% RUSTSEC-2021-0003 smallvec 1.6.0 → 0.6.14 SmallVec::insert_many overflow
```
两个 `critical 9.8` 的 CVSS 评分相同,但 EPSS 打破了平局:openssl
溢出(88% 的利用概率)升至队列首位,而
smallvec(2%)则降至接近底部。在 CISA
已知被利用列表中的发现会在 `Risk` 列中显示为 `KEV epss NN%`。
使用 `--fail-on-kev`(如果有任何漏洞被积极利用则失败)或
`--min-epss 0.5` 设置关卡。这两个数据源都可以通过 `--kev-file` /
`--epss-file` 离线提供。
每个发现都显示了其 **依赖来源**:被标记的包是
直接依赖还是间接依赖,以及引入它的依赖链:
```
fleetreach/proc-macro-error2@2.0.1 (via fleetreach-scan → … → defmt-macros)
```
完整的链条保存在 JSON (`occurrences[].dependency_path`) 中,因此无需
使用 `cargo tree -i` 即可查看 *是谁引入了某个包*。`--why `
可以一次性针对整个群体提出这个问题:
```
$ fleetreach scan --why serde
cli-tools — serde 1.0.228 (direct):
ripgrep → serde
docs-builder — serde 1.0.228 (transitive):
guide-helper → serde_json → serde
file-finder — serde 1.0.228 (transitive):
fd-find → globset → bstr → serde
```
借助 **`--resolve-features`**(可选开启,需要仓库可构建的源码),每个
发现也会被标记为已构建,还是仅存在于 `Cargo.lock` 中且从未被编译的
虚幻可选依赖;表格会用 `⚠ not in default build` 标记这些情况,并且
JSON 中会增加 `occurrences[].active` 字段。默认扫描依然保持仅读取 lockfile 且
具备良好的可移植性。
本仓库自身也进行了自我测试:提交的 [`fleet.toml`](fleet.toml) 指向
仓库根目录,因此从这里运行 `fleetreach scan` 会审计 fleetreach 自身的依赖
树(它报告了零漏洞)。
## 退出代码 (CI 契约)
自上而下评估,匹配到第一个即生效:
| 代码 | 含义 |
|------|---------|
| `3` | 用法 / 参数错误。 |
| `2` | 无法完成可信的扫描:配置无效 · advisory DB 无法加载 · DB 早于 `--max-db-age` · 零个仓库被扫描 · **任何仓库报错**(缺口意味着我们无法宣称整个群体是安全的)。 |
| `1` | 可信的扫描;有发现结果触发了拦截(`--fail-on` 或 `--fail-on-warnings`)。 |
| `0` | 可信的扫描;没有任何内容达到失败阈值。 |
错误的“安全报告”是最糟糕的输出结果,因此除非完成了一次它能够
完全认可的扫描,否则该工具绝不会以 `0` 退出。
## 设计决策 (失败即关闭)
`fleetreach` 宁愿产生噪音也不愿保持沉默:当它无法 *证明* 某些事物是
安全的时,它会将其暴露出来,而不是悄然放过。
- **未知严重性的漏洞总会触发关卡。** 没有 CVSS
评分的安全公告会被报告为 `unknown` 严重性。它仍会触发 `--fail-on` 并且仍会
在 `--min-severity` 过滤中保留;我们无法证明它低于
阈值,所以我们绝不会静默丢弃它。
- **`--db-rev` 需要 `--db`。** 将 advisory DB 固定到确切的 commit
仅对本地的 advisory-db git 克隆有效(`rustsec` 0.33 没有暴露
按版本打开的构造器;该固定操作是通过检出克隆来实现的)。
- **`--max-db-age` 在库时间未知时拒绝运行。** 如果 DB 不包含 commit
时间戳,则无法验证其新鲜度,因此运行将以 `2` 退出,而
不是假定 DB 是最新的。
## 架构
```
cli → report → correlate → scan → core
```
依赖关系严格向内指向。`core`(领域模型和 JSON 通信
契约)在工作区内没有任何依赖,其公开
API 中也没有 `rustsec` 类型,因此未来的数据丰富化将作为附加字段添加,而不会破坏
`schema_version: 1`。`scan` 是唯一触碰 `rustsec` 的 crate。每个
crate 都禁止 `unsafe`,并拒绝在
外部派生的值上使用 `unwrap`/`expect`/`panic` 系列。
有关完整的数据流和失败即关闭
主轴,请参见 [ARCHITECTURE.md](ARCHITECTURE.md),发布说明请参见
[CHANGELOG.md](CHANGELOG.md)。
## 可达性
`--reachability`(单独使用,或者 `=heuristic`)是一种带标签的源码存在
*启发式方法*,它会 grep 你的源码但从不构建任何东西。对于 Rust,它会 grep
公告中受影响的函数名;对于无需工具链的输入源,它会
grep 每个 **直接** 依赖的 import/use 语句 —— 对于 npm/Julia/RubyGems 是精确匹配
(坐标 = import 名),而对于
PyPI/NuGet/Maven/Packagist/Swift/Hex 则是通过各生态系统的名称启发式方法进行匹配
(dist→module, package-id→namespace,
group→Java-package, vendor/pkg→PSR-4, repo→Swift-module, `foo_bar`→`FooBar`)。对于
GitHub Actions,一个 `uses:` 引用就是一个活跃的 CI 步骤(可靠阳性)。该
启发式方法只会在阳性匹配时将发现 *提升* 为可达 —— 它永远不会
将 Tier-C 的发现标记为不可达,因此漏掉的 import 无法隐藏漏洞
(并且 `--reachable-only` 绝不会因为 grep 未命中而放弃某个漏洞)。目前所有 12 个生态系统都会
产生可达性信号(Go 通过 govulncheck;Cargo 还具有下文提到的可靠静态
模式)。
**npm 导入图。** 在 `--reachability` 下,npm 使用无构建的 *module 导入
图* 来代替扁平的 grep:它会解析你源码中的每个
`require`/`import`,以及(当存在 `node_modules` 时)每个已安装包中的导入,然后报告
有漏洞的包为 `Reachable`,并提供见证导入链(`your-dep → … →
vuln`)—— 包括传递依赖包。`--npm-prune-unreachable` 额外地
在存在 `node_modules` 且没有导入路径到达该包时将其标记为 `NotReachable`(因此
`--reachable-only` 会将其丢弃)。这种否定性结果是尽力而为的可靠判定:一个
它无法看到的动态 `require(expr)` 或框架自动加载可能会使得
`NotReachable` 变得不准确,这就是为什么它是一个单独的显式可选开启项。
`--reachability=static` 是一种可靠的 MIR 调用图分析,它可以证明存在漏洞的
函数是否可被调用,并提供见证链。
## MSRV
最低支持的 Rust 版本为 **1.89**(由依赖闭包决定,
而不仅仅是 `rustsec`),已在 CI 中验证。
## 许可证
根据以下任一许可证授权:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) 或
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) 或
http://opensource.org/licenses/MIT)
由你选择。
### 贡献
除非你明确声明,否则任何由你有意提交以包含在
作品中的贡献,根据 Apache-2.0 许可证的定,均应按上文所述进行
双重许可,无需任何附加条款或条件。
标签:GPT, Rust, 代码可达性分析, 依赖审计, 可视化界面, 漏洞管理, 网络流量审计, 通知系统