Files
mesh-host/packaging/operator_keys_test.go
T
jschoubben e61141f596 Keep the packages this node's compositions declare in the engine's own key, and answer them on the node seat (ADR 0565 clauses 6 and 15, issue 1953)
pacman still reads the controller's mirror because no engine wrote its key: the engine
now keeps each handed composition's package resources and, after a pass that handed
something new, writes mesh-host_packages.<node> only when the value differs, owed after
the growing bound when refused. The manifest declares the state so the grants part
creates it. The verb packages answers the key beside the mirror's key for the node and
their difference, and with write writes the key again from what was composed. H8's
integration test proves the write under the grant the grants part composes.

Needs mesh-sdk feat/node-packages (0ef7c0c) for DeclaredPackagesOf and the engine's read of the
mirror (go.mod pin left for the lead: the SDK commit is not pushed).

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-01 16:09:13 +01:00

89 lines
3.4 KiB
Go

package packaging_test
import (
"encoding/json"
"os"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The operator's public keys reach every node as a file beside the state file, fed by a setting of the node-engine
// (novox/hq ADR 0539 clauses 3 and 11): the node agent reads it, and a composition made by hand is applied only when one
// of these keys signed it. The setting may be empty, and then no operator key is trusted.
func TestTheManifestDeclaresTheOperatorKeysFileFedByASetting(t *testing.T) {
raw, err := os.ReadFile("../module.json")
if err != nil {
t.Fatal(err)
}
if _, err := catalogue.Decode(raw); err != nil {
t.Fatalf("the manifest no longer parses: %v", err)
}
var m struct {
Config map[string]struct {
Type string `json:"type"`
Default any `json:"default"`
} `json:"config"`
Resources []struct {
ID string `json:"id"`
Type string `json:"type"`
Path string `json:"path"`
Mode string `json:"mode"`
Content string `json:"content"`
} `json:"resources"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
setting, ok := m.Config["operator-signers"]
if !ok || setting.Type != "string" || setting.Default != "" {
t.Fatalf("the setting operator-signers is %+v: a string that may be empty", setting)
}
for _, r := range m.Resources {
if r.ID != "operator-keys" {
continue
}
if r.Type != "file" || r.Path != "/var/lib/mesh-host/operator-keys" || r.Mode != "0644" ||
!strings.Contains(r.Content, "${config:operator-signers}") {
t.Fatalf("the file is %+v: it is declared beside the state file, 0644, its content the setting", r)
}
return
}
t.Fatal("module.json declares no operator-keys file")
}
// The node agent hears the end of a backup on the event of node-backup's holder, so the manifest consumes it.
func TestTheManifestConsumesTheBackupEvent(t *testing.T) {
raw, err := os.ReadFile("../module.json")
if err != nil {
t.Fatal(err)
}
var m struct {
Consumes []string `json:"consumes"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
if len(m.Consumes) != 1 || m.Consumes[0] != "restic.backed-up" {
t.Fatalf("consumes %v", m.Consumes)
}
// 774: the acts bucket mesh-host_acts is not declared as state for now: a declared state of a module with no account
// of its own is carried by every node's tool runner, which would be a second writer of the engine's own keys and
// has the grants part refuse the whole user list (2026-10-30). It comes back once the runtime never carries the engine.
parsed, err := catalogue.Decode(raw)
if err != nil {
t.Fatal(err)
}
// 774 (the alert table): the state health, one key per node, the node's own health report, kept until
// written again (no TTL: a node that stops writing keeps its last word, which the watchman reads with its time).
// ADR 0577 clause 1: and the state data, one key per module placed on the node that declares data items, kept until
// the module leaves the node; created by the grants part from this manifest as health is.
// ADR 0565 clause 6: and the state packages, one key per node, its compositions' declared packages, read by pacman.
if len(parsed.State) != 3 || parsed.State[0].Name != "health" || parsed.State[0].TTLSeconds != 0 ||
parsed.State[1].Name != "data" || parsed.State[1].TTLSeconds != 0 || parsed.State[2].Name != "packages" ||
parsed.State[2].TTLSeconds != 0 {
t.Fatalf("the manifest declares the state %+v", parsed.State)
}
}