From a83cc45f6a80bc730cbcfddf59f0c203542af38f Mon Sep 17 00:00:00 2001 From: Mark Henderson Date: Mon, 27 Apr 2026 19:39:04 -0700 Subject: [PATCH] feat(backfill): support ops-secret bootstrap auth for backfill-isolation Made-with: Cursor --- app/api/projects/backfill-isolation/route.ts | 58 ++++++++++++-------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/app/api/projects/backfill-isolation/route.ts b/app/api/projects/backfill-isolation/route.ts index 92b6db5e..ec993763 100644 --- a/app/api/projects/backfill-isolation/route.ts +++ b/app/api/projects/backfill-isolation/route.ts @@ -14,9 +14,9 @@ */ import { NextResponse } from 'next/server'; -import { authSession } from '@/lib/auth/session-server'; import { query } from '@/lib/db-postgres'; -import { getOrCreateProvisionedWorkspace } from '@/lib/workspaces'; +import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth'; +import { getOrCreateProvisionedWorkspace, type VibnWorkspace } from '@/lib/workspaces'; import { ensureProjectCoolifyProject, ensureProjectResourcesTable, @@ -39,28 +39,42 @@ interface BackfillReport { warnings: string[]; } -export async function POST() { - const session = await authSession(); - if (!session?.user?.email) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - const email = session.user.email; +export async function POST(request: Request) { + // Three accepted auth modes: + // 1. NextAuth session (browser) + // 2. Bearer vibn_sk_... workspace API key (matches /api/mcp) + // 3. Bearer + ?email= (ops bootstrap so the + // maintainer can curl the backfill from a workstation without + // needing a session cookie or pre-minted API key) + let ws: VibnWorkspace | null = null; - // Resolve workspace + load all of the user's projects. - const users = await query<{ id: string }>( - `SELECT id FROM fs_users WHERE data->>'email' = $1 LIMIT 1`, - [email], - ); - if (users.length === 0) { - return NextResponse.json({ error: 'User not found' }, { status: 404 }); - } - const firebaseUserId = users[0].id; + const authHeader = request.headers.get('authorization') ?? ''; + const bearer = authHeader.toLowerCase().startsWith('bearer ') + ? authHeader.slice(7).trim() + : ''; + const opsSecret = process.env.NEXTAUTH_SECRET; + const url = new URL(request.url); + const opsEmail = url.searchParams.get('email'); + + if (bearer && opsSecret && bearer === opsSecret && opsEmail) { + const users = await query<{ id: string }>( + `SELECT id FROM fs_users WHERE data->>'email' = $1 LIMIT 1`, + [opsEmail], + ); + if (users.length === 0) { + return NextResponse.json({ error: `No fs_users row for ${opsEmail}` }, { status: 404 }); + } + ws = await getOrCreateProvisionedWorkspace({ + userId: users[0].id, + email: opsEmail, + displayName: opsEmail, + }); + } else { + const principal = await requireWorkspacePrincipal(request); + if (principal instanceof NextResponse) return principal; + ws = principal.workspace; + } - const ws = await getOrCreateProvisionedWorkspace({ - userId: firebaseUserId, - email, - displayName: session.user.name ?? email, - }); if (!ws) { return NextResponse.json({ error: 'Workspace not provisioned' }, { status: 503 }); }