nox records the hand act a sensitive vault verb is warranted by
Each sensitive vault verb judges its own caller, and nox reaches the vault as its machine's runtime, never as a person, so it could use none of them. Before rotate, retire approve, cleanup delete and secret export nox records the act through mesh-hand-acts (the vault verb as its verb, what it acts on as its what) and names it as act; a refused recording calls the vault not at all (ADR 0590 §8, issue 1126 review 1). Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -120,12 +120,7 @@ func TestEachLineCallsItsOwner(t *testing.T) {
|
||||
{"settings set zsh execute withhold --node g14 --why test", "mesh-config.config", `{"action":"set","key":"execute","module":"zsh","node":"g14","value":"withhold","why":"test"}`},
|
||||
{"settings clear zsh execute --node g14 --why test", "mesh-config.config", `{"action":"clear","key":"execute","module":"zsh","node":"g14","why":"test"}`},
|
||||
{"config history --key k --limit 5", "mesh-config.config", `{"action":"history","key":"k","limit":5}`},
|
||||
{"secret export", "mesh-vault.secret_vault_export", `{}`},
|
||||
{"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"}`},
|
||||
@@ -285,3 +280,40 @@ func TestEveryLineIsInTheHelpOnce(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ADR 0590 §8 (issue 1126 review 1): each sensitive vault verb judges its own caller, and nox reaches the vault as its
|
||||
// machine's runtime, so nox first records the hand act that warrants the line through mesh-hand-acts (the vault verb as
|
||||
// its verb, what it acts on as its what) and names it as `act`; a recording refused calls the vault not at all.
|
||||
func TestASensitiveLineRecordsItsHandActAndNamesIt(t *testing.T) {
|
||||
recorded := `{"act":{"id":"act-7","verb":"mesh-vault.x"},"said":"recorded"}`
|
||||
for _, c := range []struct{ line, address, verb, what, args string }{
|
||||
{"secret export", "mesh-vault.secret_vault_export", "mesh-vault.secret_vault_export", "the vault's sealed copies", `{"act":"act-7"}`},
|
||||
{"rotate --node ace --module plex --name token --why leak", "mesh-vault.rotate", "mesh-vault.rotate", "own/ace/plex/token",
|
||||
`{"act":"act-7","module":"plex","name":"token","node":"ace","why":"leak"}`},
|
||||
{"rotate --provider novox --provision postgres --why yearly", "mesh-vault.rotate", "mesh-vault.rotate", "provision/novox/postgres",
|
||||
`{"act":"act-7","provider":"novox","provision":"postgres","why":"yearly"}`},
|
||||
{"retire approve c1 c2 --why done", "mesh-vault.provisioner_retire_approve", "mesh-vault.provisioner_retire_approve", "c1 c2",
|
||||
`{"act":"act-7","consumers":["c1","c2"],"why":"done"}`},
|
||||
{"cleanup delete ace.plex --why done --confirm", "mesh-vault.provisioner_delete", "mesh-vault.provisioner_delete", "ace.plex",
|
||||
`{"act":"act-7","confirm":"ace.plex","consumer":"ace.plex","why":"done"}`},
|
||||
{"cleanup delete ace.plex --why dry", "mesh-vault.provisioner_delete", "mesh-vault.provisioner_delete", "ace.plex",
|
||||
`{"act":"act-7","consumer":"ace.plex","why":"dry"}`},
|
||||
} {
|
||||
got := console(t, map[string]string{"mesh-hand-acts.hand-act": recorded})
|
||||
code, _, errOut := runLine(strings.Fields(c.line)...)
|
||||
if code != 0 || len(*got) != 2 || (*got)[0].Address != "mesh-hand-acts.hand-act" || (*got)[1].Address != c.address ||
|
||||
(*got)[1].Args != c.args {
|
||||
t.Errorf("nox %s: exit %d, asked %+v, stderr %q", c.line, code, *got, errOut)
|
||||
continue
|
||||
}
|
||||
var act map[string]any
|
||||
_ = json.Unmarshal([]byte((*got)[0].Args), &act)
|
||||
if act["verb"] != c.verb || act["what"] != c.what || act["why"] == "" || act["cause"] == "" {
|
||||
t.Errorf("nox %s recorded %v", c.line, act)
|
||||
}
|
||||
}
|
||||
got := console(t, map[string]string{"mesh-hand-acts.hand-act": "!nothing serves seat:mesh-hand-acts.hand-act"})
|
||||
if code, _, errOut := runLine("secret", "export"); code != 1 || len(*got) != 1 || !strings.Contains(errOut, "nothing serves") {
|
||||
t.Errorf("a refused recording: exit %d, asked %+v, %q", code, *got, errOut)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user