diff --git a/lib/cloud-run-workspace.ts b/lib/cloud-run-workspace.ts index 8a8f592..dcbd98d 100644 --- a/lib/cloud-run-workspace.ts +++ b/lib/cloud-run-workspace.ts @@ -10,7 +10,7 @@ * - Auth is enforced by our Vibn session before the URL is revealed */ -import { GoogleAuth } from 'google-auth-library'; +import { GoogleAuth, JWT } from 'google-auth-library'; const PROJECT_ID = 'master-ai-484822'; const REGION = 'northamerica-northeast1'; @@ -18,11 +18,28 @@ const IMAGE = `${REGION}-docker.pkg.dev/${PROJECT_ID}/vibn-ide/theia:latest const VIBN_URL = process.env.NEXTAUTH_URL ?? 'https://vibnai.com'; const CLOUD_RUN_API = `https://run.googleapis.com/v2/projects/${PROJECT_ID}/locations/${REGION}/services`; +const SCOPES = ['https://www.googleapis.com/auth/cloud-platform']; async function getAccessToken(): Promise { - const auth = new GoogleAuth({ - scopes: ['https://www.googleapis.com/auth/cloud-platform'], - }); + // Prefer an explicit service account key (avoids GCE metadata scope limitations) + const keyJson = process.env.GOOGLE_SERVICE_ACCOUNT_KEY; + if (keyJson) { + const key = JSON.parse(keyJson) as { + client_email: string; + private_key: string; + }; + const jwt = new JWT({ + email: key.client_email, + key: key.private_key, + scopes: SCOPES, + }); + const token = await jwt.getAccessToken(); + if (!token.token) throw new Error('Failed to get GCP access token from service account key'); + return token.token; + } + + // Fall back to ADC (works locally or on GCE with cloud-platform scope) + const auth = new GoogleAuth({ scopes: SCOPES }); const client = await auth.getClient(); const token = await client.getAccessToken(); if (!token.token) throw new Error('Failed to get GCP access token');