Skip to content

Instantly share code, notes, and snippets.

@brianmichel
Created September 18, 2025 16:28
Show Gist options
  • Select an option

  • Save brianmichel/b555eb64956ec867575cee05aa4c1c39 to your computer and use it in GitHub Desktop.

Select an option

Save brianmichel/b555eb64956ec867575cee05aa4c1c39 to your computer and use it in GitHub Desktop.
# A simple proxy that matches the interface for a Swift Package Registry.
# make sure to `export GITHUB_TOKEN` in your environment and it should be a fine-grained token with:
# - `content:read` scope on the browser company organization.
#
# Then run `caddy run --config Caddyfile` to start the proxy.
{
# Enable extra diagnostics in logs
debug
}
:8080 {
encode zstd gzip
# --------------------------------------------
# ZIP downloads
# /{owner}/{repo}/{version}.zip
# where {version} may include slashes (e.g., release/v0.78.1)
# → https://codeload.github.com/{owner}/{repo}/zip/refs/tags/{version}
# --------------------------------------------
@zip path_regexp zipre ^/(?P<owner>[^/]+)/(?P<repo>[^/]+)/(?P<ver>.+)\.zip$
handle @zip {
# https://api.github.com/repos/${scope}/${pkg}/zipball/refs/tags/${version}
# https://api.github.com/repos/thebrowsercompany/browser-swift-test-data/zipball/refs/tags/release/v0.78.1
rewrite * /repos/{http.regexp.zipre.owner}/{http.regexp.zipre.repo}/zipball/refs/tags/{http.regexp.zipre.ver}
reverse_proxy https://api.github.com {
header_up Host api.github.com
header_up -X-Forwarded-Host
header_up X-Forwarded-Proto https
# For private ZIPs only (leave off for public):
header_up Authorization "Bearer {$GITHUB_TOKEN}"
header_up User-Agent "swift-pkg-proxy"
header_down -Server
}
}
# --------------------------------------------
# Package.swift
# /{owner}/{repo}/{version}/Package.swift
# where {version} may include slashes
# → https://raw.githubusercontent.com/{owner}/{repo}/refs/tags/{version}/Package.swift
# --------------------------------------------
@manifest path_regexp manre ^/(?P<owner>[^/]+)/(?P<repo>[^/]+)/(?P<ver>.+)/Package\.swift$
# If ?swift-version=* is present, spec allows a 303 to the "unqualified" manifest URL.
@manifest_with_swift {
path_regexp mansw ^/(?P<owner>[^/]+)/(?P<repo>[^/]+)/(?P<ver>.+)/Package\.swift$
expression {query.swift-version} != ""
}
handle @manifest_with_swift {
header Location "/{http.regexp.mansw.owner}/{http.regexp.mansw.repo}/{http.regexp.mansw.ver}/Package.swift"
header Content-Version "1"
respond 303
}
handle @manifest {
rewrite * /{http.regexp.manre.owner}/{http.regexp.manre.repo}/refs/tags/{http.regexp.manre.ver}/Package.swift
reverse_proxy https://raw.githubusercontent.com {
header_up Host raw.githubusercontent.com
header_up -X-Forwarded-Host
header_up X-Forwarded-Proto https
# Keep Authorization OFF for public raw; enable only when needed:
header_up Authorization "Bearer {$GITHUB_TOKEN}"
header_up User-Agent "swift-pkg-proxy"
header_down -Server
}
}
# --------------------------------------------
# Not-implemented endpoints (widened to handle slashed versions)
# --------------------------------------------
# List releases (GET /{scope}/{name}) → 404
@list path_regexp list ^/[^/]+/[^/]+$
handle @list {
header Content-Type application/problem+json
header Content-Version "1"
respond 404 "{\"type\":\"about:blank\",\"title\":\"Not Found\",\"status\":404,\"detail\":\"Listing releases is not supported by this proxy.\"}"
}
# Release metadata (GET /{scope}/{name}/{version...}) → 404
@metadata path_regexp meta ^/[^/]+/[^/]+/.+$
handle @metadata {
header Content-Type application/problem+json
header Content-Version "1"
respond 404 "{\"type\":\"about:blank\",\"title\":\"Not Found\",\"status\":404,\"detail\":\"Release metadata is not available from GitHub without a backend.\"}"
}
# Publish (PUT /{scope}/{name}/{version...}) → 405
@publish {
method PUT
path_regexp pub ^/[^/]+/[^/]+/.+$
}
handle @publish {
header Content-Type application/problem+json
respond 405 "{\"type\":\"about:blank\",\"title\":\"Method Not Allowed\",\"status\":405,\"detail\":\"Publishing is not supported on this server.\"}"
}
# Login → 501
@login {
path /login
method POST
}
handle @login {
respond 501
}
# Single-URL identifiers:
# /identifiers?url=https://github.com/SDWebImage/SDWebImage.git
@identifiers path /identifiers
handle @identifiers {
# Run the body as a template (so we can transform the query string)
templates {
mime application/json
}
header Content-Type application/json
header Content-Version "1"
respond 200 {
body <<JSON
{{- $u := (index (index .Req.URL.Query "url") 0) -}}
{{- $s := $u | trimPrefix "https://github.com/" | trimPrefix "http://github.com/" -}}
{{- $s = $s | trimSuffix ".git" | trimSuffix "/" -}}
{{- $id := replace "/" "." $s -}}
{{- dict "identifiers" (list $id) | toJson -}}
JSON
}
}
# Fallback
handle {
respond 404
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment