package stdio import ( "bytes" "encoding/json" "fmt" "slices" "strings" "sync" ) // Callers is a module's trusted list of who may call a verb of its (novox/hq ADR 0459 §2, ADR 0563 §8), as the mesh // writes a list setting into a file the module reads: `{"callers": [...]}`. An entry is a module's name (that module on // any machine), exactly ., or exactly person.. Each caller is the runtime's proof (CallerOf), never // an argument; nobody beyond the list is granted, a wildcard is no entry, and an unproven caller never matches. type Callers []string // ParseCallers reads a callers file: the list under `callers`, and nothing else. func ParseCallers(raw []byte) (Callers, error) { var f struct { Callers Callers `json:"callers"` } dec := json.NewDecoder(bytes.NewReader(raw)) dec.DisallowUnknownFields() if err := dec.Decode(&f); err != nil { return nil, fmt.Errorf("the callers setting is not a list of callers: %v", err) } return f.Callers, nil } // Allows says whether caller, as the runtime proved it, is one the list names. func (c Callers) Allows(caller string) bool { if caller == "" || caller == Unproven { return false } for _, entry := range c { if entry == "" || strings.ContainsAny(entry, "*> ") { continue } if entry == caller { return true } if !strings.Contains(entry, ".") { if _, module, ok := strings.Cut(caller, "."); ok && module == entry && !strings.HasPrefix(caller, "person.") { return true } } } return false } // VerbCallers is a holder's trusted list per verb (novox/hq ADR 0627 §2, design 51 *Who may call which verb*): for each // verb of the seats it holds, the callers that may call it, each entry read as Callers reads it. Two entries more stand // for a whole class: AnyCaller lets every proved caller call the verb (a read the mesh keeps open), AnyPerson every // operator's session the runtime proved as person.. It names no seat and no verb: the holder gives its verbs and // its defaults, and keeps any rule of its own seat (who may never be on a list) beside it. type VerbCallers map[string][]string // The entries of a VerbCallers list that stand for a class of callers. const ( AnyCaller = "*" AnyPerson = "operator" ) // ParseVerbCallers reads a holder's config value of verb to callers; an empty value is defaults. A verb not among verbs // is refused, so a list that names a verb the holder does not serve is said at once. func ParseVerbCallers(raw string, verbs []string, defaults VerbCallers) (VerbCallers, error) { if strings.TrimSpace(raw) == "" { return defaults, nil } var c VerbCallers if err := json.Unmarshal([]byte(raw), &c); err != nil { return nil, fmt.Errorf("callers is not a JSON object of verb to callers: %w", err) } for verb := range c { if !slices.Contains(verbs, verb) { return nil, fmt.Errorf("callers names the verb %q, which the holder does not serve", verb) } } return c, nil } // Allowed answers nil when caller, as the runtime proved it, may call verb; else the refusal naming both. An unproven // caller is never allowed, not even by AnyCaller. func (c VerbCallers) 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 _, entry := range c[verb] { switch entry { case AnyCaller: return nil case AnyPerson: if person { return nil } default: if (Callers{entry}).Allows(caller) { return nil } } } return fmt.Errorf("%s: refused for %s: not on the holder's caller list for %s", verb, caller, verb) } // ModuleOf is the module of a proved module caller, which the runtime names .. func ModuleOf(proved string) string { if _, module, ok := strings.Cut(proved, "."); ok { return module } return proved } // ConfiguredVerbCallers is the holder's list as mesh-config resolved its config value key for this machine (Config): // a JSON object of verb to callers, or that object written as a string; an unset or empty value is defaults. A value // that cannot be read is an error, never the defaults, so a broken list is said, not widened. func ConfiguredVerbCallers(key string, verbs []string, defaults VerbCallers) (VerbCallers, error) { raw, err := Config(key) if err != nil { return nil, fmt.Errorf("the config value %s cannot be read: %w", key, err) } return parseConfiguredVerbCallers(raw, verbs, defaults) } // HoldVerbCallers is ConfiguredVerbCallers held: the returned reader asks the runtime once, by a watch of the config // value key (WatchConfig), and from then on answers the list it holds, which each change of the value replaces. A call // never asks the runtime again, so a runtime that is slow or away for a moment (a timed-out ask) refuses no verb; a // change that cannot be read keeps the list last read and is said on the bundle's standard error, so a broken list is // said and never widened. Only a reader that has not yet read any value answers an error, and its next call asks again. func HoldVerbCallers(key string, verbs []string, defaults VerbCallers) func() (VerbCallers, error) { return holdVerbCallers(WatchConfig, key, verbs, defaults) } func holdVerbCallers(watch func(string, func(ProvisionChange) error) error, key string, verbs []string, defaults VerbCallers) func() (VerbCallers, error) { var start, mu sync.Mutex var held VerbCallers var bad error handle := func(c ProvisionChange) error { mu.Lock() defer mu.Unlock() if c.Refused != "" { bad = fmt.Errorf("the config value %s is not answered: %s", key, c.Refused) } else if l, err := parseConfiguredVerbCallers(c.Value, verbs, defaults); err != nil { bad = fmt.Errorf("the config value %s cannot be read: %w", key, err) } else { held, bad = l, nil return nil } if held != nil { sayf("%v: the list last read stays", bad) } return nil } read := func() (VerbCallers, error) { mu.Lock() defer mu.Unlock() if held != nil { return held, nil } if bad != nil { return nil, bad } return nil, nil } return func() (VerbCallers, error) { if l, err := read(); l != nil || err != nil { return l, err } start.Lock() defer start.Unlock() if l, err := read(); l != nil || err != nil { return l, err } if err := watch(key, handle); err != nil { return nil, fmt.Errorf("the config value %s cannot be read: %w", key, err) } l, err := read() if l == nil && err == nil { err = fmt.Errorf("the config value %s cannot be read: the runtime handed over no value", key) } return l, err } } func parseConfiguredVerbCallers(raw json.RawMessage, verbs []string, defaults VerbCallers) (VerbCallers, error) { var text string if err := json.Unmarshal(raw, &text); err == nil || len(bytes.TrimSpace(raw)) == 0 || string(bytes.TrimSpace(raw)) == "null" { return ParseVerbCallers(text, verbs, defaults) } return ParseVerbCallers(string(raw), verbs, defaults) }