package activator import ( "log" "os" "path/filepath" "strings" "testing" "time" ) func TestEnsureAdminTokenMintsOnce(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } st, _ := os.Stat(p) if st.Mode().Perm() != 0o600 { t.Fatalf("mode = %o", st.Mode().Perm()) } env, _ := readEnvFile(p) tok := env["CARLOS_ADMIN_TOKEN"] if len(tok) != 64 { t.Fatalf("token = %q", tok) } if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } env, _ = readEnvFile(p) if env["CARLOS_ADMIN_TOKEN"] != tok { t.Fatal("token rotated on second call") } } func TestEnsureAdminTokenPreservesOtherVars(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") os.WriteFile(p, []byte("DATABASE_URL=sqlite\n# comment\n"), 0o600) if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } raw, _ := os.ReadFile(p) if !strings.HasPrefix(string(raw), "DATABASE_URL=sqlite\n# comment\n") || !strings.Contains(string(raw), "CARLOS_ADMIN_TOKEN=") { t.Fatalf("file = %q", raw) } env, _ := readEnvFile(p) if env["DATABASE_URL"] != "sqlite" { t.Fatal("other var lost") } } // A looser-mode file that already exists is tightened by the mint: O_CREATE's // 0600 only ever applied to a file created here, and a 0644 file now holds a // secret every other UNIX user on the box could read. func TestEnsureAdminTokenTightensAnExistingFile(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") os.WriteFile(p, []byte("DATABASE_URL=sqlite\n"), 0o644) if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } st, _ := os.Stat(p) if st.Mode().Perm() != 0o600 { t.Fatalf("mode after mint = %o, want 600", st.Mode().Perm()) } } // The tightening is not the minting path's alone. A file that ALREADY held a // token took an early return that skipped the chmod entirely, so a 0644 env // file written by hand (or by an older tool) kept holding the instance's // secret at world-readable mode for as long as the instance lived — the mode // only ever converged for files this function itself created. func TestEnsureAdminTokenTightensAFileThatAlreadyHoldsAToken(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") tok := strings.Repeat("ab", 32) if err := os.WriteFile(p, []byte("CARLOS_ADMIN_TOKEN="+tok+"\n"), 0o644); err != nil { t.Fatal(err) } if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } st, err := os.Stat(p) if err != nil { t.Fatal(err) } if st.Mode().Perm() != 0o600 { t.Fatalf("mode of a pre-existing token file after ensure = %o, want 600", st.Mode().Perm()) } env, _ := readEnvFile(p) if env["CARLOS_ADMIN_TOKEN"] != tok { t.Fatalf("token = %q, want the pre-existing %q — tightening must not rewrite the secret", env["CARLOS_ADMIN_TOKEN"], tok) } } // captureLog redirects the standard logger for the duration of one test and // returns what was written to it. Assertions below count a marker substring // rather than compare whole buffers: a goroutine left running by an earlier // test in this package (the activator's sweeper logs) can drop a line in // here at any moment, and a test that fails on someone else's log line is a // flake, not a finding. func captureLog(t *testing.T) *strings.Builder { t.Helper() var buf strings.Builder flags := log.Flags() log.SetOutput(&buf) log.SetFlags(0) t.Cleanup(func() { log.SetOutput(os.Stderr) log.SetFlags(flags) }) return &buf } // The ruling (2026-08-24): a malformed existing token is WARNED about and // LEFT IN PLACE — never rotated. The running instance was handed this same // value at spawn, so file and process agree and its ticks authenticate; // re-minting behind its back would 401 a live instance to repair a string. // The warning carries the operator's own repair instead. func TestEnsureAdminTokenWarnsAboutAMalformedTokenAndLeavesIt(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") const body = "DATABASE_URL=sqlite\nCARLOS_ADMIN_TOKEN=deadbe\n" if err := os.WriteFile(p, []byte(body), 0o600); err != nil { t.Fatal(err) } buf := captureLog(t) if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } raw, err := os.ReadFile(p) if err != nil { t.Fatal(err) } if string(raw) != body { t.Fatalf("file after ensure = %q, want it byte-identical to %q — a malformed token is never rotated", raw, body) } got := buf.String() if !strings.Contains(got, "CARLOS_ADMIN_TOKEN") || !strings.Contains(got, p) { t.Fatalf("log = %q, want a warning naming the variable and the file", got) } if !strings.Contains(got, "left in place") { t.Fatalf("log = %q, want it to say the value was left in place", got) } if n := strings.Count(got, "not the shape"); n != 1 { t.Fatalf("warning appeared %d times, want 1: %q", n, got) } // Sticky condition, repeated caller: the runner ensures the token on every // tick for the host. One line per file per process, not one per tick. if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } if n := strings.Count(buf.String(), "not the shape"); n != 1 { t.Fatalf("warning appeared %d times across two ensures, want 1: %q", n, buf.String()) } } // The other half of the same contract: a well-formed token is silent. A // warning that fired on healthy files would be noise on every box, and the // shape check exists to be believed. func TestEnsureAdminTokenIsSilentForAWellFormedToken(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") if err := EnsureAdminToken(p); err != nil { // mint one, so the shape is by construction ours t.Fatal(err) } before, err := os.ReadFile(p) if err != nil { t.Fatal(err) } buf := captureLog(t) if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } after, err := os.ReadFile(p) if err != nil { t.Fatal(err) } if string(after) != string(before) { t.Fatalf("file changed under a well-formed token: %q → %q", before, after) } if strings.Contains(buf.String(), "CARLOS_ADMIN_TOKEN") || strings.Contains(buf.String(), "not the shape") { t.Fatalf("log = %q, want nothing said about a healthy token", buf.String()) } } // The shape is the minting format, exactly: 64 lowercase hex characters. func TestWellFormedAdminToken(t *testing.T) { good := strings.Repeat("0f", 32) for _, c := range []struct { name string tok string want bool }{ {"minted shape", good, true}, {"empty", "", false}, {"short", good[:63], false}, {"long", good + "0", false}, {"uppercase hex", strings.ToUpper(good), false}, {"non-hex", strings.Repeat("z", 64), false}, {"quoted", `"` + good[:62] + `"`, false}, } { if got := wellFormedAdminToken(c.tok); got != c.want { t.Errorf("%s: wellFormedAdminToken(%q) = %v, want %v", c.name, c.tok, got, c.want) } } } // os.Chmod is path-based chmod(2) and follows symlinks, and this now runs on // every tick for the host rather than once per instance lifetime. A same-uid // sibling — the residual spec §7.2 documents — that swaps .env for a // link must not turn the agent's tightening into a mode change somewhere // else on the box. Same guard backend_exec.go puts in front of the instance // socket's normalization, for the same reason. func TestEnsureAdminTokenRefusesToChmodThroughASymlink(t *testing.T) { dir := t.TempDir() target := filepath.Join(dir, "someone-elses-file") if err := os.WriteFile(target, []byte("CARLOS_ADMIN_TOKEN="+strings.Repeat("ab", 32)+"\n"), 0o644); err != nil { t.Fatal(err) } link := filepath.Join(dir, "h.env") if err := os.Symlink(target, link); err != nil { t.Skipf("this filesystem will not make symlinks: %v", err) } buf := captureLog(t) if err := EnsureAdminToken(link); err != nil { t.Fatal(err) } st, err := os.Stat(target) if err != nil { t.Fatal(err) } if st.Mode().Perm() != 0o644 { t.Fatalf("mode of the symlink's TARGET = %o, want the untouched 644 — the agent must not chmod through a link", st.Mode().Perm()) } if !strings.Contains(buf.String(), "SYMLINK") { t.Fatalf("log = %q, want the refusal named", buf.String()) } } // The throttle is a clock, not a latch: the chmod is retried every tick, so // the condition can come back (an operator fixes a 0644 file, something // re-widens it weeks later) and a once-per-process bool would keep the agent // silent about a world-readable secret until the next binary roll. func TestEnsureAdminTokenComplaintIsThrottledNotSilenced(t *testing.T) { p := filepath.Join(t.TempDir(), "h.env") if err := os.WriteFile(p, []byte("CARLOS_ADMIN_TOKEN=deadbe\n"), 0o600); err != nil { t.Fatal(err) } buf := captureLog(t) for i := 0; i < 3; i++ { if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } } if n := strings.Count(buf.String(), "not the shape"); n != 1 { t.Fatalf("warning appeared %d times inside the throttle window, want 1", n) } // Age the memory past the window — what a real recurrence looks like. adminTokenMu.Lock() for k := range adminTokenLogged { adminTokenLogged[k] = time.Now().Add(-adminTokenLogRepeat - time.Minute) } adminTokenMu.Unlock() if err := EnsureAdminToken(p); err != nil { t.Fatal(err) } if n := strings.Count(buf.String(), "not the shape"); n != 2 { t.Fatalf("warning appeared %d times after the window elapsed, want it said again (2)", n) } }