Refuse any change through a verb to a module with a trusted mergeable file
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

A mergeable file takes any key, not only those its content names, so an
empty runtime configuration a provider reads took a url of the caller's
through the settings verb (hq issue 340 review).
This commit is contained in:
jochen
2026-10-09 02:54:41 +02:00
parent f476494173
commit 55d8b43f30
3 changed files with 106 additions and 0 deletions
+18
View File
@@ -1081,6 +1081,16 @@ func throughAVerb() (string, bool) {
return verb, verb != ""
}
// sameLayer says whether two layers hold the same values, an absent layer and an empty one alike.
func sameLayer(a, b map[string]any) bool {
if len(a) == 0 && len(b) == 0 {
return true
}
ra, _ := json.Marshal(a)
rb, _ := json.Marshal(b)
return string(ra) == string(rb)
}
// refuseTerminalSettingsThroughAVerb refuses a layer change through a verb that would add, change or remove
// places or accesses; a change that leaves both as they were is not refused.
func refuseTerminalSettingsThroughAVerb(ctx context.Context, inv *inventory.Inventory, before, after map[string]any,
@@ -1095,6 +1105,14 @@ func refuseTerminalSettingsThroughAVerb(ctx context.Context, inv *inventory.Inve
if err != nil {
return fmt.Errorf("which settings of %s are the terminal's cannot be read, so nothing was changed: %w", module, err)
}
// A trusted mergeable file takes any key, so its module's whole layer is the terminal's (novox/hq issue 340).
if files := catalogue.TrustedMergeable(shelf[module]); len(files) > 0 && !sameLayer(before, after) {
return fmt.Errorf("the settings of %s on %s are set at the controller's terminal only, never through a verb (this "+
"line came through %q): %s merges whatever key a layer sets into a file root or a consumer trusts, so "+
"any key could point the module at a listener of the caller's, and whoever may call a verb includes "+
"agents (novox/hq issue 340; a file nothing trusts says \"trusted\": false). Nothing was changed",
module, where, verb, strings.Join(files, ", "))
}
for _, key := range catalogue.TerminalKeys(shelf[module]) {
was, _ := json.Marshal(before[key])
now, _ := json.Marshal(after[key])
@@ -282,3 +282,65 @@ func TestTheAgentsManagedSettingsAreRefusedThroughAVerb(t *testing.T) {
t.Fatalf("reading through the verb: %v", err)
}
}
// A mergeable file takes any key, not only those its content names (novox/hq issue 340): an empty runtime
// configuration that a provider reads would take a `url` of the caller's, and the provider would send its admin
// login there. So a module with a mergeable file not marked `"trusted": false` has its whole layer set at the
// terminal: through a verb, any change is refused, whatever the key.
func TestAnyKeyOfAModuleWithATrustedMergeableFileIsRefusedThroughAVerb(t *testing.T) {
open := aMesh(t)
ctx := t.Context()
register(t, open, catalogue.Manifest{Module: "keycloak", Version: "1",
Resources: []map[string]any{{"id": "runtime-config", "type": "file", "path": "/var/lib/kc/runtime.json",
"mode": "0600", "merge": "json", "content": "{}"}}})
register(t, open, catalogue.Manifest{Module: "notifier", Version: "1",
Resources: []map[string]any{{"id": "look", "type": "file", "path": "/var/lib/notifier/look.json",
"mode": "0644", "merge": "json", "trusted": false, "content": "{}"}}})
for _, m := range []string{"keycloak", "notifier"} {
if _, err := assign(ctx, open, "anchor", m); err != nil {
t.Fatal(err)
}
}
layer := func(module string) string {
t.Helper()
values, _, err := open.inventory.Layer(ctx, "anchor", module)
if err != nil {
t.Fatal(err)
}
raw, _ := json.Marshal(values)
return string(raw)
}
refused := func(what string, err error) {
t.Helper()
if err == nil || !strings.Contains(err.Error(), "controller's terminal") || !strings.Contains(err.Error(), "issue 340") {
t.Fatalf("%s: %v", what, err)
}
}
refused("a new url through the verb", throughVerb(t, "settings", map[string]any{"module": "keycloak", "node": "anchor",
"values": `{"url":"http://listener.example:8080"}`}))
refused("a new url for the mesh through the verb", throughVerb(t, "settings", map[string]any{"module": "keycloak",
"values": `{"url":"http://listener.example:8080"}`}))
if err := throughVerb(t, "command", map[string]any{"command": `settings set keycloak '{"url":"http://x"}' --node anchor`}); err == nil {
t.Fatal("the command verb set a key of a trusted mergeable file")
}
if got := layer("keycloak"); got != "null" && got != "{}" {
t.Fatalf("a refused call kept a layer: %s", got)
}
if err := atTheTerminal(t, "settings", "set", "keycloak", `{"url":"https://id.example"}`, "--node", "anchor"); err != nil {
t.Fatalf("at the terminal: %v", err)
}
kept := layer("keycloak")
refused("changed", throughVerb(t, "settings", map[string]any{"module": "keycloak", "node": "anchor",
"values": `{"url":"http://listener.example"}`}))
refused("cleared", throughVerb(t, "settings", map[string]any{"module": "keycloak", "node": "anchor", "clear": "true"}))
if got := layer("keycloak"); got != kept {
t.Fatalf("a refused call changed the layer: %s, was %s", got, kept)
}
if err := throughVerb(t, "settings", map[string]any{"module": "keycloak", "node": "anchor"}); err != nil {
t.Fatalf("reading through the verb: %v", err)
}
// A mergeable file that says out loud nothing trusts it stays the verb's.
if err := throughVerb(t, "settings", map[string]any{"module": "notifier", "node": "anchor", "values": `{"font":13}`}); err != nil {
t.Fatalf("a file marked untrusted through the verb: %v", err)
}
}