Let observers' findings and a carried holder's seat events reach the bus (issue 1952)
mesh/delivery merged: source.main moved to novox/mesh-sdk@5ae69df8ccde
mesh/delivery-group group fix/l4-quick merged: every member is merged
mesh/check pass cbbfbf3d2d55 on fea48f19cea5 | unit 2729 run, 4570 kept, 16 skipped | integration 2975 run, 4493 kept, 25 skipped | over bound: unit, …
mesh/delivery merged: source.main moved to novox/mesh-sdk@5ae69df8ccde
mesh/delivery-group group fix/l4-quick merged: every member is merged
mesh/check pass cbbfbf3d2d55 on fea48f19cea5 | unit 2729 run, 4570 kept, 16 skipped | integration 2975 run, 4493 kept, 25 skipped | over bound: unit, …
A finding's field `token` is named like a credential, so the tool runner refused every finding that carried it; it is `ref` now, and a finding written under the old name is still read. A module the tool runner carries got no grant for its own held seat's events, so the self-check could not say `checked`; a held plain seat's events are now in the holder's seat traffic, its membership and its runtime's grants. Quick vs thorough: quick, these fixes for L4's take-over now; the thorough fix (research 032 / ADR 0240's health view extension) is decided later. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -251,6 +251,7 @@ func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) {
|
||||
if err := json.Unmarshal(want[i].Memberships, &wasM); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
heldEventsBeyond(gotM, wasM)
|
||||
if !reflect.DeepEqual(gotM, wasM) {
|
||||
t.Errorf("the memberships differ from the controller's:\n%s", raw)
|
||||
}
|
||||
@@ -825,6 +826,37 @@ func healthChecks(t *testing.T) {
|
||||
URL: "nats://a:4222"}); w.Valid() != nil || w.OwnSecret() != "broker-nats-tools" {
|
||||
t.Errorf("the tools account is held in %q (%v)", w.OwnSecret(), w.Valid())
|
||||
}
|
||||
// Issue 1952: a module that holds a seat says its own seat's events, also when the tool runner carries it, so the
|
||||
// self-check's `checked`, the keeper's condition events and the healers' `healer-acted` reach their hearers. Its
|
||||
// membership lists them, the runtime is granted them; a user of the seat is not, nor a machine's event on a node seat
|
||||
// (granted per machine, to the holder's own account only).
|
||||
selfCheck := Declared{Module: "mesh-self-check", Holds: []Seat{{Name: "mesh-self-check", Scope: "mesh", Emits: []string{"checked"}}}}
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
d Declared
|
||||
subject string
|
||||
may bool
|
||||
}{
|
||||
{"the self-check says checked", selfCheck, "mesh.seat.mesh-self-check.event.checked", true},
|
||||
{"the keeper says a condition raised", Declared{Module: "mesh-conditions", Holds: []Seat{{Name: "mesh-conditions", Scope: "mesh",
|
||||
Emits: []string{"condition-raised", "condition-cleared"}}}}, "mesh.seat.mesh-conditions.event.condition-cleared", true},
|
||||
{"a user does not say the seat's events", Declared{Module: "mesh-delivery-view", Uses: []Seat{{Name: "mesh-self-check",
|
||||
Scope: "mesh", Emits: []string{"checked"}}}}, "mesh.seat.mesh-self-check.event.checked", false},
|
||||
{"the holder says no other seat's", selfCheck, "mesh.seat.mesh-conditions.event.condition-raised", false},
|
||||
{"a machine's event on a node seat is not composed here", Declared{Module: "pause", Holds: []Seat{{Name: "node-power",
|
||||
Scope: "node", Emits: []string{"paused.*"}}}}, "mesh.seat.node-power.event.paused.b", false},
|
||||
} {
|
||||
m := MembershipFor("a", c.d, Placements{})
|
||||
listed := m.SeatTraffic != nil && slices.ContainsFunc(m.SeatTraffic.Publish, func(p string) bool { return p == c.subject })
|
||||
perms, err := PermissionsFor(Principal{Kind: KindNodeTools, Node: "a", Carries: []Declared{c.d}})
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", c.name, err)
|
||||
}
|
||||
if listed != c.may || MayPublish(perms, c.subject) != c.may {
|
||||
t.Errorf("%s: the membership lists %s %v and the runtime may publish it %v, want %v", c.name, c.subject, listed,
|
||||
MayPublish(perms, c.subject), c.may)
|
||||
}
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, u := range users {
|
||||
name := u.Username()
|
||||
@@ -879,3 +911,52 @@ func healthChecks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// heldEventsBeyond takes out of the copy's memberships the one row they list beyond the controller's on purpose (issue
|
||||
// 1952): a held seat's own events in its holder's seat traffic, so a module the tool runner carries may say them. The
|
||||
// controller's composer is frozen; any other difference is still a fault.
|
||||
func heldEventsBeyond(got, was any) {
|
||||
gotAll, _ := got.(map[string]any)
|
||||
wasAll, _ := was.(map[string]any)
|
||||
for key, m := range gotAll {
|
||||
gm, _ := m.(map[string]any)
|
||||
traffic, _ := gm["seat-traffic"].(map[string]any)
|
||||
if traffic == nil {
|
||||
continue
|
||||
}
|
||||
listedBefore := map[string]bool{}
|
||||
if wm, _ := wasAll[key].(map[string]any); wm != nil {
|
||||
if wt, _ := wm["seat-traffic"].(map[string]any); wt != nil {
|
||||
for _, p := range asStrings(wt["publish"]) {
|
||||
listedBefore[p] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
var kept []any
|
||||
for _, p := range asStrings(traffic["publish"]) {
|
||||
if parts := strings.Split(p, "."); !listedBefore[p] && len(parts) == 5 && parts[0] == "mesh" && parts[1] == "seat" && parts[3] == "event" {
|
||||
continue
|
||||
}
|
||||
kept = append(kept, p)
|
||||
}
|
||||
if kept == nil {
|
||||
delete(traffic, "publish")
|
||||
} else {
|
||||
traffic["publish"] = kept
|
||||
}
|
||||
if len(traffic) == 0 {
|
||||
delete(gm, "seat-traffic")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func asStrings(v any) []string {
|
||||
list, _ := v.([]any)
|
||||
out := make([]string, 0, len(list))
|
||||
for _, x := range list {
|
||||
if s, ok := x.(string); ok {
|
||||
out = append(out, s)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user