Skip to content

Migrate Tier-2 LLM to Vertex AI with GCP service-account auth - #23

Open
KevinRusu wants to merge 1 commit into
benevolentbandwidth:mainfrom
KevinRusu:feat/vertex-ai-tier2
Open

Migrate Tier-2 LLM to Vertex AI with GCP service-account auth#23
KevinRusu wants to merge 1 commit into
benevolentbandwidth:mainfrom
KevinRusu:feat/vertex-ai-tier2

Conversation

@KevinRusu

Copy link
Copy Markdown
Contributor

Summary

  • Migrated Tier-2 LLM auth from a GEMINI_API_KEY to Vertex AI with GCP service-account auth, per b2's no-API-keys policy (Gemini access is now granted through Vertex, authenticated by the beacon-app-service service account).
  • No API key is read, stored, or shipped anywhere anymore — auth is Application Default Credentials locally (via gcloud auth application-default login --impersonate-service-account=...) and the attached service account automatically on Cloud Run.
  • Added a Cloud Run deployment pipeline (cloudbuild.yaml) — deployment was previously undefined; only a Dockerfile existed.
  • The wire contract is unchanged: AnalyzeResponse (0–10 safety_score, label, action, reason) is reused as the Vertex structured-output schema, so the safety-scale contract carries over untouched.

Changes by area

API (api/)

  • providers/gemini_provider.pyGeminiProvider.__init__ now builds genai.Client(vertexai=True, project=..., location=...) instead of genai.Client(api_key=...); reads GOOGLE_CLOUD_PROJECT / GOOGLE_CLOUD_LOCATION and raises ProviderConfigError if the project isn't set. The prompt, system instruction, and analyze() call are unchanged.
  • .env.example — dropped GEMINI_API_KEY; added GOOGLE_CLOUD_PROJECT/GOOGLE_CLOUD_LOCATION plus the ADC login command as a comment.
  • requirements.txt — pinned google-genai to the exact tested version (2.8.0) instead of a loose >=1.0, for reproducible Cloud Run builds.
  • DockerfileCMD now honors Cloud Run's injected $PORT (--port ${PORT:-3000}), defaulting to 3000 locally.
  • cloudbuild.yaml (new) — build → push to Artifact Registry → gcloud run deploy as beacon-app-service, with the Vertex env vars wired in. Public endpoint by design (no client secret; abuse control is the origin allowlist + rate limit).
  • main.py — updated a stale comment referencing GEMINI_API_KEY; startup behavior (fail fast on missing config) is unchanged.
  • tests/test_provider_config.py (new) — asserts that constructing GeminiProvider without GOOGLE_CLOUD_PROJECT raises ProviderConfigError. No network involved.
  • README.md — new local-auth step, updated environment-variable table, and a "Deploy (Cloud Run)" section with IAM prerequisites.

Extension (extension/)

  • No changes — this migration is server-side only. The extension has no client secret and doesn't touch auth.

Testing done

  • pytest api/tests/ — 18/18 pass (17 pre-existing + the new provider-config test), all against MockProvider (USE_MOCK=true), so none require credentials.
  • Verified the installed google-genai==2.8.0 SDK accepts the vertexai/project/location client kwargs, and that the missing-project guard fires correctly before any network call.
  • Not yet verified end-to-end: a live call to Gemini through Vertex. Blocked on one IAM grant — roles/iam.serviceAccountTokenCreator for the local dev account on beacon-app-service

Copilot AI review requested due to automatic review settings July 27, 2026 22:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the Tier-2 LLM integration from Gemini API-key auth to Vertex AI using GCP Application Default Credentials / Cloud Run service-account auth, and introduces a Cloud Build → Artifact Registry → Cloud Run deployment pipeline for the API.

Changes:

  • Switch GeminiProvider to instantiate google-genai in Vertex mode using GOOGLE_CLOUD_PROJECT / GOOGLE_CLOUD_LOCATION and fail fast on missing config.
  • Add Cloud Run deployment pipeline via api/cloudbuild.yaml and update container startup to honor Cloud Run’s injected $PORT.
  • Update docs/examples and add a regression test to ensure missing Vertex config raises ProviderConfigError.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
api/tests/test_provider_config.py Adds a unit test asserting missing GOOGLE_CLOUD_PROJECT fails fast with ProviderConfigError.
api/requirements.txt Pins google-genai to 2.8.0 for reproducible builds.
api/README.md Updates env var docs for Vertex configuration (but currently has a markdown formatting issue and missing sections claimed in the PR description).
api/providers/gemini_provider.py Migrates provider auth/config from API key to Vertex AI client construction.
api/main.py Updates startup comment to reference Vertex config failure behavior.
api/Dockerfile Changes CMD to use ${PORT} for Cloud Run compatibility.
api/cloudbuild.yaml Adds Cloud Build pipeline to build/push/deploy to Cloud Run with required env vars.
api/.env.example Removes GEMINI_API_KEY and adds Vertex env vars.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/README.md
- `GET /health` — liveness probe, no auth, no rate limit.

> **Tip:** Keep `USE_MOCK=true` while developing. Switch to `USE_MOCK=false` only when you need a real Gemini response.
``` No newline at end of file
Comment thread api/README.md
Comment on lines +32 to 35
| `USE_MOCK` | No (default: `true`) | Skip Gemini and use a deterministic mock. No credentials needed. |
| `GOOGLE_CLOUD_PROJECT` | Only if `USE_MOCK=false` | GCP project for Vertex AI (`b2-beacon1`). Auth is via ADC / the runtime service account — no API key. |
| `GOOGLE_CLOUD_LOCATION` | No (default: `us-east1`) | Vertex AI region. |
| `GEMINI_MODEL` | No (default: `gemini-2.5-flash-lite`) | Gemini model name. Override to migrate to a newer model without a code change. |
Comment thread api/Dockerfile
Comment on lines +15 to +17
# Shell-form CMD so ${PORT} expands: Cloud Run injects PORT and expects the
# container to listen on it; locally PORT is unset and we default to 3000.
CMD uvicorn main:app --host 0.0.0.0 --port ${PORT:-3000} --proxy-headers
Comment thread api/cloudbuild.yaml
Comment on lines +25 to +38
# Published extension origin, e.g. chrome-extension://<id>. Empty accepts all
# origins (dev only). A single origin — commas would clash with the env-var
# delimiter below.
_ALLOWED_ORIGINS: ""

steps:
# 1. Build the container image.
- name: gcr.io/cloud-builders/docker
args:
- build
- -t
- ${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_AR_REPO}/${_SERVICE}:${_TAG}
- .

Comment thread api/cloudbuild.yaml
Comment on lines +58 to +60
- --allow-unauthenticated
- --port=3000
- --set-env-vars=USE_MOCK=false,GOOGLE_CLOUD_PROJECT=${PROJECT_ID},GOOGLE_CLOUD_LOCATION=${_REGION},GEMINI_MODEL=gemini-2.5-flash-lite,ALLOWED_EXTENSION_ORIGINS=${_ALLOWED_ORIGINS},FORWARDED_ALLOW_IPS=*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants