diff --git a/packages/workspace-manager/Dockerfile b/packages/workspace-manager/Dockerfile index e4006bb5c4..422c749dbe 100644 --- a/packages/workspace-manager/Dockerfile +++ b/packages/workspace-manager/Dockerfile @@ -1,20 +1,20 @@ -/** - * @license - * Copyright 2026 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ +# Copyright 2026 Google LLC +# SPDX-License-Identifier: Apache-2.0 # Standard Hub Dockerfile FROM node:20-slim WORKDIR /app -COPY package.json package-lock.json ./ -RUN npm ci +# In a monorepo, we typically don't have a local package-lock.json +# so we use npm install instead of npm ci for individual package builds. +COPY package.json ./ +RUN npm install COPY . . RUN npm run build EXPOSE 8080 -CMD ["npm", "start"] +# Use node directly for better signal handling (SIGTERM) +CMD ["node", "dist/index.js"] diff --git a/packages/workspace-manager/src/index.ts b/packages/workspace-manager/src/index.ts index d8eb0f0234..1766a1d027 100644 --- a/packages/workspace-manager/src/index.ts +++ b/packages/workspace-manager/src/index.ts @@ -10,7 +10,7 @@ import { workspaceRouter } from './routes/workspaceRoutes.js'; export const app = express(); app.use(express.json()); -const PORT = process.env.PORT || 8080; +const PORT = process.env['PORT'] || 8080; app.get('/health', (_req, res) => { res.send({ status: 'ok' }); @@ -20,7 +20,7 @@ app.get('/health', (_req, res) => { app.use('/workspaces', workspaceRouter); // Only listen if not in test mode -if (process.env.NODE_ENV !== 'test') { +if (process.env['NODE_ENV'] !== 'test') { app.listen(PORT, () => { // eslint-disable-next-line no-console console.log(`Workspace Hub listening on port ${PORT}`); diff --git a/packages/workspace-manager/terraform/modules/workspace-hub/main.tf b/packages/workspace-manager/terraform/modules/workspace-hub/main.tf index 585e5a6db3..ba986d0fab 100644 --- a/packages/workspace-manager/terraform/modules/workspace-hub/main.tf +++ b/packages/workspace-manager/terraform/modules/workspace-hub/main.tf @@ -18,10 +18,10 @@ resource "google_project_iam_member" "firestore_user" { member = "serviceAccount:${google_service_account.hub_sa.email}" } -resource "google_project_iam_member" "sa_user" { - project = var.project_id - role = "roles/iam.serviceAccountUser" - member = "serviceAccount:${google_service_account.hub_sa.email}" +resource "google_service_account_iam_member" "sa_user" { + service_account_id = "projects/${var.project_id}/serviceAccounts/${var.compute_default_sa}" + role = "roles/iam.serviceAccountUser" + member = "serviceAccount:${google_service_account.hub_sa.email}" } resource "google_cloud_run_v2_service" "hub" { diff --git a/packages/workspace-manager/terraform/modules/workspace-hub/variables.tf b/packages/workspace-manager/terraform/modules/workspace-hub/variables.tf index c90b3cc672..10b0f3997b 100644 --- a/packages/workspace-manager/terraform/modules/workspace-hub/variables.tf +++ b/packages/workspace-manager/terraform/modules/workspace-hub/variables.tf @@ -16,3 +16,8 @@ variable "hub_image_uri" { description = "The Docker image URI for the Workspace Hub" type = string } + +variable "compute_default_sa" { + description = "The Compute Engine default service account email" + type = string +} diff --git a/packages/workspace-manager/tsconfig.json b/packages/workspace-manager/tsconfig.json index 47845999bc..e61cd5fc32 100644 --- a/packages/workspace-manager/tsconfig.json +++ b/packages/workspace-manager/tsconfig.json @@ -1,9 +1,24 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noImplicitAny": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": true, + "verbatimModuleSyntax": true, + "lib": ["ES2023"], + "module": "NodeNext", + "moduleResolution": "nodenext", + "target": "es2022", + "types": ["node", "vitest/globals"], "outDir": "./dist", - "rootDir": "./src", - "composite": false + "rootDir": "./src" }, "include": ["src/**/*"], "exclude": ["node_modules", "**/*.test.ts"] diff --git a/scripts/deploy-hub.sh b/scripts/deploy-hub.sh index 4f0dd232fc..5cd3c78f31 100644 --- a/scripts/deploy-hub.sh +++ b/scripts/deploy-hub.sh @@ -6,24 +6,40 @@ set -e # Configuration PROJECT_ID=$(gcloud config get-value project) +if [ -z "$PROJECT_ID" ]; then + echo "Error: No GCP project configured. Run 'gcloud config set project [PROJECT_ID]'" + exit 1 +fi + REGION="us-west1" +REPO_NAME="workspaces" IMAGE_NAME="workspace-hub" SERVICE_NAME="workspace-hub" +IMAGE_URI="$REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/$IMAGE_NAME" echo "Using Project: $PROJECT_ID" +# 0. Ensure Artifact Registry exists +if ! gcloud artifacts repositories describe "$REPO_NAME" --location="$REGION" &>/dev/null; then + echo "Creating Artifact Registry repository: $REPO_NAME" + gcloud artifacts repositories create "$REPO_NAME" \ + --repository-format=docker \ + --location="$REGION" \ + --description="Gemini CLI Workspaces Repository" +fi + # 1. Build and Push the Hub Image -# (Assuming the Dockerfile is in the current package for the hub) -echo "Building and pushing $IMAGE_NAME..." -gcloud builds submit --tag "gcr.io/$PROJECT_ID/$IMAGE_NAME" packages/workspace-manager/ +echo "Building and pushing $IMAGE_NAME to Artifact Registry..." +gcloud builds submit --tag "$IMAGE_URI" packages/workspace-manager/ # 2. Deploy to Cloud Run echo "Deploying $SERVICE_NAME to Cloud Run..." gcloud run deploy "$SERVICE_NAME" \ - --image "gcr.io/$PROJECT_ID/$IMAGE_NAME" \ + --image "$IMAGE_URI" \ --platform managed \ --region "$REGION" \ - --allow-unauthenticated \ + --no-allow-unauthenticated \ + --service-account "workspace-hub-sa@$PROJECT_ID.iam.gserviceaccount.com" \ --set-env-vars "GOOGLE_CLOUD_PROJECT=$PROJECT_ID" echo "Deployment complete!"