console: remove dead channelDeleter interface and refusal branch
Store.Delete is now required by the Store interface, making the channelDeleter type assertion and "can't retire yet" fallback dead code. Delete directly on the store. Also remove the now-unused newConsoleFixtureWith and its wrap parameter, and delete TestRetireWithoutDeletePrimitive which duplicated the ghost-canary case already in TestRetireCanary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 files changed,
+2
−39
internal/console/server.go+1 −14internal/console/server_test.go+1 −25
diff --git a/internal/console/server.go b/internal/console/server.go| index af9dde602..61807d3f7 100644 |
| --- a/internal/console/server.go |
| +++ b/internal/console/server.go |
| @@ -1307,14 +1307,6 @@ func (s *Server) handleRollback(w http.ResponseWriter, r *http.Request) { |
| // name becomes a channel path segment and an on-box state file name. |
| var canaryNameRe = regexp.MustCompile(`^[a-z][a-z0-9-]{0,31}$`) |
| -// channelDeleter is the retirement primitive the console needs from the |
| -// release store: remove one channel-pointer key. release.Store does not |
| -// carry it yet (see the slice-3 report) — stores that grow it get canary |
| -// retirement enabled, everything else degrades to a polite refusal. |
| -type channelDeleter interface { |
| - Delete(ctx context.Context, key string) error |
| -} |
| - |
| // channelHosts lists the registry hosts whose routes follow app's channel, |
| // and reports whether the registry could be read at all. The two call sites |
| // deliberately treat that error differently: handleNewCanary's use is |
| @@ -1463,12 +1455,7 @@ func (s *Server) handleRetireCanary(w http.ResponseWriter, r *http.Request) { |
| back("err", "Could not read the release store. Please try again.") |
| return |
| } |
| - del, canDelete := s.cfg.Releases.(channelDeleter) |
| - if !canDelete { |
| - back("err", "This deployment's release store can't retire channels yet — ask an operator to remove "+key+".") |
| - return |
| - } |
| - if err := del.Delete(ctx, key); err != nil { |
| + if err := s.cfg.Releases.Delete(ctx, key); err != nil { |
| log.Printf("console: retire %s %s: %v", app, channel, err) |
| back("err", "Retiring the canary failed: "+err.Error()) |
| return |
diff --git a/internal/console/server_test.go b/internal/console/server_test.go| index b6c5fd75a..1803992fc 100644 |
| --- a/internal/console/server_test.go |
| +++ b/internal/console/server_test.go |
| @@ -44,18 +44,8 @@ func newConsoleFixture(t *testing.T) *consoleFixture { |
| // newConsoleFixtureKeyed builds the fixture with or without the channel |
| // signing key (withKey=false is the read-only deployment shape). |
| func newConsoleFixtureKeyed(t *testing.T, withKey bool) *consoleFixture { |
| - return newConsoleFixtureWith(t, withKey, nil) |
| -} |
| - |
| -// newConsoleFixtureWith additionally lets a test wrap the release store the |
| -// server sees (e.g. hide the Delete primitive). |
| -func newConsoleFixtureWith(t *testing.T, withKey bool, wrap func(release.Store) release.Store) *consoleFixture { |
| t.Helper() |
| regPath, relStore, priv, pub := buildFixtures(t) |
| - serverStore := relStore |
| - if wrap != nil { |
| - serverStore = wrap(relStore) |
| - } |
| st, err := Open(filepath.Join(t.TempDir(), "console.db")) |
| if err != nil { |
| t.Fatal(err) |
| @@ -73,7 +63,7 @@ func newConsoleFixtureWith(t *testing.T, withKey bool, wrap func(release.Store) |
| Origin: ts.URL, |
| Keymail: fk.srv.URL, |
| Registry: regPath, |
| - Releases: serverStore, |
| + Releases: relStore, |
| ReleasePub: pub, |
| AppScheme: "http", // instance polls reach httptest apps, not TLS |
| } |
| @@ -776,20 +766,6 @@ func TestRetireCanaryFailsClosedOnRegistryError(t *testing.T) { |
| } |
| } |
| -func TestRetireWithoutDeletePrimitive(t *testing.T) { |
| - // Now that Delete is part of the Store interface, all stores support it. |
| - // Retirement should work as long as the channel pointer exists and no hosts follow it. |
| - // This test verifies the plumbing is in place by retiring a non-existent canary |
| - // and checking for the expected error (which exercises the Delete path). |
| - fx := newConsoleFixtureWith(t, true, nil) |
| - c := signInPaul(t, fx) |
| - csrf := sessionToken(t, fx, c) |
| - postForm(t, c, fx.u("/apps/kass/canary/retire"), url.Values{"csrf": {csrf}, "name": {"nonexistent"}}) |
| - if _, _, body := get(t, c, fx.u("/apps/kass")); !strings.Contains(body, "No canary named") { |
| - t.Fatal("retire of nonexistent canary should show 'No canary named' error") |
| - } |
| -} |
| - |
| func TestAppPageInstances(t *testing.T) { |
| fx := newConsoleFixture(t) |
| c := signInPaul(t, fx) |