Files
mesh-catalog/modules/distribution/internal/holder/callers.go
T
jschoubben b665156b0f A3k finding 2: distribution reads its caller list as mesh-config resolves it, not from an environment nothing renders
The node-engine fills ${config:} only in files, unit names, owners and groups, never in a
process's environment, so MESH_CONFIG_CALLERS was never set and design 51's defaults always held.
The tools bundle now reads `callers` through stdio.Config on each call (holder.ConfiguredCallers,
Verbs.WithCallers per call); the program, which has no runtime resolving config, asks its own
tools bundle's new registry_callers on each wake of the windows (manifest invokes). The
environment variable is gone.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 13:54:17 +01:00

131 lines
5.1 KiB
Go

// Package holder is distribution's holding of the two image seats, `container-image-registry` and
// `oci-artifact-registry`, and of the old seat `mesh-artifact-store` until its window closes (novox/hq design 51 *The
// four registry seats*, ADR 0605, ADR 0611, ADR 0617 §2). A build module publishes into a seat through `publish` and
// `publish-part`: the parts land in distribution's own object store `incoming`, are hashed, checked against the
// builder's `builder_versions` and stored in the artifact store, which listens on its node's loopback; the store's port
// is the program's, reads open, writes from its own process alone (front.go).
package holder
import (
"fmt"
"slices"
"sort"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// The seats distribution holds, and the old one it holds until its window closes.
const (
ImageSeat = "container-image-registry"
ArtifactSeat = "oci-artifact-registry"
OldSeat = "mesh-artifact-store"
)
// The verbs of the seats (design 26 *A seat's definition*; design 51 *One contract*).
const (
VerbPublish = "publish"
VerbPublishPart = "publish-part"
VerbVersions = "versions"
VerbRemove = "remove"
VerbMirror = "mirror"
VerbTags = "tags"
VerbHold = "hold"
VerbRelease = "release"
)
// Seats are the seats distribution answers verbs on.
var Seats = []string{ImageSeat, ArtifactSeat}
// VerbsOf are a seat's verbs: mirror and tags on the image seat alone; hold and release on both of distribution's.
func VerbsOf(seat string) []string {
v := []string{VerbPublish, VerbPublishPart, VerbVersions, VerbRemove, VerbHold, VerbRelease}
if seat == ImageSeat {
v = append(v, VerbMirror, VerbTags)
}
sort.Strings(v)
return v
}
// Callers is the holder's trusted config value `callers`: per verb, the callers that may call it, read as mesh-sdk's
// seat-neutral list per verb reads it (ADR 0627 §2). The holder checks the caller the tool runner proved and stamped on
// the request (design 25 § 12.4), never a name in the request's body.
type Callers = stdio.VerbCallers
// DefaultCallers is the list design 51 *Who may call which verb* names: publish and publish-part the build modules;
// mirror mesh-build-image; remove the builder (a tagged version) and the artifact sweep's holder (retention); hold the
// artifact sweep's holder alone; release that holder, and the operator's session only through registry_holds (Operator
// below). versions is read by anyone on the mesh, as the store's reads are.
func DefaultCallers() Callers {
builds := []string{"mesh-build-go", "mesh-build-image", "mesh-build-node"}
return Callers{
VerbPublish: builds,
VerbPublishPart: builds,
VerbMirror: {"mesh-build-image"},
VerbRemove: {"mesh-delivery-builder", SweepHolder},
VerbHold: {SweepHolder},
VerbRelease: {SweepHolder, Operator},
VerbVersions: {Anyone},
VerbTags: {Anyone},
}
}
// SweepHolder is the module holding the seat `mesh-artifact-sweep`, the artifact sweep.
const SweepHolder = "artifact-store-tools"
// The entries of a list that stand for a class, and the caller the runtime names for a call it could not prove.
const (
Anyone = stdio.AnyCaller
Operator = stdio.AnyPerson
Unproven = stdio.Unproven
)
// Self is distribution's own account: never on release's list, so registry_holds cannot release in its own name.
const Self = "distribution"
// ParseCallers reads the config value; an empty value is DefaultCallers. A verb no seat has is refused, and Self on
// release's list is refused (design 51).
func ParseCallers(raw string) (Callers, error) {
c, err := stdio.ParseVerbCallers(raw, VerbsOf(ImageSeat), DefaultCallers())
if err != nil {
return nil, err
}
return selfNotReleasing(c)
}
// ConfiguredCallers is the config value `callers` as mesh-config resolved it for this machine, read through the tools
// runtime's stdio.Config on each call (never an environment variable: nothing renders a config value into a
// program's environment); unset is DefaultCallers, and Self on release's list is refused as ParseCallers refuses it.
func ConfiguredCallers() (Callers, error) {
c, err := stdio.ConfiguredVerbCallers(CallersConfig, VerbsOf(ImageSeat), DefaultCallers())
if err != nil {
return nil, err
}
return selfNotReleasing(c)
}
// CallersConfig is the config value's key, and CallersTool the tools bundle's tool answering it as resolved: the
// program, which has no tools runtime, asks that tool over the bus (manifest invokes).
const (
CallersConfig = "callers"
CallersTool = "registry_callers"
)
// WithCallers is v with the caller list c: a copy for one call, so a list read on that call never changes another's.
func (v *Verbs) WithCallers(c Callers) *Verbs {
h := *v.Holder
h.Callers = c
out := *v
out.Holder = &h
return &out
}
func selfNotReleasing(c Callers) (Callers, error) {
if slices.Contains(c[VerbRelease], Self) {
return nil, fmt.Errorf("callers puts %s on release's list: registry_holds would release in its own name", Self)
}
return c, nil
}
// CallerModule is the module of a proved module caller, which the runtime stamps `<node>.<module>`.
func CallerModule(proved string) string { return stdio.ModuleOf(proved) }