From 52f759cc006de050aec6748e8fe6dbb213039bc1 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 21 Mar 2026 14:21:55 +0000 Subject: [PATCH] fix(e2e): pass Authorization header in import session cleanup helpers - Add getStoredAuthHeader helper that reads charon_auth_token from localStorage and constructs an Authorization: Bearer header - Apply the header to all page.request.* API calls in readImportStatus and issuePendingSessionCancel - The previous code relied on the browser cookie jar for these cleanup API calls; with Secure=true on auth cookies, browsers refuse to send cookies over HTTP to 127.0.0.1 (IP address, not localhost hostname) causing silent 401s that left pending ImportSession rows in the DB - Unreleased sessions caused all subsequent caddy-import tests to show the pending-session banner instead of the Caddyfile textarea, failing every test after the first - The fix mirrors how the React app authenticates: via Authorization header, which is transport-independent and works on both HTTP and HTTPS --- tests/core/caddy-import/import-page-helpers.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/core/caddy-import/import-page-helpers.ts b/tests/core/caddy-import/import-page-helpers.ts index 73194b45..22b2c4ba 100644 --- a/tests/core/caddy-import/import-page-helpers.ts +++ b/tests/core/caddy-import/import-page-helpers.ts @@ -4,6 +4,11 @@ import { readFileSync } from 'fs'; import { STORAGE_STATE } from '../../constants'; const IMPORT_PAGE_PATH = '/tasks/import/caddyfile'; + +async function getStoredAuthHeader(page: Page): Promise> { + const token = await page.evaluate(() => localStorage.getItem('charon_auth_token')).catch(() => null); + return token ? { Authorization: `Bearer ${token}` } : {}; +} const SETUP_TEST_EMAIL = process.env.E2E_TEST_EMAIL || 'e2e-test@example.com'; const SETUP_TEST_PASSWORD = process.env.E2E_TEST_PASSWORD || 'TestPassword123!'; const IMPORT_BLOCKING_STATUS_CODES = new Set([401, 403, 302, 429]); @@ -252,7 +257,7 @@ export async function resetImportSession(page: Page): Promise { async function readImportStatus(page: Page): Promise<{ hasPending: boolean; sessionId: string }> { try { - const statusResponse = await page.request.get('/api/v1/import/status'); + const statusResponse = await page.request.get('/api/v1/import/status', { headers: await getStoredAuthHeader(page) }); if (!statusResponse.ok()) { return { hasPending: false, sessionId: '' }; } @@ -272,16 +277,17 @@ async function readImportStatus(page: Page): Promise<{ hasPending: boolean; sess } async function issuePendingSessionCancel(page: Page, sessionId: string): Promise { + const authHeader = await getStoredAuthHeader(page); if (sessionId) { await page .request - .delete(`/api/v1/import/cancel?session_uuid=${encodeURIComponent(sessionId)}`) + .delete(`/api/v1/import/cancel?session_uuid=${encodeURIComponent(sessionId)}`, { headers: authHeader }) .catch(() => null); } // Keep legacy endpoints for compatibility across backend variants. - await page.request.delete('/api/v1/import/cancel').catch(() => null); - await page.request.post('/api/v1/import/cancel').catch(() => null); + await page.request.delete('/api/v1/import/cancel', { headers: authHeader }).catch(() => null); + await page.request.post('/api/v1/import/cancel', { headers: authHeader }).catch(() => null); } async function clearPendingImportSession(page: Page): Promise {