# GCP Observatory Read Adapter ## Definition of Working - Working target: an authenticated GCP staging API returns one canonical claim with source/evidence provenance and a separately labeled proposal ledger. - Operator path: `GET /v1/claims/sample` or `GET /v1/claims/{uuid}` with the server-only `X-Api-Key` value. - Done means: the response names `teleo_canonical`, the dedicated IAM database principal and `kb_observatory_read`, reports a read-only transaction and denied write privileges, and live anonymous/write HTTP attempts return `401`/`405`. - Not done: the VPS `teleo-pg`, a public Cloud SQL address, a browser-visible key, a mock-only receipt, or a production Vercel repoint. - Required tier: `T3_live_readonly`. ## Existing Connector Boundary The current `living-ip/livingip-web` main branch reads claims through `src/lib/api.ts`. It selects `NEXT_PUBLIC_API_URL` and otherwise falls back to `http://77.42.65.182:8081`, then calls the legacy `/api/claims` routes. That is the VPS-local/public Observatory path. It is not safe to replace that public environment variable with this protected API: the response shape differs and the adapter key must never enter a `NEXT_PUBLIC_` variable or browser bundle. The existing Teleo route `GET /api/kb/claims` is the compatibility reference for route-scoped authentication, but its default database/container settings still describe the VPS-local process. This service is a separate GCP runtime; it does not change Argus or PR #148's Leo runtime files. ## Runtime Contract - Cloud Run service: `observatory-read-adapter-staging` in `europe-west6`. - Direct VPC egress: `teleo-staging-net` / `teleo-staging-europe-west6`. - Cloud SQL: `teleo-501523:europe-west6:teleo-pgvector-standby`, private IP. - Database: `teleo_canonical` only. - Build identity: `sa-artifact-builder@teleo-501523.iam.gserviceaccount.com`; image build/push only. - Staging deploy/canary identity: `sa-observatory-deployer@teleo-501523.iam.gserviceaccount.com`; an exact workflow/main-only WIF provider, a five-permission Cloud Run custom role, repository read, exact runtime `actAs`, and exact secret access. Never grant deploy permissions to the artifact builder. - Runtime identity: `sa-observatory-read-adapter@teleo-501523.iam.gserviceaccount.com`. - IAM database user: `sa-observatory-read-adapter@teleo-501523.iam`. - Database authorization role: `kb_observatory_read` (`NOLOGIN`). - API authentication: route-scoped key from Secret Manager secret `observatory-read-api-key-staging`; the value is not in Git or deploy logs. - No mutation routes exist. Authenticated unsupported methods return `405`. The Cloud SQL Python Connector uses Application Default Credentials from the Cloud Run service identity, automatic IAM database authentication, and private IP. Every request starts a read-only transaction and refuses the response if the database, IAM principal, authorization membership, required reads, or effective write-denial checks drift. ## One-Time Staging Bootstrap These are staging mutations. Run them only with an authenticated GCP operator; they do not route production traffic. 1. Reauthenticate the project operator, then run the first full direct check: ```bash gcloud projects describe teleo-501523 --format=value(projectId) python3 ops/check_gcp_infra_readiness.py ``` 2. Review the exact dry-run packet. It enables only required APIs, creates separate staging deploy/runtime identities, creates the dedicated `observatory-read-adapter-main` WIF provider, keeps the artifact builder narrow, scopes Cloud SQL connect/login to `teleo-pgvector-standby`, and scopes secret access to `observatory-read-api-key-staging`: ```bash python3 ops/plan_observatory_read_adapter_gcp.py python3 ops/plan_observatory_read_adapter_gcp.py --format shell ``` The shell output is unexecuted and uses `set -euo pipefail`. Apply it only after review with an authenticated `teleo-501523` administrator. The deployer custom role contains only `run.services.create`, `run.services.update`, `run.services.get`, `run.services.setIamPolicy`, and `run.operations.get`; it contains no delete permission. Do not add `run.admin`, `run.developer`, `cloudsql.admin`, `secretmanager.admin`, `compute.admin`, Editor, or Owner to either lane identity. 3. Add the dedicated runtime service account as a Cloud SQL IAM service-account user on `teleo-pgvector-standby`. 4. From the existing private GCP VM database-admin path, run `ops/observatory_read_role.sql` against `teleo_canonical` with `OBSERVATORY_DB_IAM_USER=sa-observatory-read-adapter@teleo-501523.iam`. Do not read, copy, or retain the administrator password. 5. Create `observatory-read-api-key-staging`, add a generated whitespace-free 32-byte-or-longer value through stdin only when no enabled version exists, and grant that secret's accessor role only to the runtime service account and the dedicated staging deploy/canary identity. Deployment pins the exact enabled version; it does not inject `latest` into Cloud Run. 6. Dispatch the read-only preflight from merged `main`: ```bash gh workflow run gcp-observatory-read-adapter.yml \ --repo living-ip/teleo-infrastructure \ --ref main \ -f action=preflight_staging ``` Require a passing `observatory-read-adapter-preflight` artifact before a bounded `action=deploy_staging` dispatch. The preflight verifies the exact WIF condition, custom-role permission sets, project/resource IAM bindings, Cloud Run service agent, private VPC/subnet relationship, private-only Cloud SQL network and IAM authentication, trimmed IAM database user, exact secret policy/value shape, and the run-unique immutable image. It also rejects any artifact-builder deploy, runtime `actAs`, secret, or service binding. The workflow always builds a run-unique immutable image, deploys at most two Cloud Run instances, and retains the positive response plus anonymous `401` and authenticated POST `405` receipts. The retained positive receipt contains identity/provenance, counts, and proposal/live state only; claim text, source URLs, excerpts, unknown future provenance fields, and secret values are removed by an explicit tested allowlist. The live gate binds the response to the exact project, private instance, database principal, Git revision, Cloud Run image digest, runtime identity, and pinned secret version. It does not modify Vercel. The app-level `X-Api-Key` remains the staging authentication boundary, so anonymous Cloud Run invocation reaches the adapter and returns the required `401` instead of a platform-generated status. ## Current T2 Receipt And Exact T3 Gate GitHub Actions run `29389090997` proves the existing `living-ip-github` WIF provider can federate as the artifact builder, run the checker, upload its artifact, and clean up credentials. The checker reported `8` pass, `10` blocked, `0` fail. Eight blocks are missing inventory permissions on the artifact-builder identity; two are missing restore/replication proof. This is partial OIDC/T2 evidence, not T3 and not authorization to deploy with that identity. The exact external action is for `billy@livingip.xyz` to reauthenticate gcloud and ADC, prove `gcloud projects describe teleo-501523`, run `python3 ops/check_gcp_infra_readiness.py`, review and execute the planner's shell output as a project IAM/API administrator, then apply `ops/observatory_read_role.sql` from the existing private database-admin path. The general readiness identity and artifact-builder identity are not deployer substitutes. After those actions, dispatch `preflight_staging`; only a passing artifact permits `deploy_staging`. A passing preflight remains T2 setup proof: the fail-closed live claim and negative receipts are what establish T3. The IAM basis is the Google Cloud deployment contract for Cloud Run (Cloud Run access, Artifact Registry repository read, and exact runtime `actAs`), Secret Manager resource-level accessor grants, Direct VPC access through the default Cloud Run service agent, and conditional Cloud SQL client access to one named instance: - https://docs.cloud.google.com/run/docs/deploying - https://docs.cloud.google.com/run/docs/authenticating/public - https://docs.cloud.google.com/run/docs/configuring/vpc-direct-vpc - https://docs.cloud.google.com/iam/docs/workload-identity-federation-with-deployment-pipelines - https://docs.cloud.google.com/secret-manager/docs/manage-access-to-secrets - https://docs.cloud.google.com/sql/docs/postgres/iam-conditions ## Unexecuted Cutover Packet Production cutover requires a separate exact authorization and a `living-ip/livingip-web` change. Do not execute these steps from this lane. 1. Add server-only Vercel secrets `OBSERVATORY_CANONICAL_API_URL` and `OBSERVATORY_CANONICAL_API_KEY` to a protected preview environment. The URL targets the GCP service; neither setting may use `NEXT_PUBLIC_`. 2. Add a Next.js server route or server action that calls the GCP API, validates `livingip.observatory-canonical-claim.v1`, and maps it to the Observatory UI. The browser calls only the same-origin Next.js route. 3. Prove preview Deployment Protection, anonymous denial, source/evidence rendering, proposal/live labels, and no browser key exposure. 4. Obtain exact production-repoint authorization naming the reviewed `livingip-web` commit and Vercel project before changing production values. ## Unexecuted Rollback Packet 1. Revert the authorized `livingip-web` connector commit or disable its server-side feature flag. 2. Restore the prior production Vercel values and redeploy the last accepted production revision. 3. Verify `/claims` again uses the prior `/api/claims` contract. 4. Leave the private Cloud SQL instance and adapter role intact while receipts are reviewed; scale the staging Cloud Run service to zero if isolation is required. 5. Delete the staging service/role/secret only under a separate cleanup decision. Rollback never adds a Cloud SQL public IP and never redirects the adapter to VPS `teleo-pg`.