diff --git a/app/src/pages/DebugPage.test.tsx b/app/src/pages/DebugPage.test.tsx
index c4b8d92fa9..e25ddb4f0e 100644
--- a/app/src/pages/DebugPage.test.tsx
+++ b/app/src/pages/DebugPage.test.tsx
@@ -1,4 +1,5 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { fireEvent } from '@testing-library/react';
import { render, screen, waitFor } from '../test-utils';
import { DebugPage } from './DebugPage';
@@ -83,4 +84,82 @@ describe('DebugPage', () => {
});
});
+ // /debug routes are gated by `require_admin` (api/routers/debug.py). The
+ // browser handles the gate via an X-Admin-Token sessionStorage UX; these
+ // tests cover the 401/503 branch + submit/clear flow that the existing
+ // tests miss (and the codecov/patch gate flagged at 65% diff coverage).
+ it('renders the admin-token form on 401', async () => {
+ sessionStorage.clear();
+ vi.stubGlobal('fetch', vi.fn(() => Promise.resolve({ ok: false, status: 401 })));
+
+ render();
+
+ await waitFor(() => {
+ expect(screen.getByPlaceholderText('X-Admin-Token')).toBeInTheDocument();
+ });
+ expect(screen.getByRole('button', { name: /unlock/i })).toBeInTheDocument();
+ expect(screen.getByText(/admin token required/i)).toBeInTheDocument();
+ });
+
+ it('renders the admin-token form on 503 with the not-configured hint', async () => {
+ sessionStorage.clear();
+ vi.stubGlobal('fetch', vi.fn(() => Promise.resolve({ ok: false, status: 503 })));
+
+ render();
+
+ await waitFor(() => {
+ expect(screen.getByText(/admin auth not configured/i)).toBeInTheDocument();
+ });
+ });
+
+ it('submits the token, sends X-Admin-Token, and persists to sessionStorage', async () => {
+ sessionStorage.clear();
+ let callIndex = 0;
+ const fetchMock = vi.fn((url: string, init?: RequestInit) => {
+ callIndex += 1;
+ // First /debug/status → 401 (no token yet); subsequent calls → ok.
+ if (url.includes('/debug/ping')) {
+ return Promise.resolve({
+ ok: true,
+ json: () => Promise.resolve({ database_connected: true, response_time_ms: 10, timestamp: '2026-04-27T00:00:00Z' }),
+ });
+ }
+ if (callIndex === 1) {
+ return Promise.resolve({ ok: false, status: 401 });
+ }
+ // Verify the header is sent on the retry.
+ const hdr = (init?.headers as Record | undefined)?.['X-Admin-Token'];
+ if (hdr !== 'secret-xyz') return Promise.resolve({ ok: false, status: 401 });
+ return Promise.resolve({ ok: true, json: () => Promise.resolve(mockDebugData) });
+ });
+ vi.stubGlobal('fetch', fetchMock);
+
+ render();
+
+ const input = await screen.findByPlaceholderText('X-Admin-Token');
+ fireEvent.change(input, { target: { value: 'secret-xyz' } });
+ fireEvent.click(screen.getByRole('button', { name: /unlock/i }));
+
+ await waitFor(() => {
+ expect(screen.getAllByText('scatter-basic').length).toBeGreaterThan(0);
+ });
+ expect(sessionStorage.getItem('anyplot.adminToken')).toBe('secret-xyz');
+ });
+
+ it('clears the stored token and re-prompts', async () => {
+ sessionStorage.setItem('anyplot.adminToken', 'stored-token');
+ vi.stubGlobal('fetch', vi.fn(() => Promise.resolve({ ok: false, status: 401 })));
+
+ render();
+
+ const clearBtn = await screen.findByRole('button', { name: /clear stored token/i });
+ fireEvent.click(clearBtn);
+
+ await waitFor(() => {
+ expect(sessionStorage.getItem('anyplot.adminToken')).toBeNull();
+ });
+ // Form is still on screen because fetch still returns 401.
+ expect(screen.getByPlaceholderText('X-Admin-Token')).toBeInTheDocument();
+ });
+
});
diff --git a/core/database/repositories.py b/core/database/repositories.py
index cb8c7cddfa..1537b413d9 100644
--- a/core/database/repositories.py
+++ b/core/database/repositories.py
@@ -161,9 +161,7 @@ async def get_all(self) -> list[Spec]:
session must use `get_all_with_code()` to avoid MissingGreenlet.
"""
impls_loader = selectinload(Spec.impls)
- result = await self.session.execute(
- select(Spec).options(impls_loader.selectinload(Impl.library))
- )
+ result = await self.session.execute(select(Spec).options(impls_loader.selectinload(Impl.library)))
return list(result.scalars().all())
async def get_all_with_code(self) -> list[Spec]: