Files
mesh-catalog/modules/mesh-cli/cmd/mesh-cli/main.go
T
jschoubben 0f0ec66e9a 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
2026-11-02 12:29:56 +01:00

246 lines
8.2 KiB
Go

// Command mesh-cli is the operator's command on every node: `mesh-cli <command line>`, in interactive zsh also `nox`.
//
// Each line calls the seat verb or the module tool that owns its job (novox/hq issue 1126: the controller that ran
// these lines before is unassigned), through this machine's console, the mesh MCP server on loopback (console.go).
// A line no seat or module owns says so and names what to use instead. `enrol open` runs here and asks nothing.
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"os/signal"
"runtime/debug"
"sort"
"strings"
"syscall"
)
// standardInput is mesh-cli's own standard input, and whether it is a terminal (or a device such as /dev/null); a
// variable so a test can say.
var standardInput = func() (io.Reader, bool) {
info, err := os.Stdin.Stat()
if err != nil {
return os.Stdin, true
}
return os.Stdin, info.Mode()&os.ModeCharDevice != 0
}
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
code := run(ctx, os.Args[1:], os.Stdout, os.Stderr)
stop()
os.Exit(code)
}
func run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
if len(args) == 0 || args[0] == "-h" || args[0] == "--help" || args[0] == "help" {
fmt.Fprint(stderr, usage())
if len(args) == 0 {
return 2
}
return 0
}
// A verb's own process carries the verb it runs for; a verb is never a person.
if verb := os.Getenv("MESH_VERB"); verb != "" {
fmt.Fprintf(stderr, "mesh-cli: this process runs for the verb %q, and a verb is never the operator. "+
"Nothing was called\n", verb)
return 1
}
switch args[0] {
case "version":
fmt.Fprintln(stdout, version())
return 0
case "search":
if len(args) < 2 {
fmt.Fprintln(stderr, "mesh-cli: give the words: nox search <words>")
return 2
}
return show(ctx, "mesh_search", map[string]any{"query": strings.Join(args[1:], " ")}, nil, stdout, stderr)
case "describe":
if len(args) != 2 {
fmt.Fprintln(stderr, "mesh-cli: give one address: nox describe <address>")
return 2
}
return show(ctx, "mesh_describe", map[string]any{"address": args[1]}, nil, stdout, stderr)
}
// `enrol open` is local: it opens a sealed enrolment token with the operator's private key and asks nothing of the
// mesh (novox/hq ADR 0587 §8).
if len(args) >= 2 && args[0] == "enrol" && args[1] == "open" {
in, terminal := standardInput()
return enrolOpen(args[2:], in, terminal, stdout, stderr)
}
c, rest := find(args)
if c == nil {
if instead, ok := unowned[args[0]]; ok {
return noOwner(args[0], instead, stderr)
}
fmt.Fprintf(stderr, "mesh-cli: %q is not a command. nox help lists them; nox search <words> finds a seat verb "+
"or a tool, and nox call <address> calls it\n", args[0])
return 2
}
if c.build == nil {
return noOwner(strings.Join(c.words, " "), c.instead, stderr)
}
k, err := c.read(rest)
if err != nil {
fmt.Fprintf(stderr, "mesh-cli: %v. Nothing was called\n nox %s %s\n", err, strings.Join(c.words, " "), c.usage)
return 2
}
if h, ok := k.Args["act"].(*handAct); ok {
id, code := recordAct(ctx, *h, stderr)
if code != 0 {
return code
}
k.Args["act"] = id
}
if k.Address == "mesh-delivery-view.view_status" {
return status(ctx, stdout, stderr)
}
return show(ctx, "mesh_call", map[string]any{"address": k.Address, "arguments": k.Args}, c.render, stdout, stderr)
}
// recordAct records the hand act a sensitive vault verb is warranted by, through mesh-hand-acts, and answers its id;
// a recording refused or unread calls the vault not at all (novox/hq ADR 0590 §8).
func recordAct(ctx context.Context, h handAct, stderr io.Writer) (string, int) {
a, err := meshCall(ctx, "mesh-hand-acts.hand-act", map[string]any{"verb": h.Verb, "what": h.What, "why": h.Why,
"cause": "operator"})
if err != nil {
return "", failed(err, stderr)
}
if a.IsError {
fmt.Fprintln(stderr, "mesh-cli: the hand act was not recorded, so "+h.Verb+" was not called: "+strings.TrimRight(a.Text, "\n"))
return "", 1
}
var rec struct {
Act struct {
ID string `json:"id"`
} `json:"act"`
}
if err := json.NewDecoder(strings.NewReader(a.Text)).Decode(&rec); err != nil || rec.Act.ID == "" {
fmt.Fprintf(stderr, "mesh-cli: mesh-hand-acts answered no act's id (%q), so %s was not called\n", a.Text, h.Verb)
return "", 1
}
return rec.Act.ID, 0
}
// noOwner says a line has no owner since the controller went, and what to use.
func noOwner(what, instead string, stderr io.Writer) int {
fmt.Fprintf(stderr, "mesh-cli: nox %s: %s.\n", what, gone)
if instead != "" {
fmt.Fprintf(stderr, " instead: %s\n", instead)
} else {
fmt.Fprintln(stderr, " no seat or module does this now; nox search <words> finds what does nearby")
}
return 1
}
// show calls one of the console's tools and prints what it answered: an answer marked an error on standard error, with
// exit 1.
func show(ctx context.Context, tool string, args map[string]any, render func(string) string, stdout, stderr io.Writer) int {
a, err := consoleTool(ctx, tool, args)
if err != nil {
return failed(err, stderr)
}
if a.IsError {
fmt.Fprintln(stderr, "mesh-cli: "+strings.TrimRight(a.Text, "\n"))
return 1
}
text := a.Text
if render != nil {
text = render(text)
}
fmt.Fprintln(stdout, strings.TrimRight(text, "\n"))
return 0
}
// failed says why a call did not come back, and never as nothing having run unless nothing answered.
func failed(err error, stderr io.Writer) int {
switch {
case errors.Is(err, context.Canceled):
fmt.Fprintln(stderr, "mesh-cli: stopped waiting; the call may still run")
return 130
case errors.Is(err, context.DeadlineExceeded):
fmt.Fprintln(stderr, "mesh-cli: no answer in time; the call may have run. Check before repeating a change")
return 1
}
fmt.Fprintf(stderr, "mesh-cli: %v\n", err)
return 1
}
// status is the delivery view's status. When the view does not answer, that is said first and loudly, and what the
// condition keeper and mesh-delivery hold is shown in its place, each under its address, with exit 1: never shown as
// the status.
func status(ctx context.Context, stdout, stderr io.Writer) int {
a, err := meshCall(ctx, "mesh-delivery-view.view_status", nil)
if err == nil && !a.IsError {
fmt.Fprintln(stdout, strings.TrimRight(a.Text, "\n"))
return 0
}
if errors.Is(err, errNoConsole) || errors.Is(err, context.Canceled) {
return failed(err, stderr)
}
why := a.Text
if err != nil {
why = err.Error()
}
fmt.Fprintf(stderr, "mesh-cli: the status (mesh-delivery-view.view_status) did not answer: %s\n"+
"mesh-cli: what follows is not the status: the open conditions and the deliveries, read on their own\n",
strings.TrimRight(why, "\n"))
for _, address := range []string{"mesh-conditions.conditions", "mesh-delivery.deliveries"} {
fmt.Fprintf(stdout, "== %s\n", address)
show(ctx, "mesh_call", map[string]any{"address": address, "arguments": map[string]any{}}, nil, stdout, stderr)
}
return 1
}
// version is what this binary was built from.
func version() string {
info, ok := debug.ReadBuildInfo()
if !ok {
return "mesh-cli (unknown build)"
}
v := "mesh-cli " + info.Main.Version
for _, s := range info.Settings {
if s.Key == "vcs.revision" {
v += " " + s.Value
}
}
return v
}
// usage is every line nox takes, grouped by its first word.
func usage() string {
var b strings.Builder
b.WriteString(`mesh-cli: the operator's command (nox in interactive zsh)
Each line calls the seat verb or module tool that owns the job, through this machine's console (the mesh MCP
server on loopback). The controller that ran these lines before is unassigned (novox/hq issue 1126).
`)
lines := make([]string, 0, len(commands))
for _, c := range commands {
if c.build == nil {
continue
}
lines = append(lines, fmt.Sprintf(" nox %s %s\n %s", strings.Join(c.words, " "), c.usage, c.does))
}
sort.Strings(lines)
b.WriteString(strings.Join(lines, "\n"))
b.WriteString(`
nox search <words>
find a seat verb or a module tool
nox describe <address>
one address's arguments
nox enrol open --key <file>
open an enrolment token sealed to the operator key, here; asks nothing of the mesh
nox version
Every answer is the owner's own, as JSON. A line the controller ran that no seat owns says so and what to use.
`)
return b.String()
}