carlos / platform Public

console: the mixed-version test proves its preconditions (#229)

The test could pass on 401s from a missing token row. It now requires the
role rewrite to change exactly one row, checks that the token authenticates
as deploy before the rewrite (positive control on the channels door), and
requires every door's no-token answer to be the gate's own 401 "not signed
in", so an unrouted path cannot pass as a door.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 8ecd088d7f06d4c9af9a499f1a3783d3b5b66dec parent 062cf37
1 file changed, +16 −1
  • internal/console/deploymixed_test.go +16 −1
diff --git a/internal/console/deploymixed_test.go b/internal/console/deploymixed_test.go
index e2d03136c..b6f9662d3 100644
--- a/internal/console/deploymixed_test.go
+++ b/internal/console/deploymixed_test.go
@@ -58,9 +58,18 @@ func TestUnknownStoredRoleIsNotSignedInAtEveryDoor(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if _, err := fx.st.db.Exec(`UPDATE cli_tokens SET role = 'futurerole' WHERE token_hash = ?`, hashToken(raw)); err != nil {
+ // Positive control: before the role is rewritten the token authenticates
+ // as deploy, so a deploy door does not answer 401.
+ if pre := doRaw(t, http.MethodGet, fx.ts.URL+"/api/cli/apps/bab/hello/channels", raw); pre.status == http.StatusUnauthorized {
+ t.Fatalf("deploy token was refused before the role change: %d %q", pre.status, pre.body)
+ }
+ res, err := fx.st.db.Exec(`UPDATE cli_tokens SET role = 'futurerole' WHERE token_hash = ?`, hashToken(raw))
+ if err != nil {
t.Fatal(err)
}
+ if n, err := res.RowsAffected(); err != nil || n != 1 {
+ t.Fatalf("role rewrite changed %d rows (err %v), want 1", n, err)
+ }
if len(fx.srv.cliRoles) == 0 {
t.Fatal("no registered CLI doors to check")
}
@@ -72,6 +81,12 @@ func TestUnknownStoredRoleIsNotSignedInAtEveryDoor(t *testing.T) {
path = fill.ReplaceAllString(path, "x")
with := doRaw(t, method, fx.ts.URL+path, raw)
without := doRaw(t, method, fx.ts.URL+path, "")
+ // The no-token side must be the gate's own refusal, so an unrouted
+ // path (404/405 on both sides) cannot pass for a door.
+ if without.status != http.StatusUnauthorized || !strings.Contains(without.body, "not signed in") {
+ t.Errorf("%s: no token answered %d %q, want the gate's 401 not signed in", pattern, without.status, without.body)
+ continue
+ }
if with.status != without.status || with.body != without.body {
t.Errorf("%s: unknown role answered %d %q; no token answered %d %q",
pattern, with.status, with.body, without.status, without.body)