From 1826f1fc9fa8b274323d38efea9d40246d560248 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Sat, 22 Aug 2026 13:16:42 -0700 Subject: [PATCH 1/2] Catch the smoke suite up so the strict gate runs green Three tests went stale against this week's CLI changes, and one skip was the dataset's fault rather than the server's: - auth token now refuses to print a browser session cookie as a bearer token, and the smoke suite authenticates with exactly that cookie. The refusal is the command's behavior under this auth method, so assert it (exit 3, the cookie message) instead of expecting a token. - box became a command group, so bare "hey box" shows help and exits 0. Assert the help names "hey box view" instead of expecting a failure. - The move test skipped forever waiting for a seen posting the seed data never has. When none exists it marks one seen itself and restores the unread state after the move-back cleanup has brought the posting home. With these, HEY_SMOKE_STRICT=1 make test-smoke passes against a current haystack dev server: 156 runs, no skips, no failures. --- tests/smoke/auth_test.go | 27 ++++++++++++--------------- tests/smoke/boxes_test.go | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/tests/smoke/auth_test.go b/tests/smoke/auth_test.go index 1e7f9962..59182171 100644 --- a/tests/smoke/auth_test.go +++ b/tests/smoke/auth_test.go @@ -2,7 +2,6 @@ package smoke_test import ( "encoding/json" - "strings" "testing" ) @@ -18,26 +17,24 @@ func TestAuthStatus(t *testing.T) { } } +// TestMain authenticates with a browser session cookie, and auth token refuses +// to print a cookie as a bearer token: HEY sends it as a Cookie header, so +// handing it out as "Authorization: Bearer" would 401 with nothing to explain +// it. The refusal is the command's behavior under this suite's auth method. func TestAuthToken(t *testing.T) { - stdout, stderr, code := hey(t, "auth", "token") - if code != 0 { - t.Fatalf("auth token failed (exit %d): %s", code, stderr) - } - stdout = strings.TrimSpace(stdout) - if stdout == "" { - t.Error("expected auth token to output a non-empty token") + _, stderr, code := hey(t, "auth", "token") + if code != 3 { + t.Fatalf("expected auth token to refuse the session cookie with exit 3, got exit %d: %s", code, stderr) } + assertContains(t, stderr, "browser session cookie") } func TestAuthTokenStored(t *testing.T) { - stdout, stderr, code := hey(t, "auth", "token", "--stored") - if code != 0 { - t.Fatalf("auth token --stored failed (exit %d): %s", code, stderr) - } - stdout = strings.TrimSpace(stdout) - if stdout == "" { - t.Error("expected auth token --stored to output a non-empty token") + _, stderr, code := hey(t, "auth", "token", "--stored") + if code != 3 { + t.Fatalf("expected auth token --stored to refuse the session cookie with exit 3, got exit %d: %s", code, stderr) } + assertContains(t, stderr, "browser session cookie") } func TestAuthRefresh(t *testing.T) { diff --git a/tests/smoke/boxes_test.go b/tests/smoke/boxes_test.go index 12bdf744..2b494f25 100644 --- a/tests/smoke/boxes_test.go +++ b/tests/smoke/boxes_test.go @@ -189,7 +189,20 @@ func TestMovePosting(t *testing.T) { } } if postingID == 0 { - skipf(t, "no seen postings in Imbox to move without changing unread state") + if len(imbox.Postings) == 0 { + skipf(t, "no postings in Imbox to move") + } + // No seen posting to borrow: mark one seen and put its unread + // state back afterwards. The restore runs after the move-back + // cleanup below, so the posting is home before it goes unseen. + postingID = imbox.Postings[0].ID + heyOK(t, "seen", intStr(postingID), "--json") + t.Cleanup(func() { + _, cleanupStderr, cleanupCode := hey(t, "unseen", intStr(postingID), "--json") + if cleanupCode != 0 { + t.Logf("could not restore posting %d to unseen: %s", postingID, cleanupStderr) + } + }) } stdout, stderr, code := hey(t, "move", intStr(postingID), "--to", "feedbox", "--json") @@ -232,7 +245,9 @@ func TestMoveRejectsBubbleUp(t *testing.T) { } func TestBoxNoArgument(t *testing.T) { - heyFail(t, "box", "--json") + // box is a command group: bare "hey box" shows its help. + stdout := heyOK(t, "box") + assertContains(t, stdout, "hey box view") } func TestBoxInvalidName(t *testing.T) { From f3997d943c574347518e2c97b4bf5677c1a01732 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Sat, 22 Aug 2026 19:09:59 -0700 Subject: [PATCH 2/2] Drop an inherited HEY_TOKEN from the smoke suite's environment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cliEnv passed the caller's environment through, and hey auth token answers HEY_TOKEN before it looks at stored credentials — so a developer or CI runner with a token exported would run the whole suite as that token instead of the cookie TestMain stored, and the auth token tests would pass for the wrong reason. Filter it once, in cliEnv, so every invocation is isolated rather than just the two tests that noticed. --- tests/smoke/helpers_test.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/smoke/helpers_test.go b/tests/smoke/helpers_test.go index 455bc278..f020abd6 100644 --- a/tests/smoke/helpers_test.go +++ b/tests/smoke/helpers_test.go @@ -180,9 +180,16 @@ func dataAs[T any](t *testing.T, resp Response) T { return v } -// cliEnv returns the environment variables used for all CLI invocations. +// cliEnv returns the environment variables used for all CLI invocations. The +// caller's HEY_TOKEN is dropped: the suite authenticates with the cookie TestMain +// stored, and an inherited token would silently stand in for it on every command. func cliEnv() []string { - env := os.Environ() + env := make([]string, 0, len(os.Environ())+6) + for _, kv := range os.Environ() { + if !strings.HasPrefix(kv, "HEY_TOKEN=") { + env = append(env, kv) + } + } env = append(env, "HEY_BASE_URL="+baseURL, "XDG_CONFIG_HOME="+configDir,