MoAz06/ReachGate
GitHub: MoAz06/ReachGate
ReachGate 基于 GitLab Orbit 代码图谱进行确定性漏洞可达性分析,从入口点遍历到漏洞定义处,判断安全发现是否真正可利用,并导出可离线验证的标准化证据。
Stars: 0 | Forks: 0
# ReachGate
基于 [GitLab Orbit](https://docs.gitlab.com/orbit/) 构建的 Agentic 漏洞可达性分诊工具。
安全扫描器只会告诉你存在漏洞。而 ReachGate 负责解答这是否要紧:它会从声明的应用程序入口点出发,沿着 Orbit 的代码图谱遍历到存在漏洞的定义处,将该路径记录为证据,并在 GitLab 内部执行确定性的分诊操作。
## 为什么需要可达性
安全团队疲于应对扫描器的输出,而且其中大部分并不重要:Datadog 的 [State of DevSecOps 2025](https://www.datadoghq.com/state-of-devsecops-2025/) 报告发现,在引入运行时和可达性上下文后,具有严重 CVSS 评分的漏洞中仅有 18% 仍保持严重级别。五分之四的“严重”发现都是噪音。分诊成为了瓶颈,而目前这一过程只能手动完成。
GitLab 已经具备了缺失的关键要素:Orbit 将代码库索引为由文件、定义、导入和调用组成的图谱。ReachGate 将该图谱转化为分诊引擎 —— 每一个判定都是一条具体的图路径(或可证明其不存在),而不是模型的臆测。
## 功能介绍
针对每一个安全发现,ReachGate 会:
1. 向 Orbit 查询该发现的代码位置 (`VulnerabilityOccurrence.location`)
2. 使用基于 `neighbors` 查询的有界 BFS 算法,从声明的入口点出发,沿着图的边(DEFINES、IMPORTS 和 CALLS)遍历到存在漏洞的定义处
3. 确定性的策略引擎(透明的规则权重,无模型评分)返回以下判定:
- **REACHABLE**(可达)—— 发布带有图路径的可审计回执;在 MR(合并请求)分诊中表现为一条评论,而在操作/Agent 升级流程中则可创建工作项
- **NOT_REACHABLE**(不可达)—— 降低优先级,并附带证据:每次遍历均完整执行(边界已耗尽)且未找到路径。这是一种穷举式的否定结论,而非敷衍。
- **UNKNOWN**(未知)—— 证据不充分(无代码位置、未索引任何内容、未解析出入口点、达到搜索限制或发生 API 错误)。ReachGate 绝不会将截断的搜索伪装成不可达的证明。
UNKNOWN 并不是敷衍:每个 UNKNOWN 判定都会携带一个明确类型的证据原因和一个确定性的下一步动作,因此缺乏代码锚点的依赖项/SCA 发现仍然保持可审查状态,而不会变成虚假的“安全”(fake-greened)。
4. 将回执(图路径 + 规则明细 + 评分 + 可达性证书)作为工作项或 MR 评论发布 —— 其中包含 GitLab 可内联渲染的 Mermaid 路径图:
```
flowchart LR
n0["📄 content/frontend/404/archives_redirect.js"]
n1["ƒ getArchivesVersions"]
n0 --> n1
classDef entry fill:#1f6feb,color:#fff,stroke:none;
classDef vuln fill:#da3633,color:#fff,stroke:none;
class n0 entry;
class n1 vuln;
```
## 入口点可配置
在 `reachgate.yml` 中声明你的应用程序攻击面:
```
version: "1"
entrypoints:
files:
- "src/routes/**/*"
- "app/controllers/**/*"
- "cmd/**/main.*"
```
ReachGate 绝不臆测从外部可达的内容。由你声明边界;引擎负责执行。
## 验证你的攻击面
声明的入口点如果匹配到 **零** 个已索引文件,是最危险的故障模式:ReachGate 将无处可遍历,并对所有内容报告 `NOT_REACHABLE`,这是一种由错误的 glob 表达式而非安全代码导致的隐蔽假阴性。`tools/reachgate_doctor.py` 是一个单命令的预检工具,能在你信任任何判定之前准确捕获该问题:
```
export GITLAB_TOKEN="glpat-xxxxx"
python tools/reachgate_doctor.py --config reachgate.yml
```
对于每个 `entrypoints.files` 模式,它会查询实时的 Orbit,根据精确的 glob 匹配器确认返回的路径,并报告匹配到的已索引文件数量(附带样本路径,通过 `--limit` 进行限制)。如果至少匹配到一个入口点则退出码为 `0`;如果配置加载成功但未匹配到任何内容则退出码为 `1`(此时 `NOT_REACHABLE` 的证据尚不可信);如果发生认证/配置错误则退出码为 `2`。
它会验证你声明的 glob 是否与 Orbit 已索引的文件相匹配。但它 **并不能** 证明攻击面是完整的,也不能推断或建议入口点:你仍然拥有该定义权。
## 每个判定都附带证书
没有记录搜索如何执行的判定仅仅是一种断言。每份回执都包含一个可折叠的 **可达性证书**:策略版本(规则权重和阈值的哈希值)、搜索边界 (`max_hops`, `max_visited`, `max_seconds`)、检查了多少个入口点、访问了多少个节点、消耗了多少次 Orbit API 调用、哪些证据模式促成了判定(图边或 `ImportedSymbol` 回退),以及是否有任何边界条件提前终止了遍历。
每份回执还带有一个稳定的 **指纹** —— 由发现标识、判定、路径、策略版本和声明的攻击面(绝不包含计时或调用次数)计算得出的哈希值。相同的发现在相同的策略下,其指纹总是完全相同的。MR 分诊利用该指纹配合每个发现的隐藏标记来更新评论:重新运行时会跳过未更改的回执,而不是发布重复内容;已更改的回执则会就地更新。工作项的创建仍是 Agent/操作升级流程的一部分;MR CI 路径在设计上仅支持评论。
CI 作业还会额外上传 `reachgate-receipts.json`:这是一个机器可读的产物,包含每份回执、完整的证书和当前生效的策略,因此判定结果可以在 GitLab 外部进行对比、审计和重放。
## 符合标准的 VEX 导出
大多数可达性工具要求你盲目信任判定结果。ReachGate 让判定变得可移植:`tools/export_vex.py` 会将回执转换为符合标准的 [OpenVEX](https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md) 文档,以便下游供应链工具可以以机器可读的方式消费可利用性上下文 —— 而不仅仅是作为一条 MR 评论。
```
python tools/export_vex.py # writes docs/proof/reachgate.openvex.json
```
这种映射非常保守,因为 VEX 的 `not_affected` 会指示所有下游消费者忽略某个 CVE:
- **REACHABLE** → `affected`(带有指明图路径的 `action_statement`)
- **NOT_REACHABLE** → `not_affected`,理由为 `vulnerable_code_not_in_execute_path` —— **仅当** 搜索是真正穷举时有效(边界已耗尽,触发的边界限制为 0,API 错误为 0)
- **UNKNOWN**,或者任何证书显示触发了边界限制或 API 错误的 `NOT_REACHABLE` → `under_investigation`,绝不返回 `not_affected`
最后一条规则是核心所在:ReachGate 拒绝基于未真正运行完成的搜索输出干净的 VEX `not_affected`。VEX 按照惯例是针对 CVE/组件 (SCA) 的产物,因此包含 CVE 的发现可以顺利映射,而 SAST/CWE 类型的发现则诚实地作为针对该项目(视为产品)的声明进行承载。`tools/verify_proof.py` 会对导出的 VEX 与相同的回执进行交叉核对,因此 VEX 声明也是可证伪的。
## 可移植的证据层 —— 不仅仅是扫描器
ReachGate 被设计为一个 **可离线验证的证据层**:相同的回执会作为可重放、符合标准的证据输出,供下游工具直接使用。确定性引擎负责裁定,AI 仅负责解释,且每个导出的声明都会根据回执进行交叉核对。[Evidence Contract](docs/EVIDENCE_CONTRACT.md) 精确声明了下游工具可以从回执中得出哪些声明,以及哪些不能得出。
- **OpenVEX** (`tools/export_vex.py` → `docs/proof/reachgate.openvex.json`) —— CVE/SCA 可利用性上下文(见上文)。
- **SARIF 2.1.0** (`tools/export_sarif.py` → `docs/proof/reachgate.sarif.json`) —— SAST/代码流证据:REACHABLE 路径会转换为基于真实图谱的 SARIF `codeFlow`/`threadFlow`,NOT_REACHABLE 保持“在配置的搜索边界内”,而 UNKNOWN 是明确类型的证据缺口,绝不会被呈现为安全。只有在回执包含具体文件时才会输出源码位置 —— 绝不凭空捏造。
- **Evidence manifest**(证据清单) (`tools/build_evidence_manifest.py` → `docs/proof/reachgate.evidence-manifest.json`) —— 针对机器可读产物(回执、OpenVEX、SARIF)的 sha256 哈希,以便审查者可以离线确认他们正在查看的确切是 ReachGate 生成的原始证据。
- **Offline verifier**(离线验证器) (`tools/verify_proof.py`) —— 仅使用标准库,无需 token,无需网络;对 OpenVEX 和 SARIF 反向核对回执,确保证据具备可证伪性。
```
python tools/export_vex.py
python tools/export_sarif.py
python tools/build_evidence_manifest.py
python tools/verify_proof.py
```
如需引导式演练,请参阅 [Judge Pack](docs/JUDGE_PACK.md)。默认情况下,所有声明仅供参考,并严格限定在配置的搜索边界内;这符合标准,但并非经过认证的拦截门禁。
## 命令行
安装完成后(`pip install -e ".[dev]"`;如果需要可选的签名/防篡改检查,请使用 `".[dev,sign]"`),离线、确定性的功能只需一个 `reachgate` 命令即可调用:
```
reachgate --help # show the full offline evidence CLI
reachgate selftest # adversarial invariant test: real passes, fake-green fails
reachgate coverage # verdict / UNKNOWN-reason / blind-spot report
reachgate coverage --format html --output coverage.html # same report as static HTML
reachgate verify # verify receipts + cross-check OpenVEX/SARIF
reachgate export-vex # OpenVEX from receipts
reachgate export-sarif # SARIF 2.1.0 from receipts
reachgate manifest # sha256 evidence manifest
reachgate proof # offline judge-proof HTML page
reachgate policy explain # read-only view of the recorded policy
reachgate fixcheck BEFORE AFTER # prove the reachability delta between two receipts
reachgate contract-check RECEIPT.json # enforce the Evidence Contract on receipts
reachgate blame RECEIPTS.json --changed-files FILE # path overlap only, never causation
reachgate explorer --output explorer.html # self-contained offline evidence explorer
reachgate judge # one command: verify -> exports -> manifest -> proof
reachgate capsule build # portable evidence capsule (zip) in dist/
```
`reachgate selftest` 是最快速的“不要盲目相信我们,用证据说话”检查:它接受真实的证据,拒绝伪造安全的证据,将 `UNKNOWN` 保留为证据缺口,并且在通过 `sign` 扩展安装时会运行可选的签名/防篡改环节(若未安装则诚实地跳过该环节)。`reachgate coverage` 是盲点报告:包含判定计数、带有明确类型下一步动作(来自 `guidance.py`)的 UNKNOWN 原因、哪些发现缺乏代码锚点,以及坦诚的局限性说明 —— 所有内容均离线提取自已捕获的回执(支持 `--format json|html` 和 `--output`)。`reachgate judge` 会端到端运行整个离线流水线,并打印出判定证明页面的路径(它绝不会自动打开浏览器)。`reachgate capsule build` 会写入 `dist/reachgate-evidence-capsule.zip`:一个可移植、可离线验证的捆绑包(包含回执、OpenVEX、SARIF、清单、判定证明 HTML、Judge Pack 以及 `HOW_TO_VERIFY.txt`)—— 具备确定性且被 gitignore 忽略。`reachgate policy explain` 直接从回执中打印记录在案的策略版本、阈值、规则权重和搜索边界,并附带真实的来源信息。`reachgate blame` 仅报告已更改文件的路径重合度,绝不暗示因果关系。`export-vex`/`export-sarif`/`manifest`/`proof` 接受 `--output` 参数以写入任意位置;如果不提供 `--output`,它们会将受版本控制的默认文件写入代码检出目录下的 `docs/proof/` 中。核心的离线 CLI 在仅进行基础安装后也能使用内置的只读证明回执,因此即使在仓库之外,`verify`、`coverage`、各种导出、`contract-check` 和 explorer 功能依然可用。`reachgate scan` **特意设计为非离线模式**:真正的扫描需要实时的 Orbit 连接和 token,因此它被记录为通过 `python -m reachgate.agent` 和 CI 作业(参见 [GitLab CI 设置](docs/GITLAB_CI_SETUP.md))实现的实时工作流。关于证据路由器的机制,请参阅 [集成方案](docs/INTEGRATIONS.md)。
## CI/CD 集成
将 ReachGate 作为建议性的 MR 分诊作业添加到你的流水线中 —— 它会在每次合并请求时运行,并自动发布确定性的分诊回执。内置的作业是非阻塞的(`allow_failure: true`),因此它绝不会自行阻塞合并。这些回执和 `reachgate-receipts.json` 产物是随时可作为拦截门禁的证据:当你决定强制执行时,可以使用 `tools/diff_receipts.py --fail-on-new-reachable` 将回执差异转化为阻塞检查。任何 `NOT_REACHABLE` 判定始终严格限定在证书中记录的已配置搜索边界内。
```
# .gitlab-ci.yml
include:
- project: 'gitlab-ai-hackathon/transcend/39037247'
file: '.gitlab-ci.yml'
ref: main
```
或者从此仓库复制 `.gitlab-ci.yml`。请将 `GITLAB_TOKEN` 设置为具有 `api` 范围且被掩码的 CI/CD 变量。
默认情况下,CI 演示使用以下两个实时的 GitLab 文档站点发现结果。若要进行项目专属运行,请通过 `REACHGATE_FINDINGS_FILE` 将作业指向 GitLab SAST 报告或原生发现 JSON;在此模式下,ReachGate 会从 `reachgate.yml`(或 `REACHGATE_CONFIG`)加载攻击面,而不是使用演示用的入口点发现机制。
真实示例:
- [MR !2](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/2) —— 第一阶段实时引擎验证:该流水线遍历了 Orbit 图谱,并将两项判定结果作为评论发布,每项均附带可达性证书。其中 SSRF 判定为 REACHABLE,路径遍历被穷举确认为 NOT_REACHABLE,并且运行过程上传了 `reachgate-receipts.json`(保存在 `docs/proof/mr2-reachgate-receipts.json 中)。同一个流水线,同一个 Orbit 图谱,在同一个合并请求上得出了截然相反的分诊结果。
- [MR !3](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/3) —— 证明 MR 分诊具备指纹幂等性的实时验证。首次运行创建了两条回执评论;重运行时两个指纹均记录为 `unchanged`(未更改),评论数量保持在 2 条,再次上传了 `reachgate-receipts.json`,并且 MR 流程未创建任何工作项。
(MR !1 是最初的早期演示运行;权威且可验证的证据存在于上述的 MR !2 和 MR !3 中,离线验证器和 `docs/proof/` 也是基于此构建的。)
## 证据展示库
使用单个命令即可自行验证(仅需标准库,无需 token,完全离线):
```
python tools/verify_proof.py
```
它将下方已捕获的回执产物与 MR 评论中声称的判定进行核对 —— 在 MR !2 和 MR !3 之间匹配指纹,
穷举式的 `NOT_REACHABLE`,坦诚的 `UNKNOWN`,且 API 错误为零
—— 并且在导出的 OpenVEX 和 SARIF 存在时,将其与这些回执进行交叉核对。
如需两分钟的重放演示,请参阅 [docs/JUDGE_REPLAY.md](docs/JUDGE_REPLAY.md);
如需完整的审查者演练,请参阅 [docs/JUDGE_PACK.md](docs/JUDGE_PACK.md);
如需可直接复制粘贴的演示命令(包括“尝试伪造安全结果”的 PASS/FAIL 对比),请参阅 [docs/DEMO_COMMANDS.md](docs/DEMO_COMMANDS.md)。
要将两个回执产物作为安全回归审查进行对比,请运行 `python tools/diff_receipts.py OLD NEW`(可选附加 `--fail-on-new-reachable`)。
### 修复验证
`reachgate fixcheck BEFORE.json AFTER.json` 是一个衍生的离线工具层,用于比较两个回执产物,并证明可达性是被 **移除**、**引入**、保持 **未更改**,还是 **无法比较**。它重用现有的回执,绝不重新裁定结论或调用 Orbit。
该工具特意保持保守:**只有当后者的回执是穷举式时**,ReachGate 才能比较两个回执产物并验证可达性是否已被移除。只有当之前的判定是 `REACHABLE`,之后的判定是进行了穷举搜索的 `NOT_REACHABLE`(边界已耗尽,未触发边界限制,API 错误为 0),且策略版本完全一致时,才能断言 `reachability_removed`。如果之后的结果是 `UNKNOWN`、非穷举的 `NOT_REACHABLE`、策略版本不同,或者发现标识不匹配,结果均为 `incomparable` —— 绝不轻易声称已“修复”。
```
reachgate fixcheck before.json after.json # text delta
reachgate fixcheck before.json after.json --format json --output delta.json
reachgate fixcheck before.json after.json --format markdown # MR-comment ready
```
默认情况下,它不会向受版本控制的证明产物写入任何内容;除非指定了 `--output`,否则输出仅发送到标准输出 (stdout)。`markdown` 格式会渲染出可直接用作 MR 评论的差异摘要(包含前后判定、状态、指纹及原因)。位于 `tests/fixtures/fixcheck/` 下标记清晰的 **合成演示夹具** 展示了 `REACHABLE -> 穷举式 NOT_REACHABLE = reachability_removed` 的工作流,且无需实时依赖项;实际使用时则是对比来自真实运行的前后回执。
打开 `docs/judge-proof.html` 或使用 `python tools/build_judge_proof.py` 重新生成它。
| 证据 | 证明了什么 | 本地证明 |
|---|---|---|
| [MR !2](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/2) 回执 | 第一阶段实时引擎验证:CI 作业发布了一份 `REACHABLE` 回执和一份穷举式的 `NOT_REACHABLE` 回执,每份均附带可达性证书。 | `docs/img/mr2-reachable-comment.png`, `docs/img/mr2-not-reachable-comment.png`, `docs/img/mr2-reachable-certificate.png`, `docs/img/mr2-not-reachable-certificate.png` |
| [MR !2](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/2) 产物 | 流水线上传了一个机器可读的 `reachgate-receipts.json` 产物,包含两项判定及证书。 | `docs/img/mr2-artifact-download.png`, `docs/proof/mr2-reachgate-receipts.json` |
| [MR !3](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/3) 重运行 | 第二阶段实时工作流验证:重新运行 MR 分诊时,两个指纹均记录为 `unchanged`,评论数量保持稳定,再次上传了产物,且 MR 流程未创建工作项。 | `docs/img/mr3-pipelines-two-passed-runs.png`, `docs/img/mr3-job-unchanged-ssrf-log.png`, `docs/img/mr3-job-unchanged-pathtraversal-artifact-log.png` |
| [MR !3](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/3) 回执 | 幂等的 MR 流程依然为审查者保留了相同的、可审计的“红/绿”回执及证书。 | `docs/img/mr3-reachable-comment-certificate.png`, `docs/img/mr3-not-reachable-comment-certificate.png` |
| [MR !3](https://gitlab.com/gitlab-ai-hackathon/transcend/39037247/-/merge_requests/3) 产物 | 重新运行仍会发布 `reachgate-receipts.json`,因此即使评论未更改,自动化流程也能获取到最新的产物。 | `docs/img/mr3-artifact-dropdown.png`, `docs/proof/mr3-reachgate-receipts-rerun.json` |
| UNKNOWN 回执 | 实时捕获的坦诚第三种判定:一个真实的已索引文件 (`gem/puma/CVE-2026-47736.yml`) 由于没有代码定义,得出了 `UNKNOWN` / `insufficient_evidence:no_definitions_indexed` 的结果 —— 绝非虚假安全的 NOT_REACHABLE。仅演示了 UNKNOWN 的一种原因,而非全部。 | `docs/proof/unknown-reachgate-receipt.json`, `docs/examples/unknown-finding.json` |
## 架构
```
reachgate.yml
|
v
agent.py -- orchestration entry point
|
+-- orbit_client.py -- Orbit REST API (traversal + neighbors queries)
+-- graph_walker.py -- bounded BFS over DEFINES/IMPORTS/CALLS edges
+-- path_strategy.py -- BFS with termination reporting (why each walk stopped)
+-- certificate.py -- reachability certificate + stable receipt fingerprint
+-- policy_engine.py -- deterministic weighted rules -> verdict + receipt
+-- actions.py -- GitLab work items, MR comments, receipts, JSON artifact
```
策略引擎是完全透明的:`risk_score = 触发的规则权重之和`。模型绝不参与裁定;它只负责解释回执。
## 设置
```
pip install -e ".[dev]"
```
设置环境变量(`GITLAB_TOKEN` 是具有 `api` 范围的 PAT,`GITLAB_PROJECT_ID` 是你的项目 ID):
```
# bash
export GITLAB_TOKEN="glpat-xxxxx"
export GITLAB_PROJECT_ID=""
```
```
# PowerShell
$env:GITLAB_TOKEN = "glpat-xxxxx"
$env:GITLAB_PROJECT_ID = ""
```
运行(在执行 `pip install -e ".[dev]"` 之后):
```
python -m reachgate.agent
```
`python -m reachgate.agent` 运行升级 / 操作流程:一个 `REACHABLE` 发现可以创建 GitLab 工作项,而在 MR 上下文中,它会发布一条普通的(非幂等的)MR 评论。对于合并请求流水线,请使用 `tools/mr_triage.py` 中仅评论、指纹幂等的流程(内置的 CI 作业已默认如此)。
## 实时演示
在一个真实的已索引项目(GitLab 文档站点)上重现可达性反转结果:
```
export GITLAB_TOKEN="glpat-xxxxx"
python tools/demo_e2e.py
```
输出:
- **发现 A** (SSRF, 高危): `REACHABLE` —— 得分 85,距离 `content/frontend/404/archives_redirect.js` 1 跳,依据 `path_found`
- **发现 B** (路径遍历, 中危): `NOT_REACHABLE` —— 得分 8,依据 `no_path_search_exhaustive`:两次遍历均在边界限制内耗尽了边界(已通过 `tools/preflight_bounds.py` 验证)
## Agentic 模式(Duo Chat + Orbit MCP)
ReachGate 还可以在 VS Code 中完全以 Agentic(智能体)方式运行:位于 `skills/reachgate/SKILL.md` 的 [Agent Skill](https://docs.gitlab.com/user/duo_agent_platform/customize/agent_skills/) 将 `/reachgate` 发布为斜杠命令,而 Orbit MCP 服务器赋予了 Duo Chat 实时访问图谱的能力。只需三个步骤:
1. 安装 [GitLab Workflow 扩展](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) 并打开此仓库
2. Orbit MCP 服务器已在 `.gitlab/duo/mcp.json` 中预配置完成 —— 请在 **GitLab: Show MCP Dashboard** 中予以批准
3. 让 Duo Chat 对一个发现执行 `/reachgate` 命令
该 Agent 会对 Orbit 执行真实的 `query_graph` 调用,遍历图谱,并应用与 Python 引擎完全相同的固定规则权重。如果 Duo/VS Code 运行日志或录像正在屏幕上显示,可以将工作项 #3 作为已记录在案的 Agentic 运行输出进行展示;否则请将声明限定为 `/reachgate` 技能及 Orbit MCP 工作流。
## 测试
```
python -m pytest
```
422 个聚焦测试通过(外加默认未选中的 5 个标记为 `standalone` 的安装门禁测试),覆盖了配置加载、发现结果文件加载(GitLab SAST 报告 + 原生 JSON)、策略引擎判定(包含 UNKNOWN)、规则触发、glob 匹配、BFS 路径策略及终止报告、ImportedSymbol 回退机制、导入路径解析、回执渲染(包含 Mermaid 路径图和证书块)、指纹稳定性、指纹幂等的 MR 评论更新、JSON 产物、可达/不可达反转、OpenVEX 导出(包含绝不伪造安全结果的防护机制)、SARIF 2.1.0 导出(codeFlow、明确类型的 UNKNOWN、字节级稳定的输出)、证据清单、包安全的 `reachgate` CLI(包含 `--output` 处理和内置证明数据)、覆盖率/盲点报告(文本/json/html)、确定性证据胶囊、带有防篡改检测的可选 Ed25519 胶囊签名、回归责任路径重合(不声明因果关系)、离线证据浏览器、对抗性的 `reachgate selftest`、带有 Markdown 输出的衍生修复验证证明、机器可检查的 Evidence Contract 验证器、伪造安全拒绝演示夹具、CI 门禁模板以及判定证明页面生成器。请单独运行 standalone 安装门禁测试:`python -m pytest -m standalone`。
## Orbit 注意事项
在构建 ReachGate 的过程中,我们发现了一些文档中未提及的 Orbit 行为:
- **无原生寻路功能。** `neighbors` 查询是基本的遍历原语。ReachGate 在此基础上实现了带有共享缓存的 BFS 算法,并受 `max_hops`、`max_visited` 和 `max_seconds` 的限制。
- **导入关系并不总是体现为边。** 对于 JavaScript,Orbit 可以将导入关系索引为 `ImportedSymbol` *节点*(包含 `file_path`、`identifier_name`、`import_path`、`import_type`),而不是 IMPORTS/CALLS 边。ReachGate 的技能和引擎均将匹配到的 `ImportedSymbol` 视为一阶路径证据。
- **Orbit MCP 服务器封装了工具。** `https://gitlab.com/api/v4/orbit/mcp` 暴露了 `list_commands` + `invoke_command` 接口;而 `query_graph` 和 `get_graph_schema` 则包含在 `invoke_command` 内部。`.gitlab/duo/mcp.json` 中的配置要求显式声明 `"type": "http"` 字段。
## 适用范围与局限性
- 攻击面来源于 `reachgate.yml`。ReachGate 绝不臆测从外部可达的内容,因此不完整的入口点 glob 可能导致假阴性;在信任新项目的判定结果之前,请先运行 `tools/reachgate_doctor.py`。
- 路径的准确性取决于 Orbit 的索引深度及其对目标仓库的语言覆盖率。`ImportedSymbol` 回退机制可以处理 Orbit 作为节点暴露的导入关系,但语言覆盖范围仍然取决于 Orbit 索引的内容。
- `NOT_REACHABLE` 仅在证书中记录的已配置搜索边界内有效:每一次遍历都在边界限制内运行直到边界耗尽,且 API 错误数为零。任何未达标的项 —— 跳数限制、节点预算、超时、查询失败 —— 都会作为 `UNKNOWN` 上报,并在回执中注明确切原因。
- 当前的 Orbit 客户端是同步的;异步请求和连接池将作为未来针对更大规模部署的改进工作。
## 许可证
MIT。版权所有 (c) 2026 Mohamed Azahrioui。
标签:GitLab, 代码安全, 漏洞可达性分析, 漏洞枚举, 逆向工具, 静态应用安全测试