Files
mesh-host/internal/system/arch_test.go
T
jschoubben e7f94e0402 A one-shot service that finished is not stopped, and a container is what it reads
Two faults that both reported success while being wrong, found while proving
the firewall module actually delivers.

A unit whose job is to apply something and exit — load a rule set, set a
sysctl — is inactive the instant it succeeds. Reading that as stopped made it
permanently unsatisfiable: the host started it, it worked, the host read back
stopped and reported the machine as not doing what it was told, on every apply,
for ever, with the rules correctly in place the whole time. That is what the
firewall has been doing on every machine it was assigned to, and why the
four-machine bed was red.

And a container took its identity from its own fields, not from the files it
reads. A file written in an earlier apply — or before the container declared it
as a dependency — left a process holding a credential the mesh had already
replaced, with everything reporting success (novox/hq 04-ISSUES/045). What a
container reads is now part of what it is, so the comparison is a standing one
rather than a tripwire that fires during one apply and never again.
2026-09-14 16:51:57 +02:00

52 lines
2.1 KiB
Go

package system
import (
"context"
"testing"
)
// A one-shot unit that did its work and exited is satisfied, not stopped.
//
// **This made the firewall permanently unsatisfiable.** Its unit loads a rule set and exits, so it
// is inactive the instant it succeeds — the host started it, it worked, the host read back
// "stopped" and reported the machine as not doing what it was told. On every apply, for ever, with
// the rules correctly in place the whole time.
func TestAOneShotThatFinishedIsRunning(t *testing.T) {
run := func(_ context.Context, _ string, _ ...string) (string, error) {
return "LoadState=loaded\nActiveState=inactive\nType=oneshot\nRemainAfterExit=no\nExecMainStatus=0\n", nil
}
state, err := arch{}.ServiceState(context.Background(), run, "nftables.service")
if err != nil {
t.Fatalf("a one-shot that succeeded was an error: %v", err)
}
if state != "running" {
t.Fatalf("a one-shot that did its work reads as %q, so it can never be satisfied", state)
}
}
// And one that failed is still stopped, or the host would report success for work that did not
// happen — which is the opposite mistake and the worse one.
func TestAOneShotThatFailedIsStopped(t *testing.T) {
run := func(_ context.Context, _ string, _ ...string) (string, error) {
return "LoadState=loaded\nActiveState=inactive\nType=oneshot\nRemainAfterExit=no\nExecMainStatus=1\n", nil
}
state, err := arch{}.ServiceState(context.Background(), run, "nftables.service")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if state != "stopped" {
t.Fatalf("a one-shot that failed reads as %q, so a broken firewall reports success", state)
}
}
// A unit that lingers deliberately is unaffected: it says so, and its active state is the answer.
func TestAOneShotThatRemainsIsJudgedByItsActiveState(t *testing.T) {
run := func(_ context.Context, _ string, _ ...string) (string, error) {
return "LoadState=loaded\nActiveState=active\nType=oneshot\nRemainAfterExit=yes\nExecMainStatus=0\n", nil
}
state, _ := arch{}.ServiceState(context.Background(), run, "thing.service")
if state != "running" {
t.Fatalf("a lingering one-shot reads as %q", state)
}
}