
proxy v0.7.0
一个用于包注册表的轻量级缓存代理。
git-pkgs proxy
一个用于软件包注册表的缓存代理。通过在本地缓存构件来加速软件包下载,减少带宽占用并提升可靠性。
版本冷却
大多数供应链攻击都依赖于速度:恶意版本发布后,在任何人察觉之前,几分钟内就会被自动化流水线拉取使用。冷却功能为新发布的版本增加了一段隔离期。启用后,代理会从元数据响应中剔除那些尚未超过可配置时间阈值的版本。
cooldown:
default: "3d" # hide versions published less than 3 days ago
ecosystems:
npm: "7d" # npm gets a longer window
cargo: "0" # disable for cargo
packages:
"pkg:npm/lodash": "0" # exempt trusted packages
3 天冷却期意味着当 lodash 发布 4.18.0 版本时,你的构建会继续使用 4.17.21,直到 3 天过去。如果新版本被证明遭到入侵,你从未暴露于风险之中。
解析顺序:包级覆盖,然后是生态系统级覆盖,最后是全局默认值。这让你可以设置一个保守的默认值,并为需要更快更新的包划定例外。完整配置参考见 docs/configuration.md。
制品扫描
冷却期只查看版本的发布时间戳——它从不检查实际字节内容。制品扫描填补了这一空白:启用后,每个制品都会被暂存到存储中,并由一个或多个外部服务(trivy、ClamAV、Wiz,或任何遵循小型 HTTP/JSON 契约的其他服务)扫描,然后才会提交到缓存并提供给客户端。
scanning:
enabled: true
signing_key: ${PROXY_SCANNING_SIGNING_KEY}
scanners:
- name: clamav
url: http://clamav-adapter:8080/scan
mode: block # a block verdict deletes the artifact and returns 403
- name: trivy
url: http://trivy-adapter:8081/scan
mode: monitor # findings are logged, never gate caching
ecosystems: [npm, pypi]
代理从不上传制品字节到扫描器。每个扫描器会收到包元数据以及一个短期有效的签名 URL 通知;扫描器自行从代理自身的存储中拉取字节。扫描器并发运行,第一个报告判定为不允许的 block 模式扫描器立即胜出,并取消其余扫描器。完整配置参考和扫描器 HTTP 契约请参见 docs/configuration.md。
支持的注册表
| 注册表 | 语言/平台 | 冷却 | 已完成 |
|---|---|---|---|
| npm | JavaScript | 是 | ✓ |
| Cargo | Rust | 是 | ✓ |
| RubyGems | Ruby | 是 | ✓ |
| Go proxy | Go | ✓ | |
| Hex | Elixir | 是* | ✓ |
| pub.dev | Dart | 是 | ✓ |
| PyPI | Python | 是 | ✓ |
| Maven | Java | ✓ | |
| Gradle Build Cache | Java/Kotlin | ✓ | |
| NuGet | .NET | 是 | ✓ |
| Composer | PHP | 是 | ✓ |
| Conan | C/C++ | ✓ | |
| Conda | Python/R | 是 | ✓ |
| CRAN | R | ✓ | |
| Julia | Julia | ✓ | |
| Swift | Swift | ✓ | |
| Container | Docker/OCI | ✓ | |
| Homebrew | macOS/Linux | ✓ | |
| Debian | Debian/Ubuntu | ✓ | |
| RPM | RHEL/Fedora | ✓ | |
| Alpine | Alpine Linux | ✓ | |
| Arch | Arch Linux | ✗ | |
| Chef | Chef | ✗ | |
| Generic | Any | ✓ | |
| Helm | Kubernetes | ✓ | |
| Vagrant | Vagrant | ✗ |
冷却需要元数据中包含发布时间戳。冷却列中没有“是”的注册表要么不暴露时间戳,要么尚未接入。
* Hex 冷却需要禁用注册表签名验证(HEX_NO_VERIFY_REPO_ORIGIN=1),因为代理会重新编码 protobuf 负载。
安装
brew install git-pkgs/git-pkgs/proxy
或者从发布页面下载二进制文件。
Helm
从 GHCR 安装 chart,并设置包管理器客户端用于访问代理的公共 URL:
helm install proxy oci://ghcr.io/git-pkgs/charts/proxy \
--set config.data.base_url=https://proxy.example.com
默认 chart 部署一个副本,后端使用 10 GiB 持久卷,在 /data 下使用 SQLite 和文件系统制品存储。有关 ingress、外部数据库和对象存储配置选项,请参见
deploy/charts/proxy/values.yaml。
快速开始
# Build from source
go build -o proxy ./cmd/proxy
# Run with defaults (listens on :8080)
./proxy
# Run with custom settings
./proxy -listen :3000 -base-url https://proxy.example.com
代理现已运行。配置你的包管理器以使用它。
OpenAPI (Swagger)
此仓库使用 swaggo 从带注释的处理器生成 OpenAPI 规范。
生成规范:
go install github.com/swaggo/swag/cmd/swag@latest
go generate ./internal/server
生成的文档写入 docs/swagger/。
当代理运行时,从以下地址获取实时规范:
http://localhost:8080/openapi.json
或将 http://localhost:8080 替换为您配置的基础 URL。此链接也会显示在仪表板上。
配置包管理器
npm
创建或编辑 ~/.npmrc:
registry=http://localhost:8080/npm/
或在 .npmrc 中按项目设置:
registry=http://localhost:8080/npm/
或使用环境变量:
npm_config_registry=http://localhost:8080/npm/ npm install
npm audit、pnpm audit、yarn npm audit 和 npm audit signatures 均可通过代理正常工作:审计和签名密钥端点会被传递到配置的上游注册表,并应用上游身份验证。因此,安全公告来自上游的数据库,而非代理自身的漏洞数据,且被冷却期扣留的版本不会被排除在报告之外。
Cargo
创建或编辑 ~/.cargo/config.toml:
[source.crates-io]
replace-with = "proxy"
[source.proxy]
registry = "sparse+http://localhost:8080/cargo/"
或在项目根目录的 .cargo/config.toml 中按项目设置。
RubyGems / Bundler
在 Gemfile 中设置 gem 源:
source "http://localhost:8080/gem"
或全局配置:
gem sources --add http://localhost:8080/gem/
bundle config mirror.https://rubygems.org http://localhost:8080/gem
Go 模块
设置 GOPROXY 环境变量:
export GOPROXY=http://localhost:8080/go,direct
或在你的 shell 配置文件中设置以实现持久化。
Homebrew
将 Homebrew 的 JSON API 和制品域名指向代理:
export HOMEBREW_API_DOMAIN=http://localhost:8080/homebrew
export HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080
该制品域在 /v2/homebrew/core/ 下代理清单和 bottle blob。GHCR 路由仅限于该仓库。源码归档、cask 应用程序下载、自定义 tap 制品以及旧式扁平文件 bottle 镜像使用 Homebrew 的正常回退 URL。通过不设置 HOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK 来保持回退启用。
启用 cache_metadata 或设置 PROXY_CACHE_METADATA=true 以保留 Homebrew JSON API 响应以供离线回退。Bottle blob 及其 OCI 清单无需此设置即可缓存。
上游默认使用 https://formulae.brew.sh/api 作为 JSON API,使用 https://ghcr.io 作为制品。要将此代理链接到另一个代理,请将其 Homebrew 端点配置为上游:
upstream:
homebrew_api: "https://upstream-proxy.example.com/homebrew"
homebrew_artifact: "https://upstream-proxy.example.com"
对应的环境变量是 PROXY_UPSTREAM_HOMEBREW_API 和 PROXY_UPSTREAM_HOMEBREW_ARTIFACT。
Hex (Elixir)
在 ~/.hex/hex.config 中配置:
{default_url, <<"http://localhost:8080/hex">>}.
或设置环境变量:
export HEX_MIRROR=http://localhost:8080/hex
pub.dev (Dart/Flutter)
设置 PUB_HOSTED_URL 环境变量:
export PUB_HOSTED_URL=http://localhost:8080/pub
PyPI (pip)
配置 pip 以使用代理:
pip install --index-url http://localhost:8080/pypi/simple/ package_name
或在 ~/.pip/pip.conf 中设置:
[global]
index-url = http://localhost:8080/pypi/simple/
Maven
添加到你的 ~/.m2/settings.xml:
<settings>
<mirrors>
<mirror>
<id>proxy</id>
<mirrorOf>central</mirrorOf>
<url>http://localhost:8080/maven/</url>
</mirror>
</mirrors>
</settings>
/maven/ 端点使用 Maven Central 作为主要上游,当主要上游返回未找到时,回退到 Gradle Plugin Portal 以获取 Gradle 插件标记元数据和相关构件。
通过同一代理端点进行 Gradle 插件解析:
pluginManagement {
repositories {
maven(url = "http://localhost:8080/maven/")
}
}
Gradle HTTP 构建缓存
在 settings.gradle(.kts) 中配置:
buildCache {
local {
enabled = false
}
remote<HttpBuildCache> {
url = uri("http://localhost:8080/gradle/")
push = true
}
}
NuGet
在 nuget.config 中配置:
<configuration>
<packageSources>
<clear />
<add key="proxy" value="http://localhost:8080/nuget/v3/index.json" />
</packageSources>
</configuration>
或使用 CLI:
dotnet nuget add source http://localhost:8080/nuget/v3/index.json -n proxy
Composer (PHP)
在 composer.json 中配置:
{
"repositories": [
{
"type": "composer",
"url": "http://localhost:8080/composer"
}
]
}
或全局设置:
composer config -g repositories.proxy composer http://localhost:8080/composer
Conan (C/C++)
将代理添加为远程仓库:
conan remote add proxy http://localhost:8080/conan
conan remote disable conancenter
在 ~/.conan2/remotes.json 中配置。
Conda
在 ~/.condarc 中配置:
channels:
- http://localhost:8080/conda/main
- http://localhost:8080/conda/conda-forge
default_channels:
- http://localhost:8080/conda/main
或通过命令设置:
conda config --add channels http://localhost:8080/conda/main
CRAN (R)
在 R 中设置仓库:
options(repos = c(CRAN = "http://localhost:8080/cran"))
或在 ~/.Rprofile 中设置以持久化:
local({
r <- getOption("repos")
r["CRAN"] <- "http://localhost:8080/cran"
options(repos = r)
})
Julia
在启动 Julia 之前设置 Pkg 服务器:
export JULIA_PKG_SERVER=http://localhost:8080/julia
或在运行中的会话内:
ENV["JULIA_PKG_SERVER"] = "http://localhost:8080/julia"
using Pkg; Pkg.update()
Swift
将代理配置为当前 Swift 包的默认注册表:
swift package-registry set --allow-insecure-http http://localhost:8080/swift