Node-engine: composition comparison, seals and differing paths are the engine's own package, internal/compositions, with the tests moved from mesh-sdk's delivery (H-1, ADR 0634 §1; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 14:53:06 +01:00
parent dcbdc70919
commit df44d21c82
15 changed files with 967 additions and 44 deletions
+8 -7
View File
@@ -19,6 +19,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/novox/mesh-host/internal/compositions"
"maps"
"reflect"
"slices"
@@ -66,7 +67,7 @@ type Env struct {
Refused func(why string, held map[string]string)
// Running is what the node runs now (agent.Everything), and Unseal opens a value sealed to this machine: a secret
// the vault seals again for each ask is kept as the box the node already runs at the same slot (the same field of
// the same resource of the same module, delivery.KeepSeals) when that box opens to the same value, so neither the
// the same resource of the same module, compositions.KeepSeals) when that box opens to the same value, so neither the
// switch to composing its own nor a restart changes a composition (ADR 0547 §3); a box held at another slot is
// never taken, though it opens to the same value (issue 1126, C1: a provider's grant and its consumer's secret).
// Either nil keeps the vault's box.
@@ -77,7 +78,7 @@ type Env struct {
// (delivery.Have.SealedAt); legacy is the list a have written before slots holds (delivery.Have.Sealed), reused
// only within its own module.
// An error is a have the bus did not answer for, never one absent: the pass is then tried again (BusFailed).
Held func(module string) (slots delivery.Seals, legacy []string, err error)
Held func(module string) (slots compositions.Seals, legacy []string, err error)
// Kept is told, after each pass that composed, what the node keeps of each module as it runs because its manifest does
// not yet say it (ADR 0601 §4), by module, so each module's have carries it (agent.KeptNow). Nil tells nobody.
Kept func(kept map[string][]string)
@@ -1093,7 +1094,7 @@ func (c *Composer) heldNow() []string {
}
// keepRunning is comp with each sealed value the node already runs at the same slot kept, where it opens to the same
// value (delivery.KeepSeals, issue 1126, C1): of what runs (running, the agent's), else of what its module's have says
// value (compositions.KeepSeals, issue 1126, C1): of what runs (running, the agent's), else of what its module's have says
// it runs (Held). A have written before slots names no slot: its boxes are reused within their own module alone, at a
// slot no box is kept for, and only one opening to the slot's value.
func (c *Composer) keepRunning(comp delivery.Composed, running []delivery.Composed) delivery.Composed {
@@ -1104,7 +1105,7 @@ func (c *Composer) keepRunning(comp delivery.Composed, running []delivery.Compos
if module == "" {
module = agent.NodeModule
}
kept := delivery.Seals{}
kept := compositions.Seals{}
var legacy []string
if c.env.Held != nil {
slots, old, err := c.env.Held(module)
@@ -1116,12 +1117,12 @@ func (c *Composer) keepRunning(comp delivery.Composed, running []delivery.Compos
}
for _, r := range running {
if r.Module == comp.Module {
for slot, box := range delivery.SealsIn(r) {
for slot, box := range compositions.SealsIn(r) {
kept[slot] = box
}
}
}
for slot, box := range delivery.SealsIn(comp) {
for slot, box := range compositions.SealsIn(comp) {
if _, ok := kept[slot]; ok {
continue
}
@@ -1132,7 +1133,7 @@ func (c *Composer) keepRunning(comp delivery.Composed, running []delivery.Compos
}
}
}
return delivery.KeepSeals(comp, kept, c.sameValue)
return compositions.KeepSeals(comp, kept, c.sameValue)
}
// waitLog is what a composer waited on: how many waits ended, the longest and what it was, and the last.
+17 -16
View File
@@ -8,6 +8,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/novox/mesh-host/internal/compositions"
"os"
"reflect"
"slices"
@@ -826,7 +827,7 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
sealed := delivery.SealsIn(c)
sealed := compositions.SealsIn(c)
if len(sealed) != 1 {
t.Fatalf("keeper's composition carries %v", sealed)
}
@@ -839,20 +840,20 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
_, beforeBox := boxOf(before)
for _, row := range []struct {
name, in, held string
slots delivery.Seals
slots compositions.Seals
kept bool
fails bool // the have's read the bus did not answer: no composition, made again later (2026-10-28)
}{
{"the have holds the rotated value at its slot", "keeper", rotatedBox, delivery.Seals{slot: rotatedBox}, true, false},
{"the have holds the value before the rotation", "keeper", beforeBox, delivery.Seals{slot: beforeBox}, false, false},
{"the have holds the rotated value at its slot", "keeper", rotatedBox, compositions.Seals{slot: rotatedBox}, true, false},
{"the have holds the value before the rotation", "keeper", beforeBox, compositions.Seals{slot: beforeBox}, false, false},
{"a have written before slots holds the rotated value", "keeper", rotatedBox, nil, true, false},
{"another module holds the same value", "lemurs", rotatedBox, delivery.Seals{"lemurs.grant-x#sealed": rotatedBox}, false, false},
{"another resource of keeper holds the same value", "keeper", rotatedBox, delivery.Seals{"keeper.other#sealed": rotatedBox}, false, false},
{"another module holds the same value", "lemurs", rotatedBox, compositions.Seals{"lemurs.grant-x#sealed": rotatedBox}, false, false},
{"another resource of keeper holds the same value", "keeper", rotatedBox, compositions.Seals{"keeper.other#sealed": rotatedBox}, false, false},
{"the bus does not answer for the have", "keeper", rotatedBox, nil, false, true},
} {
restarted := env
restarted.Running = func() []delivery.Composed { return nil }
restarted.Held = func(module string) (delivery.Seals, []string, error) {
restarted.Held = func(module string) (compositions.Seals, []string, error) {
if module != row.in {
return nil, nil, nil
}
@@ -929,13 +930,13 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
}
return nil, fmt.Errorf("not sealed to n1: %s", box)
}
coreEnv.Held = func(module string) (delivery.Seals, []string, error) {
coreEnv.Held = func(module string) (compositions.Seals, []string, error) {
if module == agent.NodeModule {
return delivery.Seals{"core-box#sealed": rotatedBox}, nil, nil
return compositions.Seals{"core-box#sealed": rotatedBox}, nil, nil
}
return nil, nil, nil
}
if got := delivery.SealsIn(New(coreEnv).keepRunning(ownComp, nil))["core-box#sealed"]; got != rotatedBox {
if got := compositions.SealsIn(New(coreEnv).keepRunning(ownComp, nil))["core-box#sealed"]; got != rotatedBox {
t.Errorf("the node's own core box after a restart is %s, want the one its key holds %s", got, rotatedBox)
}
// Issue 1126, C1, the seed-7 probe: each entry of a file's secrets (catalogue's intoFile, the shape captured from it
@@ -953,20 +954,20 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
}
for _, row := range []struct {
name string
held delivery.Seals
held compositions.Seals
want string
}{
{"the box that runs at its entry", delivery.Seals{"grafana.ini#secrets.postgres-database": rotatedBox}, rotatedBox},
{"a box at another entry", delivery.Seals{"grafana.ini#secrets.secret-key": rotatedBox}, "box-again"},
{"the box that runs at its entry", compositions.Seals{"grafana.ini#secrets.postgres-database": rotatedBox}, rotatedBox},
{"a box at another entry", compositions.Seals{"grafana.ini#secrets.secret-key": rotatedBox}, "box-again"},
} {
secretsEnv := coreEnv
secretsEnv.Held = func(module string) (delivery.Seals, []string, error) {
secretsEnv.Held = func(module string) (compositions.Seals, []string, error) {
if module == "grafana" {
return row.held, nil, nil
}
return nil, nil, nil
}
got := delivery.SealsIn(New(secretsEnv).keepRunning(ini("box-again", "box-other"), nil))
got := compositions.SealsIn(New(secretsEnv).keepRunning(ini("box-again", "box-other"), nil))
if got["grafana.ini#secrets.postgres-database"] != row.want || got["grafana.ini#secrets.secret-key"] != "box-other" {
t.Errorf("%s: the secrets kept are %v", row.name, got)
}
@@ -1009,7 +1010,7 @@ func TestTheNodeComposesItsWantsFromTheBus(t *testing.T) {
}
// What runs at the credential's slot is kept, after the composition (keepRunning, issue 1126, C1).
webComp := delivery.Composed{Node: "n1", Module: "web", Resources: []json.RawMessage{json.RawMessage(`{"id":"web.secret-pg","sealed":"{\"c\":1}"}`)}}
if got := delivery.SealsIn(pc.keepRunning(webComp, pairEnv.Running()))["web.secret-pg#sealed"]; got != `{"run":1}` {
if got := compositions.SealsIn(pc.keepRunning(webComp, pairEnv.Running()))["web.secret-pg#sealed"]; got != `{"run":1}` {
t.Errorf("web's credential composed as %s, want the box that runs", got)
}
// A node that cannot compose tells the agent once, and once again when it composes (the agent's haves say it).