goproxy

package
v0.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package goproxy implements proxies.CacheProxy for Go modules.

It implements the Go module proxy protocol (GOPROXY spec) and caches immutable responses (.info, .mod, .zip) on disk. Mutable endpoints (list, @latest) are passed through to the upstream proxy without caching.

ephemerd runs one shared instance on the bridge gateway IP so all job containers can reach it. Containers see it as GOPROXY=http://<gateway>:<port>. Jobs have no write access to the cache — they just make HTTP requests.

Why one shared cache across every job is safe

This is load-bearing and worth writing down, because the cache key is the request path and nothing else — no job, repo or owner identity takes part, so a module a job for repo A pulled is served to a job for repo B.

  1. Jobs cannot write the cache. They speak HTTP; only this daemon writes files.
  2. Key and content cannot disagree. cacheAndServe stores upstream's response for a path under the key derived from that same path, so a job can pick WHICH key gets populated but never WHAT goes in it.
  3. The `go` client authenticates modules itself, via go.sum and the checksum database. sumdb requests are passed straight through and never cached, so a mismatched .zip fails verification in the client. Note this is a property of the CLIENT, not of this proxy — this proxy verifies nothing, and a job that opts itself out (GOFLAGS=-mod=mod, GONOSUMDB, GOPRIVATE) only harms itself.
  4. Mutable endpoints (/@v/list, /@latest) are passed through, so a job cannot pin another job's view of "latest".

What sharing DOES expose is disk: any job can request arbitrarily many module versions and fill the node. That is what Prune bounds.

Index

Constants

View Source
const (
	// DefaultMaxCacheBytes is the ceiling applied when Config.MaxCacheBytes
	// is unset. See config.ModuleProxyConfig.MaxCacheGB for why 20 GiB.
	DefaultMaxCacheBytes int64 = 20 << 30

	// DefaultPruneInterval is how often eviction runs when
	// Config.PruneInterval is unset.
	DefaultPruneInterval = time.Hour
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	CacheDir   string // on-disk cache directory
	Upstream   string // upstream proxy URL (default: https://proxy.golang.org)
	ListenAddr string // address to listen on (e.g., "10.88.0.1:8082")
	Cleanup    bool   // wipe cache dir on Stop

	// MaxCacheBytes bounds the on-disk cache. Prune evicts
	// least-recently-used files until the directory is back under it.
	// Zero selects DefaultMaxCacheBytes; a negative value means unbounded.
	MaxCacheBytes int64

	// PruneInterval is how often the eviction pass runs. Zero selects
	// DefaultPruneInterval; a negative value disables periodic pruning
	// (Prune can still be called directly).
	PruneInterval time.Duration

	Log *slog.Logger
}

Config for the Go module caching proxy.

type Proxy

type Proxy struct {
	// contains filtered or unexported fields
}

Proxy is a caching Go module proxy server.

func New

func New(cfg Config) *Proxy

New creates a Go module caching proxy. Call Start() to begin serving.

func (*Proxy) Addr

func (p *Proxy) Addr() string

Addr returns the address the proxy is listening on.

func (*Proxy) EnvVars

func (p *Proxy) EnvVars() []string

EnvVars returns the environment variables to inject into job containers.

The advertised address is the CONFIGURED one (the bridge gateway), not p.Addr(): when the listener falls back to the wildcard, Addr() reports "[::]:8082", which is meaningless inside a container.

The "|" separator (not ",") is what makes this fail open. With ",direct" the go command only falls through to the origin on 404/410 — a proxy that is down, wedged, or returning 5xx hard-fails the build. With "|direct" it falls through on ANY error, so a broken cache degrades to a slower build instead of a red job.

func (*Proxy) Name

func (p *Proxy) Name() string

Name returns the proxy name for logging.

func (*Proxy) Prune added in v0.2.2

func (p *Proxy) Prune() (int64, error)

Prune evicts least-recently-used files until the cache directory is at or below MaxCacheBytes, then removes the directories that emptied. It returns the number of bytes freed.

This is the only thing bounding the cache. Every job on the node shares it and any job can ask for arbitrarily many module versions, so without a bound one job can fill the disk and degrade every job that follows it on that node. Safe to call at any time; it only ever removes cache files.

func (*Proxy) Start

func (p *Proxy) Start() error

Start begins serving the proxy. Returns after the listener is bound.

func (*Proxy) Stop

func (p *Proxy) Stop() error

Stop shuts down the proxy and optionally wipes the cache.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL