package provision import ( "context" "encoding/json" "io" "log/slog" "os" "path/filepath" "runtime" "strings" "sync" "testing" ) // recRunner records every command issued (to assert chown + pct set ran with correct args). type recRunner struct { mu sync.Mutex cmds [][]string fail string // if a command's name == fail, return an error } func (r *recRunner) RunStdin(ctx context.Context, _ io.Reader, name string, args ...string) ([]byte, []byte, error) { return r.Run(ctx, name, args...) } func (r *recRunner) Run(_ context.Context, name string, args ...string) ([]byte, []byte, error) { r.mu.Lock() r.cmds = append(r.cmds, append([]string{name}, args...)) r.mu.Unlock() if name == r.fail { return nil, []byte("boom"), io.ErrUnexpectedEOF } return nil, nil, nil } func (r *recRunner) find(name string) []string { r.mu.Lock() defer r.mu.Unlock() for _, c := range r.cmds { if c[0] == name { return c } } return nil } // hasExact reports whether any recorded command matches the given args exactly (name + all args). // Needed because several `pct` invocations are recorded; find() only returns the first. func (r *recRunner) hasExact(want ...string) bool { r.mu.Lock() defer r.mu.Unlock() for _, c := range r.cmds { if len(c) != len(want) { continue } match := true for i := range c { if c[i] != want[i] { match = false break } } if match { return true } } return false } // mintMinter returns a fixed token and records the vmid it was minted for. type mintMinter struct { token string vmids []int } func (m *mintMinter) Mint(vmid int) (string, error) { m.vmids = append(m.vmids, vmid) return m.token, nil } func testLogger() *slog.Logger { return slog.New(slog.NewTextHandler(io.Discard, nil)) } func newInput() Input { return Input{ VMID: 8200, Customer: DocCustomer{ID: "cust-8200"}, Hub: DocHub{URL: "https://hub.felhom.eu", RetrievalPassword: "five-word-passphrase"}, Endpoint: "192.168.0.162:8443", Fingerprint: "ab12cd", } } func TestProvision_WritesChownsAndAttaches(t *testing.T) { dir := t.TempDir() runner := &recRunner{} minter := &mintMinter{token: "SECRET-TOKEN-XYZ"} bh := NewBackHalf(minter, runner, dir, testLogger()) res, err := bh.Provision(context.Background(), newInput()) if err != nil { t.Fatalf("provision: %v", err) } // token minted for the right guest if len(minter.vmids) != 1 || minter.vmids[0] != 8200 { t.Fatalf("mint vmids: %v", minter.vmids) } // bootstrap.json written 0600, contains the token + customer, valid contract bootPath := filepath.Join(res.HostDir, "bootstrap.json") info, err := os.Stat(bootPath) if err != nil { t.Fatalf("stat bootstrap: %v", err) } // Unix perms are not modeled on Windows; the 0600 is enforced on the Linux target (where the // agent runs). Assert only where the OS honors it. if runtime.GOOS != "windows" { if perm := info.Mode().Perm(); perm != 0o600 { t.Fatalf("bootstrap perms: got %o want 600", perm) } } raw, _ := os.ReadFile(bootPath) var doc Doc if err := json.Unmarshal(raw, &doc); err != nil { t.Fatalf("bootstrap not valid JSON: %v", err) } if doc.Schema != SchemaV2 || doc.Customer.ID != "cust-8200" || doc.LocalAPI.Token != "SECRET-TOKEN-XYZ" { t.Fatalf("bootstrap content wrong: %+v", doc) } if doc.Hub.URL != "https://hub.felhom.eu" || doc.Hub.RetrievalPassword != "five-word-passphrase" { t.Fatalf("hub wrong (want url + retrieval_password, no host key): %+v", doc.Hub) } if doc.LocalAPI.Endpoint != "192.168.0.162:8443" || doc.LocalAPI.Fingerprint != "ab12cd" { t.Fatalf("local_api wrong: %+v", doc.LocalAPI) } // chown to the mapped guest-root ran on the host dir chown := runner.find("chown") if chown == nil || chown[1] != "-R" || chown[2] != "100000:100000" || chown[3] != res.HostDir { t.Fatalf("chown command wrong: %v", chown) } // pct set attached the read-only bind mount at the default high slot pct := runner.find("pct") if pct == nil { t.Fatal("pct set not called") } joined := strings.Join(pct, " ") if !strings.Contains(joined, "set 8200 -mp9") || !strings.Contains(joined, res.HostDir+",mp=/etc/felhom-bootstrap,ro=1") { t.Fatalf("pct set command wrong: %v", pct) } if res.MountKey != "mp9" || res.GuestPath != "/etc/felhom-bootstrap" { t.Fatalf("result placement wrong: %+v", res) } } // F3: the provisioned customer guest must be set onboot:1 so it auto-starts after a host // reboot/power-cut (the golden bakes onboot:0 as a template). Assert the exact pct invocation. // F-3 (DRILL-day0-vm-2026-07-12): a ROOT-run provision must chown the guests/ + guests// // PARENT dirs to the state-dir's owner (chown --reference, NON-recursive — the bootstrap leaf // stays the mapped guest-root's). A non-root run must NOT issue it (the dirs are already // agent-created). Companion red-proof: remove the geteuid()==0 chown block in Provision → the // root case fails (no such invocation recorded); the non-root case alone stays green. func TestProvision_RootRunOwnsGuestsParents(t *testing.T) { orig := geteuid defer func() { geteuid = orig }() for _, tc := range []struct { name string euid int want bool }{ {"root run issues the parent chown", 0, true}, {"non-root run does not", 1001, false}, } { t.Run(tc.name, func(t *testing.T) { geteuid = func() int { return tc.euid } dir := t.TempDir() runner := &recRunner{} bh := NewBackHalf(&mintMinter{token: "T"}, runner, dir, testLogger()) if _, err := bh.Provision(context.Background(), newInput()); err != nil { t.Fatalf("provision: %v", err) } guestsDir := filepath.Join(dir, "guests") vmidDir := filepath.Join(guestsDir, "8200") got := runner.hasExact("chown", "--reference="+dir, guestsDir, vmidDir) if got != tc.want { t.Fatalf("parent chown issued=%v want=%v; recorded: %v", got, tc.want, runner.cmds) } // Never recursive — the guest-root bootstrap subtree must stay untouched. if runner.hasExact("chown", "-R", "--reference="+dir, guestsDir, vmidDir) { t.Fatal("parent chown ran recursively") } }) } } // Companion red-proof: removing the `b.run(... -onboot 1)` call in Provision makes this FAIL // (no such invocation recorded) — re-applying the call turns it green. func TestProvision_SetsOnbootOne(t *testing.T) { dir := t.TempDir() runner := &recRunner{} bh := NewBackHalf(&mintMinter{token: "t"}, runner, dir, testLogger()) if _, err := bh.Provision(context.Background(), newInput()); err != nil { t.Fatalf("provision: %v", err) } if !runner.hasExact("pct", "set", "8200", "-onboot", "1") { t.Fatalf("expected `pct set 8200 -onboot 1` to be issued; recorded: %v", runner.cmds) } } // The Result must never carry the token, and the token must not appear in any field returned to // the caller (secret discipline — only the 0600 file + the store hash hold it). func TestProvision_ResultHasNoToken(t *testing.T) { dir := t.TempDir() bh := NewBackHalf(&mintMinter{token: "SECRET-TOKEN-XYZ"}, &recRunner{}, dir, testLogger()) res, err := bh.Provision(context.Background(), newInput()) if err != nil { t.Fatal(err) } blob, _ := json.Marshal(res) if strings.Contains(string(blob), "SECRET-TOKEN-XYZ") { t.Fatalf("token leaked into the Result: %s", blob) } } func TestProvision_RejectsIncompleteInput(t *testing.T) { dir := t.TempDir() bh := NewBackHalf(&mintMinter{token: "t"}, &recRunner{}, dir, testLogger()) bad := Input{VMID: 8200} // no endpoint/fingerprint/customer if _, err := bh.Provision(context.Background(), bad); err == nil { t.Fatal("expected an error for incomplete input") } } // A failed chown surfaces an error (and does not proceed to attach). func TestProvision_ChownFailureStops(t *testing.T) { dir := t.TempDir() runner := &recRunner{fail: "chown"} bh := NewBackHalf(&mintMinter{token: "t"}, runner, dir, testLogger()) if _, err := bh.Provision(context.Background(), newInput()); err == nil { t.Fatal("expected chown failure to surface") } if runner.find("pct") != nil { t.Fatal("pct set ran despite a chown failure") } }