carlos / platform Public

test: mask the operator's real login from every carlos subprocess

TestAccountsCLI's no-owner refusal case found the box's real production
credential and created a real account per run — carlosTestEnv points
CARLOS_CREDENTIALS into the tempdir for every e2e carlos invocation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGdTfzwT492ysLPDaWfpvJ
Paul Campbell 181f150f19cfe88b7d16df83b7a4c571f072f7ab parent 15209ae
3 files changed, +58 −20
  • CLAUDE.md +4 −0
  • e2e_test.go +35 −18
  • scopedkeys_e2e_test.go +19 −2
diff --git a/CLAUDE.md b/CLAUDE.md
index b1797c72e..c1c195707 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -50,6 +50,10 @@ capable model — exact values, file paths and interfaces go in the brief.
"verified" reports in one day.
- Icons are vendored Lucide (in-code SVG constants, never CDN); emoji is
content, icons are chrome.
+- **A test that shells out to the carlos binary must set `CARLOS_CREDENTIALS`
+ into its tempdir.** The fallback is the operator's real login; a logged-in
+ laptop running `go test ./...` minted 40+ real accounts on the production
+ console before this was isolated (`carlosTestEnv`).
## Deploy reality (2026-08-02)
diff --git a/e2e_test.go b/e2e_test.go
index 2b1005feb..d7dcc6277 100644
--- a/e2e_test.go
+++ b/e2e_test.go
@@ -63,6 +63,23 @@ func e2eGet(t *testing.T, base, host, path string) (int, string) {
return resp.StatusCode, string(b)
}
+// carlosTestEnv is os.Environ() with the operator's real login masked:
+// CARLOS_CREDENTIALS points into the test's own tempdir, where no
+// credential exists. Every subprocess that runs the carlos binary MUST
+// build its env through this. A test that inherits the real
+// ~/.carlos/credentials is one `go test ./...` on a logged-in laptop away
+// from writing to a production console — which is exactly how 40+ test
+// accounts got minted on the flagship (2026-08-04).
+//
+// Duplicated in scopedkeys_e2e_test.go: this file is package main_test (an
+// external test package), that one is package main, and the two cannot
+// share an unexported helper across the package boundary.
+func carlosTestEnv(t *testing.T, extra ...string) []string {
+ t.Helper()
+ env := append(os.Environ(), "CARLOS_CREDENTIALS="+filepath.Join(t.TempDir(), "credentials"))
+ return append(env, extra...)
+}
+
func e2eShipSite(t *testing.T, store release.Store, version string, files map[string]string) {
t.Helper()
dir := t.TempDir()
@@ -685,7 +702,7 @@ func TestAccountsCLI(t *testing.T) {
}
storeDir := filepath.Join(tmp, "store")
regPath := filepath.Join(tmp, "registry.db")
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+storeDir)
+ env := carlosTestEnv(t, "CARLOS_DEPLOYMENT_DIR="+storeDir)
run := func(args ...string) string {
t.Helper()
cmd := exec.Command(carlosBin, args...)
@@ -892,7 +909,7 @@ func TestAccountsMigrateTakesTheLiveObjects(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- env := append(os.Environ(),
+ env := carlosTestEnv(t,
"CARLOS_DEPLOYMENT_DIR="+storeDir,
"CARLOS_RELEASE_PUBKEY="+pubB64)
run := func(args ...string) (string, error) {
@@ -1046,7 +1063,7 @@ func TestAccountsMigrateConvergesADivergedPointer(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- env := append(os.Environ(),
+ env := carlosTestEnv(t,
"CARLOS_DEPLOYMENT_DIR="+storeDir,
"CARLOS_RELEASE_PUBKEY="+pubB64)
run := func(args ...string) (string, error) {
@@ -1319,7 +1336,7 @@ func TestAccountsMigrateLegacyIntoOps(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- env := append(os.Environ(),
+ env := carlosTestEnv(t,
"CARLOS_DEPLOYMENT_DIR="+storeDir,
"CARLOS_RELEASE_PUBKEY="+pubB64)
run := func(args ...string) (string, error) {
@@ -1432,7 +1449,7 @@ func TestEnvCLI(t *testing.T) {
}
storeDir := filepath.Join(tmp, "store")
regPath := filepath.Join(tmp, "registry.db")
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+storeDir)
+ env := carlosTestEnv(t, "CARLOS_DEPLOYMENT_DIR="+storeDir)
run := func(args ...string) string {
t.Helper()
cmd := exec.Command(carlosBin, args...)
@@ -1483,7 +1500,7 @@ func TestSecretsCLI(t *testing.T) {
}
storeDir := filepath.Join(tmp, "store")
regPath := filepath.Join(tmp, "registry.db")
- baseEnv := os.Environ()
+ baseEnv := carlosTestEnv(t)
run := func(env []string, args ...string) string {
t.Helper()
cmd := exec.Command(carlosBin, args...)
@@ -1561,7 +1578,7 @@ func TestEnvironmentBundlesCLI(t *testing.T) {
t.Fatalf("build carlos: %v\n%s", err, out)
}
storeDir := filepath.Join(tmp, "store")
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+storeDir)
+ env := carlosTestEnv(t, "CARLOS_DEPLOYMENT_DIR="+storeDir)
run := func(args ...string) string {
t.Helper()
cmd := exec.Command(carlosBin, args...)
@@ -1708,7 +1725,7 @@ func TestExecDeliveryCLI(t *testing.T) {
t.Fatalf("build carlos: %v\n%s", err, out)
}
storeDir := filepath.Join(tmp, "store")
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+storeDir)
+ env := carlosTestEnv(t, "CARLOS_DEPLOYMENT_DIR="+storeDir)
run := func(args ...string) string {
t.Helper()
cmd := exec.Command(carlosBin, args...)
@@ -1814,7 +1831,7 @@ func TestEnvironmentMergeVisibleFromCLI(t *testing.T) {
t.Fatalf("build carlos: %v\n%s", err, out)
}
storeDir := filepath.Join(tmp, "store")
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+storeDir)
+ env := carlosTestEnv(t, "CARLOS_DEPLOYMENT_DIR="+storeDir)
run := func(args ...string) {
t.Helper()
cmd := exec.Command(carlosBin, args...)
@@ -1890,7 +1907,7 @@ func TestRouteCLI(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- env := append(os.Environ(),
+ env := carlosTestEnv(t,
"CARLOS_DEPLOYMENT_DIR="+storeDir,
"CARLOS_RELEASE_PUBKEY="+pubB64)
run := func(args ...string) (string, error) {
@@ -2208,7 +2225,7 @@ func (f *routeTestFixture) run(env []string, args ...string) (string, error) {
}
func (f *routeTestFixture) fullEnv() []string {
- return append(os.Environ(),
+ return carlosTestEnv(f.t,
"CARLOS_DEPLOYMENT_DIR="+f.storeDir,
"CARLOS_RELEASE_PUBKEY="+f.pubB64)
}
@@ -2302,7 +2319,7 @@ func TestRouteRefusesWithoutPubkey(t *testing.T) {
// Mutation-proven gap: flipping the pub==nil branch back to
// overridable=true left the whole suite green until this flag was added
// here.
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+f.storeDir) // no CARLOS_RELEASE_PUBKEY
+ env := carlosTestEnv(f.t, "CARLOS_DEPLOYMENT_DIR="+f.storeDir) // no CARLOS_RELEASE_PUBKEY
out, err := f.run(env, "route", "-registry", f.regPath, "-host", "demo.example.com",
"-channel", "stable", "-allow-version-change")
if err == nil {
@@ -2327,7 +2344,7 @@ func TestRouteRefusesWithoutStore(t *testing.T) {
f.addRoute(registry.Route{Host: "demo.example.com", Kind: "instance",
App: "demo", Channel: "canary/x", Version: "v1", Status: "ready"})
- env := append(os.Environ(), "CARLOS_RELEASE_PUBKEY="+f.pubB64) // no store env at all
+ env := carlosTestEnv(f.t, "CARLOS_RELEASE_PUBKEY="+f.pubB64) // no store env at all
out, err := f.run(env, "route", "-registry", f.regPath, "-host", "demo.example.com", "-channel", "stable")
if err == nil {
t.Fatalf("route with no deployment store configured was accepted:\n%s", out)
@@ -2359,7 +2376,7 @@ func TestRouteRefusesOnBadSignature(t *testing.T) {
// TestRouteRefusesWithoutPubkey (re-review NEW 2): a bad signature is a
// worse state than an unresolvable target (suspect, not merely unknown),
// and must refuse even with the override.
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+f.storeDir, "CARLOS_RELEASE_PUBKEY="+otherPub)
+ env := carlosTestEnv(f.t, "CARLOS_DEPLOYMENT_DIR="+f.storeDir, "CARLOS_RELEASE_PUBKEY="+otherPub)
out, err := f.run(env, "route", "-registry", f.regPath, "-host", "demo.example.com",
"-channel", "stable", "-allow-version-change")
if err == nil {
@@ -2714,7 +2731,7 @@ func TestRouteEnvironmentInvalidNameRefused(t *testing.T) {
f.addRoute(registry.Route{Host: "demo.tito.example.com", Kind: "instance", App: "tito", Status: "ready"})
for _, bad := range []string{"Has-Upper", "has_underscore", strings.Repeat("a", 33)} {
- out, err := f.run(os.Environ(), "route", "-registry", f.regPath,
+ out, err := f.run(carlosTestEnv(f.t), "route", "-registry", f.regPath,
"-host", "demo.tito.example.com", "-environment", bad)
if err == nil {
t.Fatalf("invalid environment name %q was accepted:\n%s", bad, out)
@@ -2728,7 +2745,7 @@ func TestRouteEnvironmentInvalidNameRefused(t *testing.T) {
// keeps this pinned to the reservation: with the reservation removed, the
// existence rail would still refuse "default", for an unrelated reason,
// and an assertion on err alone would stay green.
- out, err := f.run(os.Environ(), "route", "-registry", f.regPath,
+ out, err := f.run(carlosTestEnv(f.t), "route", "-registry", f.regPath,
"-host", "demo.tito.example.com", "-environment", "default")
if err == nil {
t.Fatalf("-environment default was accepted:\n%s", out)
@@ -2746,7 +2763,7 @@ func TestRouteEnvironmentAloneNeedsNoPubkey(t *testing.T) {
f.addRoute(registry.Route{Host: "demo.tito.example.com", Kind: "instance", App: "tito", Status: "ready"})
f.saveEnvironment(release.OpsAccount, "tito", "demo")
- env := append(os.Environ(), "CARLOS_DEPLOYMENT_DIR="+f.storeDir) // no CARLOS_RELEASE_PUBKEY
+ env := carlosTestEnv(f.t, "CARLOS_DEPLOYMENT_DIR="+f.storeDir) // no CARLOS_RELEASE_PUBKEY
out, err := f.run(env, "route", "-registry", f.regPath,
"-host", "demo.tito.example.com", "-environment", "demo")
if err != nil {
@@ -3050,7 +3067,7 @@ func TestAccountsMigrateLegacyKeepsNewerQualifiedPointer(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- env := append(os.Environ(),
+ env := carlosTestEnv(t,
"CARLOS_DEPLOYMENT_DIR="+storeDir,
"CARLOS_RELEASE_PUBKEY="+pubB64)
run := func(args ...string) (string, error) {
diff --git a/scopedkeys_e2e_test.go b/scopedkeys_e2e_test.go
index 044b96012..a6cb352ab 100644
--- a/scopedkeys_e2e_test.go
+++ b/scopedkeys_e2e_test.go
@@ -10,6 +10,24 @@ import (
"github.com/carlosframework/platform/internal/release"
)
+// carlosTestEnv is os.Environ() with the operator's real login masked:
+// CARLOS_CREDENTIALS points into the test's own tempdir, where no
+// credential exists. Every subprocess that runs the carlos binary MUST
+// build its env through this. A test that inherits the real
+// ~/.carlos/credentials is one `go test ./...` on a logged-in laptop away
+// from writing to a production console — which is exactly how 40+ test
+// accounts got minted on the flagship (2026-08-04).
+//
+// Duplicated from e2e_test.go rather than shared: that file is package
+// main_test (an external test package with no access to this package's
+// unexported symbols), this one is package main, and the two cannot share
+// an unexported helper across the package boundary.
+func carlosTestEnv(t *testing.T, extra ...string) []string {
+ t.Helper()
+ env := append(os.Environ(), "CARLOS_CREDENTIALS="+filepath.Join(t.TempDir(), "credentials"))
+ return append(env, extra...)
+}
+
// The scoped signing key as an operator meets it: two modes of one verb, and
// a promote that signs with whatever CARLOS_RELEASE_KEY holds. Driven through
// the real binary, because the whole feature is about which secret is sitting
@@ -22,11 +40,10 @@ func TestScopedKeysCLI(t *testing.T) {
run := func(env []string, args ...string) (string, error) {
t.Helper()
cmd := exec.Command(bin, args...)
- cmd.Env = append(os.Environ(),
+ cmd.Env = carlosTestEnv(t,
append([]string{
"CARLOS_DEPLOYMENT_DIR=" + bucket,
"CARLOS_DATA_DIR=" + t.TempDir(),
- "CARLOS_CREDENTIALS=" + filepath.Join(t.TempDir(), "credentials"),
}, env...)...)
out, err := cmd.CombinedOutput()
return string(out), err