107 lines
4.2 KiB
Bash
Executable file
107 lines
4.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Build and deploy Cerebrus services (backend, frontend) and the scanner Cloud Run
|
|
# job to Cloud Run via Cloud Build.
|
|
#
|
|
# The backend config is baked into its image from apps/backend/.env.production.
|
|
# The frontend runtime proxy reads BACKEND_URL from apps/frontend/.env.production,
|
|
# which this script sets automatically on the Cloud Run service.
|
|
#
|
|
# ./deploy.sh <PROJECT_ID>
|
|
#
|
|
# Optional env overrides: REGION (default us-central1), AR_REPO (default cerebrus),
|
|
# DEPLOY_SCANNER (default 1).
|
|
set -euo pipefail
|
|
|
|
PROJECT_ID="${1:-}"
|
|
REGION="${REGION:-us-central1}"
|
|
AR_REPO="${AR_REPO:-cerebrus}"
|
|
DEPLOY_SCANNER="${DEPLOY_SCANNER:-1}"
|
|
|
|
if [[ -z "$PROJECT_ID" ]]; then
|
|
echo "Usage: ./deploy.sh <PROJECT_ID> (REGION / AR_REPO / DEPLOY_SCANNER overridable via env)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "apps/backend/.env.production" ]]; then
|
|
echo "ERROR: apps/backend/.env.production is missing — the backend image bakes it in." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "apps/frontend/.env.production" ]]; then
|
|
echo "ERROR: apps/frontend/.env.production is missing." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Read a key=value line from a .env file, stripping optional surrounding quotes.
|
|
read_env() {
|
|
local file="$1" key="$2"
|
|
local value
|
|
value="$(grep "^${key}=" "$file" 2>/dev/null | head -n1 | cut -d= -f2- | sed -E "s/^['\"]//;s/['\"]$//")" || true
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
FRONTEND_BACKEND_URL="$(read_env apps/frontend/.env.production BACKEND_URL)"
|
|
if [[ -z "$FRONTEND_BACKEND_URL" ]]; then
|
|
echo "ERROR: BACKEND_URL is not set in apps/frontend/.env.production" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Sanity-check the backend env that trips people up.
|
|
NODE_ENV="$(read_env apps/backend/.env.production NODE_ENV)"
|
|
if [[ "$NODE_ENV" != "production" ]]; then
|
|
echo "WARNING: NODE_ENV in apps/backend/.env.production is '${NODE_ENV:-(unset)}', expected 'production'." >&2
|
|
fi
|
|
|
|
SCAN_CALLBACK_URL="$(read_env apps/backend/.env.production SCAN_CALLBACK_URL)"
|
|
if [[ -n "$SCAN_CALLBACK_URL" && "$SCAN_CALLBACK_URL" == *"cerebrus-frontend"* ]]; then
|
|
echo "WARNING: SCAN_CALLBACK_URL points to the frontend ($SCAN_CALLBACK_URL)." >&2
|
|
echo " It must point to the backend URL or scanner /internal callbacks will fail." >&2
|
|
fi
|
|
|
|
echo "==> Project: $PROJECT_ID Region: $REGION Repo: $AR_REPO"
|
|
gcloud config set project "$PROJECT_ID" >/dev/null
|
|
|
|
echo "==> Enabling required APIs"
|
|
gcloud services enable run.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com
|
|
|
|
echo "==> Ensuring Artifact Registry repo '$AR_REPO'"
|
|
gcloud artifacts repositories describe "$AR_REPO" --location="$REGION" >/dev/null 2>&1 || \
|
|
gcloud artifacts repositories create "$AR_REPO" \
|
|
--repository-format=docker --location="$REGION" --description="Cerebrus images"
|
|
|
|
echo "==> Granting Cloud Build permission to deploy to Cloud Run"
|
|
PROJECT_NUMBER="$(gcloud projects describe "$PROJECT_ID" --format='value(projectNumber)')"
|
|
CB_SA="${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com"
|
|
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
|
|
--member="serviceAccount:${CB_SA}" --role="roles/run.admin" --condition=None >/dev/null
|
|
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
|
|
--member="serviceAccount:${CB_SA}" --role="roles/iam.serviceAccountUser" --condition=None >/dev/null
|
|
|
|
# Build + push + deploy backend and frontend.
|
|
for app in backend frontend; do
|
|
IMAGE="${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO}/${app}"
|
|
echo "==> Building & deploying cerebrus-${app} (${IMAGE})"
|
|
SUBS="_REGION=${REGION},_IMAGE=${IMAGE}"
|
|
if [[ "$app" == "frontend" ]]; then
|
|
SUBS="${SUBS},_BACKEND_URL=${FRONTEND_BACKEND_URL}"
|
|
fi
|
|
gcloud builds submit \
|
|
--config "apps/${app}/cloudbuild.yaml" \
|
|
--substitutions="$SUBS" \
|
|
.
|
|
done
|
|
|
|
# Build + push + deploy the scanner Cloud Run job (used when SCAN_RUNNER=cloudrun).
|
|
if [[ "$DEPLOY_SCANNER" == "1" ]]; then
|
|
SCANNER_IMAGE="${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO}/scanner"
|
|
echo "==> Building & deploying scanner job (${SCANNER_IMAGE})"
|
|
gcloud builds submit \
|
|
--config "apps/cli/cloudbuild.yaml" \
|
|
--substitutions="_REGION=${REGION},_IMAGE=${SCANNER_IMAGE}" \
|
|
.
|
|
fi
|
|
|
|
echo "==> Done. Cerebrus services:"
|
|
gcloud run services list --platform=managed --region="$REGION" \
|
|
--filter="metadata.name~^cerebrus-(backend|frontend)$" \
|
|
--format='table(metadata.name, status.url)'
|