package main import ( "strings" "testing" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" ) // echoEnvironment makes the test binary, run as a command line, say the verb and caller it was given (TestMain). const echoEnvironment = "MESH_TEST_ECHO_ENVIRONMENT" var cliNodes = []inventory.Node{ {Name: "control", Account: "operator"}, {Name: "laptop", Account: "operator"}, {Name: "unnamed"}, } func cliAsked(account string, uid uint32, line ...string) link.CLIAsked { return link.CLIAsked{Line: line, Account: account, UID: uid, Session: "session-1.scope"} } // Who is the controller's terminal, and who is an ordinary call or refused (novox/hq ADR 0272 §4). func TestMeshCLIIsTheTerminalOnlyForTheControlNodesOperator(t *testing.T) { control := []string{"control"} cases := []struct { name, node string asked link.CLIAsked control []string terminal bool refused string why string }{ {"the control-node's operator", "control", cliAsked("operator", 1000, "status"), control, true, "", "the controller's terminal"}, {"another node's operator", "laptop", cliAsked("operator", 1000, "status"), control, false, "", "agents on laptop may run as operator"}, {"another account", "control", cliAsked("agent", 1001, "status"), control, false, "operator account (operator) only", ""}, {"root", "control", cliAsked("root", 0, "status"), control, false, "never root", ""}, {"a node with no operator account", "unnamed", cliAsked("operator", 1000, "status"), control, false, "does not know unnamed's operator account", ""}, {"a node the mesh does not know", "elsewhere", cliAsked("operator", 1000, "status"), control, false, "not a node this mesh knows", ""}, {"two control-nodes", "control", cliAsked("operator", 1000, "status"), []string{"control", "laptop"}, false, "", "2 control-nodes"}, } for _, c := range cases { v := judgeCLI(c.node, c.asked, cliNodes, c.control) if v.terminal != c.terminal { t.Errorf("%s: terminal %v, want %v (%+v)", c.name, v.terminal, c.terminal, v) } if c.refused == "" && v.refused != "" || c.refused != "" && !strings.Contains(v.refused, c.refused) { t.Errorf("%s: refused %q, want %q", c.name, v.refused, c.refused) } if c.why != "" && !strings.Contains(v.why, c.why) { t.Errorf("%s: why %q, want %q", c.name, v.why, c.why) } } } // The terminal runs its line without MESH_VERB, even where this process carries one; an ordinary call names // mesh-cli; both record who asked through mesh-cli. // An ordinary call meets every refusal of the generic command verb, and nothing runs; a server is never run. // **Which node is the terminal does not follow a verb** (review of ADR 0272): the controller's module is assigned // and unassigned at the terminal alone, so no caller of `assign` can move the terminal to a node of its choosing. // Asked through the acts themselves, as the verbs ask them; refused before any store is touched (none is given). // An ordinary `settings set|clear` goes down the settings verb's own path: composed as that verb composes it, and // run with MESH_VERB set, so its refusals — the terminal-only keys among them — are the settings command's own, // not a blanket refusal of the generic command (review of ADR 0272). func TestAnOrdinarySettingsLineTakesTheSettingsVerbsPath(t *testing.T) { cases := []struct { line []string want string err string }{ {[]string{"settings", "set", "zsh", `{"execute":"withhold"}`, "--node", "laptop"}, `settings set zsh {"execute":"withhold"} --node laptop`, ""}, {[]string{"settings", "set", "zsh", "{}", "--replace"}, "settings set zsh {} --replace", ""}, {[]string{"settings", "clear", "zsh", "--node", "laptop"}, "settings clear zsh --node laptop", ""}, {[]string{"settings", "show", "zsh", "--history"}, "settings show zsh --history", ""}, {[]string{"settings", "preferences"}, "settings preferences", ""}, {[]string{"settings", "set", "zsh"}, "", "settings"}, {[]string{"settings", "set", "zsh", "{}", "--sideways"}, "", "--sideways"}, } for _, c := range cases { argv, err := ordinaryLine(c.line) if c.err != "" { if err == nil || !strings.Contains(err.Error(), c.err) { t.Errorf("%q: refused with %v, want %q", c.line, err, c.err) } continue } if err != nil || strings.Join(argv, " ") != c.want { t.Errorf("%q: composed %q (%v), want %q", c.line, argv, err, c.want) } } // Anything else still meets the generic command verb's refusals. if _, err := ordinaryLine([]string{"retire", "delete", "x"}); err == nil { t.Error("a repair composed as an ordinary line") } } // Every line is said in the controller's journal, with its call, who asked where and how it ran — its command word // only, never the rest of the line (review of ADR 0272). // **An ordinary line runs only what the generic command verb would** (review of ADR 0272, ADR 0266): its reading // forms, and never a command that is the terminal's alone. Each of these, from another node's operator, is refused // and runs nothing. // **`calls` never shows a mesh-cli line's answer** (review of ADR 0272): the verb's own answer is read for a line // served over a bus, and neither the answer's text nor the base64 JSON writes its bytes in is there. // **Only the terminal's line carries the terminal's mark** (review of ADR 0272): a mark the serving controller's // environment holds — leaked, or set by anything — is stripped from every other command line it runs, a verb's and // an ordinary mesh-cli line alike, so neither reads as the terminal. // **Only a login session is the terminal** (review of ADR 0272): the operator's account on the control-node, asking // from a service — the tool runner, a user unit — and not a login session, is an ordinary call. func TestOnlyALoginSessionIsTheTerminal(t *testing.T) { control := []string{"control"} v := judgeCLI("control", link.CLIAsked{Line: []string{"status"}, Account: "operator", UID: 1000}, cliNodes, control) if v.terminal || v.refused != "" || !strings.Contains(v.why, "login session") { t.Fatalf("a line from no login session reads %+v", v) } v = judgeCLI("control", link.CLIAsked{Line: []string{"status"}, Account: "operator", UID: 1000, Session: "session-3.scope"}, cliNodes, control) if !v.terminal { t.Fatalf("a line from a login session on the control-node reads %+v", v) } }