RunTimeAdmin/PACKRAI
GitHub: RunTimeAdmin/PACKRAI
一款基于 lock file 解析的超高速 SBOM 生成与 CVE 暴露查询工具,支持生成 CycloneDX 和 SPDX 标准格式。
Stars: 0 | Forks: 0
# PackrAI
仅需一条命令,即可从任何 GitHub 仓库或本地项目生成准确、合规的 SBOM。
```
npx packrai RunTimeAdmin/myapp@v2.1.0
```
在 5 秒内生成 **CycloneDX 1.6** 和 **SPDX 2.3**。无需 Docker。无需代理。无需配置文件。
## 快速开始
```
# 扫描 GitHub repo 的特定 tag
npx packrai owner/repo@v1.2.0
# 扫描默认分支
npx packrai owner/repo
# 扫描本地目录
npx packrai ./my-project
# 私有 repo (自动使用 $GITHUB_TOKEN)
npx packrai owner/private-repo
# 跳过漏洞查找 (更快, offline-safe)
npx packrai owner/repo --no-vulns
```
输出文件将写入当前目录:
```
bom.cyclonedx.json ← CycloneDX 1.6
bom.spdx.json ← SPDX 2.3
```
## 为什么选择 PackrAI
| | PackrAI | Syft | Trivy |
|---|---|---|---|
| **速度** | **250–465ms** | 9–28s | 10–87s |
| **方式** | Lock-file 解析 | 文件系统扫描 | 文件系统 + 镜像扫描 |
| **传递依赖** | 完整依赖图 | 部分 | 部分 |
| **依赖图** | ✅ | ✅ | ❌ |
| **零配置** | ✅ | ❌ | ❌ |
| **GitHub URL** | ✅ | ❌ | ❌ |
| **集中式仓库** | ✅ (自托管) | ❌ | ❌ |
**为什么 lock file 优于文件系统扫描:**
Lock file 就是已解析的依赖图。它们是权威的、确定性的且精确的 —— 没有启发式方法,没有猜测,也没有重复计算。Syft 和 Trivy 会遍历文件系统并推断包,这对于传递依赖来说速度更慢且准确性更低。
## 基准测试结果
PackrAI 在所有三个基准测试仓库中均低于 500ms,因为它直接读取已解析的 lock file,而不是遍历文件系统或执行更广泛的镜像式分析。在 `nestjs/nest` 上,它耗时 463ms 完成,而 Syft 为 27.7s,Trivy 为 86.5s —— 在此基准测试设置下,速度比 Syft 快 60 倍,比 Trivy 快 187 倍。
| 仓库 | 生态系统 | PackrAI | Syft | Trivy |
|------|-----------|---------|------|-------|
| `nestjs/nest` | npm | **463ms** | 27 731ms | 86 550ms |
| `psf/requests` | Python | **251ms** | 9 330ms | 10 502ms |
| `BurntSushi/ripgrep` | Rust | **268ms** | 11 823ms | 15 425ms |
不同的工具解决不同的问题。Syft 和 Trivy 检查更广泛的文件系统和容器上下文 —— 这项工作确实更复杂,它们较慢的速度并不纯粹是额外开销。PackrAI 有意将范围缩小:基于 lock file 快速、确定性地生成 SBOM。
使用以下命令复现:
```
docker pull anchore/syft && docker pull aquasec/trivy
npm run bench
```
## 支持的生态系统
| 生态系统 | Lock File | 传递依赖 | 备注 |
|-----------|-----------|-------------|-------|
| **npm** | `package-lock.json` v1/v2/v3 | ✅ 完整依赖图 | 感知 Hoisting 的解析器 |
| **npm** | `pnpm-lock.yaml` v6/v9 | ✅ 完整依赖图 | Peer 后缀处理 |
| **npm** | `yarn.lock` v1 | ✅ 完整依赖图 | |
| **Python** | `poetry.lock` | ✅ 完整依赖图 | |
| **Python** | `Pipfile.lock` | ✅ 完整依赖图 | |
| **Python** | `requirements.txt` | ⚠️ 仅直接依赖 | 缺失传递依赖时发出警告 |
| **Rust** | `Cargo.lock` | ✅ 完整依赖图 | SHA-256 校验和 |
| **Go** | `go.mod` + `go.sum` | ✅ 完整依赖图 | 直接/间接依赖检测 |
| **Java** | `pom.xml` | ✅ + `mvn` 传递依赖 | 解析 `${property}` 变量 |
| **Java** | `gradle.lockfile` | ✅ 完整依赖图 | 感知 Scope;需要 `--write-locks` |
| **.NET** | `packages.lock.json` | ✅ 完整依赖图 | SHA-512 哈希;需要 `RestorePackagesWithLockFile` |
| **Ruby** | `Gemfile.lock` | ✅ 完整依赖图 | 通过 Bundler 获取 SHA-1 校验和 |
| **PHP** | `composer.lock` | ✅ 完整依赖图 | 来自从包元数据的 MIT/BSD 许可证 |
| **Swift** | `Package.resolved` | ⚠️ 仅直接依赖 | 格式中无依赖图;git SHA 哈希 |
| **Dart/Flutter** | `pubspec.lock` | ⚠️ 仅直接依赖 | 格式中无依赖图;SHA-256 哈希 |
支持 Monorepo —— PackrAI 会递归遍历最深 4 层目录,并按目录对 lock file 进行去重。
## 输出格式
### CycloneDX 1.6
```
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"components": [
{
"type": "library",
"name": "express",
"version": "4.18.2",
"purl": "pkg:npm/express@4.18.2",
"licenses": [{ "license": { "id": "MIT" } }],
"hashes": [{ "alg": "SHA-512", "content": "..." }],
"scope": "required"
}
],
"dependencies": [
{ "ref": "pkg:npm/express@4.18.2", "dependsOn": ["pkg:npm/accepts@1.3.8"] }
]
}
```
### SPDX 2.3
```
{
"spdxVersion": "SPDX-2.3",
"packages": [...],
"relationships": [
{ "spdxElementId": "SPDXRef-...", "relationshipType": "DEPENDS_ON", "relatedSpdxElement": "SPDXRef-..." }
]
}
```
这两种格式都包含:
- 所有 CISA 2025 最低要求元素
- 完整的传递依赖关系
- 加密哈希(来自 lock file 的 SHA-256 / SHA-512)
- SPDX 许可证标识符(通过 [deps.dev](https://deps.dev) 丰富)
- OSV 漏洞数据(通过 [osv.dev](https://osv.dev) 丰富)
- SBOM 质量评分(0–100)
## CLI 参考
```
packrai [options]
Arguments:
source Local path, owner/repo[@ref], or https://github.com/... URL
Options:
-o, --out Output directory (default: current directory)
-n, --name Project name override
-v, --ver Version override
-a, --author Author or organisation name
--token GitHub token for private repos (or set $GITHUB_TOKEN)
--format both | cyclonedx | spdx (default: both)
--no-vulns Skip OSV vulnerability enrichment
--no-licenses Skip deps.dev license enrichment
--no-recursive Do not recurse into subdirectories
--json Print summary as JSON (machine-readable, for CI)
-V, --version Print version
-h, --help Show help
```
### 退出码
| 代码 | 含义 |
|------|---------|
| `0` | 成功 —— 未发现严重漏洞 |
| `1` | 发现严重漏洞(仅限人类可读输出模式;在 CI 中使用 `--json` 获取非阻塞输出) |
| `2` | 致命错误 —— 未找到 lock file、克隆失败或不可恢复的解析错误 |
## GitHub Actions
将以下内容放入 `.github/workflows/sbom.yml`:
```
name: SBOM
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: PackrAI
uses: packrai/sbom-action@v1
with:
format: both
fail-on-critical: true
upload-artifact: true
```
在每次 pull request 时,PackrAI 将:
- 生成 CycloneDX + SPDX SBOM
- 向 PR 发布总结评论
- 将 SBOM 作为 artifacts 上传(保留 90 天)
- 如果发现严重漏洞则阻止合并
请参阅 [`examples/github-workflow.yml`](examples/github-workflow.yml) 获取完整的带注释示例。
## 核心平台(自托管)
PackrAI 包含一个用于组织级 SBOM 管理的 API 服务器 —— 这一层用于解答:
### 启动 API
**使用 Docker(推荐):**
```
cp .env.example .env # set ADMIN_KEY and POSTGRES_PASSWORD
docker compose up -d
```
API 可在 `http://localhost:3080` 访问。Postgres 数据持久化存储于命名卷中。
**不使用 Docker(需要 Postgres):**
```
cp .env.example .env # set DATABASE_URL and ADMIN_KEY
npm run serve
```
### 关键端点
```
# 导入 SBOM (由 GitHub Action 自动调用)
POST /api/v1/ingest
# 搜索:哪些 app 暴露于 CVE?
GET /api/v1/search?cve=CVE-2021-44228
# 列出所有 app 及其风险摘要
GET /api/v1/apps
# 组织级风险报告
GET /api/v1/report
```
请参阅 [`src/api/schema.sql`](src/api/schema.sql) 获取完整的数据库 schema。
## 开发
```
# Clone 并安装
git clone https://github.com/RunTimeAdmin/PACKRAI
cd PACKRAI
npm install
# Unit tests (无外部依赖)
npm test
# 端到端 integration test (需要先运行 docker compose up -d)
npm run e2e
# PackrAI vs Syft vs Trivy Benchmark
npm run bench
# 本地运行 CLI
node bin/packrai.js owner/repo --no-vulns
# 启动 API + Postgres
cp .env.example .env # edit ADMIN_KEY and POSTGRES_PASSWORD
docker compose up -d
```
### 项目结构
```
packrai/
├── bin/packrai.js CLI entry point
├── src/
│ ├── pipeline.js Orchestration (detect → parse → enrich → generate)
│ ├── component.js Shared component model + purl generation
│ ├── github.js GitHub URL parsing + shallow clone
│ ├── osv.js OSV vulnerability enrichment (batch API)
│ ├── licenses.js License enrichment (deps.dev API)
│ ├── parsers/
│ │ ├── npm.js package-lock.json v1/v2/v3, yarn.lock
│ │ ├── pnpm.js pnpm-lock.yaml v6/v9
│ │ ├── python.js poetry.lock, Pipfile.lock, requirements.txt
│ │ ├── cargo.js Cargo.lock
│ │ ├── golang.js go.mod + go.sum
│ │ ├── maven.js pom.xml
│ │ ├── gradle.js gradle.lockfile
│ │ ├── dotnet.js packages.lock.json (NuGet)
│ │ ├── ruby.js Gemfile.lock
│ │ ├── php.js composer.lock
│ │ ├── detect.js Lock file auto-detection + deduplication
│ │ └── index.js Parser dispatcher
│ ├── generators/
│ │ ├── cyclonedx.js CycloneDX 1.6 generator
│ │ └── spdx.js SPDX 2.3 generator
│ └── api/
│ ├── server.js Express API server
│ ├── db.js PostgreSQL connection pool
│ └── schema.sql Database schema
├── scripts/
│ └── benchmark.js Benchmark PackrAI vs Syft vs Trivy
├── Dockerfile Multi-stage API server image
├── docker-compose.yml API + Postgres stack
├── tests/
│ ├── parsers.test.js Parser unit tests (66 tests)
│ └── fixtures/ Sample lock files for testing
├── examples/
│ └── github-workflow.yml Copy-paste GitHub Actions workflow
└── action.yml GitHub Action definition
```
### 添加新的生态系统
1. 编写 `src/parsers/.js` —— 导出一个返回 `Component[]` 的 `parse*` 函数
2. 在 `src/parsers/detect.js` (`LOCK_FILE_PATTERNS`) 中添加检测条目
3. 在 `src/parsers/index.js` 中添加调度程序用例
4. 在 `src/component.js` `makePurl()` 中添加 `case ''`
5. 在 `tests/fixtures/` 中添加 fixture,并在 `tests/parsers.test.js` 中添加测试
## 标准合规性
- **CycloneDX 1.6** — OWASP BOM 规范
- **SPDX 2.3** — Linux Foundation SPDX 规范
- **NTIA 最低要求元素** — 包含所有 7 个必填字段
- **CISA 2025 最低要求元素** — purl、哈希、许可证、关系、元数据
- **EO 14028** — 关于供应链安全的美国行政令
## 已知局限性
PackrAI 是一款 **lock-file 优先** 的 SBOM 生成器。这使其在处理依赖图时快速且准确,但它并不能完全替代 Syft 或 Trivy 等文件系统扫描器。
### 未涵盖的内容
| 领域 | 详情 |
|------|--------|
| **容器/镜像扫描** | PackrAI 不会扫描 Docker 镜像层或操作系统级别的包。对于容器 SBOM,请与 Trivy 结合使用。 |
| **编译后的二进制文件** | SBOM 是从源码 lock file 生成的,而不是通过检查编译后的输出或 vendored 二进制文件生成的。 |
| **动态加载的插件** | 仅在运行时或延迟加载的依赖(未反映在 lock file 中)将不会出现。 |
| **无 lock file → 无 SBOM** | 如果项目未提交 lock file(一些库维护者有意这样做),PackrAI 无法生成传递 SBOM。`requirements.txt` 仅生成直接依赖的输出并附带警告。 |
### 各生态系统的局限性
| 生态系统 | 局限性 |
|-----------|-----------|
| **Java (Maven)** | 传递依赖解析需要在本地安装 `mvn`。如果没有它,PackrAI 将仅返回直接依赖并打印警告。 |
| **Swift / Dart** | `Package.resolved` 和 `pubspec.lock` 不包含完整的依赖图 —— 只有扁平化的解析集。这些生态系统不支持 `is_direct` 检测。 |
| **Gradle** | 要求在项目中运行过 `--write-locks` 以生成 `gradle.lockfile`。没有 lock file 的项目将被跳过。 |
| **.NET** | 要求项目中包含 `RestorePackagesWithLockFile=true`。必须提交 `packages.lock.json`。 |
### 基准测试上下文
速度比较反映了特定场景:带有已提交 lock file 的浅克隆仓库。Syft 和 Trivy 在此设置中通过 Docker 运行,这增加了约 3-5 秒的容器启动开销。原生安装会稍快一些 —— 但对于包含 lock file 的仓库来说,速度依然要慢一个数量级。有关完整的警告说明,请参阅基准测试结果部分。
## 许可证
MIT — 请参阅 [LICENSE](LICENSE)
标签:CycloneDX, MITM代理, SBOM生成, 测试用例, 自定义脚本, 请求拦截