Hear a restricted stream only from a module's own account, never the tool runner's (issue 727)
The tool runner's bus account carried the heard grants, consumer and bind word of every module it runs, and every agent session on that machine reaches the bus as that account, so any session could pull a granted module's consumer on MAIL. Per ADR 0376 §1 the controller now composes a restricted stream's consumer, grants and bind word only for a module that declares runs-as; registration refuses a consumes of a restricted stream without runs-as (§2), and a grant that composes nothing is said in doctor (D-heard) and in the controller's log on every raise and send.
This commit is contained in:
@@ -49,10 +49,12 @@ func assertBusObjects(ctx context.Context, inv *inventory.Inventory, r broker.Ra
|
||||
// composed from, so a module the mesh grants a consumer's subjects has that consumer waiting.
|
||||
// Done on every raise, not only when a credential is issued: every module moved onto this bus
|
||||
// by the rollout was issued on the old one, and came up with nothing to bind to (2026-09-28).
|
||||
consumers, err := moduleConsumers(ctx, inv)
|
||||
consumers, records, err := moduleConsumersAndRecords(ctx, inv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// And a grant of a restricted stream that composes nothing, said on every raise and send (novox/hq ADR 0376 §2).
|
||||
sayWithheld(records, " ")
|
||||
// And the work queues of seats that name their caller or their kind, with each holder's worker
|
||||
// (novox/hq ADR 0259 §3): an ask queues until the router takes it, a channel's work until that kind
|
||||
// takes it.
|
||||
@@ -165,15 +167,21 @@ func unassertedObservation(err error) conditions.Observation {
|
||||
|
||||
// moduleConsumers is every module's durable consumer, from the records the user list is composed from.
|
||||
func moduleConsumers(ctx context.Context, inv *inventory.Inventory) ([]broker.ModuleConsumer, error) {
|
||||
consumers, _, err := moduleConsumersAndRecords(ctx, inv)
|
||||
return consumers, err
|
||||
}
|
||||
|
||||
// moduleConsumersAndRecords is moduleConsumers with the records they were composed from.
|
||||
func moduleConsumersAndRecords(ctx context.Context, inv *inventory.Inventory) ([]broker.ModuleConsumer, broker.Records, error) {
|
||||
records, err := inv.BusRecords(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, broker.Records{}, err
|
||||
}
|
||||
users, err := broker.Users(records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, broker.Records{}, err
|
||||
}
|
||||
return broker.ConsumersOf(users), nil
|
||||
return broker.ConsumersOf(users), records, nil
|
||||
}
|
||||
|
||||
// seatTrafficObjects is the work queues and workers of seats that name their caller or their kind, from
|
||||
|
||||
@@ -146,6 +146,11 @@ var probeRegistry = []probe{
|
||||
{ID: probeFillID, Asserts: "every module's bucket and log holds less than three quarters of its cap; one " +
|
||||
"said filling is cleared once it holds less than seven tenths", From: "ADR 0297, issue 501",
|
||||
Kind: kindBucketOrLogFilling, Raises: []string{kindBucketOrLogUnread}, Phase: 1, run: probeFill},
|
||||
// A grant of a restricted stream that composes nothing (novox/hq ADR 0376 §2): the module is carried by the
|
||||
// machine's tool runner, which never hears a restricted stream, so it hears nothing it was granted.
|
||||
{ID: probeWithheldID, Asserts: "no grant of a restricted stream names a module that composes nothing for it: every " +
|
||||
"module granted one runs as an account of its own", From: "ADR 0376 §2", Kind: kindGrantComposesNothing,
|
||||
Phase: 1, run: probeWithheldHearing},
|
||||
{ID: "DW", Asserts: "the watchdogs of the signals table ran within three of their intervals",
|
||||
From: "ADR 0227 rule 6: the watchers are watched", Kind: "watchdogs-silent", Phase: 1, run: probeWatchdogs},
|
||||
// The core's health definitions (novox/hq to-be 45 §8, ADR 0236): what a core component's new build is
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/broker"
|
||||
"github.com/novox/mesh-controller/internal/conditions"
|
||||
)
|
||||
|
||||
// A grant of a restricted stream that composes nothing (novox/hq ADR 0376 §2).
|
||||
//
|
||||
// A restricted stream is heard only by a module that runs as an account of its own (`runs-as`, ADR 0259): the
|
||||
// tool runner's bus account is the one every agent session on its machine reaches the bus as, so the controller
|
||||
// composes no consumer, grant or bind word for a module it carries (broker.ComposedHears). Where a grant still
|
||||
// names such a module, the module hears nothing it was granted, and that is said — in `doctor` and in the
|
||||
// controller's log on every raise and send — naming the module, the stream and the remedy. Never silent.
|
||||
|
||||
const (
|
||||
// probeWithheldID is the self-check's probe of it, and kindGrantComposesNothing the condition it raises.
|
||||
probeWithheldID = "D-heard"
|
||||
kindGrantComposesNothing = "grant-composes-nothing"
|
||||
)
|
||||
|
||||
// probeWithheldHearing says every granted hearing of a restricted stream composed for nothing.
|
||||
func probeWithheldHearing(ctx context.Context, d *doctor) ([]conditions.Observation, error) {
|
||||
records, err := d.open.inventory.BusRecords(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return withheldObservations(broker.WithheldOf(records)), nil
|
||||
}
|
||||
|
||||
// withheldObservations is each withheld hearing as a condition of its module on its machine.
|
||||
func withheldObservations(withheld []broker.Withheld) []conditions.Observation {
|
||||
var out []conditions.Observation
|
||||
for _, w := range withheld {
|
||||
out = append(out, conditions.Observation{Scope: conditions.ScopeModule,
|
||||
ID: w.Module + "." + strings.ToLower(w.Stream) + "." + w.Node,
|
||||
Kind: kindGrantComposesNothing, Machine: w.Node, Severity: conditions.Warning,
|
||||
Summary: w.Said(), Said: fmt.Sprintf("%s on %s granted %s; composed nothing", w.Module, w.Node, w.Stream)})
|
||||
}
|
||||
return sortedFound(out)
|
||||
}
|
||||
|
||||
// sayWithheld puts every withheld hearing in the controller's log, once per raise or send that composes it.
|
||||
func sayWithheld(records broker.Records, indent string) {
|
||||
for _, w := range broker.WithheldOf(records) {
|
||||
fmt.Printf("%sA GRANT COMPOSES NOTHING: %s\n", indent, w.Said())
|
||||
}
|
||||
}
|
||||
|
||||
// withheldWords are the plain words of a withheld hearing: the module, the machine and what to do.
|
||||
func withheldWords(o conditions.Observation) words {
|
||||
module, m := "a module", machineOr(o, "a machine")
|
||||
if o.Scope == conditions.ScopeModule && idPart(o, 0) != "" {
|
||||
module = idPart(o, 0)
|
||||
}
|
||||
return words{Headline: clip(conditions.Capital(fmt.Sprintf("%s on %s hears nothing it was granted", module, m)), 60),
|
||||
Needs: fmt.Sprintf("give %s an account of its own in its manifest; the details say which stream.", module),
|
||||
Explanation: fmt.Sprintf("You granted %s part of a stream that only modules running under an account of "+
|
||||
"their own may hear. It runs inside the shared tool runner on %s, which every assistant session there "+
|
||||
"also uses, so the mesh gives it none of that stream.", module, m),
|
||||
Resolved: fmt.Sprintf("%s on %s hears what it was granted, or is no longer granted it", module, m)}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/broker"
|
||||
"github.com/novox/mesh-controller/internal/conditions"
|
||||
)
|
||||
|
||||
// A grant naming a module the tool runner carries composes nothing, and doctor says so in plain words, naming the
|
||||
// module, the stream and the remedy (novox/hq ADR 0376 §2).
|
||||
func TestAGrantThatComposesNothingIsSaid(t *testing.T) {
|
||||
records := broker.Records{Nodes: []string{"ace"}, Assigned: map[string][]broker.Declared{"ace": {
|
||||
{Module: broker.RuntimeModule},
|
||||
{Module: "reader", Hears: []broker.Heard{{Stream: "MAIL", Emitter: "mesh-mail", Restricted: true,
|
||||
Filters: []string{"mesh.stream.mesh-mail.event.mail.mesh.>"}}}},
|
||||
{Module: "mailer", RunsAs: "mailer", Hears: []broker.Heard{{Stream: "MAIL", Emitter: "mesh-mail", Restricted: true,
|
||||
Filters: []string{"mesh.stream.mesh-mail.event.mail.mesh.>"}}}},
|
||||
}}}
|
||||
found := withheldObservations(broker.WithheldOf(records))
|
||||
if len(found) != 1 {
|
||||
t.Fatalf("said %+v", found)
|
||||
}
|
||||
o := found[0]
|
||||
if o.Kind != kindGrantComposesNothing || o.Machine != "ace" || !strings.Contains(o.Summary, "reader on ace") ||
|
||||
!strings.Contains(o.Summary, "MAIL") || !strings.Contains(o.Summary, "runs-as") {
|
||||
t.Fatalf("%+v", o)
|
||||
}
|
||||
w := plainWordings[kindGrantComposesNothing](o)
|
||||
if why, ok := conditions.PlainWords(w, "ace"); !ok {
|
||||
t.Fatalf("not plain: %s (%+v)", why, w)
|
||||
}
|
||||
registered := false
|
||||
for _, p := range probeRegistry {
|
||||
if p.ID == probeWithheldID && p.Kind == kindGrantComposesNothing && p.run != nil {
|
||||
registered = true
|
||||
}
|
||||
}
|
||||
if !registered {
|
||||
t.Fatal("doctor does not run the probe of a grant that composes nothing")
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,8 @@ var plainWordings = map[string]func(conditions.Observation) words{
|
||||
"reaches it. It keeps running what it has.", m),
|
||||
Resolved: m + " can get new instructions again"}
|
||||
}),
|
||||
// A grant of a restricted stream that composes nothing (novox/hq ADR 0376 §2).
|
||||
kindGrantComposesNothing: worded(withheldWords),
|
||||
kindAgentCanBecomeRoot: worded(func(o conditions.Observation) words {
|
||||
m := machineOr(o, "a machine")
|
||||
return words{Headline: "Sessions on " + m + " could become root",
|
||||
|
||||
Reference in New Issue
Block a user