package main // How the toolchain's install reaches the mesh's package registry (novox/hq ADR 0405 ยง5, ADR 0336; issue 1488). // The lock names @novox/mesh-sdk at the registry's public address, and npm installs a locked tarball only from the // registry it is configured with, so the install is told that registry for the @novox scope and nothing else: every // other package resolves from the public one. This is how today's build agent names it (mesh-controller // internal/builder/dependencies.go: the scope's registry from the npm-package-registry binding, the account and // secret the mesh sealed), read here from the module's own binding and secret files (module.json `binds` and // `secrets`), the same files the lab module reads. import ( "encoding/base64" "encoding/json" "fmt" "net/http" "os" "strings" ) // Scope is the npm scope the mesh's registry answers for. const Scope = "@novox" // Registry is the mesh's package registry as the binding names it. type Registry struct { URL, Username, Password string } // ReadRegistry reads the npm-package-registry binding and its sealed secret. The registry is the binding's // `public-root` when it has one (the address the lock holds), and otherwise scheme://at:port plus `npm-path`. func ReadRegistry(bindingPath, secretPath string) (Registry, error) { raw, err := os.ReadFile(bindingPath) if err != nil { return Registry{}, fmt.Errorf("no package registry is bound to this module: %w", err) } var b struct { At string `json:"at"` As string `json:"as"` Serves struct { Scheme string `json:"scheme"` Port int `json:"port"` NpmPath string `json:"npm-path"` PublicRoot string `json:"public-root"` } `json:"serves"` } if err := json.Unmarshal(raw, &b); err != nil { return Registry{}, fmt.Errorf("the package registry binding is not JSON: %w", err) } url := b.Serves.PublicRoot if url == "" && b.At != "" && b.Serves.NpmPath != "" { scheme := b.Serves.Scheme if scheme == "" { scheme = "http" } url = fmt.Sprintf("%s://%s:%d%s", scheme, b.At, b.Serves.Port, b.Serves.NpmPath) } if url == "" { return Registry{}, fmt.Errorf("the package registry binding names no address") } if !strings.HasSuffix(url, "/") { url += "/" } secret, err := os.ReadFile(secretPath) if err != nil { return Registry{}, fmt.Errorf("the package registry's secret cannot be read: %w", err) } return Registry{URL: url, Username: b.As, Password: strings.TrimSpace(string(secret))}, nil } // Npmrc is the npm configuration text for the install: the @novox scope at the registry, with the account's // credential for it when there is one. func (r Registry) Npmrc() string { var sb strings.Builder fmt.Fprintf(&sb, "%s:registry=%s\n", Scope, r.URL) if r.Username != "" && r.Password != "" { hostPath := r.URL if i := strings.Index(hostPath, "://"); i >= 0 { hostPath = hostPath[i+1:] } fmt.Fprintf(&sb, "%s:_auth=%s\n", hostPath, base64.StdEncoding.EncodeToString([]byte(r.Username+":"+r.Password))) } return sb.String() } // authorize gives a request to the registry the account's credential, when there is one. func (r Registry) authorize(req *http.Request) { if r.Username != "" && r.Password != "" { req.SetBasicAuth(r.Username, r.Password) } }