contriboss/vein

GitHub: contriboss/vein

Vein 是一个高性能的多生态包代理与缓存服务器,通过统一端点为 RubyGems、crates.io 和 npm 提供本地缓存和供应链保护能力。

Stars: 23 | Forks: 2

# Vein 💎 一个快速、智能的多生态包代理/缓存工具,支持 RubyGems、crates.io 和 npm。 **统一端点:** Bundler、ore-light、Cargo 和 npm 都可以指向同一个 Vein 基础 URL。同一台服务器通过路径/请求头检测来处理 RubyGems、crates.io sparse index 及 crate 下载,以及 npm metadata 和 tarballs。目前支持对 RubyGems 的上游进行配置;crates.io 和 npm 使用固定的上游。 ## 什么是 Vein? Vein 是一个针对多个包生态系统的**智能缓存代理**,它可以: - 通过可配置的上游代理 RubyGems - 带缓存地镜像 crates.io sparse index 和 crate 下载 - 带缓存地代理 npm registry 的元数据和 tarballs - 在重复请求时从本地存储提供缓存的制品 - 可以在没有 RubyGems 上游的情况下运行;crates.io 和 npm 仍然使用其内置的上游 - 基于 Rama(模块化服务框架)构建 - 极简配置 - 在常见设置下开箱即用 ## 为什么选择 Vein? - **极速**:基于 Rama 的高性能代理 - **智能缓存**:只需缓存一次制品,之后直接从本地提供 - **供应链保护**:隔离系统(目前支持 RubyGems;正逐步扩展至其他生态系统) - **极简配置**:crates.io 和 npm 开箱即用;当需要 Vein 获取新 gems 时,只需添加 RubyGems 上游 - **简单部署**:单一二进制文件,没有复杂的依赖 - **多 registry 端点**:RubyGems + crates.io + npm 共享一个基础 URL - **Ore 集成**:与 ore-light 的回退机制无缝协作 ## 快速开始 ``` # 使用 Docker 运行 docker run -p 8346:8346 -v vein-data:/data ghcr.io/contriboss/vein:latest # 或者使用 docker-compose curl -O https://raw.githubusercontent.com/contriboss/vein/master/docker-compose.yml docker-compose up -d # 或者从源码构建 cargo build --release ./target/release/vein serve ``` ## 工作原理 ``` Client Request → Vein → Local Cache? ├─ Hit → Serve from filesystem └─ Miss → Fetch from upstream (RubyGems / crates.io / npm) ├─ Cache locally └─ Serve to client ``` **永久缓存:** 制品文件(gems、crates、npm tarballs)在首次获取时即被缓存,此后均从本地提供。Index/元数据端点通过 TTL + 重新验证进行缓存。 **简洁架构:** 使用 SQLite(默认)或 PostgreSQL 存储元数据 + 使用文件系统存储缓存制品(默认存储根目录:`./cache`)。 ## 功能 - [x] 基于 Rama 的 HTTP 代理 - [x] SQLite/PostgreSQL 清单(持久化元数据) - [x] 文件系统存储(默认 `./cache/`,带有按生态系统划分的子文件夹) - [x] 智能缓存解析器 - [x] 流式缓存(在提供服务的同时进行缓存) - [x] SHA256 验证 - [x] 极简配置 - [x] Docker 镜像 - [x] 包名/版本/平台解析 - [x] 带有指标的请求日志记录 - [x] 损坏时的缓存重新验证 - [x] 带有可配置上游的 RubyGems 代理 - [x] crates.io sparse index + crate 下载缓存 - [x] npm registry 元数据 + tarball 缓存 - [x] 用于目录、隔离和 SBOM 检查的管理控制面板 - [x] CycloneDX SBOM 提取,带有管理预览和下载 API(目前支持 RubyGems;正逐步扩展) - [x] 隔离系统(防范供应链攻击,目前支持 RubyGems;正逐步扩展) ### 用法 ``` # (可选)编写配置文件 – 默认值与此代码片段类似 cat <<'TOML' > vein.toml [server] host = "0.0.0.0" port = 8346 [storage] path = "./cache" [database] path = "./vein.db" # 可选:为未缓存的 gems 启用 RubyGems 获取 # [upstream] # url = "https://rubygems.org" TOML # 启动 proxy(RubyGems、crates.io 和 npm 在一个 endpoint 上) cargo run -- serve --config vein.toml # 检查 cache 统计信息 cargo run -- stats --config vein.toml ``` ### CycloneDX SBOM 访问 **范围:** 目前为缓存的 RubyGems 生成 SBOM。路线图是将 SBOM 生成扩展到 Vein 支持的其他生态系统,包括 crates.io 和 npm。 - **管理控制面板:** 启动 `make admin`,然后浏览至 `http://127.0.0.1:9400/catalog/?version=` 以预览生成的 SBOM,并直接从 UI 下载 JSON。 - **代理端点:** 任何客户端都可以通过在运行中的 Vein 代理上调用 `GET /.well-known/vein/sbom?name=&version=[&platform=]` 来获取 SBOM,而无需管理 UI。响应是一个 CycloneDX 1.5 文档,带有 `Content-Type: application/json` 和便于下载的文件名。对于默认的 `ruby` 构建版本,请省略 `platform` 查询;对于原生变体(例如 `arm64-darwin`),请提供此参数。 - SBOM 在 gem 首次缓存时自动生成,并在重新获取该 gem 时刷新。 ### 隔离(供应链保护) **范围:** 目前隔离功能应用于 RubyGems 元数据/索引响应。路线图是将相同的保护应用到 Vein 支持的其他生态系统,包括 crates.io 和 npm。 Vein 可以延迟新 gem 版本在 Bundler 索引中的出现时间,从而为社区争取时间,在恶意包到达您的 CI/CD 之前将其拦截。 **工作原理:** - 新的 gem 版本会被隔离一段可配置的时间(默认:3 天) - `bundle update` 和 `bundle outdated` 将无法看到被隔离的版本 - 直接安装(`gem install foo -v 1.2.3`)仍然有效(显式选择) - 隔离期满后,版本会自动提升 **真实场景(rest-client 1.6.13,2019 年 8 月):** - 发布了恶意版本,约 12 小时后被撤销 - 在此期间运行 `bundle update` 的任何 CI/CD 都会受到破坏 - 使用 Vein 的 3 天隔离:零暴露风险 **在配置中启用:** ``` [delay_policy] enabled = true default_delay_days = 3 skip_weekends = true # Don't release on Sat/Sun business_hours_only = true # Only release during business hours release_hour_utc = 10 # Release at 10:00 UTC # 针对每个 gem 的 overrides(支持 glob patterns) [[delay_policy.gems]] name = "rails*" pattern = true delay_days = 7 # Extra scrutiny for Rails ecosystem [[delay_policy.gems]] name = "internal-*" pattern = true delay_days = 0 # Trust internal gems # Pin 特定版本以供即时使用 [[delay_policy.pinned]] name = "rails" version = "8.0.1" reason = "Security patch - verified safe" ``` **CLI 命令:** ``` # 显示 quarantine 状态 vein quarantine status # 列出 quarantine 中的版本 vein quarantine list # 手动 promote 过期版本 vein quarantine promote # Approve 一个版本以供立即发布 vein quarantine approve rails 8.0.1 --reason "Security patch" # Block 恶意版本 vein quarantine block badgem 1.0.0 --reason "Malware detected" ``` **管理界面:** 在管理服务器上浏览至 `/quarantine` 以查看统计信息并批准/阻止相应版本。 ### 配置 最小配置(crates.io 和 npm 使用默认值即可工作;需要时配置 RubyGems 上游): ``` # vein.toml [server] port = 8346 # default [storage] path = "./cache" # default # 可选:为未缓存的 gems 启用 RubyGems 获取 # [upstream] # url = "https://rubygems.org" ``` 完整配置选项: ``` [server] host = "0.0.0.0" port = 8346 workers = 4 # Rama worker threads [upstream] url = "https://rubygems.org" # Optional RubyGems upstream fallback_urls = [] [storage] path = "./cache" [database] path = "vein.db" # SQLite inventory [logging] level = "info" # debug, info, warn, error json = false [delay_policy] enabled = false # Enable quarantine system default_delay_days = 3 # Default quarantine period skip_weekends = true # Don't release on weekends business_hours_only = true # Only release during business hours release_hour_utc = 9 # Hour to release (0-23) ``` ### 存储架构 Vein 采用 **数据库 + 文件系统** 架构以实现最佳性能: #### SQLite (`vein.db`) 或 PostgreSQL - 持久化元数据存储 **用途**:所有缓存包的权威数据源 **存储内容**: - 完整的包元数据(名称、版本、平台) - 文件系统路径 - SHA256 校验和 - 文件大小 - 最后访问时间戳 **使用时机**: - 在缓存未命中时,验证是否需要获取包 - 在缓存写入时,存储元数据 ## 开发 ``` # Build(SQLite backend,默认) cargo build --release # 使用 PostgreSQL backend 进行 Build cargo build --release --no-default-features --features postgres,tls # 运行(带 logging) RUST_LOG=debug cargo run -- serve # 测试 cargo test ``` **注意:** SQLite 和 PostgreSQL 在编译时是互斥的。请选择其中之一。 ## Docker 部署 ### 基本用法 ``` # 拉取 image docker pull ghcr.io/contriboss/vein:latest # 使用 persistent volumes 运行 docker run -d \ --name vein \ -p 8346:8346 \ -v vein-data:/data \ -e RUST_LOG=info \ ghcr.io/contriboss/vein:latest # 查看日志 docker logs -f vein ``` ### 使用 Docker Compose(推荐) 包含的 `docker-compose.yml` 会启动一个**完全配置好的、可用于生产环境的** Vein 代理,并带有 PostgreSQL 后端: ``` # 克隆并启动 git clone https://github.com/contriboss/vein.git cd vein docker compose up -d # 验证健康状态 docker compose ps # Both services should show "healthy" # 查看日志 docker compose logs -f vein # 停止服务 docker compose down ``` **包含内容:** - PostgreSQL 18 及持久化存储 - 带有自动迁移的 Vein 代理(无需手动设置) - 两个服务的健康检查 - 预先配置好的网络 将 Bundler、Cargo 或 npm 指向 `http://localhost:8346` 即可大功告成。 ### 自定义配置 ``` # 创建配置文件 cp vein.example.toml vein.toml # 根据需要编辑... # 使用自定义 config 运行 docker run -d \ --name vein \ -p 8346:8346 \ -v $(pwd)/vein.toml:/data/vein.toml:ro \ -v vein-data:/data \ vein:latest serve --config /data/vein.toml ``` ## 部署 ### Systemd 服务 ``` [Unit] Description=Vein Package Proxy After=network.target [Service] Type=simple User=vein ExecStart=/usr/local/bin/vein serve --config /etc/vein/vein.toml Restart=always [Install] WantedBy=multi-user.target ``` ### 在 Nginx 之后 ``` upstream vein { server localhost:8346; } server { listen 443 ssl http2; server_name packages.company.com; location / { proxy_pass http://vein; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` ## 与 ore-light 的关系 - **ore-light**:基于 Go 的 Bundler 替代方案(客户端 gem 管理) - **Vein**:多生态包代理/缓存(服务端包分发) ore-light 是一个可以使用 Vein RubyGems 端的客户端。 Vein 本身的范围更广:它还能从相同的基础 URL 为 crates.io 和 npm 流量提供服务。 ## 为什么选择 Rama(而不是 Pingora) Vein 最初基于 Cloudflare 的 Pingora 框架构建。然而,Pingora **完全缺乏对 FreeBSD 的支持**,并且修复此问题的贡献被忽略了。一个旨在添加 FreeBSD 支持的 PR 没有得到任何回应。 因此我迁移到了 [Rama](https://github.com/plabayo/rama),它: - 在 FreeBSD 15.0-STABLE(以及 Linux、macOS、Windows、iOS、Android)上完美编译 - 具有真正的模块化架构(而不是仅仅挂个“模块化”的名头) - 欢迎个人的贡献,而不仅仅是大公司的贡献 - 不会将您锁定在固执己见的模式中,当您超出边界时被迫去 fork 代码 对于需要灵活性和多平台支持的项目来说,Rama 是一个更健康的选择。 谢谢,Cloudflare。 ## 商业用途与扩展 Vein 基于 [Rama](https://github.com/plabayo/rama) 构建,这是一个由 [Plabayo](https://plabayo.tech) 开发的模块化服务框架。 **项目状态**:Vein 是一个**副业项目**,并将保持免费和开源。它不会商业化。 **HTTP 功能**:刻意保持基础。Vein 只做它需要做的事:代理、缓存、提供包。没有计划添加复杂的 HTTP 功能或企业级功能。 **需要更多功能?** 需要额外功能(高级路由、身份验证、监控、协议扩展)的公司应**直接聘请 Plabayo** 来扩展 Vein: - 扩展可以是公开的(贡献给上游)或私有的(内部 fork) - 这使 Vein 保持专注,并将工作交给了构建基础 的团队 - 避免让作者变成全职的代理顾问 **支持合同**:Plabayo 为基于 Rama 的项目提供商业服务合同。请通过 https://plabayo.tech 联系他们 ## 许可证 Vein 采用双重许可: - **个人/个人使用**:MIT 许可证(见 [LICENSE-MIT](./LICENSE-MIT)) - **商业/公司使用**:AGPL-3.0(见 [LICENSE-AGPL](./LICENSE-AGPL)) 您可以选择最适合您用例的许可证。如果在商业组织内使用,则适用 AGPL-3.0 条款。
标签:Cargo, npm, RubyGems, 包代理, 可视化界面, 测试用例, 缓存服务器, 请求拦截, 通知系统, 镜像服务