
パッケージレジストリ向けの軽量キャッシングプロキシ。
パッケージレジストリ用のキャッシュプロキシ。アーティファクトをローカルにキャッシュすることでパッケージのダウンロードを高速化し、帯域幅の使用量を削減して信頼性を向上させます。
ほとんどのサプライチェーン攻撃はスピードに依存しています。悪意のあるバージョンが公開されると、誰も気づく前に数分以内に自動化されたパイプラインによって消費されてしまいます。クールダウン機能は、新しく公開されたバージョンに隔離期間を追加します。有効にすると、プロキシは設定可能なしきい値を経過するまでメタデータレスポンスからバージョンを除外します。```yaml 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` を公開したとき、3日が経過するまでビルドは `4.17.21` を使い続けるという意味です。新しいリリースが侵害されていることが判明しても、あなたは一切影響を受けません。
解決順序: パッケージオーバーライド、次にエコシステムオーバーライド、次にグローバルデフォルト。これにより、保守的なデフォルトを設定しつつ、より迅速な更新が必要なパッケージに対して例外を設けることができます。完全な設定リファレンスについては [docs/configuration.md](https://github.com/git-pkgs/proxy/blob/main/docs/configuration.md) を参照してください。
## アーティファクトスキャン
クールダウンはバージョンの公開タイムスタンプのみを参照し、実際のバイト列を検査することはありません。アーティファクトスキャンはそのギャップを埋めます。有効にすると、すべてのアーティファクトはストレージにステージングされ、キャッシュにコミットされてクライアントに配信される前に、1つ以上の外部サービス(trivy、ClamAV、Wiz、または小規模な HTTP/JSON コントラクトを話すその他のサービス)によってスキャンされます。```yaml
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モードのスキャナが最初にnot-allowedの判定を報告した時点で即座に勝者となり、残りはキャンセルされます。完全な設定リファレンスとスキャナの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 | ✗ |
クールダウンにはメタデータ内の公開タイムスタンプが必要です。クールダウン列に「はい」がないレジストリは、タイムスタンプを公開していないか、まだ対応が完了していないかのいずれかです。
* Hexのクールダウンは、プロキシがprotobufペイロードを再エンコードするため、レジストリ署名検証を無効化する必要があります(HEX_NO_VERIFY_REPO_ORIGIN=1)。
brew install git-pkgs/git-pkgs/proxy
または、[releases page](https://github.com/git-pkgs/proxy/releases) からバイナリをダウンロードしてください。
### Helm
GHCR からチャートをインストールし、パッケージマネージャークライアントがプロキシに到達するために使用する公開 URL を設定します:```bash
helm install proxy oci://ghcr.io/git-pkgs/charts/proxy \
--set config.data.base_url=https://proxy.example.com
デフォルトのチャートは、/data 配下で SQLite とファイルシステムアーティファクトストレージを使用し、10 GiB の永続ボリュームに支えられた 1 つのレプリカをデプロイします。イングレス、外部データベース、オブジェクトストレージの設定オプションについては、deploy/charts/proxy/values.yaml を参照してください。
go build -o proxy ./cmd/proxy
./proxy
./proxy -listen :3000 -base-url https://proxy.example.com
プロキシが起動しました。パッケージマネージャーがこれを使用するように設定してください。
## OpenAPI (Swagger)
このリポジトリでは、swaggo を使用してアノテーション付きハンドラーから OpenAPI 仕様を生成します。
仕様を生成します:```bash
go install github.com/swaggo/swag/cmd/swag@latest
go generate ./internal/server
生成されたファイルは docs/swagger/ に書き込まれます。
プロキシが実行されている場合、以下の場所からライブスペックを取得できます:
http://localhost:8080/openapi.jsonまたは、http://localhost:8080 を設定済みのベース URL に置き換えてください。このリンクはダッシュボードにも表示されます。
~/.npmrc を作成または編集します:```
registry=http://localhost:8080/npm/
または `.npmrc` でプロジェクトごとに設定します:```
registry=http://localhost:8080/npm/
または環境変数を使用します:```bash npm_config_registry=http://localhost:8080/npm/ npm install
### Cargo
`~/.cargo/config.toml` を作成または編集します:```toml
[source.crates-io]
replace-with = "proxy"
[source.proxy]
registry = "sparse+http://localhost:8080/cargo/"
プロジェクトルートの .cargo/config.toml でプロジェクトごとに設定することもできます。
Gemfile で gem ソースを設定します:```ruby
source "http://localhost:8080/gem"
グローバルに設定する場合:```bash
gem sources --add http://localhost:8080/gem/
bundle config mirror.https://rubygems.org http://localhost:8080/gem
GOPROXY環境変数を設定します:```bash export GOPROXY=http://localhost:8080/go,direct
または永続化のためにシェルプロファイルに記述します。
### Homebrew
Homebrew の JSON API とアーティファクトドメインをプロキシに向けます:```bash
export HOMEBREW_API_DOMAIN=http://localhost:8080/homebrew
export HOMEBREW_ARTIFACT_DOMAIN=http://localhost:8080
artifact ドメインは /v2/homebrew/core/ 配下のマニフェストとボトルブロブをプロキシします。GHCR ルーティングはそのリポジトリに限定されます。ソースアーカイブ、cask アプリケーションのダウンロード、カスタム tap の artifact、およびレガシーなフラットファイルボトルミラーは、Homebrew の通常のフォールバック URL を使用します。HOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK を未設定のままにしてフォールバックを有効に保ってください。
cache_metadata を有効にするか、PROXY_CACHE_METADATA=true を設定すると、オフラインフォールバック用に Homebrew JSON API のレスポンスを保持します。ボトルブロブとその OCI マニフェストはこの設定なしでキャッシュされます。
アップストリームはデフォルトで JSON API には https://formulae.brew.sh/api、artifact には https://ghcr.io になります。このプロキシを別のプロキシにチェーンするには、その Homebrew エンドポイントをアップストリームとして設定します:```yaml
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` で設定します:```erlang
{default_url, <<"http://localhost:8080/hex">>}.
または環境変数を設定します:```bash export HEX_MIRROR=http://localhost:8080/hex
### pub.dev (Dart/Flutter)
環境変数 PUB_HOSTED_URL を設定します:```bash
export PUB_HOSTED_URL=http://localhost:8080/pub
pip をプロキシ経由で使用するように設定します:```bash pip install --index-url http://localhost:8080/pypi/simple/ package_name
または `~/.pip/pip.conf` に設定します:```ini
[global]
index-url = http://localhost:8080/pypi/simple/
~/.m2/settings.xml に追加します:```xml
proxy
central
http://localhost:8080/maven/
`/maven/` エンドポイントは、プライマリ上流として Maven Central を使用し、プライマリ上流が not found を返した場合、Gradle プラグインマーカーのメタデータおよび関連アーティファクトについて Gradle Plugin Portal にフォールバックします。
同じプロキシエンドポイント経由での Gradle プラグイン解決の場合:```kotlin
pluginManagement {
repositories {
maven(url = "http://localhost:8080/maven/")
}
}
settings.gradle(.kts) で設定します:```kotlin
buildCache {
local {
enabled = false
}
remote {
url = uri("http://localhost:8080/gradle/")
push = true
}
}
### NuGet
`nuget.config` で設定します:```xml
<configuration>
<packageSources>
<clear />
<add key="proxy" value="http://localhost:8080/nuget/v3/index.json" />
</packageSources>
</configuration>
またはCLIを使用します:```bash dotnet nuget add source http://localhost:8080/nuget/v3/index.json -n proxy
### Composer (PHP)
`composer.json` で設定します:```json
{
"repositories": [
{
"type": "composer",
"url": "http://localhost:8080/composer"
}
]
}
またはグローバルに設定します:```bash composer config -g repositories.proxy composer http://localhost:8080/composer
### Conan (C/C++)
プロキシをリモートとして追加します:```bash
conan remote add proxy http://localhost:8080/conan
conan remote disable conancenter
~/.conan2/remotes.json で設定します。
~/.condarc で設定します:```yaml
channels:
またはコマンドで設定します:```bash
conda config --add channels http://localhost:8080/conda/main
R でリポジトリを設定します:```r options(repos = c(CRAN = "http://localhost:8080/cran"))
または永続化するには `~/.Rprofile` に記述します:```r
local({
r <- getOption("repos")
r["CRAN"] <- "http://localhost:8080/cran"
options(repos = r)
})
Julia を起動する前に Pkg サーバーを設定します:```bash export JULIA_PKG_SERVER=http://localhost:8080/julia
実行中のセッション内で:```julia
ENV["JULIA_PKG_SERVER"] = "http://localhost:8080/julia"
using Pkg; Pkg.update()
現在の Swift パッケージのデフォルトレジストリとしてプロキシを設定します:```bash swift package-registry set --allow-insecure-http http://localhost:8080/swift
Registry の依存関係は、`Package.swift` 内でスコープ付きパッケージ識別子を使用します:```swift
dependencies: [
.package(id: "apple.swift-argument-parser", from: "1.2.0")
]
プロキシは依存関係の解決とソースのダウンロードをサポートしています。swift package-registry publish による公開はサポートされていません。
/etc/docker/daemon.json でプロキシをレジストリミラーとして使用するように Docker を設定します:```json
{
"registry-mirrors": ["http://localhost:8080"]
}
その後、Docker を再起動します:```bash
sudo systemctl restart docker
またはイメージを直接プルします:```bash docker pull localhost:8080/library/nginx:latest
### Helm
各HTTPチャートリポジトリに名前を設定し、対応するプロキシURLをHelmに追加します:```yaml
upstream:
helm:
bitnami: "https://charts.bitnami.com/bitnami"
detect コマンドは、プロジェクトの依存関係マニフェストをスキャンして既知の脆弱性を探すことで、サプライチェーンリスクを特定します。以下のことを行います:
package.json、requirements.txt、go.mod、Cargo.toml、pom.xml など)を探します。# 現在のディレクトリをスキャン
scantist detect
# 特定のプロジェクトディレクトリをスキャン
scantist detect --path /path/to/project
# 出力形式を指定
scantist detect --format json
scantist detect --format sarif
CRITICAL lodash <4.17.21 Prototype Pollution (CVE-2021-23337)
HIGH minimist <1.2.6 Prototype Pollution (CVE-2021-44906)
MEDIUM axios <0.21.2 SSRF (CVE-2021-3749)
| フラグ | 説明 |
|---|---|
--path | スキャンするディレクトリ(デフォルト: .) |
--format | 出力形式: text、json、sarif(デフォルト: text) |
--severity | 最低重大度でフィルタリング: low、medium、high、critical |
--ignore | 無視するパッケージまたは CVE ID のカンマ区切りリスト |
--fail-on | この重大度以上でゼロ以外の終了コードを返す |
| コード | 意味 |
|---|---|
0 | 脆弱性は見つかりませんでした |
1 | 脆弱性が見つかりました(--fail-on のしきい値以上) |
2 | スキャンエラー(無効なパス、解析失敗) |
| helm repo add bitnami http://localhost:8080/helm/bitnami | |
| helm repo update | |
| helm pull bitnami/nginx |
プロキシは、通常のメタデータキャッシュ設定を使用して `index.yaml` をキャッシュし、インデックスから SHA-256 ダイジェストを検証した後にチャートアーカイブをキャッシュします。
OCI レジストリに保存されているチャートの場合は、名前付き OCI アップストリームを設定し、予約済みの `upstream/{name}` プレフィックスをチャート参照に追加します:```yaml
upstream:
oci:
ghcr: "https://ghcr.io"
I don't see any content to translate. Please provide the Markdown chunk you'd like translated from English to Japanese.```bash helm pull oci://localhost:8080/upstream/ghcr/owner/charts/mychart --version 1.0.0 --plain-http
### Debian / APT
APT が `/etc/apt/sources.list.d/proxy.list` 内のプロキシを使用するように設定します:```
deb http://localhost:8080/debian stable main contrib
既存の sources.list エントリを置き換えてから、次を実行します:```bash sudo apt update
上流はデフォルトで `http://deb.debian.org/debian` です。別の APT リポジトリ(例: Ubuntu)をプロキシするには、設定ファイルで `upstream.debian` を、または環境変数で `PROXY_UPSTREAM_DEBIAN` を設定します:```yaml
upstream:
debian: "http://archive.ubuntu.com/ubuntu"
yum/dnf が /etc/yum.repos.d/proxy.repo 内のプロキシを使用するように設定します:```ini
[proxy-fedora]
name=Fedora via Proxy
baseurl=http://localhost:8080/rpm/releases/$releasever/Everything/$basearch/os/
enabled=1
gpgcheck=0
次に:```bash
sudo dnf clean all
sudo dnf update
/etc/apk/repositories をプロキシに向けます。デフォルトのリポジトリ名
alpine は公式ミラー (https://dl-cdn.alpinelinux.org/alpine) をプロキシします:```
http://localhost:8080/apk/alpine/v3.22/main
http://localhost:8080/apk/alpine/v3.22/community
次に:```bash
apk update
リポジトリインデックス(v2 の APKINDEX.tar.gz と v3 の Packages.adb)、分離署名、およびパッケージはバイト単位で変更されずに配信されるため、apk の通常の署名検証は引き続き機能します。インデックスはメタデータキャッシュ(metadata_ttl、stale フォールバック)を使用し、.apk パッケージは共有アーティファクトキャッシュに保存され、上流に到達できない場合でも利用可能なままです。
他のミラーやプライベートリポジトリをプロキシするには、upstream.apk の下に名前付き上流を設定します(これは組み込みのデフォルトを置き換えます。まだ必要なら alpine を再追加してください):```yaml
upstream:
apk:
alpine: "https://dl-cdn.alpinelinux.org/alpine"
private: "https://apk.example.com"
## 検出
### 検出の仕組み
`detect` は、`--path` で指定されたディレクトリを再帰的にスキャンし、各ファイルを順番に処理します。各ファイルは次の順序で処理されます。
1. **ファイルの読み取り** — ファイルが読み込まれます。バイナリファイルはスキップされます。
2. **パーサーの選択** — ファイル拡張子に基づいてパーサーが選択されます。
3. **パース** — パーサーがファイルから `Package` オブジェクトを抽出します。
4. **マッチング** — 各 `Package` は、`--rules` で指定されたルールファイルに対してマッチングされます。
5. **レポート** — マッチした結果は、`--format` で指定された形式で出力されます。
### パーサー
パーサーは、ファイルからパッケージ情報を抽出する役割を担います。各パーサーは特定のファイルタイプを処理します。
| パーサー | ファイルタイプ |
|--------|-----------|
| `apk` | Alpine APK データベース |
| `dpkg` | Debian dpkg データベース |
| `rpm` | RPM データベース |
| `lock` | ロックファイル (package-lock.json, yarn.lock, etc.) |
| `sbom` | SBOM ファイル (SPDX, CycloneDX) |
| `os` | OS リリースファイル |
### ルール
ルールは、パッケージを既知の脆弱性と照合するために使用されます。ルールは YAML 形式で記述され、`--rules` フラグで指定されたディレクトリに配置されます。
ルールファイルの例:
```yaml
rules:
- name: "CVE-2021-44228"
description: "Log4Shell"
package:
name: "log4j"
version: "< 2.15.0"
severity: "critical"
--format フラグは、検出結果の出力形式を制御します。サポートされている形式は次のとおりです。
| 形式 | 説明 |
|---|---|
table | 人間が読みやすい表形式 (デフォルト) |
json | JSON 形式 |
sarif | SARIF 形式 |
csv | CSV 形式 |
# ディレクトリをスキャンして結果を表形式で出力
detect --path /path/to/scan
# ルールを指定して JSON 形式で出力
detect --path /path/to/scan --rules /path/to/rules --format json
# 特定のパーサーのみを使用
detect --path /path/to/scan --parsers dpkg,rpm
apk は各リポジトリ行自体にアーキテクチャとインデックスファイル名を追加します。
### GitHub Releases / mise (aqua バックエンド)
名前付きの汎用アップストリームを設定します:```yaml
upstream:
generic:
github: "https://github.com"
github-api: "https://api.github.com"
次に、miseの設定(~/.config/mise/config.toml、mise ≥ 2025.9.3)でGitHub URLを書き換えます:```toml
[settings.url_replacements]
"regex:^https://github\\.com/([^/]+)/([^/]+)/releases/download/(.+)" = "http://localhost:8080/generic/github/$1/$2/releases/download/$3"
"regex:^https://api\\.github\\.com/(.*)" = "http://localhost:8080/generic/github-api/$1"
リリースアセットは初回ダウンロード後に永続的にキャッシュされ、GitHubがダウンしている間もインストールを続けます。`api.github.com` 経由のタグ検索は `metadata_ttl` の間キャッシュされ、障害やレート制限時には古いものが提供されます。`mise.lock` をコミットし、`mise install --locked` でインストールすれば、固定されたインストールにはAPI呼び出しが一切不要になります。フリートがGitHubの匿名レート制限を超える場合は、`upstream.auth` の下に `https://api.github.com` 用のベアラートークンを追加してください。
## 設定
プロキシは以下の方法で設定できます:
1. コマンドラインフラグ(最優先)
2. 環境変数
3. 設定ファイル(YAMLまたはJSON)
### コマンドラインフラグ```
-config string Path to configuration file
-listen string Address to listen on (default ":8080")
-base-url string Public URL of this proxy (default "http://localhost:8080")
-storage-url string Storage URL (file://, s3://, gs://, azblob://)
-storage-path string Path to artifact storage directory (deprecated, use -storage-url)
-database-driver string Database driver: sqlite or postgres (default "sqlite")
-database-path string Path to SQLite database file (default "./cache/proxy.db")
-database-url string PostgreSQL connection URL
-log-level string Log level: debug, info, warn, error (default "info")
-log-format string Log format: text, json (default "text")
-access-log string Path to the JSONL access log
-version Print version and exit
PROXY_LISTEN=:8080 PROXY_BASE_URL=http://localhost:8080 PROXY_UI_URL=http://localhost:8080 # Optional; defaults to PROXY_BASE_URL PROXY_STORAGE_URL=file:///var/cache/proxy/artifacts PROXY_DATABASE_DRIVER=sqlite PROXY_DATABASE_PATH=./cache/proxy.db PROXY_DATABASE_URL=postgres://user:pass@localhost/proxy?sslmode=disable PROXY_LOG_LEVEL=info PROXY_LOG_FORMAT=text PROXY_ACCESS_LOG_PATH=/var/log/proxy/access.jsonl PROXY_UPSTREAM_SWIFT=https://tuist.dev/api/registry/swift
### 設定ファイル```yaml
listen: ":8080"
base_url: "http://localhost:8080"
storage:
url: "file:///var/cache/proxy/artifacts"
max_size: "10GB" # Optional: evict LRU when exceeded
database:
driver: "sqlite"
path: "/var/lib/proxy/cache.db"
log:
level: "info"
format: "text"
access_log:
path: "/var/log/proxy/access.jsonl" # Optional JSONL activity log
# Optional: override upstream URLs
upstream:
npm: "https://registry.npmjs.org"
cargo: "https://index.crates.io"
swift: "https://tuist.dev/api/registry/swift"
# Optional: version cooldown (see above)
cooldown:
default: "3d"
設定リファレンス(configuration reference)で、すべてのアップストリームキー、環境変数、デフォルトURLを確認してください。
設定ファイルを使用して実行:```bash ./proxy -config /etc/proxy/config.yaml
### PostgreSQL
SQLite がデフォルトであり、単一ノード構成では問題なく動作します。マルチノード構成の場合、またはマネージドデータベースを希望する場合は、Postgres に切り替えてください:```yaml
database:
driver: "postgres"
url: "postgres://user:password@localhost:5432/proxy?sslmode=disable"
または環境変数経由で:```bash PROXY_DATABASE_DRIVER=postgres PROXY_DATABASE_URL=postgres://user:password@localhost:5432/proxy?sslmode=disable
プロキシは初回実行時にテーブルを自動的に作成します。
### S3ストレージ
プロキシは、キャッシュされたアーティファクトをローカルファイルシステムの代わりにS3または任意のS3互換サービス(MinIO、R2など)に保存できます。```yaml
storage:
url: "s3://my-bucket-name?region=us-east-1"
MinIOのようなS3互換サービス向け:```yaml storage: url: "s3://my-bucket?endpoint=http://localhost:9000&disableSSL=true&s3ForcePathStyle=true"
認証情報は標準の AWS 環境変数(`AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY`、`AWS_REGION`)で設定します。
### Google Cloud Storage
プロキシは `gs://` URL スキームを使用して、キャッシュされたアーティファクトを GCS バケットに保存できます。```yaml
storage:
url: "gs://my-bucket-name"
認証にはApplication Default Credentialsを使用するため、認証情報を設定や環境に埋め込む必要はありません。サポートされるソースは以下の順序です:
roles/storage.objectAdminを持つGoogleサービスアカウントにバインドします。プロキシはワークロードのトークンを自動的に使用します。GOOGLE_APPLICATION_CREDENTIALS**環境変数。gcloud auth application-default login**。gcloud iam service-accounts create git-pkgs-proxy
--project=PROJECT_ID
gsutil iam ch
serviceAccount:git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com:objectAdmin
gs://my-bucket-name
gcloud iam service-accounts add-iam-policy-binding
git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com
--role=roles/iam.workloadIdentityUser
--member="serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]"
kubectl annotate serviceaccount KSA_NAME
--namespace=NAMESPACE
iam.gke.io/gcp-service-account=git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com
#### Workload Identity を使用した直接配信(署名付き URL)
`direct_serve: true` が有効な場合、プロキシは署名付き GCS URL への HTTP 302 リダイレクトを発行します。Workload Identity は秘密鍵を提供しないため、GCS バックエンドは [IAM Credentials `signBlob` API](https://docs.cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob) を呼び出します。サービスアカウント自身にトークン作成者ロールを付与してください:```bash
gcloud iam service-accounts add-iam-policy-binding \
git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com \
--role=roles/iam.serviceAccountTokenCreator \
--member="serviceAccount:git-pkgs-proxy@PROJECT_ID.iam.gserviceaccount.com"
プロキシサーバーを起動します。コマンドが指定されていない場合、これがデフォルトのコマンドです。```bash proxy serve [flags] proxy [flags] # same as 'proxy serve'
### mirror
PURL、SBOMファイル、またはレジストリ全体からキャッシュを事前に投入します。オフラインでの可用性を確保したり、デプロイ前にキャッシュをウォームアップするのに役立ちます。```bash
# Mirror specific package versions
proxy mirror pkg:npm/[email protected] pkg:cargo/[email protected]
# Mirror all versions of a package
proxy mirror pkg:npm/lodash
# Mirror from a CycloneDX or SPDX SBOM
proxy mirror --sbom sbom.cdx.json
# Preview what would be mirrored
proxy mirror --dry-run pkg:npm/lodash
# Control parallelism
proxy mirror --concurrency 8 pkg:npm/[email protected]
mirror コマンドは serve と同じストレージおよびデータベースのフラグを受け付けます。すでにキャッシュされているアーティファクトはスキップされます。
サーバーの実行中は、mirror API も利用できます:```bash
curl -X POST http://localhost:8080/api/mirror
-H "Content-Type: application/json"
-d '{"purls": ["pkg:npm/[email protected]"]}'
curl -X POST http://localhost:8080/api/mirror
-H "Content-Type: application/json"
-d '{"sbom":{"bomFormat":"CycloneDX","components":[{"purl":"pkg:npm/[email protected]"}]}}'
curl -X DELETE http://localhost:8080/api/mirror/mirror-1
### stats
サーバーを実行せずにキャッシュ統計を表示します。```bash
# Text output
proxy stats
# JSON output
proxy stats -json
# Custom database path
proxy stats -database-path /var/lib/proxy/cache.db
# With PostgreSQL
proxy stats -database-driver postgres -database-url postgres://user:pass@localhost/proxy
# Show top 20 most popular packages
proxy stats -popular 20
Packages: 45 Versions: 128 Artifacts: 128 Total size: 892.4 MB Total hits: 1547
Packages by ecosystem: npm 32 cargo 13
Most popular packages:
Recently cached: npm/[email protected] (2024-01-15 14:32, 54.2 KB) cargo/[email protected] (2024-01-15 14:28, 412.8 KB)
## APIエンドポイント
### レジストリプロトコル
| エンドポイント | 説明 |
|----------|-------------|
| `GET /` | ダッシュボード(Web UI) |
| `GET /health` | ヘルスチェックと上流サーキットブレーカーの状態(JSON、HTTP 200 は正常、503 は異常) |
| `GET /stats` | キャッシュ統計(JSON) |
| `GET /metrics` | Prometheusメトリクス |
| `GET /npm/*` | npmレジストリプロトコル |
| `GET /cargo/*` | Cargo sparseインデックスプロトコル |
| `GET /gem/*` | RubyGemsプロトコル |
| `GET /go/*` | Goモジュールプロキシプロトコル |
| `GET /hex/*` | Hex.pmプロトコル |
| `GET /pub/*` | pub.devプロトコル |
| `GET /pypi/*` | PyPI simple/JSON API |
| `GET /maven/*` | Mavenリポジトリプロトコル |
| `GET /nuget/*` | NuGet V3 API |
| `GET /composer/*` | Composer/Packagistプロトコル |
| `GET /conan/*` | Conan C/C++プロトコル |
| `GET /conda/*` | Conda/Anacondaプロトコル |
| `GET /cran/*` | CRAN(R)プロトコル |
| `GET /julia/*` | Julia Pkgサーバープロトコル |
| `GET /swift/*` | Swift Package Registry v1プロトコル |
| `GET /helm/{repository}/*` | HTTP Helmチャートリポジトリプロトコル |
| `GET /homebrew/*` | Homebrew JSON API |
| `GET /v2/*` | OCI/Dockerレジストリプロトコル |
| `GET /v2/homebrew/core/*` | GHCRからのHomebrew coreボトルマニフェストとブロブ |
| `GET /apk/{repository}/*` | Alpine APKリポジトリプロトコル |
| `GET /generic/{name}/*` | 汎用HTTPダウンロードプロキシ(GitHubリリースアセット、mise/aqua) |
| `GET /debian/*` | Debian/APTリポジトリプロトコル |
| `GET /rpm/*` | RPM/Yumリポジトリプロトコル |
### ミラーAPI
| エンドポイント | 説明 |
|----------|-------------|
| `POST /api/mirror` | ミラージョブを開始(`purls`またはインライン`sbom`を含むJSONボディ) |
| `GET /api/mirror/{id}` | ジョブのステータスと進捗を取得 |
| `DELETE /api/mirror/{id}` | 実行中のジョブをキャンセル |
### エンリッチメントAPI
プロキシは、パッケージメタデータのエンリッチメント、脆弱性スキャン、および古いバージョンの検出のためのRESTエンドポイントを提供します。
| エンドポイント | 説明 |
|----------|-------------|
| `GET /api/package/{ecosystem}/{name}` | パッケージメタデータを取得 |
| `GET /api/package/{ecosystem}/{name}/{version}` | 脆弱性を含むバージョンメタデータを取得 |
| `GET /api/vulns/{ecosystem}/{name}` | パッケージのすべての脆弱性を取得 |
| `GET /api/vulns/{ecosystem}/{name}/{version}` | 特定のバージョンの脆弱性を取得 |
| `POST /api/outdated` | 複数のパッケージの古いバージョンをチェック |
| `POST /api/bulk` | パッケージメタデータの一括検索 |
#### パッケージメタデータの取得```bash
curl http://localhost:8080/api/package/npm/lodash
応答:```json { "ecosystem": "npm", "name": "lodash", "latest_version": "4.17.21", "license": "MIT", "license_category": "permissive", "description": "Lodash modular utilities", "homepage": "https://lodash.com/", "repository": "https://github.com/lodash/lodash", "registry_url": "https://registry.npmjs.org" }
#### 脆弱性を含むバージョンを取得```bash
curl http://localhost:8080/api/package/npm/lodash/4.17.0
応答:```json { "package": { "ecosystem": "npm", "name": "lodash", "latest_version": "4.17.21", "license": "MIT", "license_category": "permissive" }, "version": { "ecosystem": "npm", "name": "lodash", "version": "4.17.0", "license": "MIT", "published_at": "2016-06-17T03:59:56Z", "yanked": false, "is_outdated": true }, "vulnerabilities": [ { "id": "GHSA-p6mc-m468-83gw", "summary": "Prototype Pollution in lodash", "severity": "HIGH", "cvss_score": 7.4, "fixed_version": "4.17.12" } ], "is_outdated": true, "license_category": "permissive" }
#### 古いパッケージの確認```bash
curl -X POST http://localhost:8080/api/outdated \
-H "Content-Type: application/json" \
-d '{
"packages": [
{"ecosystem": "npm", "name": "lodash", "version": "4.17.0"},
{"ecosystem": "pypi", "name": "requests", "version": "2.25.0"}
]
}'
応答:```json { "results": [ { "ecosystem": "npm", "name": "lodash", "version": "4.17.0", "latest_version": "4.17.21", "is_outdated": true }, { "ecosystem": "pypi", "name": "requests", "version": "2.25.0", "latest_version": "2.31.0", "is_outdated": true } ] }
#### 一括パッケージ検索```bash
curl -X POST http://localhost:8080/api/bulk \
-H "Content-Type: application/json" \
-d '{
"purls": [
"pkg:npm/[email protected]",
"pkg:pypi/[email protected]"
]
}'
応答:```json { "packages": { "pkg:npm/lodash": { "ecosystem": "npm", "name": "lodash", "latest_version": "4.17.21", "license": "MIT", "license_category": "permissive" }, "pkg:pypi/requests": { "ecosystem": "pypi", "name": "requests", "latest_version": "2.31.0", "license": "Apache-2.0", "license_category": "permissive" } } }
### 統計レスポンス (HTTPエンドポイント)```json
{
"cached_artifacts": 142,
"total_size_bytes": 523456789,
"total_size": "499.2 MB",
"storage_url": "file:///path/to/cache/artifacts",
"database_path": "./cache/proxy.db"
}
## Web インターフェース
プロキシは `/ui` 配下で Web UI を提供します。別途フロントエンドのビルドは不要です -- テンプレートとアセットはバイナリに埋め込まれています。`GET /` は `/ui/` にリダイレクトされます。UI は独自のプレフィックス配下にマウントされているため、リバースプロキシでパッケージエンドポイントとは異なるアクセスルールを適用できます(例えば、`PathPrefix(/ui)` には認証を要求しつつ、`/npm` や `/pypi` などはビルドマシンに対してオープンなままにする、といったことが可能です)。
- **ダッシュボード** (`/ui/`) -- キャッシュ統計、人気パッケージ、最近キャッシュされたアーティファクト、脆弱性の概要。
- **インストールガイド** (`/ui/install`) -- エコシステムごとの設定手順。ここで調べ直す必要はありません。
- **パッケージブラウザ** (`/ui/packages`) -- キャッシュされたすべてのパッケージを、エコシステムによるフィルタリングと、ヒット数・サイズ・名前・脆弱性数によるソートで閲覧できます。
- **検索** (`/ui/search?q=...`) -- キャッシュされたパッケージを名前で検索します。
- **パッケージ詳細** (`/ui/package/{ecosystem}/{name}`) -- パッケージのメタデータ、ライセンス、脆弱性、バージョン一覧。2 つのバージョンを選択して比較できます。
- **バージョン詳細** (`/ui/package/{ecosystem}/{name}/{version}`) -- バージョンごとのメタデータ、整合性ハッシュ、アーティファクトのキャッシュ状態、ヒット数。
- **ソースブラウザ** (`/ui/package/{ecosystem}/{name}/{version}/browse`) -- キャッシュされたアーカイブ内のファイルを、テキストファイルのシンタックスハイライトと画像プレビュー付きで閲覧できます。
- **バージョン差分** (`/ui/package/{ecosystem}/{name}/compare/{v1}...{v2}`) -- キャッシュされた 2 つのバージョンの並列差分。追加・削除・変更されたファイルを表示します。
## モニタリング
プロキシは `GET /metrics` で Prometheus メトリクスを公開します。すべてのメトリクス名には `proxy_` というプレフィックスが付きます。
| メトリクス | 型 | ラベル | 説明 |
|--------|------|--------|-------------|
| `proxy_requests_total` | counter | `ecosystem`, `status` | パッケージエコシステムと HTTP ステータス別のプロキシ応答数 |
| `proxy_request_duration_seconds` | histogram | `ecosystem`, `status` | プロキシリクエストの所要時間 |
| `proxy_cache_hits_total` | counter | `ecosystem` | キャッシュヒット数 |
| `proxy_cache_misses_total` | counter | `ecosystem` | キャッシュミス数 |
| `proxy_cache_size_bytes` | gauge | | キャッシュされたアーティファクトの合計サイズ |
| `proxy_cached_artifacts_total` | gauge | | キャッシュされたアーティファクトの数 |
| `proxy_upstream_fetch_duration_seconds` | histogram | `ecosystem` | アップストリームからの取得に費やした時間 |
| `proxy_upstream_errors_total` | counter | `ecosystem`, `error_type` | アップストリーム取得の失敗 |
| `proxy_storage_operation_duration_seconds` | histogram | `operation` | ストレージの読み書きレイテンシ |
| `proxy_storage_errors_total` | counter | `operation` | ストレージの読み書き失敗 |
| `proxy_active_requests` | gauge | | 処理中のリクエスト |
| `proxy_health_probe_failures_total` | counter | `step` | 失敗したステップ (`write`, `size`, `read`, `verify`, `delete`) 別のストレージヘルスプローブ失敗数。 |
| `proxy_circuit_breaker_state` | gauge | `registry` | アップストリームレジストリごとのアーティファクト取得サーキットブレーカーの状態 (0 は closed、2 は open)。そのレジストリのブレーカーが一度でもトリップした後に公開されます。 |
| `proxy_circuit_breaker_trips_total` | counter | `registry` | アップストリームレジストリごとのサーキットブレーカーのトリップ数。 |
キャッシュサイズとアーティファクト数は 60 秒ごとに更新されます。サーキットブレーカーの状態は `/metrics` のスクレイプごと、および `/health` リクエストごとにフェッチャーから読み取られるため、`proxy_circuit_breaker_trips_total` はそれらの読み取りの間に見えたトリップ数をカウントします — 2 回のスクレイプの間に完全に open になって復旧したブレーカーはカウントされません。残りのメトリクスはリクエストごとに更新されます。
ブレーカーのメトリクスはアップストリームホストごとに 1 つのシリーズを持ちますが、起動以降に少なくとも一度トリップしたホストについてのみです。ブレーカーはプロキシがアーティファクトを取得するホストごとに作成され、一部のエコシステムではそのホストは設定ではなくアップストリームのメタデータから取得されます(composer はパッケージの `dist.url` から、helm は `index.yaml` 内のチャート URL から取得します)。そのため、すべてのホストを公開すると、アップストリームのコンテンツによってプロセスの生存期間中シリーズ数が増え続けることになります。一度トリップしたホストは報告を続けるため、復旧してもシリーズが消えるのではなく 0 への遷移として現れます。`/health` は永続的な時系列ではなく、トリップの有無にかかわらずすべてのブレーカーを一覧表示します。
`registry` ラベルは、アーティファクトの取得元 URL のホストです。この URL はアップストリームのメタデータから取得されることがあるため、常にホストを読み取れるとは限りません — 例えば、パースに失敗する署名付きの `dist.url` などです — そのようなブレーカーは代わりに `hostless-url-<digest>` というラベルが付きます。ここで digest は起動時に新しく生成された値をキーとします。`/metrics` も `/health` も認証を必要としないため、取得 URL がラベルやキーとして公開されることはありません。digest はプロセスが動作している間そのブレーカーを識別しますが、その背後にある URL を明かすことも、選んだ URL をそれに照合させることもできません。
`proxy_circuit_breaker_state == 2` が数分以上持続した場合にアラートを出してください。ブレーカーが open の間は、そのアップストリームのアーティファクトダウンロードはキャッシュミスのたびに HTTP 502 で失敗し、バックオフ間隔ごとに 1 つのプローブリクエストだけがアップストリームに到達します。キャッシュされたアーティファクトは提供され続け、同じエコシステムのメタデータも同様です(メタデータはサーキットブレーカーを経由しません)。そのため、インストールはアップストリームの部分的な障害のように見える形で失敗します。
### ヘルスチェック
`/health` はサブシステムのヘルス状態を構造化された JSON レポートとして返します。すべてのチェックが成功すれば HTTP 200、いずれかが失敗すれば 503 を返します。```json
{
"status": "ok",
"checks": {
"database": {"status": "ok"},
"storage": {"status": "ok"}
},
"circuit_breakers": {
"registry.npmjs.org": "closed",
"static.crates.io": "open"
}
}
失敗したチェックには "error" フィールドが含まれます。ストレージ障害には、どのプローブステップが失敗したかを示す "step" フィールドも含まれます(write、size、read、verify、delete)。データベースチェックが失敗すると、ストレージエントリは {"status": "skipped"} を報告するため、レスポンスは常に同じキーセットを持ちます。
circuit_breakers は、各アップストリームのアーティファクト取得サーキットブレーカーの状態("open" または "closed")を、アップストリームホストをキーとして報告します。または、取得 URL に読み取るホストがない場合は Monitoring で説明されている hostless-url-<digest> プレースホルダーをキーとします。このキーは、プロキシが少なくとも 1 つのアップストリームからアーティファクトを取得するまで省略され、ホストはそのホストに対してブレーカーが作成された時点で初めて現れます。ブレーカーはアップストリームの障害が繰り返されるとトリップし、指数バックオフ後にアップストリームを再試行します。ブレーカーが開いている間、そのホストのアーティファクトダウンロードは、キャッシュミス時にアップストリームに接触せず HTTP 502 を返します。すでにキャッシュされたアーティファクトは、キャッシュがフェッチャーより先にチェックされるため、引き続きストレージから提供されます。ブレーカーはバックオフ期間中ずっと "open" として報告されます。これには、回復をテストするために 1 つのプローブリクエストを許可するハーフオープン期間も含まれます。ブレーカーの状態はプロセスごと、かつメモリ内にあるため、再起動でクリアされますが、回復に再起動は必要ありません。バックオフはブレーカーが開いている限り再試行を続けるため、アップストリームが再び応答するようになれば自然にクローズします。
開いたブレーカーは status を "error" に設定したり、HTTP ステータスコードを変更したりしません。これは特定のアップストリームが応答を拒否していることを報告するものであり、このプロキシがトラフィックを受け取るのに適していないというわけではありません。また、1 つの不健全なアップストリームのためにレディネスプローブを失敗させると、他のすべてのエコシステムに対してもポッドがローテーションから外れてしまいます。これに対するアラートには proxy_circuit_breaker_state を使用してください。
ストレージプローブの結果は、リモートバックエンドのプローブコストを抑えるために health.storage_probe_interval(デフォルト 30 秒)の間キャッシュされます。プローブは最大 10 秒間(ハードコードされたプローブごとのタイムアウト)内部ミューテックスを保持するため、/health は liveness プローブではなく Kubernetes の readiness プローブとして意図されています。遅い S3 のラウンドトリップはポッドを再起動させるのではなく、ローテーションから外すべきです。
Prometheus のスクレイプ設定:```yaml scrape_configs:
## 本番環境へのデプロイ
### Systemd サービス
`/etc/systemd/system/proxy.service` を作成します:```ini
[Unit]
Description=git-pkgs proxy
After=network.target
[Service]
Type=simple
User=proxy
ExecStart=/usr/local/bin/proxy -config /etc/proxy/config.yaml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
有効化して起動:```bash sudo systemctl enable proxy sudo systemctl start proxy
### Docker
リポジトリには Dockerfile が含まれています。ビルドと実行:```bash
docker build -t proxy .
docker run -p 8080:8080 -v proxy-data:/data proxy
Postgres と S3 を使用する場合:```bash
docker run -p 8080:8080
-e PROXY_DATABASE_DRIVER=postgres
-e PROXY_DATABASE_URL=postgres://user:pass@db:5432/proxy
-e PROXY_STORAGE_URL=s3://my-bucket?region=us-east-1
-e AWS_ACCESS_KEY_ID=...
-e AWS_SECRET_ACCESS_KEY=...
proxy
### リバースプロキシの背後で
nginx、Apache、または別のリバースプロキシの背後で実行する場合、`base_url` を公開URLに設定します:```yaml
base_url: "https://proxy.example.com"
UI がパッケージエンドポイントとは異なるホスト名でアクセスされる場合 — たとえば、UI がドメイン上で公開されている一方、ビルドマシンが Docker ネットワークエイリアスにアクセスする場合 — は、ui_base_url を別途設定します。base_url はパッケージマネージャーとメタデータ書き換えが使用する URL であり、ui_base_url は Web UI を訪れる人間に通知される URL(canonical/og:url タグおよびインストールガイドのバナー)です:```yaml
base_url: "http://pkg-proxy:8080" # internal alias for build machines
ui_base_url: "https://proxy.example.com/ui" # public UI URL
未設定の場合、`ui_base_url` は `base_url` にデフォルト設定されます。
> **警告:** プロキシは UI とパッケージエンドポイントを同じリスナーで提供します。`ui_base_url` を設定しても、UI が人間に対して通知する URL が変わるだけで、同じホスト名とポートでパッケージエンドポイントに到達できなくなるわけではありません。プロキシを公開リバースプロキシの背後に置く場合、公開ルートを `PathPrefix(/ui)`(または使用するプロキシの同等の設定)に制限してください。そうしないと、`/npm`、`/pypi`、およびその他のパッケージエンドポイントが UI とともに公開されたままになります。
nginx の例。公開ホストを UI に制限し、パッケージエンドポイントは内部リスナーからのみ到達可能にします:```nginx
server {
listen 443 ssl;
server_name proxy.example.com;
location /ui/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
}
location / {
return 404;
}
}
PathPrefix(/ui) を使用した Traefik の例。これにより、パブリックルーターは UI トラフィックのみにマッチします:```yaml
labels:
traefik.enable: "true"
traefik.http.services.pkg-proxy.loadbalancer.server.port: "8080"
traefik.http.routers.pkg-proxy.rule: "Host(proxy.example.com) && PathPrefix(/ui)"
traefik.http.routers.pkg-proxy.entrypoints: "websecure"
## キャッシュ管理
プロキシは、設定されたストレージディレクトリに次の構造でアーティファクトを保存します:```
cache/artifacts/
├── npm/
│ └── lodash/
│ └── 4.17.21/
│ └── lodash-4.17.21.tgz
├── cargo/
│ └── serde/
│ └── 1.0.193/
│ └── serde-1.0.193.crate
├── oci/
│ └── library/nginx/
│ └── sha256:abc123.../
│ └── sha256:abc123...
├── deb/
│ └── nginx/
│ └── 1.18.0-6/
│ └── nginx_1.18.0-6_amd64.deb
└── rpm/
└── nginx/
└── 1.24.0-1.fc39/
└── nginx-1.24.0-1.fc39.x86_64.rpm
キャッシュメタデータはSQLite(デフォルト)またはPostgreSQLに保存されます。ローカルキャッシュをクリアするには:```bash rm -rf ./cache/artifacts/* rm ./cache/proxy.db
プロキシは次回起動時にデータベースを再作成します。
## ソースからのビルド
要件:
- Go (`go.mod` でプロジェクトのバージョンが宣言されています)```bash
git clone https://github.com/git-pkgs/proxy.git
cd proxy
go build -o proxy ./cmd/proxy
テストを実行します:```bash go test ./...
## ライセンス
GPL-3.0-or-later
| Chef | Chef | ✗ |
| Generic | Any | ✓ |
| Helm | Kubernetes | ✓ |
| Vagrant | Vagrant | ✗ |