From 61a43ad9b42a06f38b8dd564ed94343fa8c423a5 Mon Sep 17 00:00:00 2001 From: Mark Henderson Date: Fri, 6 Mar 2026 18:01:33 -0800 Subject: [PATCH] pass giteaRepo to agent runner; add runner secret auth on PATCH - Sessions route now reads giteaRepo from project.data and forwards it to /agent/execute so the runner can clone/update the correct repo - PATCH route now validates x-agent-runner-secret header to prevent unauthorized session output injection Made-with: Cursor --- .../[projectId]/agent/sessions/[sessionId]/route.ts | 10 +++++++--- app/api/projects/[projectId]/agent/sessions/route.ts | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/api/projects/[projectId]/agent/sessions/[sessionId]/route.ts b/app/api/projects/[projectId]/agent/sessions/[sessionId]/route.ts index b1ebf14..36d4672 100644 --- a/app/api/projects/[projectId]/agent/sessions/[sessionId]/route.ts +++ b/app/api/projects/[projectId]/agent/sessions/[sessionId]/route.ts @@ -64,10 +64,14 @@ export async function PATCH( ) { /** * Internal endpoint called by vibn-agent-runner to append output lines - * and update status. Not exposed to users directly. - * - * Body: { status?, outputLine?, changedFile? } + * and update status. Requires x-agent-runner-secret header. */ + const secret = process.env.AGENT_RUNNER_SECRET ?? ""; + const incomingSecret = req.headers.get("x-agent-runner-secret") ?? ""; + if (secret && incomingSecret !== secret) { + return NextResponse.json({ error: "Forbidden" }, { status: 403 }); + } + try { const { sessionId } = await params; const body = await req.json() as { diff --git a/app/api/projects/[projectId]/agent/sessions/route.ts b/app/api/projects/[projectId]/agent/sessions/route.ts index 3258415..44cce77 100644 --- a/app/api/projects/[projectId]/agent/sessions/route.ts +++ b/app/api/projects/[projectId]/agent/sessions/route.ts @@ -65,9 +65,9 @@ export async function POST( await ensureTable(); - // Verify ownership - const owns = await query<{ id: string }>( - `SELECT p.id FROM fs_projects p + // Verify ownership and fetch giteaRepo + const owns = await query<{ id: string; data: Record }>( + `SELECT p.id, p.data FROM fs_projects p JOIN fs_users u ON u.id = p.user_id WHERE p.id = $1 AND u.data->>'email' = $2 LIMIT 1`, [projectId, session.user.email] @@ -76,6 +76,8 @@ export async function POST( return NextResponse.json({ error: "Project not found" }, { status: 404 }); } + const giteaRepo = owns[0].data?.giteaRepo as string | undefined; + // Create the session row const rows = await query<{ id: string }>( `INSERT INTO agent_sessions (project_id, app_name, app_path, task, status, started_at) @@ -95,6 +97,7 @@ export async function POST( projectId, appName, appPath, + giteaRepo, // e.g. "mark/sportsy" — agent runner uses this to clone/update the repo task: task.trim(), }), }).catch(err => {