06-Operations / 06.03.Infrastructure-Operations

06.03.Infrastructure Operations

06.03. Infrastructure Operations

This document describes the Terraform infrastructure steps for deploying the Car Pulse Tracker API to GCP Cloud Run.

Prerequisites

Ensure the following containers are running:

docker container ls
# Expected:
# con-bnc-cpt-conf-validator
# con-bnc-cpt-tf-runner
# con-bnc-cpt-tpl-gen

If not running, start them:

cd /opt/bnc/bnc-cpt/bnc-cpt-utl
make do-setup-bnc-cpt-all

Environment Variables

All commands require: - ENV - Environment: inf, dev, tst, prd, or all - STEP - The terraform step name - ORG - Organization code (default: bnc) - APP - Application code (default: cpt)


Infrastructure Steps Overview

Step Name Description
000 gcp-remote-bucket Terraform state bucket
001 enable-gcp-services Enable required GCP APIs
003 gcp-iam-users IAM user assignments
007 dns DNS zone setup and records
015 gcp-buckets-for-sites-static GCS buckets + HTTPS LB + CDN + SSL for WUI
025 gcp-artifact-registry Docker image repository with cleanup policies
027 gcp-memorystore-redis Memorystore Redis for session/cache
028 gcp-vpc-connector VPC connector for Cloud Run → Redis
029 create-gcp-secrets Secret Manager secrets
030 gcp-cloud-run Cloud Run API deployment
120 github-general-secrets GitHub Actions secrets for CI/CD
140 gcp-cloud-monitor Cloud Monitoring: log-based metrics, alert policies, health dashboard

001-enable-gcp-services

Enable required GCP APIs including artifactregistry.googleapis.com, run.googleapis.com, and secretmanager.googleapis.com.

Generate Config (All Environments)

for env in inf dev tst prd all; do ENV=$env STEP=001-enable-gcp-services ORG=bnc APP=cpt make do-generate-config-for-step; done

Provision

ENV=dev STEP=001-enable-gcp-services ORG=bnc APP=cpt make do-provision

Deprovision

ENV=dev STEP=001-enable-gcp-services ORG=bnc APP=cpt make do-deprovision

Plan Only

ENV=dev STEP=001-enable-gcp-services ORG=bnc APP=cpt make do-tf-plan

025-gcp-artifact-registry

Creates Docker image repository in GCP Artifact Registry for storing API container images.

Resources Created

Generate Config (All Environments)

for env in inf dev tst prd all; do ENV=$env STEP=025-gcp-artifact-registry ORG=bnc APP=cpt make do-generate-config-for-step; done

Provision

ENV=dev STEP=025-gcp-artifact-registry ORG=bnc APP=cpt make do-provision

Deprovision

ENV=dev STEP=025-gcp-artifact-registry ORG=bnc APP=cpt make do-deprovision

Plan Only

ENV=dev STEP=025-gcp-artifact-registry ORG=bnc APP=cpt make do-tf-plan

Outputs

After provisioning, the Docker image path will be:

europe-north1-docker.pkg.dev/bnc-cpt-{env}/bnc-cpt-api/cpt-api:latest

Push Docker Image

After provisioning the registry, push your Docker image:

# Authenticate Docker with Artifact Registry
gcloud auth configure-docker europe-north1-docker.pkg.dev

# Build and push image
docker build -t europe-north1-docker.pkg.dev/bnc-cpt-dev/bnc-cpt-api/cpt-api:latest \
  -f /opt/bnc/bnc-cpt/bnc-cpt-utl/src/docker/cpt-api/Dockerfile.x86_64 \
  /opt/bnc/bnc-cpt

docker push europe-north1-docker.pkg.dev/bnc-cpt-dev/bnc-cpt-api/cpt-api:latest

029-create-gcp-secrets

Creates Secret Manager secrets for sensitive configuration values. Note: This step creates the secret containers only - actual values must be added manually.

Resources Created

Generate Config (All Environments)

for env in inf dev tst prd all; do ENV=$env STEP=029-create-gcp-secrets ORG=bnc APP=cpt make do-generate-config-for-step; done

Provision

ENV=dev STEP=029-create-gcp-secrets ORG=bnc APP=cpt make do-provision

Deprovision

ENV=dev STEP=029-create-gcp-secrets ORG=bnc APP=cpt make do-deprovision

Plan Only

ENV=dev STEP=029-create-gcp-secrets ORG=bnc APP=cpt make do-tf-plan

Add Secret Values

After provisioning, add actual secret values using gcloud CLI:

# Stripe Secret Key
echo -n "sk_test_your_stripe_key" | \
  gcloud secrets versions add bnc-cpt-stripe-secret-key \
  --data-file=- --project=bnc-cpt-dev

# Stripe Webhook Secret
echo -n "whsec_your_webhook_secret" | \
  gcloud secrets versions add bnc-cpt-stripe-webhook-secret \
  --data-file=- --project=bnc-cpt-dev

# PayPal Client ID
echo -n "your_paypal_client_id" | \
  gcloud secrets versions add bnc-cpt-paypal-client-id \
  --data-file=- --project=bnc-cpt-dev

# PayPal Client Secret
echo -n "your_paypal_client_secret" | \
  gcloud secrets versions add bnc-cpt-paypal-client-secret \
  --data-file=- --project=bnc-cpt-dev

# JWT Secret Key
echo -n "your_jwt_secret_key_min_32_chars" | \
  gcloud secrets versions add bnc-cpt-jwt-secret-key \
  --data-file=- --project=bnc-cpt-dev

# Admin Password Hash (bcrypt)
echo -n '$2b$12$your_bcrypt_hash_here' | \
  gcloud secrets versions add bnc-cpt-admin-password-hash \
  --data-file=- --project=bnc-cpt-dev

Or use GCP Console: 1. Go to https://console.cloud.google.com/security/secret-manager?project=bnc-cpt-dev 2. Click on each secret 3. Click "New Version" 4. Enter the secret value


030-gcp-cloud-run

Deploys the FastAPI backend to GCP Cloud Run.

Resources Created

Configuration by Environment

Setting dev tst prd
Memory 1Gi 1Gi 2Gi
CPU 1 1 2
Min Instances 0 0 1
Max Instances 10 10 100
DEBUG True False False

Generate Config (All Environments)

for env in inf dev tst prd all; do ENV=$env STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-generate-config-for-step; done

Provision

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-provision

Deprovision

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-deprovision

Plan Only

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-tf-plan

Outputs

After successful deployment: - Service URL: https://bnc-cpt-api-{env}-xxxxxxxxxx-lz.a.run.app - Health Check: https://<service-url>/health

Verify Deployment

# Get the service URL
gcloud run services describe bnc-cpt-api-dev \
  --region=europe-north1 \
  --project=bnc-cpt-dev \
  --format='value(status.url)'

# Test health endpoint
curl https://<service-url>/health

140-gcp-cloud-monitor

Provisions Cloud Monitoring resources: log-based metrics, alert policies, notification channels, and a health dashboard.

Resources Created

Prerequisites

Generate Config

for env in dev tst prd; do
  ENV=$env STEP=140-gcp-cloud-monitor ORG=bnc APP=cpt make do-generate-config-for-step
done

Provision

ENV=dev STEP=140-gcp-cloud-monitor ORG=bnc APP=cpt make do-provision

Deprovision

ENV=dev STEP=140-gcp-cloud-monitor ORG=bnc APP=cpt make do-deprovision

Plan Only

ENV=dev STEP=140-gcp-cloud-monitor ORG=bnc APP=cpt make do-tf-plan

Configuration

Alert thresholds and notification emails are configured in bnc-cpt-cnf/bnc-cpt/{env}.env.yaml under 140-gcp-cloud-monitor:

140-gcp-cloud-monitor:
  sender_email: sys@carpulsetracker.com
  recipient_email: yordan.georgiev@csitea.net
  gcp_region: "europe-north1"
  gcp_zone: "europe-north1-a"

View Dashboard

After provisioning, the dashboard is visible in Google Cloud Console:

https://console.cloud.google.com/monitoring/dashboards?project=bnc-cpt-{env}

View Active Alerts

gcloud alpha monitoring policies list --project=bnc-cpt-dev --format="table(displayName,enabled)"

Full Deployment Workflow

Generate All Configs (All Steps, All Environments)

for step in 001-enable-gcp-services 025-gcp-artifact-registry 029-create-gcp-secrets 030-gcp-cloud-run 140-gcp-cloud-monitor; do
  for env in inf dev tst prd all; do
    ENV=$env STEP=$step ORG=bnc APP=cpt make do-generate-config-for-step
  done
done

Initial Setup (Single Environment)

Deploy all infrastructure in order for a specific environment:

# Step 1: Enable GCP APIs
ENV=dev STEP=001-enable-gcp-services ORG=bnc APP=cpt make do-provision

# Step 2: Create Artifact Registry
ENV=dev STEP=025-gcp-artifact-registry ORG=bnc APP=cpt make do-provision

# Step 3: Create Secrets
ENV=dev STEP=029-create-gcp-secrets ORG=bnc APP=cpt make do-provision

# Step 4: Add secret values (see 029 section above)

# Step 5: Build and push Docker image (see 025 section above)

# Step 6: Deploy to Cloud Run
ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-provision

# Step 7: Provision Monitoring (alerts + dashboard)
ENV=dev STEP=140-gcp-cloud-monitor ORG=bnc APP=cpt make do-provision

Full Teardown (Reverse Order)

Remove all infrastructure:

# Remove Cloud Run
ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-deprovision

# Remove Secrets
ENV=dev STEP=029-create-gcp-secrets ORG=bnc APP=cpt make do-deprovision

# Remove Artifact Registry
ENV=dev STEP=025-gcp-artifact-registry ORG=bnc APP=cpt make do-deprovision

# Note: Usually keep 001-enable-gcp-services as other resources may depend on it

Troubleshooting

View Terraform State

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-tf-state-list

Show Specific Resource

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt TARGET="google_cloud_run_v2_service.api" make do-tf-state-show

Replace Specific Resource

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt TARGET="google_cloud_run_v2_service.api" make do-tf-replace-target

Import Existing Resource

ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt \
  RESOURCE_ADDRESS="google_cloud_run_v2_service.api" \
  ID="projects/bnc-cpt-dev/locations/europe-north1/services/bnc-cpt-api-dev" \
  make do-tf-import

View Cloud Run Logs

gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=bnc-cpt-api-dev" \
  --project=bnc-cpt-dev \
  --limit=50 \
  --format="table(timestamp,textPayload)"

Quick Reference

Generate Configs for All Steps

# All environments for a single step
for env in inf dev tst prd all; do ENV=$env STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-generate-config-for-step; done

# All steps for all environments
for step in 001-enable-gcp-services 025-gcp-artifact-registry 029-create-gcp-secrets 030-gcp-cloud-run; do
  for env in inf dev tst prd all; do ENV=$env STEP=$step ORG=bnc APP=cpt make do-generate-config-for-step; done
done

Provision by Environment

# Development
ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-provision

# Test
ENV=tst STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-provision

# Production
ENV=prd STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-provision

Deprovision by Environment

# Development
ENV=dev STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-deprovision

# Test
ENV=tst STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-deprovision

# Production
ENV=prd STEP=030-gcp-cloud-run ORG=bnc APP=cpt make do-deprovision

Bash Deployment Functions

The following bash functions provide streamlined deployment workflows from your local machine. All commands run from bnc-cpt-utl/.

Overview

Function Description
do_gcp_build_and_push_api_image Build Docker image and push to Artifact Registry
do_gcp_deploy_cloud_run Deploy Cloud Run service via Terraform
do_gcp_delete_cloud_run Delete Cloud Run service (with production safety)
do_gcp_deploy_api_full Full deployment: build, push, and deploy

do_gcp_build_and_push_api_image

Build the API Docker image locally and push to GCP Artifact Registry.

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Build and push for dev environment
ENV=dev ./run -a do_gcp_build_and_push_api_image

# Build and push for production
ENV=prd ./run -a do_gcp_build_and_push_api_image

What it does: 1. Authenticates Docker with GCP Artifact Registry 2. Builds the image using --target production (multi-stage Dockerfile) 3. Tags and pushes to europe-north1-docker.pkg.dev/{project}/bnc-cpt-api/cpt-api:latest

Prerequisites: - GCP service account key at ~/.gcp/.bnc/key-bnc-cpt-{env}.json - Artifact Registry provisioned (step 025) - Docker running locally


do_gcp_deploy_cloud_run

Deploy Cloud Run service using Terraform. Generates config and runs terraform apply.

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Deploy to dev
ENV=dev ./run -a do_gcp_deploy_cloud_run

# Deploy to test
ENV=tst ./run -a do_gcp_deploy_cloud_run

# Deploy to production
ENV=prd ./run -a do_gcp_deploy_cloud_run

What it does: 1. Generates Terraform config from YAML (do-generate-config-for-step) 2. Runs terraform apply via do-provision

Prerequisites: - Docker image already pushed to Artifact Registry - Secrets provisioned with values (step 029) - Terraform runner container running


do_gcp_delete_cloud_run

Delete Cloud Run service and associated resources.

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Delete dev service
ENV=dev ./run -a do_gcp_delete_cloud_run

# Delete test service
ENV=tst ./run -a do_gcp_delete_cloud_run

# Delete production (requires confirmation)
ENV=prd ./run -a do_gcp_delete_cloud_run

Safety feature: Production environment requires explicit YES confirmation to prevent accidental deletion.

What it does: 1. Generates Terraform config 2. Runs terraform destroy via do-deprovision


do_gcp_deploy_api_full

Complete API deployment workflow: build, push, and deploy in one command.

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Full deployment to dev
ENV=dev ./run -a do_gcp_deploy_api_full

# Full deployment to production
ENV=prd ./run -a do_gcp_deploy_api_full

What it does: 1. Builds Docker image (do_gcp_build_and_push_api_image) 2. Pushes to Artifact Registry 3. Deploys to Cloud Run (do_gcp_deploy_cloud_run)


Deploy to All Environments

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Full deployment to all environments
for env in dev tst prd; do
  ENV=$env ./run -a do_gcp_deploy_api_full
done

# Or just deploy (image already pushed)
for env in dev tst prd; do
  ENV=$env ./run -a do_gcp_deploy_cloud_run
done

Verify Deployments

After deployment, verify each environment:

# Get service URLs
for env in dev tst prd; do
  url=$(gcloud run services describe bnc-cpt-api-$env \
    --region=europe-north1 \
    --project=bnc-cpt-$env \
    --format='value(status.url)' 2>/dev/null)
  echo "$env: $url"
done

# Test health endpoints
curl https://bnc-cpt-api-dev-xxxxxxxxxx-lz.a.run.app/health
curl https://bnc-cpt-api-tst-xxxxxxxxxx-lz.a.run.app/health
curl https://bnc-cpt-api-prd-xxxxxxxxxx-lz.a.run.app/health

Browser-Accessible Endpoints

Each Cloud Run deployment exposes the following endpoints accessible via browser:

Endpoint Description
/health Health check - returns {"status":"healthy","service":"cpt-api"}
/docs Swagger UI - Interactive API documentation
/redoc ReDoc - Alternative API documentation
/openapi.json OpenAPI schema (JSON format)

Environment URLs:

Environment Base URL
dev https://bnc-cpt-api-dev-oa334vnbwq-lz.a.run.app
tst https://bnc-cpt-api-tst-{hash}-lz.a.run.app
prd https://bnc-cpt-api-prd-{hash}-lz.a.run.app

Quick Links (dev environment):

Get Your Environment's URL:

# Get the base URL for an environment
ENV=dev
gcloud run services describe bnc-cpt-api-$ENV \
  --region=europe-north1 \
  --project=bnc-cpt-$ENV \
  --format='value(status.url)'

# Open in browser (macOS)
open "$(gcloud run services describe bnc-cpt-api-$ENV \
  --region=europe-north1 \
  --project=bnc-cpt-$ENV \
  --format='value(status.url)')/docs"

# Open in browser (Linux)
xdg-open "$(gcloud run services describe bnc-cpt-api-$ENV \
  --region=europe-north1 \
  --project=bnc-cpt-$ENV \
  --format='value(status.url)')/docs"

API Endpoints (require authentication):

Endpoint Method Description
/api/v1/auth/login/json POST JWT authentication
/api/v1/payment/create-intent POST Create payment intent
/api/v1/payment/verify POST Verify payment
/api/v1/payment/receipt/{id}/pdf GET Download receipt PDF
/api/v1/tesla/oauth/initiate POST Start Tesla OAuth flow

Environment Configuration

Cloud Run settings per environment (from bnc-cpt-cnf/bnc-cpt/*.env.yaml):

Setting inf dev tst prd
Memory 512Mi 1Gi 1Gi 2Gi
CPU 1 1 1 2
Min Instances 0 0 0 1
Max Instances 5 10 10 100
DEBUG True True False False
PAYPAL_MODE sandbox sandbox sandbox live

Updating Configuration

To modify Cloud Run settings:

  1. Edit the YAML config: yaml # bnc-cpt-cnf/bnc-cpt/dev.env.yaml steps: 030-gcp-cloud-run: cloud_run_memory: "2Gi" cloud_run_cpu: "2"

  2. Redeploy: bash ENV=dev ./run -a do_gcp_deploy_cloud_run


GitHub Actions CD Workflow

The API is deployed automatically via GitHub Actions when code is pushed to the main branch. The workflow is defined in bnc-cpt-api/.github/workflows/cd.yaml.

Trigger Deployment via GitHub CLI

# Trigger deployment to dev
gh workflow run cd.yaml -f environment=dev --repo csitea/bnc-cpt-api

# Trigger deployment to all environments sequentially
for env in inf dev tst prd; do
  gh workflow run cd.yaml -f environment=$env --repo csitea/bnc-cpt-api
  sleep 30  # Wait between deployments
done

# Check workflow runs
gh run list --workflow=cd.yaml --repo csitea/bnc-cpt-api

# Watch latest run
gh run watch --repo csitea/bnc-cpt-api

# View run logs
gh run view --log --repo csitea/bnc-cpt-api

CD Workflow Features

The CD workflow: - Builds Docker image and pushes to Artifact Registry - Deploys to Cloud Run with all secrets from config - Dynamically reads secrets from bnc-cpt-cnf/{env}.env.json - Handles custom domain mapping (non-blocking if domain not verified)

Configuration Driven Deployment

Secrets are read dynamically from config file:

# Secrets are defined in bnc-cpt-cnf/bnc-cpt/{env}.env.yaml
# Under: steps.030-gcp-cloud-run.secret_environment_variables

# After config change, regenerate JSON:
make do-generate-env-json ENV=dev

# Then trigger redeployment
gh workflow run cd.yaml -f environment=dev --repo csitea/bnc-cpt-api

Custom Domain API Endpoints

All environments have custom domain mappings via Cloud Run:

Environment API Base URL Swagger UI
inf https://inf.api.carpulsetracker.com https://inf.api.carpulsetracker.com/docs
dev https://dev.api.carpulsetracker.com https://dev.api.carpulsetracker.com/docs
tst https://tst.api.carpulsetracker.com https://tst.api.carpulsetracker.com/docs
prd https://api.carpulsetracker.com https://api.carpulsetracker.com/docs
prd (alias) https://prd.api.carpulsetracker.com https://prd.api.carpulsetracker.com/docs

Health Check All Environments

# Quick health check for all environments
for env in inf dev tst prd; do
  if [ "$env" = "prd" ]; then
    url="https://api.carpulsetracker.com"
  else
    url="https://$env.api.carpulsetracker.com"
  fi
  echo -n "$env: "
  curl -s "$url/health" | jq -r '.status'
done

# Using uniform URL pattern (with prd.api alias)
for env in inf dev tst prd; do
  echo -n "$env: "
  curl -s "https://$env.api.carpulsetracker.com/health" | jq -r '.status'
done

API Version Check

for env in inf dev tst prd; do
  echo "=== $env ==="
  curl -s "https://$env.api.carpulsetracker.com/api" | jq '.'
done

WUI (Frontend) Deployment

The Vue frontend is deployed to GCS buckets and served via Cloud CDN Load Balancer.

WUI Environments

Environment URL GCS Bucket CDN URL Map
inf https://inf.carpulsetracker.com gs://bnc-cpt-inf-site-static bnc-cpt-inf-wui-https-url-map
dev https://dev.carpulsetracker.com gs://bnc-cpt-dev-site-static bnc-cpt-dev-wui-https-url-map
tst https://tst.carpulsetracker.com gs://bnc-cpt-tst-site-static bnc-cpt-tst-wui-https-url-map
prd https://carpulsetracker.com gs://bnc-cpt-prd-site-static bnc-cpt-prd-wui-https-url-map

Deploy WUI (Shell Action)

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Deploy to single environment
ENV=dev ./run -a do_gcp_deploy_wui

# Deploy to all environments
for env in inf dev tst prd; do
  ENV=$env ./run -a do_gcp_deploy_wui
done

What the deploy action does (5 steps): 1. Builds Vue app inside wui container (npm run build) 2. Verifies dist directory was created 3. Syncs dist to GCS bucket (gsutil rsync) 4. Invalidates CDN cache (gcloud compute url-maps invalidate-cdn-cache) 5. Verifies deployment (HTTP 200 check on index.html)

Prerequisites: - WUI container running: make do-setup-wui - GCP keys at ~/.gcp/.bnc/key-bnc-cpt-{env}.json - GCS buckets provisioned (Terraform step 015-gcp-buckets-for-sites-static)

CDN Cache Invalidation

The deploy action automatically invalidates CDN cache. To manually invalidate:

# Single environment
gcloud auth activate-service-account --key-file=$HOME/.gcp/.bnc/key-bnc-cpt-dev.json
gcloud compute url-maps invalidate-cdn-cache bnc-cpt-dev-wui-https-url-map \
  --path="/*" --project=bnc-cpt-dev

# All environments
for env in inf dev tst prd; do
  gcloud auth activate-service-account --key-file=$HOME/.gcp/.bnc/key-bnc-cpt-${env}.json 2>/dev/null
  gcloud compute url-maps invalidate-cdn-cache bnc-cpt-${env}-wui-https-url-map \
    --path="/*" --project=bnc-cpt-${env}
done

Cache Headers

The index.html file has Cache-Control: no-cache, no-store, must-revalidate to ensure users always get the latest version. Asset files (JS, CSS, images) use content hashing in filenames and can be cached.

To set cache headers manually:

gsutil setmeta -h "Cache-Control:no-cache, no-store, must-revalidate" \
  gs://bnc-cpt-dev-site-static/index.html

Linear Issue Management

Fetch Linear Issue

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# By issue ID
ISSUE_ID=BNC-61 ./run -a do_linear_fetch_issue

# By URL
URL="https://linear.app/boxinom-csitea/issue/BNC-61/..." ./run -a do_linear_fetch_issue

Close Linear Issue

# Close as Done (default)
ISSUE_ID=BNC-61 ./run -a do_linear_close_issue

# Close with different state
ISSUE_ID=BNC-61 STATE=Cancelled ./run -a do_linear_close_issue

# Close with comment
ISSUE_ID=BNC-61 COMMENT="Deployed to all envs" ./run -a do_linear_close_issue

Prerequisites: Linear API key at ~/.linear/api_key


GCP Secrets Sync from Google Sheet

See the full documentation in bnc-cpt-inf/doc/bnc-cpt.ISG.md under "GCP SECRETS SYNC FROM GOOGLE SHEET".

Quick Reference

cd /opt/bnc/bnc-cpt/bnc-cpt-utl

# Sync secrets for single environment
make do-gcp-sync-secrets ENV=dev

# Sync all environments
for env in inf dev tst prd; do
  echo "=== Syncing secrets for $env ==="
  make do-gcp-sync-secrets ENV=$env
done

# Dry run (preview only)
make do-gcp-sync-secrets ENV=dev DRY_RUN=1

Note: Empty values in the Google Sheet are automatically replaced with "n/a" to ensure Cloud Run can mount all configured secrets