mirror of
https://github.com/hanzoai/mod.git
synced 2026-09-30 22:56:06 +00:00
A module path is identity, not an address: `module github.com/hanzoai/o11y` is what every dependent's go.mod names, so the toolchain took a direct VCS fetch to github.com and needed a credential valid there. This answers for the name and reads the source from git.hanzo.ai, so a build resolves the module it already names with no GitHub credential in it. Resolution is the toolchain's own — module zips have rules about nested modules, vendor directories, symlinks, file modes and case collisions, and a zip that gets one wrong hashes differently and fails every caller's go.sum. Clients set GOPROXY and GONOSUMDB. Not GOPRIVATE: it means "bypass the proxy AND the checksum database", and bypassing the proxy is what reaches for github.com. Skipping the public checksum database for our namespaces is not skipping verification — go.sum still pins every module and is checked against these bytes. Inside our namespaces a failure answers 502, never 404: in this protocol 404 means "ask the next proxy", and the next proxy is public.
62 lines
1.6 KiB
Go
62 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// Configuration is read from the environment because every value here is
|
|
// deployment wiring — where the forge is, which namespaces we answer for — and
|
|
// none of it is a runtime policy anyone edits.
|
|
func main() {
|
|
forge := env("FORGE", "https://git.hanzo.ai")
|
|
token := os.Getenv("FORGE_TOKEN")
|
|
addr := env("ADDR", ":8080")
|
|
root := env("ROOT", "/var/lib/mod")
|
|
|
|
names := strings.Split(env("NAMESPACES", "github.com/hanzoai"), ",")
|
|
for i, n := range names {
|
|
names[i] = strings.Trim(strings.TrimSpace(n), "/")
|
|
}
|
|
|
|
dir := filepath.Join(root, "scratch")
|
|
if err := os.MkdirAll(dir, 0o700); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
// One scratch module gives the toolchain the module context its resolution
|
|
// commands need. It requires nothing and builds nothing.
|
|
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module scratch\n"), 0o600); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
p := &Proxy{
|
|
Namespaces: names,
|
|
Forge: strings.TrimSuffix(forge, "/"),
|
|
Upstream: env("UPSTREAM", "https://proxy.golang.org"),
|
|
Token: token,
|
|
Dir: dir,
|
|
Cache: filepath.Join(root, "cache"),
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
mux.Handle("/", p)
|
|
// Liveness has to answer without touching the forge, or a forge blip
|
|
// restarts a proxy that is working.
|
|
mux.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Write([]byte("ok\n"))
|
|
})
|
|
|
|
log.Printf("mod: serving %s from %s on %s", strings.Join(names, " "), p.Forge, addr)
|
|
log.Fatal(http.ListenAndServe(addr, mux))
|
|
}
|
|
|
|
func env(k, def string) string {
|
|
if v := os.Getenv(k); v != "" {
|
|
return v
|
|
}
|
|
return def
|
|
}
|