Stage 1 — the host reports what a machine is and can do

Tier 0's first slice, per novox/hq 03-DESIGN/01-to-be/05-the-node-host.md. It
applies nothing, connects to nothing, listens on nothing. 2.9 MB, static, no
dynamic dependencies: copy it onto a machine and run it is the whole install,
which is the property ADR 0041 rests on.

A capability is detected, never assumed. Every detector runs something that only
succeeds if the thing FUNCTIONS — the daemon is asked for its version, the
package database is queried, the firewall is asked to list a ruleset, which
needs the privilege as well as the tool. 04-ISSUES/007 is the fault this
prevents: a client on disk with its daemon down looks exactly like a working
runtime, and a node assigned work on that basis fails when the work arrives.

Every verdict carries the reason and the method. A capability reported absent
with no reason is the same fault in a new place: something nobody can act on.

Two bugs found by running rather than reasoning, both silent:

systemctl is-system-running exits non-zero for every state except `running` —
including `degraded`, which means units failed and the init is emphatically
there. Reading the exit code reported NO service manager on a machine whose init
it was. That is 007 in the mirror, and both directions place work wrongly. A
verdict now reads what a tool says about itself, not only how it exited.

And `mesh-host inventory --json` printed text: the standard library stops
parsing at the first non-flag argument, so the flag sat unread and the command
exited 0 having ignored what was asked. The parser now takes the subcommand off
the front, and a stray or mistyped argument is refused rather than dropped.

Detection deliberately does NOT follow ADR 0008. That rule governs applying
state, where a failed step means the machine is not what was asked for. A failed
probe is a finding — "absent, because the probe failed" — and aborting would
replace one legible absence with total ignorance of the rest.

25 tests: structure and logic with a fake runner, and the same detectors against
this machine, because a test that fakes the system under detection asserts only
that the fake behaves as expected.
This commit is contained in:
2026-08-26 00:25:08 +02:00
commit 73c010e7ef
12 changed files with 1257 additions and 0 deletions
+206
View File
@@ -0,0 +1,206 @@
package profile
import (
"context"
"fmt"
"os"
"strings"
)
// Named capabilities. Constants rather than strings at the call site, because a capability
// nothing declares is a capability nothing can require, and a typo would produce exactly that.
const (
CapContainerRuntime = "container-runtime"
CapPackageManager = "package-manager"
CapServiceManager = "service-manager"
CapFirewall = "firewall"
CapOverlay = "overlay"
CapGraphicalSession = "graphical-session"
CapPrivileged = "privileged"
)
// commandCapability is the shape most detectors take: run something, and treat a working
// invocation as evidence.
//
// It runs a command that only succeeds if the thing is FUNCTIONING, never `--version` alone.
// A version string proves a binary is on disk, which is the assumption 04-ISSUES/007 records
// as false: the package was installed and the daemon was not running.
type commandCapability struct {
name string
command string
args []string
// why describes what a success actually proves, and is reported as the detector's `How`.
why string
// interpret decides the verdict from what the command said and how it exited.
//
// Exists because "exit zero" is not a universal answer. A degraded service manager reports
// its state on stdout and exits non-zero — it is running, and reading only the exit code
// declared no service manager on a machine whose init it was. That is 04-ISSUES/007 in the
// mirror: 007 is installed-but-broken reported present; this is working-but-imperfect
// reported absent. Both place work wrongly, and this one was only visible by running
// against a real machine.
//
// nil means the ordinary rule: success is exit zero.
interpret func(stdout string, err error) (present bool, detail string)
runner Runner
}
func (c commandCapability) Name() string { return c.name }
func (c commandCapability) Detect(ctx context.Context) Verdict {
out, err := c.runner(ctx, c.command, c.args...)
interpret := c.interpret
if interpret == nil {
interpret = exitZero
}
present, detail := interpret(out, err)
if strings.TrimSpace(detail) == "" {
// A verdict with no reason is the fault in a new place: something nobody can act on.
// Reached when a command fails silently, which systemctl does.
if present {
detail = "responded"
} else {
detail = fmt.Sprintf("%s gave no reason", c.command)
}
}
return Verdict{Name: c.name, Present: present, Detail: firstLine(detail), How: c.why}
}
// exitZero is the ordinary rule: the command worked, so the capability is there.
func exitZero(stdout string, err error) (bool, string) {
if err != nil {
return false, err.Error()
}
return true, stdout
}
// systemRunning reads what an init system says about itself rather than how it exited.
//
// `is-system-running` exits non-zero for every state except `running` — including `degraded`,
// which means units failed and the init is emphatically present. Treating that as absent made
// a machine running systemd report no service manager.
func systemRunning(stdout string, err error) (bool, string) {
state := strings.TrimSpace(firstLine(stdout))
switch state {
case "running", "degraded", "starting", "maintenance", "stopping":
return true, state
case "":
if err != nil {
return false, err.Error()
}
return false, "said nothing"
default:
// `offline` and `unknown` mean it is not managing this machine.
return false, state
}
}
func firstLine(s string) string {
s = strings.TrimSpace(s)
if i := strings.IndexByte(s, '\n'); i >= 0 {
s = s[:i]
}
if len(s) > 200 {
s = s[:200] + "…"
}
return s
}
// privileged reports whether the host can change this machine at all.
//
// Reported as a capability rather than checked at startup on purpose: a host that cannot act
// is still a host that can report, and novox/hq ADR 0036 says what varies between nodes lives
// here rather than in the definition of a node.
type privileged struct{}
func (privileged) Name() string { return CapPrivileged }
func (privileged) Detect(context.Context) Verdict {
uid := os.Geteuid()
if uid == 0 {
return Verdict{
Name: CapPrivileged, Present: true,
Detail: "effective uid 0",
How: "effective uid — the host changes a machine, which needs root",
}
}
return Verdict{
Name: CapPrivileged, Present: false,
Detail: fmt.Sprintf("effective uid %d, not 0", uid),
How: "effective uid — the host changes a machine, which needs root",
}
}
// graphicalSession reports whether anything could display a window here.
//
// Environment rather than a probe, because a display server is reachable through a socket a
// detector would have to guess at, and the variables are what an application would use anyway.
// Stated so the limit is visible: this detects that a session is ADVERTISED, which is weaker
// than the other detectors here.
type graphicalSession struct{}
func (graphicalSession) Name() string { return CapGraphicalSession }
func (graphicalSession) Detect(context.Context) Verdict {
const how = "DISPLAY / WAYLAND_DISPLAY — weaker than the other checks: advertised, not probed"
if d := os.Getenv("WAYLAND_DISPLAY"); d != "" {
return Verdict{Name: CapGraphicalSession, Present: true, Detail: "wayland: " + d, How: how}
}
if d := os.Getenv("DISPLAY"); d != "" {
return Verdict{Name: CapGraphicalSession, Present: true, Detail: "x11: " + d, How: how}
}
return Verdict{
Name: CapGraphicalSession, Present: false,
Detail: "neither DISPLAY nor WAYLAND_DISPLAY is set",
How: how,
}
}
// Default returns the detectors the host runs when nobody says otherwise.
//
// Each command is chosen to prove the thing WORKS rather than exists:
// - the container runtime is asked for server-side information, which fails when the daemon
// is down even though the client is installed — the exact shape of 04-ISSUES/007;
// - the service manager is asked whether it is the running init, not whether it is present;
// - the firewall is asked to list a ruleset, which needs both the tool and the permission.
func Default(runner Runner) []Detector {
if runner == nil {
runner = ExecRunner
}
return []Detector{
privileged{},
graphicalSession{},
commandCapability{
name: CapContainerRuntime, command: "docker", args: []string{"info", "--format", "{{.ServerVersion}}"},
why: "asks the daemon for its version — a running daemon, not an installed client",
runner: runner,
},
commandCapability{
name: CapPackageManager, command: "pacman", args: []string{"-Q", "pacman"},
why: "queries the package database — a working database, not a binary on disk",
runner: runner,
},
commandCapability{
name: CapServiceManager, command: "systemctl", args: []string{"is-system-running"},
why: "reads the init's own account of its state — degraded is still running",
interpret: systemRunning,
runner: runner,
},
commandCapability{
name: CapFirewall, command: "nft", args: []string{"list", "ruleset"},
why: "lists the ruleset — needs the tool AND the privilege to use it",
runner: runner,
},
commandCapability{
name: CapOverlay, command: "wg", args: []string{"show", "interfaces"},
why: "asks the kernel for interfaces — needs the module, not just the tool",
runner: runner,
},
}
}
// isRoot is the same question `privileged` answers, exposed for tests that must check the
// detector against something other than itself.
func isRoot() bool { return os.Geteuid() == 0 }
+118
View File
@@ -0,0 +1,118 @@
// Package profile answers one question: what can this machine be asked to do?
//
// A capability is DETECTED, never assumed. That distinction is the whole point of this
// package and it is not pedantry — novox/hq 04-ISSUES/007 records the fault it exists to
// prevent: an installed package was treated as a capability, and a node was assigned work it
// could not perform because the package was present and the thing was not running.
//
// So a capability here is not "is it installed". It is "does it work", and every detector
// says how it knows.
package profile
import (
"context"
"errors"
"fmt"
"os/exec"
"runtime"
"sort"
"strings"
"time"
)
// Verdict is what a detector concluded, and why.
//
// Why is not decoration. A capability reported absent with no reason is the same problem in a
// new place: something that cannot be acted on. The reason is what a person reads when a node
// will not take work they expected it to take.
type Verdict struct {
Name string `json:"name"`
// Present is true only when the capability is usable, not merely installed.
Present bool `json:"present"`
// Detail says what was observed — a version, a path, or why it is absent.
Detail string `json:"detail"`
// How names the check that produced this, so a wrong answer can be found.
How string `json:"how"`
}
// Detector decides one capability. It is given a context so a hung probe cannot hang the host.
type Detector interface {
Name() string
Detect(ctx context.Context) Verdict
}
// Runner executes a command. Replaceable in tests for the pure-logic layer ONLY — every
// detector in this package is exercised against the real machine as well, because a test that
// fakes the system under detection asserts that the fake behaves as expected
// (novox/hq ADR 0034).
type Runner func(ctx context.Context, name string, args ...string) (stdout string, err error)
// ExecRunner runs a real command, with output captured and stdin closed.
func ExecRunner(ctx context.Context, name string, args ...string) (string, error) {
cmd := exec.CommandContext(ctx, name, args...)
cmd.Stdin = nil
out, err := cmd.Output()
if err != nil {
var exit *exec.ExitError
if errors.As(err, &exit) {
return string(out), fmt.Errorf("%s exited %d: %s",
name, exit.ExitCode(), strings.TrimSpace(string(exit.Stderr)))
}
return string(out), fmt.Errorf("%s: %w", name, err)
}
return string(out), nil
}
// Profile is every verdict, in a stable order.
type Profile struct {
Architecture string `json:"architecture"`
Kernel string `json:"kernel"`
Capabilities []Verdict `json:"capabilities"`
}
// Has reports whether a named capability is present. Unknown names are absent, not an error:
// asking about a capability nothing detects is a question with a true answer.
func (p Profile) Has(name string) bool {
for _, v := range p.Capabilities {
if v.Name == name {
return v.Present
}
}
return false
}
// Missing lists the names that are not present, in order. What a node cannot do is the half
// that decides whether work may be placed on it.
func (p Profile) Missing() []string {
var out []string
for _, v := range p.Capabilities {
if !v.Present {
out = append(out, v.Name)
}
}
sort.Strings(out)
return out
}
// Detect runs every detector and collects the verdicts.
//
// A detector that fails does not fail the profile. This is deliberately NOT the rule in
// novox/hq ADR 0008: that rule governs applying state, where a failed step means the machine
// is not what was asked for. Detection is the opposite — a failed probe is a finding, and the
// finding is "absent, because the probe failed", which is exactly what a caller needs to know.
// Aborting would replace one legible absence with total ignorance.
func Detect(ctx context.Context, detectors []Detector, timeout time.Duration) Profile {
p := Profile{
Architecture: runtime.GOARCH,
Kernel: runtime.GOOS,
}
for _, d := range detectors {
probeCtx, cancel := context.WithTimeout(ctx, timeout)
p.Capabilities = append(p.Capabilities, d.Detect(probeCtx))
cancel()
}
sort.Slice(p.Capabilities, func(i, j int) bool {
return p.Capabilities[i].Name < p.Capabilities[j].Name
})
return p
}
+90
View File
@@ -0,0 +1,90 @@
package profile
import (
"context"
"os/exec"
"strings"
"testing"
"time"
)
// Against the real machine. novox/hq ADR 0034: structure and logic are tested first, behaviour
// against a real system alongside, and mocking the boundary is forbidden — a test that fakes
// the system under detection asserts that the fake behaves as expected.
//
// These do not assert WHICH capabilities this machine has; that varies per machine and is the
// point of detecting. They assert that detection tells the truth about whatever is here.
func TestAgainstThisMachine_detectionAgreesWithReality(t *testing.T) {
got := Detect(context.Background(), Default(nil), 10*time.Second)
if got.Architecture == "" || got.Kernel == "" {
t.Fatal("the machine did not report its own architecture or kernel")
}
if len(got.Capabilities) == 0 {
t.Fatal("no capability was reported at all")
}
// The claim is checkable independently: a capability reported present must have a command
// that is actually on this machine. The reverse is deliberately NOT asserted — a command
// being present while the capability is absent is exactly the fault 04-ISSUES/007 records,
// and this suite exists partly to let that state be observed rather than assumed away.
commands := map[string]string{
CapContainerRuntime: "docker",
CapPackageManager: "pacman",
CapServiceManager: "systemctl",
CapFirewall: "nft",
CapOverlay: "wg",
}
for name, command := range commands {
if !got.Has(name) {
continue
}
if _, err := exec.LookPath(command); err != nil {
t.Errorf("%s reported present, but %q is not on this machine: %v", name, command, err)
}
}
for _, v := range got.Capabilities {
t.Logf(" %-20s present=%-5v %s", v.Name, v.Present, v.Detail)
}
}
func TestAgainstThisMachine_privilegeIsReportedHonestly(t *testing.T) {
// The host changes machines, so whether it can is the capability that decides what the
// rest of it may attempt. Reporting it wrongly in either direction is worse than not
// reporting it: claimed-and-absent means work is accepted and fails, and absent-when-held
// means a capable node refuses work.
var verdict Verdict
for _, v := range Detect(context.Background(), Default(nil), 5*time.Second).Capabilities {
if v.Name == CapPrivileged {
verdict = v
}
}
if verdict.Name == "" {
t.Fatal("privilege was not reported at all")
}
// Checked against the process's own view rather than against the detector's.
root := isRoot()
if verdict.Present != root {
t.Errorf("privilege reported %v; this process is root=%v", verdict.Present, root)
}
if !strings.Contains(verdict.Detail, "uid") {
t.Errorf("privilege detail does not say what it observed: %q", verdict.Detail)
}
}
func TestAgainstThisMachine_detectionIsBounded(t *testing.T) {
// Every probe runs a command on a real machine. If any of them can block, the host has a
// startup that sometimes never finishes — the least debuggable failure there is.
start := time.Now()
Detect(context.Background(), Default(nil), 2*time.Second)
elapsed := time.Since(start)
budget := 2 * time.Second * time.Duration(len(Default(nil)))
if elapsed > budget {
t.Fatalf("detection took %s, past its own %s budget", elapsed, budget)
}
t.Logf("detected %d capabilities in %s", len(Default(nil)), elapsed)
}
+195
View File
@@ -0,0 +1,195 @@
package profile
import (
"context"
"errors"
"strings"
"testing"
"time"
)
// The decision each test defends is named in the test, per novox/hq ADR 0034. These cover
// structure and logic; profile_system_test.go covers the same detectors against the real
// machine, because a test that fakes the system under detection asserts only that the fake
// behaves as expected.
func TestIssue007_installedIsNotUsable(t *testing.T) {
// 04-ISSUES/007 — an installed package is not a capability. The client was present and the
// daemon was down, and the node took work it could not do. A detector whose command fails
// must report ABSENT, however installed the thing looks.
failing := func(context.Context, string, ...string) (string, error) {
return "", errors.New("docker exited 1: Cannot connect to the Docker daemon")
}
got := Detect(context.Background(), Default(failing), time.Second)
if got.Has(CapContainerRuntime) {
t.Fatal("a runtime whose daemon refuses the connection was reported present")
}
for _, v := range got.Capabilities {
if v.Name != CapContainerRuntime {
continue
}
if !strings.Contains(v.Detail, "Cannot connect") {
t.Fatalf("the reason was lost; detail was %q", v.Detail)
}
if v.How == "" {
t.Fatal("a verdict with no stated method cannot be checked when it is wrong")
}
}
}
func TestEveryVerdictSaysHowItKnows(t *testing.T) {
// A capability reported absent with no reason is the fault in a new place: something
// nobody can act on. Both outcomes must carry a method.
for _, runner := range []Runner{
func(context.Context, string, ...string) (string, error) { return "ok", nil },
func(context.Context, string, ...string) (string, error) { return "", errors.New("nope") },
} {
for _, v := range Detect(context.Background(), Default(runner), time.Second).Capabilities {
if strings.TrimSpace(v.How) == "" {
t.Errorf("%s reports present=%v with no stated method", v.Name, v.Present)
}
if strings.TrimSpace(v.Detail) == "" {
t.Errorf("%s reports present=%v with no detail", v.Name, v.Present)
}
}
}
}
func TestDetectionSurvivesAFailingProbe(t *testing.T) {
// Deliberately NOT ADR 0008. That rule governs APPLYING state, where a failed step means
// the machine is not what was asked for. A failed probe is a finding, and aborting would
// replace one legible absence with total ignorance of the rest.
only := func(ctx context.Context, name string, args ...string) (string, error) {
if name == "pacman" {
return "pacman 7.0.0", nil
}
return "", errors.New("not here")
}
got := Detect(context.Background(), Default(only), time.Second)
if len(got.Capabilities) != len(Default(nil)) {
t.Fatalf("expected every detector to report, got %d of %d",
len(got.Capabilities), len(Default(nil)))
}
if !got.Has(CapPackageManager) {
t.Error("the one working capability was lost among the failures")
}
}
func TestAProbeCannotHangTheHost(t *testing.T) {
// A host that blocks forever on a wedged command reports nothing at all, which is worse
// than reporting the capability absent.
blocking := func(ctx context.Context, name string, args ...string) (string, error) {
<-ctx.Done()
return "", ctx.Err()
}
done := make(chan Profile, 1)
go func() { done <- Detect(context.Background(), Default(blocking), 50*time.Millisecond) }()
select {
case got := <-done:
if got.Has(CapFirewall) {
t.Error("a probe that never answered was reported present")
}
case <-time.After(5 * time.Second):
t.Fatal("detection did not return — a wedged probe hung the host")
}
}
func TestUnknownCapabilityIsAbsentNotAnError(t *testing.T) {
// Asking about a capability nothing detects is a question with a true answer.
p := Detect(context.Background(), nil, time.Second)
if p.Has("something-nothing-detects") {
t.Error("an undetected capability reported present")
}
}
func TestMissingListsWhatCannotBeAskedOf(t *testing.T) {
// What a node CANNOT do is the half that decides whether work may be placed on it.
none := func(context.Context, string, ...string) (string, error) { return "", errors.New("no") }
missing := Detect(context.Background(), Default(none), time.Second).Missing()
if len(missing) == 0 {
t.Fatal("everything failed and nothing was reported missing")
}
for i := 1; i < len(missing); i++ {
if missing[i-1] > missing[i] {
t.Fatalf("Missing() is not ordered: %v", missing)
}
}
}
func TestTheProfileIsOrdered(t *testing.T) {
// Two runs on an unchanged machine produce the same profile. Without this, comparing what
// a node was against what it is would report differences that are only ordering.
ok := func(context.Context, string, ...string) (string, error) { return "fine", nil }
first := Detect(context.Background(), Default(ok), time.Second)
second := Detect(context.Background(), Default(ok), time.Second)
if len(first.Capabilities) != len(second.Capabilities) {
t.Fatal("two runs disagreed on how many capabilities exist")
}
for i := range first.Capabilities {
if first.Capabilities[i].Name != second.Capabilities[i].Name {
t.Fatalf("ordering is not stable at %d: %q then %q",
i, first.Capabilities[i].Name, second.Capabilities[i].Name)
}
}
}
func TestADegradedInitIsStillAnInit(t *testing.T) {
// Found by running against a real machine, not by reasoning. `systemctl is-system-running`
// exits non-zero for every state except `running` — including `degraded`, which means some
// units failed and the init is emphatically present. Reading the exit code declared no
// service manager on a machine whose init it was.
//
// This is 04-ISSUES/007 in the mirror: 007 is installed-but-broken reported present; this
// is working-but-imperfect reported absent. Both make the mesh place work wrongly.
degraded := func(ctx context.Context, name string, args ...string) (string, error) {
if name == "systemctl" {
return "degraded\n", errors.New("systemctl exited 1: ")
}
return "", errors.New("not here")
}
got := Detect(context.Background(), Default(degraded), time.Second)
if !got.Has(CapServiceManager) {
t.Fatal("a degraded init was reported absent — the machine would refuse work it can do")
}
for _, v := range got.Capabilities {
if v.Name == CapServiceManager && v.Detail != "degraded" {
t.Errorf("the state was lost; detail was %q", v.Detail)
}
}
}
func TestAnInitThatIsNotManagingThisMachineIsAbsent(t *testing.T) {
// The other side of the same rule. `offline` means it is installed and not in charge —
// which must not be read as present just because a state came back.
for _, state := range []string{"offline", "unknown"} {
runner := func(ctx context.Context, name string, args ...string) (string, error) {
if name == "systemctl" {
return state + "\n", errors.New("systemctl exited 1: ")
}
return "", errors.New("not here")
}
if Detect(context.Background(), Default(runner), time.Second).Has(CapServiceManager) {
t.Errorf("state %q was reported as a working service manager", state)
}
}
}
func TestAFailureWithNoMessageStillCarriesAReason(t *testing.T) {
// systemctl fails with empty stderr, which produced a verdict reading "exited 1:" — absent,
// with nothing anyone could act on.
silent := func(context.Context, string, ...string) (string, error) { return "", errors.New("") }
for _, v := range Detect(context.Background(), Default(silent), time.Second).Capabilities {
if v.Present {
continue
}
if strings.TrimSpace(v.Detail) == "" || strings.HasSuffix(strings.TrimSpace(v.Detail), ":") {
t.Errorf("%s is absent for no stated reason: %q", v.Name, v.Detail)
}
}
}