#!/bin/bash # 05-cloudrun-deploy.sh — Deploy OSVauco agent to Cloud Run via Docker + gcloud # Run in: Cloud Shell or local terminal # Requires: gcloud CLI (no ADK CLI needed) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" ENV_FILE="${SCRIPT_DIR}/../.env" if [ -f "${ENV_FILE}" ]; then set -a; source "${ENV_FILE}"; set +a fi : "${PROJECT_ID:?Set PROJECT_ID in .env}" : "${REGION:?Set REGION in .env}" : "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE in .env}" : "${AGENT_SA:?Set AGENT_SA in .env}" # ── Region Guard ──────────────────────────────────────────────────────── source "$(dirname "$0")/99-region-guard.sh" DEPLOY_REGION="${DEPLOY_REGION:-${REGION}}" log_region_context "Cloud-Run" "$DEPLOY_REGION" "SELECTED" REPO="${DEPLOY_REGION}-docker.pkg.dev/${PROJECT_ID}/osvauco-repo" IMAGE="${REPO}/osvauco-agent:latest" AGENT_PATH="${SCRIPT_DIR}/../agents/core-logic" AGENT_SA_NAME=$(echo "${AGENT_SA}" | cut -d@ -f1) echo "=== 05: Cloud Run Deploy to ${DEPLOY_REGION} ===" bash "${SCRIPT_DIR}/00-authcheck.sh" # Enable required APIs gcloud services enable \ run.googleapis.com \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ iam.googleapis.com \ --project="${PROJECT_ID}" --quiet # Create agent service account if it doesn't exist (idempotent) if ! gcloud iam service-accounts describe "${AGENT_SA}" \ --project="${PROJECT_ID}" &>/dev/null; then gcloud iam service-accounts create "${AGENT_SA_NAME}" \ --display-name="OSVauco Agent SA" \ --project="${PROJECT_ID}" echo "✓ Service account created: ${AGENT_SA}" else echo "✓ Service account already exists: ${AGENT_SA}" fi # Grant the SA roles it needs at runtime for ROLE in \ roles/aiplatform.user \ roles/secretmanager.secretAccessor \ roles/logging.logWriter \ roles/cloudtrace.agent \ roles/monitoring.metricWriter; do gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${AGENT_SA}" \ --role="${ROLE}" --quiet done echo "✓ Runtime roles granted to ${AGENT_SA}" # Grant caller iam.serviceAccountUser on the SA (needed for --service-account flag) CALLER=$(gcloud config get-value account 2>/dev/null) gcloud iam service-accounts add-iam-policy-binding "${AGENT_SA}" \ --member="user:${CALLER}" \ --role="roles/iam.serviceAccountUser" \ --project="${PROJECT_ID}" --quiet echo "✓ iam.serviceAccountUser granted to ${CALLER}" # Create Artifact Registry repo if it doesn't exist gcloud artifacts repositories describe osvauco-repo \ --location="${DEPLOY_REGION}" --project="${PROJECT_ID}" &>/dev/null || \ gcloud artifacts repositories create osvauco-repo \ --repository-format=docker \ --location="${DEPLOY_REGION}" \ --project="${PROJECT_ID}" --quiet echo "✓ Artifact Registry repo ready" # IAM for Cloud Build compute SA PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)") COMPUTE_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${COMPUTE_SA}" \ --role="roles/cloudbuild.builds.builder" --quiet gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --member="serviceAccount:${COMPUTE_SA}" \ --role="roles/secretmanager.secretAccessor" --quiet echo "✓ Cloud Build IAM bindings applied" # Configure Docker for Artifact Registry gcloud auth configure-docker "${DEPLOY_REGION}-docker.pkg.dev" --quiet # Build image via Cloud Build echo "Building image via Cloud Build..." gcloud builds submit "${AGENT_PATH}" \ --tag="${IMAGE}" \ --project="${PROJECT_ID}" \ --region="${DEPLOY_REGION}" echo "✓ Image built: ${IMAGE}" # Deploy to Cloud Run echo "Deploying to Cloud Run..." gcloud run deploy "${CLOUD_RUN_SERVICE}" \ --image="${IMAGE}" \ --region="${DEPLOY_REGION}" \ --project="${PROJECT_ID}" \ --service-account="${AGENT_SA}" \ --set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID},GOOGLE_CLOUD_LOCATION=${DEPLOY_REGION},GOOGLE_GENAI_USE_VERTEXAI=True" \ --no-allow-unauthenticated \ --port=8080 \ --memory=1Gi \ --cpu=1 \ --min-instances=0 \ --max-instances=3 \ --quiet echo "" echo "=== 05: Cloud Run Deploy COMPLETE ===" SERVICE_URL=$(gcloud run services describe "${CLOUD_RUN_SERVICE}" \ --region="${DEPLOY_REGION}" --project="${PROJECT_ID}" \ --format="value(status.url)" 2>/dev/null || echo "(pending)") echo " Service URL: ${SERVICE_URL}" echo "" echo " To call (authenticated):" echo " TOKEN=\$(gcloud auth print-identity-token)" echo " curl -H \"Authorization: Bearer \$TOKEN\" -H 'Content-Type: application/json' \\" echo " -d '{\"message\": \"Hello\"}' \${SERVICE_URL}/run" echo "" echo " COST NOTE: Cloud Run scales to 0. No idle cost." echo " Delete with: gcloud run services delete ${CLOUD_RUN_SERVICE} --region=${DEPLOY_REGION} --quiet"