CAT-D2: distribution's caller list and its question to the builder are mesh-sdk's shared parts
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
reg "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/parts"
|
||||
|
||||
@@ -60,24 +61,6 @@ func (k kept[T]) List() ([]T, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// builderVersions asks the builder's builder_versions (ADR 0605 §4).
|
||||
type builderVersions struct{}
|
||||
|
||||
func (builderVersions) Recorded(name, version, digest string) (bool, string, error) {
|
||||
raw, err := stdio.Ask("mesh-delivery-builder.builder_versions", map[string]any{"name": name, "version": version, "digest": digest})
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
var a struct {
|
||||
Recorded *bool `json:"recorded"`
|
||||
Why string `json:"why"`
|
||||
}
|
||||
if err := json.Unmarshal(raw, &a); err != nil || a.Recorded == nil {
|
||||
return false, "", fmt.Errorf("builder_versions answered no recorded: %s", raw)
|
||||
}
|
||||
return *a.Recorded, a.Why, nil
|
||||
}
|
||||
|
||||
func say(seat, event string, body holder.Event) error {
|
||||
return stdio.SeatPublish("mesh.seat."+seat+".event."+event, eventBody(event, body), body.ID)
|
||||
}
|
||||
@@ -438,7 +421,7 @@ func main() {
|
||||
}
|
||||
base, _ := url.Parse("http://127.0.0.1:5001")
|
||||
store := &holder.OCI{Base: base, Registry: os.Getenv("MESH_REGISTRY_REACH"), Upstream: &holder.Upstream{}}
|
||||
h := &holder.Holder{Callers: callers, Objects: parts.BusObjects(holder.IncomingObjects), Builder: builderVersions{}, Store: store, Say: say, Finding: finding,
|
||||
h := &holder.Holder{Callers: callers, Objects: parts.BusObjects(holder.IncomingObjects), Builder: delivery.BuilderVersions{Ask: stdio.Ask}, Store: store, Say: say, Finding: finding,
|
||||
Transfers: parts.BusTransfers[holder.Opening](holder.TransfersState)}
|
||||
v := &holder.Verbs{Holder: h, Catalog: store, Holds: kept[holder.Hold]{state: "holds", key: holder.Hold.Key}, Mirrors: mirrors{}}
|
||||
go followMirrors(v)
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
package holder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
)
|
||||
|
||||
// The seats distribution holds, and the old one it holds until its window closes.
|
||||
@@ -46,10 +46,10 @@ func VerbsOf(seat string) []string {
|
||||
return v
|
||||
}
|
||||
|
||||
// Callers is the holder's trusted config value `callers` (the form ADR 0363 gives a restricted family): per verb, the
|
||||
// modules that may call it. 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 map[string][]string
|
||||
// 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
|
||||
@@ -72,15 +72,12 @@ func DefaultCallers() Callers {
|
||||
// SweepHolder is the module holding the seat `mesh-artifact-sweep`, the artifact sweep.
|
||||
const SweepHolder = "artifact-store-tools"
|
||||
|
||||
// Anyone on a verb's list lets every proved caller call it.
|
||||
const Anyone = "*"
|
||||
|
||||
// Operator on a list stands for the operator's session, the caller the tool runner proves as `person.<name>` (ADR 0386
|
||||
// §7): a release by hand through registry_holds carries it on, never distribution's own account.
|
||||
const Operator = "operator"
|
||||
|
||||
// Unproven is the caller the runtime names for a call it could not prove (mesh-sdk stdio.Unproven).
|
||||
const Unproven = "unproven"
|
||||
// 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"
|
||||
@@ -88,44 +85,15 @@ 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) {
|
||||
if strings.TrimSpace(raw) == "" {
|
||||
return DefaultCallers(), nil
|
||||
c, err := stdio.ParseVerbCallers(raw, VerbsOf(ImageSeat), DefaultCallers())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var c Callers
|
||||
if err := json.Unmarshal([]byte(raw), &c); err != nil {
|
||||
return nil, fmt.Errorf("callers is not a JSON object of verb to modules: %w", err)
|
||||
}
|
||||
known := VerbsOf(ImageSeat)
|
||||
for verb, mods := range c {
|
||||
if !slices.Contains(known, verb) {
|
||||
return nil, fmt.Errorf("callers names the verb %q, which no seat of distribution's has", verb)
|
||||
}
|
||||
if verb == VerbRelease && slices.Contains(mods, Self) {
|
||||
return nil, fmt.Errorf("callers puts %s on release's list: registry_holds would release in its own name", Self)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// Allowed answers nil when caller may call verb, else the refusal naming the verb and the caller.
|
||||
func (c Callers) Allowed(verb, caller string) error {
|
||||
if caller == "" || caller == Unproven {
|
||||
return fmt.Errorf("%s: refused: the request carries no caller the tool runner proved", verb)
|
||||
}
|
||||
person := strings.HasPrefix(caller, "person.")
|
||||
for _, m := range c[verb] {
|
||||
switch {
|
||||
case m == Anyone, m == Operator && person, !person && m == CallerModule(caller):
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s: refused for %s: not on the holder's caller list for %s", verb, caller, verb)
|
||||
}
|
||||
|
||||
// CallerModule is the module of a proved module caller, which the runtime stamps `<node>.<module>`.
|
||||
func CallerModule(proved string) string {
|
||||
if i := strings.LastIndexByte(proved, '.'); i >= 0 {
|
||||
return proved[i+1:]
|
||||
}
|
||||
return proved
|
||||
}
|
||||
func CallerModule(proved string) string { return stdio.ModuleOf(proved) }
|
||||
|
||||
Reference in New Issue
Block a user