anupamojha-eng/agentic-remediation-factory
GitHub: anupamojha-eng/agentic-remediation-factory
Sentinel 是一款自主式 CVE 漏洞修复工具,能自动修补构建文件与源代码、在 Docker 沙箱中验证构建并提交修复 PR。
Stars: 0 | Forks: 0
# Sentinel — 自主 CVE 修复
[](LICENSE)
[](https://www.python.org/)
[](https://pypi.org/project/sentinel-remediation/)
[](#supported-ecosystems)
**Sentinel 打通了 CVE 修复的“最后一公里”。**
大多数工具只会告诉你哪里有漏洞。Sentinel 则会修复它 —— 在无需人工干预的情况下,开启一个经过验证且通过构建的 pull request。
```
CVE detected → fork repo → resolve full dep tree → query OSV →
patch build files + source code → verify build in sandbox → open PR
```
**Sentinel 开启的实时演示 PR:**
- Java: [monitorjbl/excel-streaming-reader#271](https://github.com/monitorjbl/excel-streaming-reader/pull/271) — Log4Shell + Apache POI CVE,修补了 `pom.xml` + Java 源码
- Python: [vulnerable-data-pipeline#2](https://github.com/anupamojha-eng/vulnerable-data-pipeline/pull/2) — 5 个 PyPI CVE,修补了 `requirements.txt` + `config.py` + `cache.py`
## 安装说明
```
pip install sentinel-remediation
```
需要在本地运行 Docker。在 `.env` 文件中设置凭证(参见[快速开始](#quick-start))。
## 用法
### 修复单个仓库中的 CVE
```
# 修复任何公开 GitHub repo 中的 CVE
sentinel fix-cve --repo https://github.com/org/repo
# 针对特定 branch
sentinel fix-cve --repo https://github.com/org/repo --branch develop
# 强制使用特定 LLM provider
sentinel fix-cve --repo https://github.com/org/repo --llm gemini
# 覆盖 model
sentinel fix-cve --repo https://github.com/org/repo --llm anthropic --model claude-sonnet-4-6
```
Sentinel 会 fork 该仓库,开启一个 sandbox 容器,执行扫描、修补、验证,并开启一个 PR —— 通常在 3 分钟内完成。
### 扫描整个 GitHub 组织
```
# 扫描所有 repo — 生成 HTML 报告,不创建 PR(默认安全)
sentinel scan-org --org my-org
# 按 severity 和语言过滤
sentinel scan-org --org my-org --severity CRITICAL HIGH --language java python
# 将范围限定为匹配特定 pattern 的 repo
sentinel scan-org --org my-org --include "platform-*" --exclude "*-test"
# 扫描所有 CRITICAL 发现并创建修复 PR
sentinel scan-org --org my-org --severity CRITICAL --create-prs
# 将报告保存到特定路径,同时输出 JSON
sentinel scan-org --org my-org --report security-report.html --json-out results.json
# GitHub Enterprise
sentinel scan-org --org my-org --github-url https://github.mycompany.com/api/v3
```
`scan-org` **默认以 dry-run 模式运行** —— 它会扫描每个仓库并生成报告,但不会触及任何代码或开启任何 PR。传递 `--create-prs` 参数以启用完整修复。
HTML 报告会显示:
- 摘要:已扫描的仓库、受影响的仓库、按严重程度划分的 CVE、已创建的 PR
- 各仓库的 CVE 表格,包含 advisory ID、受影响的包、修复版本
- 干净的仓库列表
- 任何扫描错误
## 为什么与众不同
| 工具 | 检测漏洞 | 修补构建文件 | 修补源代码 | 验证构建 | 开启 PR |
|---|---|---|---|---|---|
| Dependabot | ✅ | ✅ | ❌ | ❌ | ✅ |
| Snyk | ✅ | 部分 | ❌ | ❌ | ✅ |
| Renovate | ✅ | ✅ | ❌ | ❌ | ✅ |
| **Sentinel** | ✅ | ✅ | ✅ | ✅ | ✅ |
Dependabot 只会升级版本。Sentinel 不仅升级版本,*还*会修复代码中危险的调用点 —— 然后在触及你的仓库之前证明构建仍然通过。
## Sentinel 的功能
### 三层修复
**第一层 — 传递性 CVE 检测**
使用原生构建工具解析*完整*的依赖树(不仅仅是已声明的依赖),然后针对每个包(包括传递依赖)查询 OSV REST API。捕获那些通过框架悄悄引入的 CVE。
**第二层 — 构建文件修补**
LLM 将 `pom.xml`、`build.gradle`、`build.gradle.kts`、`gradle/libs.versions.toml`、`requirements.txt` 和 `pyproject.toml` 升级到最低安全版本。处理版本变量、BOM 导入、Kotlin DSL 和 Gradle 版本目录。
**第三层 — 源代码修补**
通过 grep 在源文件中搜索危险的调用点模式 —— 包括特定于 CVE 的模式和一组始终检查的内置反模式:
**Python 反模式(始终检查):**
| 模式 | 风险 |
|---------|------|
| `yaml.load(` | 通过不安全的反序列化引发 RCE |
| `pickle.loads(` / `pickle.load(` | 通过反序列化引发 RCE |
**Java 反模式(始终检查):**
| 模式 | 风险 |
|---------|------|
| `new ObjectInputStream(` | Java 反序列化 RCE |
| `Runtime.getRuntime().exec(` | OS 命令注入 |
| `new ProcessBuilder(` | OS 命令注入 |
| `MessageDigest.getInstance("MD5"` | 弱哈希 |
| `MessageDigest.getInstance("SHA-1"` | 弱哈希 |
| `new Random(` | 不安全的随机性 |
| `DocumentBuilderFactory.newInstance(` | XML External Entity (XXE) |
| `XMLInputFactory.newInstance(` | XML External Entity (XXE) |
### PR 审计追踪
Sentinel 开启的每个 PR 都包含一条结构化的证据链:
- 处理的 CVE
- 发生变更的文件及其匹配到的模式
- 构建验证状态和尝试次数
- 截断的构建输出(可折叠)
- 时间戳
### 合并前验证
在开启 PR 之前,每个补丁都会在一个隔离的 Docker sandbox(JDK 17 + Maven/Gradle,Python 3 + pip)中进行测试。如果构建失败,Sentinel 会提取错误,将其反馈给 LLM,并最多重试 3 次。
### 无法开启 PR 时的兜底方案
如果 GitHub API 不可用或受到速率限制,Sentinel 会从容器中提取 diff 并将其作为 `sentinel-patch-.diff` 在本地保存,同时附带应用说明。修复内容永远不会丢失。
## 支持的生态系统
| 构建系统 | 检测 | 传递性扫描 | 源代码修补 | 验证命令 |
|---|---|---|---|---|
| Maven (`pom.xml`) | ✅ | `mvn dependency:list` | ✅ `.java` | `mvn clean compile` |
| Gradle Groovy | ✅ | `gradle dependencies` | ✅ `.java` | `gradle compileJava` |
| Gradle KTS | ✅ | `gradle dependencies` | ✅ `.java` | `gradle compileJava` |
| Gradle 版本目录 | ✅ | `gradle dependencies` | ✅ `.java` | `gradle compileJava` |
| `requirements.txt` | ✅ | `pip install` + `pip list` | ✅ `.py` | `pip install && pytest` |
| `pyproject.toml` | ✅ | `pip install` + `pip list` | ✅ `.py` | `pip install && pytest` |
## 快速开始
```
# 1. 安装
pip install sentinel-remediation
# 2. 设置 credentials
cp .env.example .env
# 编辑 .env — 添加 GITHUB_TOKEN 和至少一个 LLM key:
# ANTHROPIC_API_KEY (Claude — 推荐,准确率最高)
# GEMINI_API_KEY (Gemini Flash — 高性价比替代方案)
# 3. 构建 sandbox image(一次性,约 5 分钟)
docker build -t cve-fixer-sandbox:latest sandbox/
# 4. 运行
sentinel fix-cve --repo https://github.com/anupamojha-eng/vulnerable-data-pipeline
```
### 通过 API 运行(FastAPI 服务器)
```
python3 orchestrator/driver.py # starts on :8080
curl -X POST http://localhost:8080/remediate \
-H "Content-Type: application/json" \
-d '{"repo_url": "https://github.com/org/repo", "target_tag": "main"}'
```
## 架构
```
┌─────────────────────────────────────────────────────────┐
│ orchestrator/ │
│ │
│ cli.py `sentinel` CLI — fix-cve + scan-org │
│ driver.py FastAPI service — HTTP entry point │
│ │
│ org_scanner.py OrgScanner │
│ ├─ scan() iterate repos → quick scan │
│ ├─ _detect_and_extract_deps() GitHub contents API │
│ ├─ _query_osv() OSV batch API, severity map │
│ └─ create_prs_for_results() delegate to factory │
│ │
│ report.py ReportGenerator │
│ ├─ generate_html() professional HTML report │
│ └─ generate_json() machine-readable JSON output │
│ │
│ factory.py RemediationFactory │
│ ├─ _detect_build_system() Maven/Gradle/Python │
│ ├─ _scan_internal() resolve deps → OSV API │
│ │ └─ _scan_with_osv_scanner() fallback │
│ ├─ _get_verify_command() build tool selector │
│ └─ retry loop (MAX=3) smart error routing │
│ │
│ remediator.py RemediationActor │
│ ├─ get_vulnerable_code_files() grep → source files │
│ ├─ get_affected_java_files() parse compile errors │
│ ├─ autonomous_patch() LLM → write → verify │
│ ├─ create_pull_request() branch → push → PR │
│ ├─ _build_pr_body() audit trail │
│ └─ _patch_fallback() save diff locally │
│ │
│ llm_client.py SecurityAgentClient │
│ ├─ _AnthropicProvider Claude Opus 4.8 (default) │
│ ├─ _GeminiProvider Gemini 2.5 Flash (alt) │
│ ├─ get_vulnerable_patterns() CVE → grep strings │
│ └─ get_remediation_plan() full patch plan │
│ │
│ telemetry.py Observability │
│ ├─ setup_telemetry() OTLP or console export │
│ ├─ TokenUsageTracker per-run token + cost report │
│ └─ record_llm_tokens() OTel counters + cost tracker │
└─────────────────────────────────────────────────────────┘
│
│ Docker SDK
▼
┌─────────────────────────────────────────────────────────┐
│ sandbox/ (Docker image) │
│ │
│ JDK 17 · Maven 3.9 · Gradle 9.4 · OSV-Scanner │
│ Python 3 · pip3 · git │
│ │
│ Isolated per-run: no shared state between remediations │
└─────────────────────────────────────────────────────────┘
```
## 运行测试
```
# 快速 unit test(无需 Docker,无需 API key)
pytest tests/test_python_support.py tests/test_patching.py \
tests/test_build_detection.py tests/test_scanner.py -v
# Docker e2e — 需要 Docker + LLM key
pytest tests/test_e2e_docker.py -v -s # Java
pytest tests/test_e2e_python_docker.py -v -s # Python
# Source patching e2e
pytest tests/test_java_source_patching_e2e.py -v -s
pytest tests/test_python_source_patching_e2e.py -v -s
# 完整 pipeline — 需要 Docker + LLM key + GITHUB_TOKEN
pytest tests/test_real_repo_e2e.py -v -s # Java
pytest tests/test_real_python_repo_e2e.py -v -s # Python
```
## 可观测性
每次运行都会发出 OTel traces 和 metrics。设置 `OTEL_EXPORTER_OTLP_ENDPOINT` 以将其发送到任何后端(Grafana、Datadog、Honeycomb)。如果未设置,则默认输出到控制台。
### Traces
| Span | Attributes |
|------|-----------|
| `sentinel.remediation` | `repo`, `branch`, `build_system`, `cve_count`, `pr_url` |
| `sentinel.scan` | `cve_count`, `cves` |
| `sentinel.patch` | `attempt` |
| `sentinel.llm_call` | `stage`, `model` |
| `sentinel.verify` | `attempt`, `exit_code` |
| `sentinel.pr_create` | `pr_url`, `success` |
### Metrics
| Metric | 类型 | 标签 |
|--------|------|------|
| `sentinel.remediation_duration_seconds` | histogram | `build_system` |
| `sentinel.scan_duration_seconds` | histogram | `build_system` |
| `sentinel.verify_duration_seconds` | histogram | `build_system`, `attempt` |
| `sentinel.cves_found_total` | counter | `build_system` |
| `sentinel.patch_attempts_total` | counter | `build_system`, `attempt` |
| `sentinel.pr_opened_total` | counter | `build_system`, `success` |
| `sentinel.llm_tokens_total` | counter | `model`, `stage`, `repo`, `type` |
| `sentinel.llm_cost_usd_total` | counter | `model`, `stage`, `repo` |
### Token 及成本报告
在每次运行结束时打印 —— 显示各阶段的 token 使用量、cache 命中情况、节省的 cache 成本(美元)以及总成本:
```
════════════════════════════════════════════════════════════════════════════════
Sentinel Token & Cost Report
Repo: https://github.com/org/repo
════════════════════════════════════════════════════════════════════════════════
Stage Model In Out Cache↓ Cache↑ Cost
──────────────────────────────────────────────────────────────────────────────
pattern_detect claude-opus-4-8 1,234 89 — — $0.0185
patch claude-opus-4-8 12,456 823 — 8,234 $0.0234
cache saved: -$0.1235
──────────────────────────────────────────────────────────────────────────────
TOTAL 13,690 912 — 8,234 $0.0419
Cache savings:.................................... -$0.1235
Net cost (after savings):......................... $0.0419
════════════════════════════════════════════════════════════════════════════════
```
Cache↓ = 从 cache 读取的 token · Cache↑ = 写入 cache 的 token
## 技术栈
- **CLI**: Click — `sentinel fix-cve --repo `
- **Orchestrator**: Python / FastAPI — 容器生命周期、重试循环、GitHub API
- **Sandbox**: Docker(JDK 17、Maven 3.9.15、Gradle 9.4.1、OSV-Scanner、Python 3 + pip)
- **Scanning**: `mvn dependency:list` / `gradle dependencies` / `pip list` + OSV REST API;OSV-Scanner(兜底)
- **Reasoning**: 多提供商 — Anthropic Claude(默认)或 Google Gemini
- **Version control**: PyGithub — fork、branch、commit、PR
### LLM 提供商对比
| | Claude Opus 4.8(默认) | Gemini 2.5 Flash |
|---|---|---|
| 复杂的多文件补丁 | 优秀 | 良好 |
| JSON 输出可靠性 | 优秀 | 良好 |
| 重试时的 prompt caching | 是(节省约 80%) | 否 |
| 速度 | 中等 | 快 |
| 单次运行成本 | 较高 | 较低 |
为 Claude 设置 `ANTHROPIC_API_KEY`,为 Gemini 设置 `GEMINI_API_KEY`,或者同时设置两者(同时设置时 Claude 优先)。
使用 `ANTHROPIC_MODEL=claude-sonnet-4-6` 或 `GEMINI_MODEL=gemini-2.5-pro` 进行覆盖。
## 微调的本地模型(路线图)
长期目标是打造一个 `sentinel-patcher` 模型 —— 一个专门针对 CVE 修补进行微调的小型量化模型 —— 直接嵌入到 Docker sandbox 镜像中。这消除了所有的外部 API 调用,并使 Sentinel 能够完全在气隙环境下运行。
### MLOps pipeline
```
┌──────────────────────────────────────────────────────────────────────┐
│ DATA COLLECTION built ✅ │
│ │
│ training/collect_osv.py OSV data dumps (Maven + PyPI) │
│ └─ synthetic pairs: vulnerable build file → patched file │
│ │
│ training/collect_github.py GitHub security fix PRs │
│ └─ real before/after diffs from merged security PRs │
│ │
│ training/sentinel_logger.py Self-improvement loop │
│ └─ every verified Sentinel run → appended to train set │
│ │
│ All output → training/data/train.jsonl (chat JSONL format) │
└──────────────────────────┬───────────────────────────────────────────┘
│ ~4,000+ examples
▼
┌──────────────────────────────────────────────────────────────────────┐
│ FINE-TUNING built ✅ │
│ │
│ training/train.py Unsloth QLoRA on Qwen2.5-Coder-7B │
│ └─ runs anywhere with GPU: Colab, Modal, RunPod │
│ └─ exports Q4_K_M GGUF (~4GB) │
│ └─ pushes to Hugging Face Hub │
│ │
│ training/train_modal.py Serverless GPU wrapper │
│ └─ modal run training/train_modal.py │
│ └─ spins up A100 on demand (~$5/run, ~30 min) │
│ └─ tears down automatically when done │
│ │
│ Triggered by: retrain.yml GitHub Actions │
│ └─ on push to sentinel_self.jsonl (new verified patches) │
│ └─ weekly cron (Sunday 2am UTC, fresh OSV data) │
│ └─ manually via workflow_dispatch │
└──────────────────────────┬───────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────┐
│ EVALUATION (CI QUALITY GATE) built ✅ │
│ │
│ training/evaluate.py runs inference on held-out eval.jsonl │
│ │
│ Scores each prediction on 5 dimensions: │
│ json_valid output parses as valid JSON │
│ schema_valid patches / changes / analysis keys present │
│ files_match all expected files patched │
│ version_correct fixed version present, vulnerable version gone │
│ no_regression non-security lines preserved unchanged │
│ │
│ pass@1 = all 5 pass threshold: 80% │
│ │
│ GitHub Actions runs this on every model update + weekly schedule │
│ CI fails if pass@1 < threshold → previous model kept │
└──────────────┬───────────────────────────┬──────────────────────────┘
│ pass ✅ │ fail ❌
▼ ▼
┌──────────────────────────────┐ ┌────────────────────────────────┐
│ DEPLOY planned⏳│ │ ALERT │
│ │ │ │
│ Published to HF Hub: │ │ CI fails, previous model kept │
│ anupamojha/sentinel-patcher │ └────────────────────────────────┘
│ │
│ retrain.yml rebuilds Docker │
│ image with new model ref │
│ │
│ Uses llama.cpp server at │
│ localhost:8080 — zero │
│ external API calls │
└──────────────────────────────┘
│
▼ feedback
┌──────────────────────────────────────────────────────────────────────┐
│ SELF-IMPROVEMENT LOOP built ✅ │
│ │
│ Set SENTINEL_TRAINING_LOG=training/data/sentinel_self.jsonl │
│ Every verified patch (build passes) → appended to training data │
│ When dataset grows by 500+ examples → trigger fine-tuning again │
│ │
│ Model improves on the exact CVEs it encounters in production │
└──────────────────────────────────────────────────────────────────────┘
```
### 如今运行该 pipeline
```
# 1. 收集训练数据(来自 OSV + GitHub 的约 4,000 个示例)
python training/collect_osv.py --ecosystems Maven PyPI --limit 2000 \
--out training/data/osv.jsonl
GITHUB_TOKEN=... python training/collect_github.py --limit 200 \
--out training/data/github.jsonl
# 2. 拆分为 train / eval
python training/evaluate.py --split training/data/osv.jsonl \
--eval-out training/data/eval.jsonl \
--train-out training/data/train.jsonl
# 3a. 本地训练(需要 GPU — Google Colab 或类似环境)
HF_TOKEN=... python training/train.py \
--data training/data/train.jsonl \
--hf-repo anupamojha/sentinel-patcher-7b \
--push-to-hub
# 3b. 在 Modal cloud GPU 上训练(约 $5,A100,约 30 分钟 — 无需本地 GPU)
pip install modal && modal setup
modal run training/train_modal.py \
--hf-repo anupamojha/sentinel-patcher-7b
# 4. 评估 model 质量(CI gate)
ANTHROPIC_API_KEY=... python training/evaluate.py \
--eval-set training/data/eval.jsonl \
--provider anthropic --threshold 0.75
# 5. 在生产 run 中启用自我改进
SENTINEL_TRAINING_LOG=training/data/sentinel_self.jsonl \
sentinel fix-cve --repo https://github.com/org/repo
```
**CI 工作流:**
- `.github/workflows/model-eval.yml` — 每次推送到 `training/` 时运行评估,每周一次
- `.github/workflows/retrain.yml` — 当 `sentinel_self.jsonl` 增加或每周一次时触发完整重新训练;需要在 GitHub 中配置 `MODAL_TOKEN_ID`、`MODAL_TOKEN_SECRET`、`HF_TOKEN` secrets
## 路线图
- [ ] 通过 llama.cpp 服务器将模型嵌入到 Docker sandbox 镜像中(已构建 train.py + train_modal.py)
- [ ] 将 `SENTINEL_LOCAL_MODEL` 环境变量作为第三个提供商接入 llm_client.py
- [ ] `sentinel fix-antipatterns` — 独立的反模式修复,无需 CVE 触发
- [ ] OSV 离线 cache —— 从 OSV 数据转储构建的本地 SQLite,无需 API 调用
- [ ] Go (`go.mod`) 和 Rust (`Cargo.toml`) 生态系统支持
- [ ] GitHub Actions 集成 —— 在 Dependabot 告警 webhook 上触发
- [ ] 容器镜像扫描 —— 与 Chainguard Wolfi 或 distroless 基础镜像搭配使用
## 安全
有关漏洞披露政策,请参见 [SECURITY.md](SECURITY.md)。
## 许可证
Apache License 2.0 — 详见 [LICENSE](LICENSE)。
版权所有 2026 Anupam Ojha
标签:AI编程助手, DevSecOps, GPT, 上游代理, 代码修复, 依赖更新, 后台面板检测, 模块化设计, 漏洞管理, 用户代理, 自动化修复, 请求拦截, 逆向工具