nox cleanup delete confirms with the holder's name, as the vault asks
mesh/delivery merged: source.main moved to novox/mesh-catalog@32c4c52261c4
mesh/check checking 63de1f7e0dd7 on 32c4c52261c4

The vault deletes a retired holder only when confirm repeats its name, so
sending confirm "true" could never delete anything. The stand-in console now
also says which machine answered as a block of its own, as node-tools does.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 10:47:56 +01:00
parent 9523050a98
commit 63de1f7e0d
2 changed files with 11 additions and 3 deletions
+6 -1
View File
@@ -317,8 +317,13 @@ var commands = []command{
if len(l.pos) != 1 || !l.has("why") {
return call{}, usageErr("give the consumer and --why")
}
a := pick(l, "why", "confirm")
a := pick(l, "why")
a["consumer"] = l.pos[0]
// The vault deletes only when confirm repeats the holder's name (mesh-vault retirement.go); without
// --confirm it answers what it would delete.
if l.has("confirm") {
a["confirm"] = l.pos[0]
}
return call{"mesh-vault.provisioner_delete", a}, nil
}},
{words: []string{"cleanup"}, does: "every retired holder per provider", build: fixed("mesh-vault.provisioner_retirement")},
+5 -2
View File
@@ -62,7 +62,8 @@ func console(t *testing.T, answers map[string]string) *[]asked {
isError := strings.HasPrefix(text, "!")
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{"jsonrpc": "2.0", "id": 1, "result": map[string]any{
"content": []any{map[string]any{"type": "text", "text": strings.TrimPrefix(text, "!")}}, "isError": isError}})
"content": []any{map[string]any{"type": "text", "text": strings.TrimPrefix(text, "!")},
map[string]any{"type": "text", "text": "answered by ace"}}, "isError": isError}})
}))
t.Cleanup(srv.Close)
t.Setenv("MESH_CONSOLE", srv.URL+"/mcp")
@@ -123,6 +124,8 @@ func TestEachLineCallsItsOwner(t *testing.T) {
{"operator key show", "mesh-vault.vault_status", `{}`},
{"rotate --node ace --module plex --name token --why leak", "mesh-vault.rotate", `{"module":"plex","name":"token","node":"ace","why":"leak"}`},
{"retire approve c1 c2 --why done", "mesh-vault.provisioner_retire_approve", `{"consumers":["c1","c2"],"why":"done"}`},
{"cleanup delete ace.plex --why done --confirm", "mesh-vault.provisioner_delete", `{"confirm":"ace.plex","consumer":"ace.plex","why":"done"}`},
{"cleanup delete ace.plex --why dry", "mesh-vault.provisioner_delete", `{"consumer":"ace.plex","why":"dry"}`},
{"collect --confirm --why space", "mesh-artifact-sweep.collect", `{"confirm":"true","why":"space"}`},
{"images ace", "mesh-artifact-sweep.images", `{"node":"ace"}`},
{"licence use g14 work", "anthropic-licence-manager.switch", `{"consumer":"g14","licence":"work"}`},
@@ -195,7 +198,7 @@ func TestAnswersRefusalsAndSilenceAreSaid(t *testing.T) {
t.Errorf("an error answer: exit %d, stdout %q, stderr %q", code, out, errOut)
}
placement := `{"keys":{"novox":{"placement":{"decided":{"address":"10.10.0.1","site":"hub"},"modules":[{},{}]}},` +
`"ace":{"placement":{"decided":{"address":"10.10.0.2"},"modules":[{}]}}}}` + "\nanswered by ace"
`"ace":{"placement":{"decided":{"address":"10.10.0.2"},"modules":[{}]}}}}`
console(t, map[string]string{"mesh-placement.placement": placement})
if code, out, _ := runLine("nodes"); code != 0 || !strings.HasPrefix(out, "ace ") ||
!strings.Contains(out, "10.10.0.1") || !strings.Contains(out, "2 modules") || !strings.HasSuffix(out, "answered by ace\n") {