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 小时。 ![包分析视图,包含交互式依赖图、OSV 严重性着色和仓库元数据](https://static.pigsec.cn/wp-content/uploads/repos/cas/37/37f1775a9f4b765668f0df2b691915cf439a853f589ee4363df07123ec33a7d7.png) ![CVE 查询视图,显示咨询详情、严重性和修复指南](https://static.pigsec.cn/wp-content/uploads/repos/cas/5c/5c5da14bcb75237f7afdfe239d83d0058ece8d64ce004d72463202fa71dd0c71.png) ![仓库导入视图,包含解析后的完整依赖链图和导出工具栏](https://static.pigsec.cn/wp-content/uploads/repos/cas/91/91bc9a93001ef334162b524f78fde995dfcf6732ce426e83579a7b9c0fb48b0c.png) ## 架构 在启动时,服务会为每个受支持的包管理器注册一个实现。每个实现都符合简单的 `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, 依赖分析, 开源治理, 搜索引擎查询, 日志审计, 漏洞查询, 自定义脚本, 请求拦截