carlos / platform Public

activator: the token file is tightened and shape-checked on the early return

EnsureAdminToken returned early the moment it found a CARLOS_ADMIN_TOKEN
line, and the chmod lived on the minting path only — so an env file that was
already 0644 when the platform first looked at it kept holding the
instance's secret at world-readable mode for the life of the instance. The
mode only ever converged for files this function itself created. Tightening
now runs on both paths; a chmod that fails does NOT fail the ensure (the
token still works, and refusing a wake over a mode trades hardening for an
outage) — it logs, once per file.

The same early return also took an existing value entirely on trust. A torn
write (an append interrupted, a file truncated by a full disk) leaves a
short or garbled token that will 401 every tick, and the operator meets it
as "scheduled work stopped working" rather than as a diagnosis. It is now
shape-checked against the exact format this function mints: 64 lowercase hex
characters.

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 in order to tidy a string.
Consistency beats hygiene, and the warning carries the one safe repair
(stop the instance, delete the line, restart). It is also not proof of
corruption: before the platform minted these, Eleven's tooling wrote them
by hand, and a hand-written value of another shape works fine.

Both complaints are deduplicated per (condition, file) per process. They are
sticky conditions and every caller repeats — the runner ensures the token on
every tick for the host — so an undeduplicated line would be thousands a day
saying the same thing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 4f902ac9e7abc2ffa47d68abe8502935d4ba2abd parent e8fa127
2 files changed, +224 −4
  • internal/activator/admintoken.go +85 −4
  • internal/activator/admintoken_test.go +139 −0
diff --git a/internal/activator/admintoken.go b/internal/activator/admintoken.go
index 225de9f2b..9ee178208 100644
--- a/internal/activator/admintoken.go
+++ b/internal/activator/admintoken.go
@@ -24,6 +24,7 @@ import (
"crypto/rand"
"encoding/hex"
"fmt"
+ "log"
"os"
"strings"
"sync"
@@ -36,13 +37,66 @@ import (
// first spawn's child holds the first.
var adminTokenMu sync.Mutex
+// adminTokenLogged remembers which (condition, file) pairs have already had
+// their complaint logged, so the two conditions below are diagnoses rather
+// than a log flood. Both of them are STICKY — a 0644 file the agent cannot
+// chmod, a token the wrong shape — and every one of the callers repeats: the
+// runner ensures the token on every tick for the host (every 15s while a
+// timer is due), so an un-deduplicated line would be thousands a day saying
+// the same thing. Read and written only under adminTokenMu.
+//
+// Per-process, deliberately: an agent restart says it again, which is the
+// one moment an operator is reading these logs anyway.
+var adminTokenLogged = map[string]bool{}
+
+// logOncePerFile emits msg the first time it is asked for this (path, kind)
+// pair and stays quiet afterwards. Keyed by kind as well as path so a file
+// that is both un-tightenable AND holding a malformed token still reports
+// both — one condition must not swallow the other's only line. Caller holds
+// adminTokenMu.
+func logOncePerFile(kind, path, msg string) {
+ key := kind + "\x00" + path
+ if adminTokenLogged[key] {
+ return
+ }
+ adminTokenLogged[key] = true
+ log.Print(msg)
+}
+
+// wellFormedAdminToken reports whether tok has the exact shape this file
+// mints: 64 lowercase hex characters (32 random bytes, hex-encoded). A
+// torn write — an append interrupted mid-line, a file truncated by a full
+// disk — can leave a short or garbled value that authenticates nothing,
+// and the failure it produces afterwards ("401 on every tick") points at
+// the wrong thing entirely.
+//
+// A token that fails this is not necessarily broken: before the platform
+// minted these, Eleven's tooling wrote them by hand, and a hand-written
+// value of another shape works perfectly well as long as the instance and
+// the file agree. That is exactly why a failure here is a WARNING and never
+// a rotation — see EnsureAdminToken.
+func wellFormedAdminToken(tok string) bool {
+ if len(tok) != 64 {
+ return false
+ }
+ for i := 0; i < len(tok); i++ {
+ c := tok[i]
+ if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
+ return false
+ }
+ }
+ return true
+}
+
// EnsureAdminToken makes sure path (an instance's own <host>.env) carries a
// CARLOS_ADMIN_TOKEN, minting one if it does not. The file is the instance's,
// not the agent's: every other line in it is preserved untouched and an
// existing token is never rewritten. The file ends up 0600 whether it was
-// created here or already existed in a looser mode — the same mode the env
-// file carries everywhere else, and the only thing standing between another
-// UNIX user on the box and the instance's secret.
+// created here, already existed in a looser mode, or already held a token —
+// that is the same mode the env file carries everywhere else, and the only
+// thing standing between another UNIX user on the box and the instance's
+// secret. An existing token is also shape-checked, and a value that isn't
+// the shape this mints is reported and left exactly as it is.
func EnsureAdminToken(path string) error {
adminTokenMu.Lock()
defer adminTokenMu.Unlock()
@@ -52,7 +106,34 @@ func EnsureAdminToken(path string) error {
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("read %s: %w", path, err)
}
- if parseEnvBytes(raw)["CARLOS_ADMIN_TOKEN"] != "" {
+ if tok := parseEnvBytes(raw)["CARLOS_ADMIN_TOKEN"]; tok != "" {
+ // The early return is NOT a no-op. Two things still have to be true
+ // of a file that already holds the secret.
+ //
+ // First, the mode. The chmod below used to run only on the minting
+ // path, so an env file that was already 0644 when the platform found
+ // a token in it stayed 0644 — holding the very secret the mode is
+ // there to protect. Tightening is idempotent and costs one syscall
+ // per ensure; failing it does NOT fail the ensure, because the token
+ // still works and refusing the wake over a mode would trade a
+ // hardening for an outage.
+ if err := os.Chmod(path, 0o600); err != nil {
+ logOncePerFile("chmod", path, fmt.Sprintf("activator: %s holds CARLOS_ADMIN_TOKEN but could not be tightened to 0600: %v — another UNIX user on this box may be able to read the instance's secret", path, err))
+ }
+ // Second, the shape. A torn write leaves a value that will 401 every
+ // tick, and the platform must say so rather than let the operator
+ // discover it as "scheduled work stopped working".
+ //
+ // It is LEFT IN PLACE, never rotated (ruling, 2026-08-24). The
+ // running instance was handed this same value at spawn, so file and
+ // process agree and ticks authenticate; re-minting behind the
+ // instance's back would 401 a live instance instead of repairing
+ // anything. Consistency beats hygiene here, and the operator has the
+ // one safe repair — stop the instance, delete the line, let the next
+ // spawn mint it.
+ if !wellFormedAdminToken(tok) {
+ logOncePerFile("shape", path, fmt.Sprintf("activator: CARLOS_ADMIN_TOKEN in %s is not the shape the platform mints (64 hex characters) — left in place, because the running instance holds this same value and rotating it would lock the platform out of a live instance; if it is corrupt, stop the instance, delete the line and restart it to have one minted", path))
+ }
return nil
}
secret := make([]byte, 32)
diff --git a/internal/activator/admintoken_test.go b/internal/activator/admintoken_test.go
index a2c095408..a4dec130b 100644
--- a/internal/activator/admintoken_test.go
+++ b/internal/activator/admintoken_test.go
@@ -1,6 +1,7 @@
package activator
import (
+ "log"
"os"
"path/filepath"
"strings"
@@ -60,3 +61,141 @@ func TestEnsureAdminTokenTightensAnExistingFile(t *testing.T) {
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)
+ }
+ }
+}