feat(e2e): deployed-environment E2E harness + gated test-auth (v0.52.0)
The §9 pipeline's PPE+E2E stage was unreachable: e2e/metadata.spec.js was bound to Tier-1-only scaffolding (docker-seeded faceted collection, SQLite-injected owner, Mailpit OTC sink). This makes the same suite run against a deployed host. - backend: POST /auth/test/login — fail-closed, secret-gated, single- identity owner test-login (404 unless E2E_TEST_AUTH_SECRET + E2E_TEST_AUTH_EMAIL both set; constant-time compare; loud startup warn). 6 vertical tests; backend 665 green. Documented in backend/.env.example. - e2e/lib/auth.js: branch on E2E_TEST_AUTH_SECRET (deployed test-login vs local Mailpit OTC); OWNER_EMAIL from E2E_OWNER_EMAIL. Spec unchanged so the localhost Tier-1 path keeps working. - testing/seed-ppe.sh: seed a dedicated, prod-untouching PPE registry + content repo (faceted bdd collection) — real OHM content never touched. - docs/design/2026-06-07-deployed-env-e2e-harness.md; CHANGELOG; VERSION + frontend/package.json -> 0.52.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+30
-7
@@ -1,11 +1,36 @@
|
||||
import { waitForLatestOtc, clearMailpit } from './mailpit.js'
|
||||
|
||||
// Sign in through the §6.2 OTC path, leaving the rfc_session cookie on the
|
||||
// page's browser context (page.request shares the page context's cookie jar,
|
||||
// so a subsequent page.goto is authenticated). The Tier-1 seed pre-provisions
|
||||
// `e2e-owner@example.test` as a granted deployment owner, so signing in as that
|
||||
// address yields write access to the metadata edit/bulk paths (SLICE-4/5).
|
||||
// Sign in and leave the rfc_session cookie on the page's browser context
|
||||
// (page.request shares the page context's cookie jar, so a subsequent
|
||||
// page.goto is authenticated). Two paths, chosen by environment:
|
||||
//
|
||||
// * DEPLOYED (PPE): when E2E_TEST_AUTH_SECRET is set, use the gated
|
||||
// `/auth/test/login` shortcut (v0.52.0). The deployed env has no
|
||||
// Mailpit sink to read an OTC code from, so the suite presents the
|
||||
// shared secret and the server mints an owner session for the one
|
||||
// configured E2E_TEST_AUTH_EMAIL. See backend/app/main.py.
|
||||
// * LOCAL (Tier-1 docker stack): no secret set → the original §6.2 OTC
|
||||
// path through Mailpit. The Tier-1 backend-seed pre-grants
|
||||
// e2e-owner@example.test as a deployment owner, so signing in as that
|
||||
// address yields write access (SLICE-4/5).
|
||||
//
|
||||
// OWNER_EMAIL is the identity both paths sign in as: E2E_OWNER_EMAIL when
|
||||
// set (PPE points it at E2E_TEST_AUTH_EMAIL), else the Tier-1 default.
|
||||
export const OWNER_EMAIL =
|
||||
process.env.E2E_OWNER_EMAIL || 'e2e-owner@example.test'
|
||||
|
||||
export async function signIn(page, email) {
|
||||
const secret = process.env.E2E_TEST_AUTH_SECRET
|
||||
if (secret) {
|
||||
const r = await page.request.post('/auth/test/login', {
|
||||
data: { email },
|
||||
headers: { 'X-Test-Auth-Secret': secret },
|
||||
})
|
||||
if (!r.ok()) throw new Error(`test-auth login failed: ${r.status()} ${await r.text()}`)
|
||||
return
|
||||
}
|
||||
|
||||
// Local Tier-1 OTC path through Mailpit.
|
||||
await clearMailpit()
|
||||
const req = await page.request.post('/auth/otc/request', { data: { email } })
|
||||
if (!req.ok()) throw new Error(`otc request failed: ${req.status()}`)
|
||||
@@ -13,5 +38,3 @@ export async function signIn(page, email) {
|
||||
const verify = await page.request.post('/auth/otc/verify', { data: { email, code } })
|
||||
if (!verify.ok()) throw new Error(`otc verify failed: ${verify.status()}`)
|
||||
}
|
||||
|
||||
export const OWNER_EMAIL = 'e2e-owner@example.test'
|
||||
|
||||
Reference in New Issue
Block a user