stevologic/oss-deps-explorer
GitHub: stevologic/oss-deps-explorer
一个提供REST API和浏览器UI的轻量级Web应用,用于跨多个包生态系统查询、可视化和审计软件依赖关系及其安全状态。
Stars: 3 | Forks: 0
# oss-deps-explorer
`oss-deps-explorer` 是一个轻量级的 Web 应用,它提供了一个 REST API 和可选的浏览器 UI,用于探索包依赖关系。该服务代理了多个包生态系统,并返回所请求包的依赖关系。依赖数据是从稳定的 [deps.dev](https://deps.dev) v3 API 获取的(支持 npm、PyPI、Go、Maven、Cargo、RubyGems 和 NuGet),以及从 Packagist 获取(支持 Composer)。当 Redis 可用时,响应会被缓存在 Redis 中 24 小时。



## 架构
在启动时,服务会为每个受支持的包管理器注册一个实现。每个实现都符合简单的 `Manager` 接口。请求由使用 Gorilla Mux 的 Go HTTP 服务器处理。当 Redis 可达时,依赖图会根据 `cache.ttl` 设置缓存在 Redis 中;否则,服务将在没有缓存的情况下继续运行。一个可选的 Web 前端使用相同的 API 在浏览器中可视化依赖关系。
可选功能包括:
* 使用 `-recursive` 标志进行递归依赖解析。
* 通过 `-vuln` 标志从 [OSV.dev](https://osv.dev) 进行漏洞查询。
缺乏严重性数据的安全公告会通过针对 OSV 解析其 CVE/GHSA 别名来进行补充。
* 使用 `-scorecard` 获取来自 OpenSSF Scorecard 的仓库健康详情。
* 仓库 URL 与依赖数据一起缓存,以实现更快的 Scorecard 查询。
* 当提供 `-graph` 或在依赖查询请求中传递 `graph=true` 时,输出 GraphViz 可视图表。
也可以通过 `/api/purl/{purl}` 端点使用 [包 URL](https://github.com/package-url/purl-spec) 获取依赖。
Deps.dev API 基础 URL 通过 `/api/config` 公开。可以从 `/api/suggest/{manager}/{query}` 请求包名建议,并可以在 UI 中为每个包管理器从 `/api/versions?manager=&name=[&namespace=]` 请求版本建议。
### 支持的包管理器
| 管理器 | 路径组件映射 | 备注 |
|---------|-----------------------|-------|
| `npm` | namespace = scope, name = package | 对于无作用域的包,namespace 可以为空 |
| `pypi` | name = package | namespace 被忽略 |
| `go` | namespace + name 组成模块路径 | 示例:`github.com` 作为 namespace,`gorilla/mux` 作为 name |
| `maven` | namespace = groupId, name = artifactId | 使用 Maven Central POM 文件 |
| `cargo` | name = crate | namespace 被忽略 |
| `rubygems` | name = gem | namespace 被忽略 |
| `nuget` | name = package ID | namespace 被忽略 |
| `composer` | namespace = vendor, name = package | 使用 Packagist API |
对于 npm、PyPI、Maven 和 Cargo,deps.dev 提供解析后的依赖图数据。对于 Go、RubyGems 和 NuGet,服务使用当前的 deps.dev requirements 端点并返回直接要求。Composer 使用 Packagist 元数据,并尽最大努力解析常见的 Composer 版本约束以进行递归查找。
### Web UI
内置的 UI(由 API 二进制文件在 `/` 提供服务,或者从 `ui` 容器在端口 8081 上独立提供服务)提供三种分析模式:
* **Package** – 解析直接和传递依赖,包括 OSV 漏洞分类、OpenSSF Scorecard 数据、仓库元数据卡片、交互式依赖图,以及 JSON/CycloneDX/SPDX/GraphViz/CSV 导出。
* **CVE** – 通过 CVE、GHSA、OSV 或 PYSEC ID 查询安全公告(对于 OSV 未包含的公告,会回退到 NVD),查看受影响的包、严重性、参考和修复指南,并可直接切入包分析。
* **Repository** – 导入 GitHub 仓库的依赖图 SBOM,用于许可证策略审查、OSV 分类和过滤后的 CSV/CycloneDX/SPDX/DOT 导出,包括被跳过(不支持的)依赖。来自 SBOM 的版本范围规范(例如 `^2.2.1`)会被解析为最新匹配的发行版,以便范围包能与精确版本包一起加入 OSV 着色和依赖链解析。
每个视图都是一个可共享的深层链接 —— `?manager=npm&name=express&version=4.18.2`、`?cve=CVE-2024-3094` 或 `?repo=owner/name` —— 并且浏览器的后退/前进按钮可以在以前查看过的分析之间导航。浅色和深色主题遵循系统偏好,可以在页眉中进行切换。
## 配置
配置通过 YAML 文件提供。包含了一个示例 `config.yaml`:
```
server:
port: "8080"
redis:
addr: "redis:6379"
password: ""
db: 0
cache:
ttl: 24h
proxy:
url: ""
package_manager:
npm: "https://api.deps.dev/v3"
pypi: "https://api.deps.dev/v3"
go: "https://api.deps.dev/v3"
maven: "https://api.deps.dev/v3"
cargo: "https://api.deps.dev/v3"
rubygems: "https://api.deps.dev/v3"
nuget: "https://api.deps.dev/v3"
composer: "https://repo.packagist.org"
```
## 本地运行
构建二进制文件并直接运行:
```
go build -o oss-deps-explorer ./cmd/oss-deps-explorer
./oss-deps-explorer -config config.yaml
```
服务监听 `config.yaml` 中指定的端口(默认为 `8080`)。
### 仓库元数据工具
使用 `repometa` 命令获取有关 GitHub 仓库的基本信息,无需任何身份验证:
```
go run ./cmd/repometa /
```
输出包括描述、许可证、打开和已关闭的 Pull Request、提交次数以及其他详细信息。
### 用于代理工作流的 MCP 服务器
该项目包含一个配套的 Model Context Protocol 服务器,适用于需要依赖智能而无需抓取 UI 的代理。MCP 服务器是一个 stdio 进程,它会调用运行中的 `oss-deps-explorer` API,因此代理使用与 Web 应用相同的依赖解析、OSV 查询、仓库元数据和 Scorecard 数据。
首先启动 API:
```
docker-compose up --build api redis
```
然后运行 MCP 服务器:
```
go run ./cmd/oss-deps-mcp -api http://localhost:8080
```
你也可以使用 `OSS_DEPS_EXPLORER_API` 设置 API URL:
```
OSS_DEPS_EXPLORER_API=http://localhost:8080 go run ./cmd/oss-deps-mcp
```
构建独立的二进制文件:
```
go build -o oss-deps-mcp ./cmd/oss-deps-mcp
```
MCP 客户端配置示例:
```
{
"mcpServers": {
"oss-deps-explorer": {
"command": "go",
"args": [
"run",
"./cmd/oss-deps-mcp",
"-api",
"http://localhost:8080"
],
"env": {
"OSS_DEPS_EXPLORER_API": "http://localhost:8080"
}
}
}
}
```
该服务器公开只读工具:
| 工具 | 用途 |
|------|---------|
| `search_packages` | 在深入分析之前搜索受支持的生态系统 |
| `research_dependencies` | 解析直接/传递依赖、OSV 状态、父路径和可选的 Scorecard 数据 |
| `assess_package_reputation` | 总结仓库元数据和 OpenSSF Scorecard 信誉信号 |
| `plan_vulnerability_remediation` | 根据 OSV 公告、已修复版本和依赖路径提供升级和覆盖指导 |
用于传递依赖研究的工具参数示例:
```
{
"manager": "npm",
"name": "axios",
"version": "1.13.0",
"recursive": true,
"vulnerabilities": true,
"scorecard": true
}
```
### 在 Windows 上运行
通过设置 `GOOS` 环境变量来构建 Windows 二进制文件:
```
GOOS=windows go build -o oss-deps-explorer.exe ./cmd/oss-deps-explorer
oss-deps-explorer.exe -config config.yaml
```
或者使用 Docker Desktop 运行服务:
```
docker-compose up --build
```
如果你有 WSL 可用,你也可以在 WSL 环境中按照 Linux 说明进行操作。
## 使用 Docker 运行
该仓库包含用于 API 和 UI 的 Dockerfile,以及一个 `docker-compose.yml` 文件,以简化服务的运行:
```
docker-compose up --build
```
然后 API 将在 `localhost:8080` 上可用,UI 将在 `localhost:8081` 上可用。
在 UI 的依赖图中单击节点(或其标签)可直接转入对该包的应用内分析;每个包的注册表链接在依赖列表和安全面板中保持可用。
`docker-compose.yml` 是本地开发栈。生产部署使用 `docker-compose.prod.yml` —— 请参阅[部署到生产环境](#deploying-to-production-ossdedev)。
## 部署到生产环境 (ossde.dev)
生产栈(`docker-compose.prod.yml`)运行四个服务:Caddy(TLS 终止和路由)、Go API、nginx UI 和 Redis。Caddy 是唯一发布端口的服务 —— 它提供 `https://ossde.dev` 服务,将 `/api/*` 路由到 API,将其他所有内容路由到 UI,并自动配置 Let's Encrypt 证书(持久化在 `caddy_data` 卷中,因此证书可以在重启和重新部署后保留)。
### 服务器先决条件
- 一台安装了 Docker Engine 和 compose 插件的 Linux 服务器
- 打开端口 80 和 443(如果你想要 HTTP/3,还需要打开 443/udp)
- 指向该服务器的 `ossde.dev` 的 DNS A 记录
### 首次部署
```
sudo git clone https://github.com/stevologic/oss-deps-explorer /opt/oss-deps-explorer
cd /opt/oss-deps-explorer
./deploy.sh
```
`deploy.sh` 检出 `origin/main`,构建镜像,启动栈,并等待 API 健康检查通过后再报告成功。
### 保持最新
`deploy.sh` 是幂等的,并受锁文件保护,因此你可以使用 cron 安排它以自动跟踪 `main`:
```
*/5 * * * * /opt/oss-deps-explorer/deploy.sh >> /var/log/oss-deps-explorer-deploy.log 2>&1
```
当 `HEAD` 已经与 `origin/main` 匹配并且所有服务都在运行时,它会立即退出而不影响 Docker。覆盖项:
- `FORCE=1 ./deploy.sh` — 即使已经是最新的也重新构建并重启
- `BRANCH=development ./deploy.sh` — 跟踪不同的分支
失败的健康检查会使脚本以退出代码 1 退出,并打印容器状态以及最近的 API 日志,因此 cron 的输出(或你的日志文件)会显示出了什么问题。
### 依赖卡片
单击节点会显示从 GitHub 公共 API 中提取的额外仓库详细信息(无需身份验证)。该卡片显示:
- 仓库描述
- 主要语言
- 归档状态
- 创建和更新时间戳
- 默认分支
- 关注者或订阅者数量
- Star 和 Fork 数量
- 打开的 Issue 数量
- 许可证信息
- 打开和已关闭的 Pull Request 数量
- 总提交次数和最新提交日期
- 来自 OSV 的最高漏洞分数(悬停查看详情)
### 使用 Helm 部署
在 `helm/oss-deps-explorer` 下提供了一个最小的 Helm chart。使用以下命令安装:
```
helm install deps-explorer ./helm/oss-deps-explorer
```
该 chart 默认在端口 `8080` 上公开服务。
## 命令行标志
二进制文件接受以下标志:
| 标志 | 描述 |
|------|-------------|
| `-config` | YAML 配置文件的路径 |
| `-recursive` | 设置后,通过重复查询每个依赖来获取传递依赖 |
| `-vuln` | 包含来自 OSV.dev 的漏洞信息 |
| `-scorecard` | 包含 OpenSSF Scorecard 数据 |
| `-graph` | 输出 GraphViz dot 表示而不是 JSON |
## API 用法
```
GET /api/dependencies/{manager}/{namespace}/{name}/{version}
GET /api/dependencies/{manager}/{name}/{version}
GET /api/purl/{purl}
GET /api/config
GET /api/suggest/{manager}/{query}
GET /api/versions?manager=&name=[&namespace=]
GET /api/repo/{repo}
GET /api/github/dependencies?repo=/
GET /api/lookup?manager=&name=&version=[&namespace=][&recursive=true][&vuln=true][&scorecard=true][&graph=true]
```
npm 的示例(无 namespace):
```
curl http://localhost:8080/api/dependencies/npm/express/4.18.2
curl http://localhost:8080/api/purl/pkg:npm/express@4.18.2
```
可选的布尔查询参数 `recursive`、`vuln`、`scorecard` 和 `graph` 可以按请求覆盖服务器标志:
```
curl "http://localhost:8080/api/dependencies/npm/express/4.18.2?recursive=true&vuln=true&scorecard=true"
curl "http://localhost:8080/api/dependencies/npm/express/4.18.2?graph=true"
```
响应 JSON 具有以下简单形状:
```
{
"dependencies": {
"": ""
},
"repositories": {
"": ""
}
}
```
使用 `-recursive` 标志运行时,响应还包括一个 `parents` 对象,该对象将每个依赖映射到引入它的一个或多个包。直接依赖映射到包含空字符串的数组。如果任何传递依赖无法解析,响应将包含一个描述失败原因的 `errors` 数组。当提供 `-vuln` 标志时,将包含一个 `vulnerabilities` 对象,其中包含已解析包的 OSV.dev 漏洞信息。使用 `-scorecard` 标志时,`scorecards` 对象会为任何由 GitHub 仓库支持的包提供 OpenSSF Scorecard 结果。
`/lookup` 端点公开相同的功能,但使用查询参数而不是路径段。
当请求 `graph=true` 时,响应是内容类型为 `text/vnd.graphviz` 的 GraphViz DOT。递归图导出使用 `parents` 数据来保留直接和传递边,而不是将每个包平铺在根节点下。DOT 输出使用版本属性声明包节点,因此无依赖包和版本清单在图形工具中仍然可见。节点包含 OSV 状态颜色,并且在导出漏洞上下文时包含嵌入式图例。
UI 安全分类面板还可以将当前分析导出为 JSON、CycloneDX SBOM、GraphViz DOT 或易受攻击包的 CSV。
`/api/github/dependencies` 端点导入仓库的 GitHub 依赖图 SBOM 数据,并返回按受支持的包管理器分组的可分析包 URL。当 GitHub 的 SPDX SBOM 包含 `licenseConcluded` 或 `licenseDeclared` 时,每个包都包含清理过的许可证字段,其中 `license` 优先使用已结论的值,如果不存在则回退到已声明的值。UI 仓库导入视图公开了许可证摘要过滤器、包上的许可证标签、缺失许可证隔离,以及带有许可证、许可证策略、OSV 分类、源根、直接父级和依赖路径列的过滤 CSV 库存导出,以便进行合规移交。许可证策略过滤器会标记 copyleft、缺失、自定义和未列入白名单的 SPDX 表达式,以便可以快速隔离法律审查队列。一旦构建了依赖链,相同的过滤仓库包视图还可以导出oneDX JSON,其中包含 GitHub 许可证元数据、许可证策略属性、OSV 状态属性,以及带有依赖边和路径属性的已解析传递组件。它还可以将活动的过滤视图导出为 SPDX 2.3 JSON,其中包含包许可证字段、策略评论、OSV 评论和依赖关系,适用于首选 SPDX 移交的合规系统。仓库图工具栏将过滤后的图导出为 GraphViz DOT,包括解析的传递边、许可证策略属性和 OSV 状态属性,以便进行架构和合规审查。可复制和下载的 Markdown 审计简报总结了活动视图的许可证审查计数、OSV 发现和依赖链覆盖率,以便进行工单或审查移交。
仓库导入视图可以通过 `?repo=owner/name` 链接重新打开或共享,成功导入会将 URL 规范化为 GitHub 仓库 slug 以便进行审查移交。带有不受支持的包 URL 或生态系统的 GitHub SBOM 记录将作为跳过的依赖项保留,并包含许可证、许可证策略和外部引用元数据,以便审查者可以将它们过滤、简报并导出为 CSV 或 JSON,而不是仅仅看到不支持的计数。
示例:
```
curl "http://localhost:8080/api/lookup?manager=npm&name=express&version=4.18.2&recursive=true&vuln=true&scorecard=true"
```
## 示例请求
以下是针对每个受支持管理器的示例调用,并附有缩短的输出:
```
# npm
curl -s http://localhost:8080/api/dependencies/npm/express/4.18.2 | head -c 80
{"dependencies":{"accepts":"~1.3.8",...}}
curl -s http://localhost:8080/api/dependencies/npm/@babel/core/7.21.0 | head -c 80
{"dependencies":{"@ampproject/remapping":"^2.2.0",...}}
# pypi
curl -s http://localhost:8080/api/dependencies/pypi/requests/2.31.0 | head -c 80
{"dependencies":{"PySocks (!=1.5.7,>=1.5.6) ; extra == 'socks',...}}
curl -s http://localhost:8080/api/dependencies/pypi/urllib3/2.2.0 | head -c 80
{"dependencies":{"brotli>=1.0.9; (platform_python_implementation == 'CPython') and extra == 'brotli',...}}
# go
curl -s http://localhost:8080/api/dependencies/go/github.com/gorilla/mux/v1.8.1 | head -c 80
{"dependencies":{}}
curl -s http://localhost:8080/api/dependencies/go/github.com/stretchr/testify/v1.8.2 | head -c 80
{"dependencies":{"github.com/davecgh/go-spew":"v1.1.1",...}}
# maven
curl -s http://localhost:8080/api/dependencies/maven/org.apache.commons/commons-lang3/3.12.0 | head -c 80
{"dependencies":{"com.google.code.findbugs:jsr305":"3.0.2",...}}
curl -s http://localhost:8080/api/dependencies/maven/junit/junit/4.13.2 | head -c 80
{"dependencies":{"org.hamcrest:hamcrest-core":"${hamcrestVersion}",...}}
# cargo
curl -s http://localhost:8080/api/dependencies/cargo/rand/0.8.5 | head -c 80
{"dependencies":{"bincode":"^1.2.1",...}}
curl -s http://localhost:8080/api/dependencies/cargo/serde/1.0.200 | head -c 80
{"dependencies":{"serde_derive":"^1"}}
```
### 完整输出示例
以下显示了上述请求之一返回的完整 JSON:
```
curl -s http://localhost:8080/api/dependencies/npm/express/4.18.2 | jq
{
"dependencies": {
"qs": "6.11.0",
"depd": "2.0.0",
"etag": "~1.8.1",
"send": "0.18.0",
"vary": "~1.1.2",
"debug": "2.6.9",
"fresh": "0.5.2",
"cookie": "0.5.0",
"accepts": "~1.3.8",
"methods": "~1.1.2",
"type-is": "~1.6.18",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"encodeurl": "~1.0.2",
"proxy-addr": "~2.0.7",
"body-parser": "1.20.1",
"escape-html": "~1.0.3",
"http-errors": "2.0.0",
"on-finished": "2.4.1",
"safe-buffer": "5.2.1",
"utils-merge": "1.0.1",
"content-type": "~1.0.4",
"finalhandler": "1.2.0",
"range-parser": "~1.2.1",
"serve-static": "1.15.0",
"array-flatten": "1.1.1",
"path-to-regexp": "0.1.7",
"setprototypeof": "1.2.0",
"cookie-signature": "1.0.6",
"merge-descriptors": "1.0.1",
"content-disposition": "0.5.4"
},
"repositories": {
"express": "github.com/expressjs/express"
},
"vulnerabilities": {
"express": [
{ "id": "GHSA-xxxx" }
]
}
}
```
### 递归依赖示例
使用 `-recursive` 标志启动服务器以跟踪传递依赖:
```
oss-deps-explorer -config config.yaml -recursive -vuln -scorecard
```
带有扩展输出的示例请求:
```
# npm
curl -s http://localhost:8080/api/dependencies/npm/express/4.18.2 | head -c 80
# maven
curl -s http://localhost:8080/api/dependencies/maven/org.apache.commons/commons-lang3/3.12.0 | head -c 80
# go
curl -s http://localhost:8080/api/dependencies/go/github.com/stretchr/testify/v1.8.2 | head -c 80
```
任何无法解析的依赖都将出现在 JSON 响应的 `errors` 数组中。
## 故障排除
如果 API 对于你确信存在的版本返回 `package not found`,请验证该版本是否存在于 deps.dev 数据集中:
```
curl https://api.deps.dev/v3/systems//packages//versions/:dependencies
```
对于 Go、RubyGems 和 NuGet,请改为检查 deps.dev requirements 端点:
```
curl https://api.deps.dev/v3/systems//packages//versions/:requirements
```
如果此请求失败或返回 `403 Forbidden`,则你的环境可能阻止了出站 HTTPS 请求。通过在 `config.yaml` 中设置 `proxy.url` 或设置 `HTTP_PROXY` 环境变量来配置 HTTP 代理,以便服务可以访问 `api.deps.dev`。
## 贡献
有关指南,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。本项目在 [MIT 许可证](LICENSE)下发布。
标签:Go, Redis, REST API, Ruby工具, TCP SYN 扫描, WebSocket, Web UI, 依赖分析, 开源治理, 搜索引擎查询, 日志审计, 漏洞查询, 自定义脚本, 请求拦截