A module's own secret is asked for by a verb and typed at the desk, bounded, the prompt naming who asked (hq ADR 0277)
mesh/merge-gate pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without …
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

The give verb opened the desk's hidden prompt for a module's own secret, with the desk named. Now the
secret-ask verb (secret ask <node> <module> <name> [--at <desk>]) opens the same prompt from anywhere on
the mesh, with the desk the module's machine unless named, and give composes the same line. Every ask
is recorded in the store before the prompt opens (migration 0091): one open ask per secret, three an
hour, so an agent cannot keep a prompt in front of the operator. The prompt names who asked, from the
bus's word on the caller cut to a name's characters, never an argument of the call. The value stays
typed at the desk, sealed to the one call and then to the module's machine, never in an argument, a
log or an event; a secret the mesh makes itself and a trusted party's secret are refused as before.
This commit is contained in:
jochen
2026-10-10 15:24:08 +02:00
parent 9c69b9da17
commit c97942d591
10 changed files with 445 additions and 32 deletions
+21 -5
View File
@@ -768,10 +768,22 @@ func (a *verbArguments) commandLine() ([]string, error) {
}
return append(argv, "--json"), nil
case "give":
// The same line as secret-ask with the desk named (novox/hq ADR 0277): one path, one set of bounds.
if err := need("node", "module", "secret", "at"); err != nil {
return nil, err
}
return []string{"secret", "accept", str("node"), str("module"), str("secret"), "--at-desk", str("at")}, nil
return []string{"secret", "ask", str("node"), str("module"), str("secret"), "--at", str("at")}, nil
case "secret-ask":
// A module's own secret asked for, typed by the operator at the desk (novox/hq ADR 0277): never a value
// in the arguments. The desk is the module's machine unless at names another.
if err := need("node", "module", "secret"); err != nil {
return nil, err
}
argv := []string{"secret", "ask", str("node"), str("module"), str("secret")}
if at := str("at"); at != "" {
argv = append(argv, "--at", at)
}
return argv, nil
case "rotate":
if p := str("provision"); p != "" {
argv := []string{"rotate", p}
@@ -1538,10 +1550,11 @@ var terminalOnlyCommands = map[string]string{
"licence": "the licences' secrets",
}
// givenAtTheDesk is exactly the line the `give` verb composes, and nothing beside it: `secret accept <node>
// <module> <secret> --at-desk <machine>`, with no other word — no value, no file, no provider.
// givenAtTheDesk is exactly the line the `give` and `secret-ask` verbs compose, and nothing beside it: `secret ask
// <node> <module> <secret>`, with `--at <machine>` or no other word — no value, no file, no provider (novox/hq
// ADR 0277). The terminal's own `secret accept … --at-desk` is the terminal's.
func givenAtTheDesk(argv []string) bool {
if len(argv) != 7 || argv[0] != "secret" || argv[1] != "accept" || argv[5] != "--at-desk" {
if (len(argv) != 5 && len(argv) != 7) || argv[0] != "secret" || argv[1] != "ask" {
return false
}
for _, w := range argv[2:5] {
@@ -1549,7 +1562,10 @@ func givenAtTheDesk(argv []string) bool {
return false
}
}
return argv[6] != "" && !strings.HasPrefix(argv[6], "-")
if len(argv) == 5 {
return true
}
return argv[5] == "--at" && argv[6] != "" && !strings.HasPrefix(argv[6], "-")
}
// terminalOnly refuses, through any verb, a command that is the operator's at the controller's terminal