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生成, 测试用例, 自定义脚本, 请求拦截