import { NextRequest, NextResponse } from "next/server"; import { getSessionUser, canMutate } from "@/lib/session"; import { getTenant } from "@/lib/k8s"; import { writePackageSecrets } from "@/lib/openbao"; import { getPackageDef } from "@/lib/packages"; export async function POST( req: NextRequest, { params }: { params: Promise<{ name: string }> } ) { const user = await getSessionUser(); if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!canMutate(user)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const { name } = await params; const body = await req.json(); const { packageId, secrets } = body as { packageId: string; secrets: Record; }; if (!packageId || !secrets || typeof secrets !== "object") { return NextResponse.json( { error: "Missing packageId or secrets" }, { status: 400 } ); } const pkgDef = getPackageDef(packageId); if (!pkgDef) return NextResponse.json({ error: "Unknown package" }, { status: 400 }); if (!pkgDef.requiresSecrets) return NextResponse.json( { error: "Package does not require secrets" }, { status: 400 } ); const requiredKeys = (pkgDef.secrets || []).map((s) => s.key); const missing = requiredKeys.filter((k) => !secrets[k]?.trim()); if (missing.length > 0) { return NextResponse.json( { error: `Missing: ${missing.join(", ")}` }, { status: 400 } ); } try { const tenant = await getTenant(name); if (!tenant) return NextResponse.json({ error: "Not found" }, { status: 404 }); if ( !user.isPlatform && tenant.metadata.labels?.["pieced.ch/zitadel-org-id"] !== user.orgId ) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } // Use tenant-{name} to match the operator's vault path convention await writePackageSecrets(`tenant-${name}`, packageId, secrets); return NextResponse.json({ ok: true }); } catch (e: any) { console.error("Secret write error:", e.message); return NextResponse.json( { error: "Failed to store secrets" }, { status: 500 } ); } }