Files
mesh-catalog/modules/mesh-build-node/cmd/mesh-build-node/registry.go
T

82 lines
3.0 KiB
Go

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"
"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()
}