name: deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
env:
GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
GCP_REGION: ${{ vars.GCP_REGION || 'us-central1' }}
ARTIFACT_REPO: ${{ vars.ARTIFACT_REPO || 'ragmap' }}
API_SERVICE: ${{ vars.API_SERVICE || 'ragmap-api' }}
MCP_SERVICE: ${{ vars.MCP_SERVICE || 'ragmap-mcp-remote' }}
ADMIN_DASH_USER: ${{ vars.ADMIN_DASH_USER || 'admin' }}
ADMIN_DASH_PASS_SECRET: ${{ vars.ADMIN_DASH_PASS_SECRET || 'ragmap-admin-dash-pass' }}
OPENAI_API_KEY_SECRET: ${{ vars.OPENAI_API_KEY_SECRET }}
CAPTURE_AGENT_PAYLOADS: ${{ vars.CAPTURE_AGENT_PAYLOADS || 'true' }}
# Public stable URLs (Firebase Hosting by default).
API_PUBLIC_URL: ${{ vars.API_PUBLIC_URL || 'https://ragmap-api.web.app' }}
MCP_PUBLIC_URL: ${{ vars.MCP_PUBLIC_URL || 'https://ragmap-api.web.app/mcp' }}
RUNTIME_SA_EMAIL: ragmap-runtime@${{ vars.GCP_PROJECT_ID }}.iam.gserviceaccount.com
BUILD_SA_EMAIL: ragmap-build@${{ vars.GCP_PROJECT_ID }}.iam.gserviceaccount.com
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Auth to Google (WIF)
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}
- name: Setup gcloud
uses: google-github-actions/setup-gcloud@v2
- name: Install deps
run: pnpm -r install
- name: Configure Docker auth
run: gcloud auth configure-docker "${{ env.GCP_REGION }}-docker.pkg.dev" --quiet
- name: Build & push API image
run: |
set -euo pipefail
IMAGE="${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/${{ env.ARTIFACT_REPO }}/${{ env.API_SERVICE }}:${{ github.sha }}"
gcloud builds submit --project "${{ env.GCP_PROJECT_ID }}" \
--service-account "projects/${{ env.GCP_PROJECT_ID }}/serviceAccounts/${{ env.BUILD_SA_EMAIL }}" \
--gcs-log-dir "gs://${{ env.GCP_PROJECT_ID }}_cloudbuild/logs" \
--gcs-source-staging-dir "gs://${{ env.GCP_PROJECT_ID }}_cloudbuild/source" \
--config cloudbuild.dockerfile.yaml \
--substitutions=_IMAGE="$IMAGE",_DOCKERFILE="apps/api/Dockerfile" \
.
echo "API_IMAGE=$IMAGE" >> "$GITHUB_ENV"
- name: Build & push MCP image
run: |
set -euo pipefail
IMAGE="${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/${{ env.ARTIFACT_REPO }}/${{ env.MCP_SERVICE }}:${{ github.sha }}"
gcloud builds submit --project "${{ env.GCP_PROJECT_ID }}" \
--service-account "projects/${{ env.GCP_PROJECT_ID }}/serviceAccounts/${{ env.BUILD_SA_EMAIL }}" \
--gcs-log-dir "gs://${{ env.GCP_PROJECT_ID }}_cloudbuild/logs" \
--gcs-source-staging-dir "gs://${{ env.GCP_PROJECT_ID }}_cloudbuild/source" \
--config cloudbuild.dockerfile.yaml \
--substitutions=_IMAGE="$IMAGE",_DOCKERFILE="apps/mcp-remote/Dockerfile" \
.
echo "MCP_IMAGE=$IMAGE" >> "$GITHUB_ENV"
- name: Deploy Cloud Run (API)
run: |
set -euo pipefail
SECRETS="INGEST_TOKEN=ragmap-ingest-token:latest,ADMIN_DASH_PASS=${{ env.ADMIN_DASH_PASS_SECRET }}:latest"
EMBED="EMBEDDINGS_ENABLED=false"
if [ -n "${{ env.OPENAI_API_KEY_SECRET }}" ]; then
SECRETS="${SECRETS},OPENAI_API_KEY=${{ env.OPENAI_API_KEY_SECRET }}:latest"
EMBED="EMBEDDINGS_ENABLED=true"
fi
gcloud run deploy "${{ env.API_SERVICE }}" \
--project "${{ env.GCP_PROJECT_ID }}" \
--region "${{ env.GCP_REGION }}" \
--image "$API_IMAGE" \
--service-account "${{ env.RUNTIME_SA_EMAIL }}" \
--set-env-vars "RAGMAP_STORAGE=firestore,SERVICE_VERSION=0.1.0,LOG_LEVEL=info,REGISTRY_BASE_URL=https://registry.modelcontextprotocol.io,INGEST_PAGE_LIMIT=100,${EMBED},CAPTURE_AGENT_PAYLOADS=${{ env.CAPTURE_AGENT_PAYLOADS }},GCP_PROJECT_ID=${{ env.GCP_PROJECT_ID }},PUBLIC_BASE_URL=${{ env.API_PUBLIC_URL }},ADMIN_DASH_USER=${{ env.ADMIN_DASH_USER }}" \
--set-secrets "$SECRETS" \
--timeout=900 \
--allow-unauthenticated
- name: Deploy Cloud Run (MCP)
run: |
set -euo pipefail
API_URL="$(gcloud run services describe "${{ env.API_SERVICE }}" --project "${{ env.GCP_PROJECT_ID }}" --region "${{ env.GCP_REGION }}" --format='value(status.url)')"
gcloud run deploy "${{ env.MCP_SERVICE }}" \
--project "${{ env.GCP_PROJECT_ID }}" \
--region "${{ env.GCP_REGION }}" \
--image "$MCP_IMAGE" \
--service-account "${{ env.RUNTIME_SA_EMAIL }}" \
--set-env-vars "API_BASE_URL=${API_URL},PUBLIC_BASE_URL=${{ env.API_PUBLIC_URL }},PUBLIC_MCP_URL=${{ env.MCP_PUBLIC_URL }},SERVICE_VERSION=0.1.0" \
--timeout=300 \
--allow-unauthenticated
- name: Deploy Firebase Hosting
run: |
set -euo pipefail
pnpm -w dlx firebase-tools@latest deploy --only hosting:api,hosting:mcp --project "${{ env.GCP_PROJECT_ID }}" --non-interactive