//go:build linux && rootrunner package host import ( "encoding/json" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/rollout" "github.com/carlosframework/platform/internal/rootparticipation" "github.com/carlosframework/platform/internal/rootstate" ) func TestPlan14RootRetryHardenedController(t *testing.T) { if os.Getenv("PLAN14_RETRY_HARDENED") == "1" { s, err := rootstate.Open(rollout.RootFailuresDir, false, false) if err != nil { t.Fatal(err) } defer s.Close() b, err := rollout.OpenRootFailures(s, "box/en/1") if err != nil { t.Fatal(err) } p := rootUpdateSource{book: b, publish: publishRootRetry} if err := p.publishRetry(rootUpdateRecord{Route: registry.Route{Host: "h.example.com", Account: "bab", App: "km"}}, "v1"); err != nil { t.Fatal(err) } return } if os.Geteuid() != 0 { t.Fatal("root required") } for _, path := range []string{"/var/lib/carlos-claims", "/var/lib/carlos-release", rootRetryProjection, "/run/carlos-control", "/run/carlos"} { if err := os.Mkdir(path, 0755); err != nil { t.Fatal("existing fixture", path, err) } path := path t.Cleanup(func() { os.RemoveAll(path) }) } state, err := rootstate.Open(rootparticipation.Namespace, true, false) if err != nil { t.Fatal(err) } raw, _ := json.Marshal(rootparticipation.Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}) if err = state.Write("census.json", raw); err != nil { t.Fatal(err) } state.Close() bookState, err := rootstate.Open(rollout.RootFailuresDir, true, false) if err != nil { t.Fatal(err) } book, err := rollout.InitializeRootFailures(bookState, "box/en/1", nil) if err != nil { t.Fatal(err) } if _, err = book.Record(rollout.FailureRecord{Account: "bab", App: "km", Host: "h.example.com", Build: "v1", HeldDown: []string{"h.example.com"}}); err != nil { t.Fatal(err) } id := book.ID() bookState.Close() dir := generationRootRunnerDir(t) config := filepath.Join(dir, "host.env") if err := os.WriteFile(config, []byte("CARLOS_HOST_CLAIM=1\nCARLOS_DATA_DIR="+dir+"\nCARLOS_OPT_DIR="+dir+"\n"), 0600); err != nil { t.Fatal(err) } settings, err := readClaimUnitSettings(config) if err != nil || !settings.rootRetry { t.Fatal("production settings omitted retry scope", settings, err) } binary, err := os.ReadFile(os.Args[0]) if err != nil { t.Fatal(err) } runner := filepath.Join(dir, "runner.test") if err = os.WriteFile(runner, binary, 0755); err != nil { t.Fatal(err) } raw, err = unitsFS.ReadFile("units/" + claimControlUnit) if err != nil { t.Fatal(err) } var lines []string for _, line := range strings.Split(string(claimUnitContent(claimControlUnit, raw, settings)), "\n") { if strings.HasPrefix(line, "Requires=") || strings.HasPrefix(line, "After=") || strings.HasPrefix(line, "ExecStart=") { continue } lines = append(lines, line) } const unit = "plan14-p3-retry.service" path := filepath.Join("/run/systemd/system", unit) file, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) if err != nil { t.Fatal(err) } content := strings.Join(lines, "\n") + fmt.Sprintf("\nType=oneshot\nEnvironment=PLAN14_RETRY_HARDENED=1\nExecStart=%s -test.run=^TestPlan14RootRetryHardenedController$ -test.v\nTimeoutStartSec=60\nIPAddressDeny=any\n", runner) if _, err = file.WriteString(content); err != nil { t.Fatal(err) } file.Close() t.Cleanup(func() { exec.Command("systemctl", "stop", unit).Run() os.Remove(path) exec.Command("systemctl", "daemon-reload").Run() }) for _, args := range [][]string{{"daemon-reload"}, {"start", unit}} { if out, err := exec.Command("systemctl", args...).CombinedOutput(); err != nil { logs, _ := exec.Command("journalctl", "-u", unit, "--no-pager").CombinedOutput() t.Fatal(err, string(out), string(logs)) } } s, err := rootstate.Open(rootRetryProjection, false, true) if err != nil { t.Fatal(err) } defer s.Close() raw, err = s.Read("h.example.com.json") var report rootRetryStatusRecord if err != nil || json.Unmarshal(raw, &report) != nil || report.HeldBook != id || report.HeldEpoch == 0 { t.Fatal("hardened controller failed delivery", string(raw), err) } }