Files
mesh-catalog/modules/sudo/cmd/sudo-tools/main.go
T
jochen 2989c03f90
mesh/delivery-group group feat/asks-answered-on-any-channel checking: 3 of 4 member(s) ready
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate fail: builds messenger, sudo → ace, g14, novox, shanks; no bus step; a manifest the change touches fails the module check: modules/messenge…
mesh/repo-check fail: its merge-check.sh failed: long-running resources without health: 70
Run the router as its own account, ask unlinking of the linked account, and take no approval where an agent can become root (hq ADR 0259 §7, §8)
2026-10-08 18:39:09 +02:00

77 lines
3.2 KiB
Go

// sudo's tools bundle (novox/hq to-be 42 Phase 1, research 026/05): a process the node's runtime
// launches and speaks MCP over stdio to, through the Go SDK (ADR 0188, ADR 0193). It answers what
// sudo grants the operator account and whether the passwordless escalation every module's acting
// tools rely on works here. It changes nothing: the grant itself is the module's drop-in, which the
// host writes.
package main
import (
"context"
"fmt"
"os"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// binaryName is what the build names this bundle's executable: the manifest's `binary`.
const binaryName = "sudo-tools"
func bg() context.Context { return context.Background() }
func main() {
// An empty name serves as the module the runtime names (MESH_SERVED_MODULE): sudo.
if err := stdio.Serve("", tools(ThisMachine())); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func tools(m *Machine) []stdio.Tool {
return []stdio.Tool{
{
Name: "sudo_rules",
Description: "What the runtime's account may run through sudo on this machine, as `sudo -n -l` says it: " +
"the defaults in force and each rule with its run-as, tags (NOPASSWD …) and commands, and whether one " +
"lets it run everything as root without a prompt. An error when sudo itself asks for a password.",
Input: schema(map[string]any{}),
Run: func(map[string]any) (any, error) { return m.ListRules() },
},
{
Name: "sudo_check",
Description: "Does the passwordless escalation the mesh's acting tools rely on work here, and which file grants it: " +
"every rule in /etc/sudoers and its drop-ins naming the operator account, one of its groups or ALL, in " +
"the order sudo reads them, the one that decides, and whether the module's own drop-in is present.",
Input: schema(map[string]any{}),
Run: func(map[string]any) (any, error) { return m.CheckEscalation() },
},
{
Name: "sudo_escalation",
Description: "Can these accounts become root on this machine without a person: a sudo rule running every " +
"command as root with no password, or a group that is root by another name (docker, disk). Each " +
"account with yes or no and why. Asked by the self-check where the router or a channel proving its " +
"sender runs (novox/hq ADR 0259).",
Input: schema(map[string]any{"accounts": map[string]any{"type": "array", "items": map[string]any{"type": "string"},
"description": "the accounts to judge"}}),
Run: func(a map[string]any) (any, error) {
var accounts []string
if list, ok := a["accounts"].([]any); ok {
for _, x := range list {
if s, ok := x.(string); ok {
accounts = append(accounts, s)
}
}
}
return m.Escalations(accounts)
},
},
{
Name: "sudo_drop_ins",
Description: "The files of /etc/sudoers.d with owner, mode and size, whether sudo reads each (a name with a dot " +
"or ending in ~, another owner or a group- or world-writable mode is skipped), whether each parses " +
"(visudo -cf), and whether sudo's rules as a whole parse. A file that does not parse locks sudo for everyone.",
Input: schema(map[string]any{}),
Run: func(map[string]any) (any, error) { return m.ListDropIns() },
},
}
}