/** * One-shot: run ensureWorkspaceGcsProvisioned() for a specific workspace * slug against PROD GCP + PROD Postgres. Idempotent — safe to re-run. * * Unlike scripts/smoke-storage-e2e.ts this does NOT clean up; the whole * point is to persist the workspace's provisioned state into the DB. * * Usage: * cd vibn-frontend * npx -y dotenv-cli -e ../.google.env -e .env.local -- \ * npx tsx scripts/provision-workspace-gcs.ts * * Required env: * GOOGLE_SERVICE_ACCOUNT_KEY_B64 (from ../.google.env) * DATABASE_URL (from .env.local, points at prod vibn-postgres) * VIBN_SECRETS_KEY (from .env.local, ≥16 chars) */ import { queryOne } from '../lib/db-postgres'; import { ensureWorkspaceGcsProvisioned } from '../lib/workspace-gcs'; import type { VibnWorkspace } from '../lib/workspaces'; async function main(): Promise { const slug = process.argv[2]; if (!slug) { console.error('Usage: tsx scripts/provision-workspace-gcs.ts '); process.exit(2); } console.log('━'.repeat(72)); console.log(` Provision GCS for workspace: ${slug}`); console.log('━'.repeat(72)); // Fetch the current row. const ws = await queryOne( `SELECT * FROM vibn_workspaces WHERE slug = $1`, [slug], ); if (!ws) { console.error(`No vibn_workspaces row found for slug=${slug}`); process.exit(1); } console.log(` id : ${ws.id}`); console.log(` name : ${ws.name}`); console.log(` owner_user_id : ${ws.owner_user_id}`); // @ts-expect-error — new columns not yet in VibnWorkspace type console.log(` gcp_status : ${ws.gcp_provision_status ?? 'pending'}`); console.log(''); console.log('Running ensureWorkspaceGcsProvisioned()…'); const result = await ensureWorkspaceGcsProvisioned(ws); console.log(''); console.log('━'.repeat(72)); console.log(' RESULT'); console.log('━'.repeat(72)); console.log(` status : ${result.status}`); console.log(` SA : ${result.serviceAccountEmail}`); console.log(` bucket : ${result.bucket.name}`); console.log(` location : ${result.bucket.location}`); console.log(` created : ${result.bucket.timeCreated ?? '(pre-existing)'}`); console.log(` HMAC accessId : ${result.hmac.accessId}`); console.log(''); // Re-read to confirm persistence. const after = await queryOne>( `SELECT gcp_service_account_email, CASE WHEN gcp_service_account_key_enc IS NOT NULL THEN '' ELSE 'null' END AS sa_key, gcs_default_bucket_name, gcs_hmac_access_id, CASE WHEN gcs_hmac_secret_enc IS NOT NULL THEN '' ELSE 'null' END AS hmac_secret, gcp_provision_status, gcp_provision_error FROM vibn_workspaces WHERE id = $1`, [ws.id], ); console.log('DB row after:'); console.log(JSON.stringify(after, null, 2)); process.exit(0); } main().catch(err => { console.error('[provision-workspace-gcs] FAILED:', err); process.exit(1); });