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:
@@ -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