package console // The bake controls (2026-08-04 console bake controls spec §7). Properties // in the order they'd hurt if lost: OFF cannot happen without owner + // passkey (and a member probing it gets the byte-identical 404); ON is any // member's, instantly; fast-track is owner + passkey and lands on the // pointer; the stable-promote checkbox flips the flag in the same confirmed // action. import ( "context" "net/http" "net/url" "strings" "testing" "time" "github.com/carlosframework/platform/internal/release" ) // productionFlag reads the app's flag straight from the bucket, through the // same verification the adopt path uses. The fixture carries the release // public key, so there is nothing to derive. func productionFlag(t *testing.T, fx *consoleFixture, app string) *release.ProductionFlag { t.Helper() f, err := release.GetProduction(context.Background(), fx.rel, fx.pub, release.OpsAccount, app) if err != nil { t.Fatal(err) } return f } // strangerRefusal is what someone with no membership at all gets from one of // this account's app routes: a signed-in browser belonging to nobody here. // It is the yardstick the member's refusal must match byte for byte. func strangerRefusal(t *testing.T, fx *consoleFixture, code, u string, form url.Values) string { t.Helper() fx.fk.mu.Lock() prev := fx.fk.address fx.fk.mu.Unlock() fx.setUser("zoe@keymail.dev") // signs up into an account of her own defer fx.setUser(prev) c := newBrowser(t) signUp(t, fx, c, code) form.Set("csrf", sessionToken(t, fx, c)) status, _, body := postForm(t, c, u, form) if status != http.StatusNotFound { t.Fatalf("non-member posting %s = %d, want 404", u, status) } return body } // auditedBy asserts the console's OWN activity trail (store events, which is // what the app page renders) recorded this action for this actor. The // pointer's audit trail is a different record with a different purpose; a // console action that leaves no console event is an invisible one. func auditedBy(t *testing.T, fx *consoleFixture, app, action, actor, detailPart string) { t.Helper() events, err := fx.st.Events(OpsAccountID, app, 20) if err != nil { t.Fatal(err) } for _, e := range events { if e.Action == action && e.Address == actor && strings.Contains(e.Detail, detailPart) { return } } t.Fatalf("events = %+v, want a %q row by %s mentioning %q", events, action, actor, detailPart) } func TestProductionOnIsAnyMembers(t *testing.T) { fx := newConsoleFixture(t) if err := fx.st.AddMember(OpsAccountID, "sam@keymail.dev", RoleMember, time.Now()); err != nil { t.Fatal(err) } fx.setUser("sam@keymail.dev") c := newBrowser(t) signUp(t, fx, c, "code-sam-bake") csrf := sessionToken(t, fx, c) status, _, _ := postForm(t, c, fx.u("/apps/kass/production"), url.Values{"csrf": {csrf}, "production": {"on"}}) if status != http.StatusSeeOther { t.Fatalf("member turning bake ON = %d, want a plain redirect (no step-up)", status) } if f := productionFlag(t, fx, "kass"); f == nil || !f.Production { t.Fatalf("flag = %+v, want production on", f) } auditedBy(t, fx, "kass", "production", "sam@keymail.dev", "production: on") } func TestProductionOffIsOwnerPasskeyGated(t *testing.T) { fx := newConsoleFixture(t) c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) // Seed on, as any member could. if err := release.SetProduction(context.Background(), fx.rel, fx.priv, release.OpsAccount, "kass", true, "test"); err != nil { t.Fatal(err) } // Without the passkey the flag does not move. status, loc, _ := postForm(t, c, fx.u("/apps/kass/production"), url.Values{"csrf": {csrf}, "production": {"off"}}) if status != http.StatusSeeOther || !strings.HasPrefix(loc, fx.fk.srv.URL) { t.Fatalf("un-stepped-up off = %d -> %q, want a redirect into Keymail", status, loc) } if f := productionFlag(t, fx, "kass"); f == nil || !f.Production { t.Fatal("the flag flipped off with no passkey confirmation") } // With it, the held action resumes. if status, _, body := completeStepUp(t, fx, c, loc); status != http.StatusSeeOther { t.Fatalf("resumed off = %d:\n%s", status, body) } if f := productionFlag(t, fx, "kass"); f == nil || f.Production { t.Fatal("the flag did not flip off after confirmation") } auditedBy(t, fx, "kass", "production", "paul@keymail.dev", "production: off") } // A MEMBER probing the off direction meets the byte-identical 404 — before // any step-up redirect could confirm the account exists. func TestProductionOffMemberGets404(t *testing.T) { fx := newConsoleFixture(t) // Seeded ON, so "the flag stayed put" is an assertion about a value that // could have moved rather than about an absent object. if err := release.SetProduction(context.Background(), fx.rel, fx.priv, release.OpsAccount, "kass", true, "test"); err != nil { t.Fatal(err) } if err := fx.st.AddMember(OpsAccountID, "sam@keymail.dev", RoleMember, time.Now()); err != nil { t.Fatal(err) } fx.setUser("sam@keymail.dev") c := newBrowser(t) signUp(t, fx, c, "code-sam-bake2") csrf := sessionToken(t, fx, c) form := url.Values{"csrf": {csrf}, "production": {"off"}} status, _, memberBody := postForm(t, c, fx.u("/apps/kass/production"), form) if status != http.StatusNotFound { t.Fatalf("member turning bake OFF = %d, want 404", status) } if f := productionFlag(t, fx, "kass"); f == nil || !f.Production { t.Fatalf("flag = %+v after a member's refused post, want it untouched", f) } // Byte-identical, not merely same-status: the difference between "not // allowed" and "no such account" is not information this hands out. strangerBody := strangerRefusal(t, fx, "code-zoe-bake2", fx.u("/apps/kass/production"), url.Values{"production": {"off"}}) if memberBody != strangerBody { t.Fatalf("the two refusals are not byte-identical:\n(member) %q\n(stranger) %q", memberBody, strangerBody) } // http.NotFound's own, well-known output — pinned so a future change to // either path is caught even if it stays self-consistent. if memberBody != "404 page not found\n" { t.Fatalf("refusal body = %q, want the stdlib http.NotFound output", memberBody) } } // Fast-track is owner + passkey, ALWAYS. The un-stepped-up post is what // proves the second half: postGated alone would stay green with the step-up // call deleted, because it only walks the round trip when one is demanded. func TestFastTrackIsOwnerPasskeyGatedAndLands(t *testing.T) { fx := newConsoleFixture(t) c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) // The fixture's stable already points at v1. Without the passkey the // waiver does not happen. status, loc, _ := postForm(t, c, fx.u("/apps/kass/fasttrack"), url.Values{"csrf": {csrf}, "channel": {"stable"}, "confirmed": {"1"}}) if status != http.StatusSeeOther || !strings.HasPrefix(loc, fx.fk.srv.URL) { t.Fatalf("un-stepped-up fast-track = %d -> %q, want a redirect into Keymail", status, loc) } if p := fx.channelVersion(t, "kass", "stable"); p.FastTrack { t.Fatal("the bake window was waived with no passkey confirmation") } // With it, the held action resumes and lands on the pointer. if status, _, body := completeStepUp(t, fx, c, loc); status != http.StatusSeeOther { t.Fatalf("resumed fast-track = %d:\n%s", status, body) } p := fx.channelVersion(t, "kass", "stable") if !p.FastTrack { t.Fatalf("pointer = %+v, want fast_track set", p) } if len(p.Audit) == 0 || !p.Audit[0].FastTrack || p.Audit[0].Actor != "paul@keymail.dev" { t.Fatalf("audit[0] = %+v, want the waiver recorded with its actor", p.Audit) } auditedBy(t, fx, "kass", "fast-track", "paul@keymail.dev", "skipped the safety delay for v1 on stable") } // Fast-tracking a channel that never bakes is refused. It looks inert — // adopt ignores the waiver on a zero-hold channel — but the re-sign stamps a // fresh PromotedAt, which is exactly what the canary TTL lease is measured // from: the post would quietly renew the lease and leave a permanent // "fast-tracked past the bake window" badge on a channel that has no window. func TestFastTrackRefusesAChannelWithNoBakeWindow(t *testing.T) { fx := newConsoleFixture(t) shipVersion(t, fx, "kass", "v3") seedChannel(t, fx, "kass", "canary/x", "v3") before := fx.channelVersion(t, "kass", "canary/x") c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) status, _, _ := postGated(t, fx, c, fx.u("/apps/kass/fasttrack"), url.Values{"csrf": {csrf}, "channel": {"canary/x"}, "confirmed": {"1"}}) if status != http.StatusSeeOther { t.Fatalf("fast-track of a bake-free channel = %d, want the flash redirect", status) } if _, _, body := get(t, c, fx.u("/apps/kass")); !strings.Contains(body, "Channel canary/x has no safety delay running — there is nothing to skip.") { t.Fatalf("no refusal flash:\n%s", body) } after := fx.channelVersion(t, "kass", "canary/x") if after.FastTrack { t.Fatal("a bake-free channel wears the waiver badge") } if !after.PromotedAt.Equal(before.PromotedAt) { t.Fatalf("PromotedAt moved %s -> %s — the refused post renewed the canary's TTL lease", before.PromotedAt, after.PromotedAt) } if len(after.Audit) != len(before.Audit) { t.Fatalf("audit trail grew from %d to %d on a refused fast-track", len(before.Audit), len(after.Audit)) } } // A MEMBER probing fast-track meets the byte-identical 404 — the loud // instant path past the window is the owner's alone. func TestFastTrackMemberGets404(t *testing.T) { fx := newConsoleFixture(t) if err := fx.st.AddMember(OpsAccountID, "sam@keymail.dev", RoleMember, time.Now()); err != nil { t.Fatal(err) } fx.setUser("sam@keymail.dev") c := newBrowser(t) signUp(t, fx, c, "code-sam-bake3") csrf := sessionToken(t, fx, c) status, _, memberBody := postForm(t, c, fx.u("/apps/kass/fasttrack"), url.Values{"csrf": {csrf}, "channel": {"stable"}}) if status != http.StatusNotFound { t.Fatalf("member fast-tracking = %d, want 404", status) } if p := fx.channelVersion(t, "kass", "stable"); p.FastTrack { t.Fatal("a member's post waived the bake window") } // Byte-identical, not merely same-status: the difference between "not // allowed" and "no such account" is not information this hands out. strangerBody := strangerRefusal(t, fx, "code-zoe-bake3", fx.u("/apps/kass/fasttrack"), url.Values{"channel": {"stable"}}) if memberBody != strangerBody { t.Fatalf("the two refusals are not byte-identical:\n(member) %q\n(stranger) %q", memberBody, strangerBody) } // http.NotFound's own, well-known output — pinned so a future change to // either path is caught even if it stays self-consistent. if memberBody != "404 page not found\n" { t.Fatalf("refusal body = %q, want the stdlib http.NotFound output", memberBody) } } // The stable-promote prompt (spec §7): enable_bake rides the same // passkey-confirmed promote, and flips the flag on only when it is off. func TestPromoteEnableBakeFlipsTheFlag(t *testing.T) { fx := newConsoleFixture(t) shipVersion(t, fx, "kass", "v3") seedChannel(t, fx, "kass", "beta", "v3") c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) postGated(t, fx, c, fx.u("/apps/kass/promote"), url.Values{"csrf": {csrf}, "channel": {"stable"}, "version": {"v3"}, "enable_bake": {"1"}, "confirmed": {"1"}}) if p := fx.channelVersion(t, "kass", "stable"); p.Version != "v3" { t.Fatalf("stable = %s, want v3", p.Version) } if f := productionFlag(t, fx, "kass"); f == nil || !f.Production { t.Fatalf("flag = %+v after enable_bake promote, want production on", f) } // The flash tells the truth about both halves of what just happened: the // flag went on in this action, so the safety-delay note is now accurate. if _, _, body := get(t, c, fx.u("/apps/kass")); !strings.Contains(body, "Safety delay enabled.") || !strings.Contains(body, "It goes live everywhere after the safety delay") { t.Fatalf("enable_bake flash missing its two halves:\n%s", body) } } // A checkbox that could not be honored SAYS so. When the flag will not read, // the flip is never attempted — and the promote flash used to carry no trace // of that, leaving the human who ticked the box believing the app now bakes. func TestPromoteEnableBakeSaysWhenItCouldNotRead(t *testing.T) { fx := newConsoleFixture(t) shipVersion(t, fx, "kass", "v3") seedChannel(t, fx, "kass", "beta", "v3") c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) if _, err := fx.rel.Put(context.Background(), release.ProductionKey(release.OpsAccount, "kass"), []byte("{not a wrapper"), ""); err != nil { t.Fatal(err) } postGated(t, fx, c, fx.u("/apps/kass/promote"), url.Values{"csrf": {csrf}, "channel": {"stable"}, "version": {"v3"}, "enable_bake": {"1"}, "confirmed": {"1"}}) if p := fx.channelVersion(t, "kass", "stable"); p.Version != "v3" { t.Fatalf("stable = %s, want v3 — the promote itself must not depend on the flag", p.Version) } _, _, body := get(t, c, fx.u("/apps/kass")) if !strings.Contains(body, "could not be read, so the safety delay was not enabled") { t.Fatalf("the flash is silent about the unhonored checkbox:\n%s", body) } if strings.Contains(body, "Safety delay enabled.") { t.Fatal("the flash claims the safety delay was enabled over an unreadable flag") } } // The bake note is a claim about this app, not about the channel: a // non-production app adopts a held channel immediately (spec §2), so // promising a window would be a lie. func TestPromoteBakeNoteFollowsTheFlag(t *testing.T) { fx := newConsoleFixture(t) shipVersion(t, fx, "kass", "v3") c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) // No flag at all: beta holds, but this app does not bake. (edge first — // the ladder promotes a build one rung at a time.) seedChannel(t, fx, "kass", "edge", "v3") // Checked, not fired and forgotten: a refused promote would make the // absence assertion below true for the wrong reason. if status, loc, body := postForm(t, c, fx.u("/apps/kass/promote"), url.Values{"csrf": {csrf}, "version": {"v3"}, "channel": {"beta"}, "confirmed": {"1"}}); status != http.StatusSeeOther || loc != fx.path("/apps/kass") { t.Fatalf("beta promote = %d -> %q:\n%s", status, loc, body) } if p := fx.channelVersion(t, "kass", "beta"); p.Version != "v3" { t.Fatalf("beta = %+v, want v3", p) } if _, _, body := get(t, c, fx.u("/apps/kass")); strings.Contains(body, "It goes live everywhere after the safety delay") { t.Fatalf("a flagless app was promised a safety delay:\n%s", body) } // Flag on: the same rung now says so. if err := release.SetProduction(context.Background(), fx.rel, fx.priv, release.OpsAccount, "kass", true, "test"); err != nil { t.Fatal(err) } shipVersion(t, fx, "kass", "v4") seedChannel(t, fx, "kass", "edge", "v4") if status, _, body := postForm(t, c, fx.u("/apps/kass/promote"), url.Values{"csrf": {csrf}, "version": {"v4"}, "channel": {"beta"}, "confirmed": {"1"}}); status != http.StatusSeeOther { t.Fatalf("beta promote of v4 = %d:\n%s", status, body) } if _, _, body := get(t, c, fx.u("/apps/kass")); !strings.Contains(body, "It goes live everywhere after the safety delay") { t.Fatalf("a production app's held promotion did not mention the window:\n%s", body) } }