82 lines
3.0 KiB
Go
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()
|
|
}
|