---
title: "Terraform vs Live Drift"
slug: gcp-drift-report
section: GCP Infrastructure
status: stable
description: "This page compares what `alliance-gcp-infra` declares with what is actually running in each GCP project, and lists the differences."
last-updated: 2026-10-07
---

# Terraform vs Live Drift

This page compares what `alliance-gcp-infra` declares with what is actually running in each GCP project, and lists the differences. It is regenerated from data, so the tables are only as old as the last run (see the provenance line in them). The rule the comparison measures against is simple: everything created in GCP must be reflected in Terraform. For how Terraform is applied see `/docs/gcp-terraform-workflows`, for the modules see `/docs/gcp-terraform-modules`, and for the recovery implications see `/docs/disaster-recovery-plan`, which already warns that drift means a restore from git may not reproduce what runs today. This page backs that warning with specifics.

## How the comparison works

The check has two inputs. The first is a parsed inventory of the Terraform repo (`data/gcp/iac-inventory.json`, produced by `harness/gcp/iac.mjs`): every module call and resource, with the identifying arguments that can be read from the source. The second is a set of read-only live snapshots per project (`data/gcp/live/<project>.json`), holding names and a few stable attributes, never secret values. `harness/gcp/diff.mjs` then compares the two, per environment and per resource type, by name.

- **Name matching.** A declared item matches a live resource when the names are equal. A name with interpolations is turned into a pattern and matched the same way.
- **Derived names.** Several modules do not take a name directly. Secrets are named from the module parts `<system>[-<component>]-<env>-<key>`, service accounts from `<system>-<component>-<env>` (or an explicit override), and bulk-secret modules expand to a list of names. The comparison rebuilds these names from the parts, so a module call is matched against the real resource it creates. If a part is a variable or local that cannot be read from source, the name cannot be derived.
- **Unresolved names.** Items whose name is computed at plan time (a variable, a function call, a `for_each` key) cannot be matched. They are counted as "name not resolvable" and listed separately. They are neither matched nor reported missing, so a non-zero value means that part of the project is unchecked, not clean.
- **Platform-created resources excluded.** Items GCP, GKE or Cloud Build create themselves (default and GKE-created firewall rules, the default network, default compute service accounts, Cloud Build, Cloud Deploy, Cloud Functions and Cloud Run source buckets, container-analysis topics, and the auto-created Artifact Registry repositories) are recognised by name pattern and shown apart from drift. The patterns are name-based, so a platform-created item with an unusual name could still appear in the live-only list.
- **Types not compared.** If a snapshot section could not be read (permission denied, API not enabled, not collected), that type is listed as "not compared". It is never counted as "no drift".
- **Direction.** Live-only means unmanaged by Terraform. Terraform-only means declared but not found live. Matched counts distinct live names, so a pattern that matches several resources can make "matched" differ from "declared".

_Terraform inventory generated from `alliance-gcp-infra` at commit `fc9bd1d`. Live snapshots: `skilled-script-469819-f2` read 2026-10-01; `alliance-mcp-services` read 2026-10-01; `alliance-platform-services` read 2026-10-01 (nothing readable); `production-499116` read 2026-10-01; `quality-assurance-496022` read 2026-10-01; `alliance-platform-agents` read 2026-10-01. Snapshots hold names and a few stable attributes only, never secret values._

## Summary

| Environment | Project | Live read | Live (compared types) | Matched | Unmanaged | Terraform only | Platform-created | Types not compared |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `development` | `skilled-script-469819-f2` | yes | 484 | 341 | 127 | 1 | 16 | 0 |
| `mcp` | `alliance-mcp-services` | yes | 234 | 155 | 71 | 0 | 8 | 8 |
| `platform-services` | `alliance-platform-services` | no | 0 | 0 | 0 | 12 | 0 | 1 |
| `production` | `production-499116` | yes | 229 | 204 | 20 | 1 | 5 | 2 |
| `qa` | `quality-assurance-496022` | yes | 233 | 198 | 23 | 0 | 12 | 0 |
| `vertex` | `alliance-platform-agents` | yes | 114 | 45 | 61 | 5 | 8 | 4 |

## development

### Terraform compared with live state

| Resource type | Live | In Terraform | Matched | Live only (unmanaged) | Platform-created | Terraform only | Name not resolvable |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `api` | 87 | 82 | 82 | 5 | 0 | 0 | 0 |
| `cloud_run_service` | 18 | 7 | 9 | 9 | 0 | 0 | 0 |
| `cloud_run_job` | 2 | 2 | 2 | 0 | 0 | 0 | 0 |
| `cloud_sql` | 8 | 8 | 8 | 0 | 0 | 0 | 0 |
| `redis` | 2 | 2 | 2 | 0 | 0 | 0 | 0 |
| `firestore` | 5 | 4 | 0 | 5 | 0 | 0 | 4 |
| `bucket` | 26 | 14 | 14 | 7 | 5 | 0 | 0 |
| `secret` | 234 | 174 | 169 | 65 | 0 | 1 | 1 |
| `service_account` | 49 | 25 | 25 | 23 | 1 | 0 | 0 |
| `wif_pool` | 6 | 6 | 5 | 1 | 0 | 0 | 1 |
| `artifact_registry` | 13 | 11 | 11 | 1 | 1 | 0 | 0 |
| `cloudbuild_trigger` | 8 | 8 | 8 | 0 | 0 | 0 | 0 |
| `pubsub_topic` | 6 | 0 | 0 | 2 | 4 | 0 | 0 |
| `scheduler_job` | 2 | 0 | 0 | 2 | 0 | 0 | 0 |
| `gke_cluster` | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| `domain_mapping` | 7 | 0 | 0 | 7 | 0 | 0 | 0 |
| `firewall_rule` | 8 | 3 | 3 | 0 | 5 | 0 | 0 |
| `vpc_network` | 2 | 2 | 2 | 0 | 0 | 0 | 0 |

### Live but not in Terraform

127 resources of the compared types exist in the project without a matching Terraform declaration.

| Resource type | Name |
| --- | --- |
| `api` | `apikeys` |
| `api` | `firebaserules` |
| `api` | `firestore` |
| `api` | `orgpolicy` |
| `api` | `siteverification` |
| `cloud_run_service` | `bug-diagnosis-agent` |
| `cloud_run_service` | `docs-update-agent` |
| `cloud_run_service` | `gcp-mcp-server` |
| `cloud_run_service` | `gke-workload-health-agent` |
| `cloud_run_service` | `openstatus-alert-agent` |
| `cloud_run_service` | `pr-latency-agent` |
| `cloud_run_service` | `pr-review-eligibility-agent` |
| `cloud_run_service` | `secrets-drift-agent` |
| `cloud_run_service` | `user-addition-agent` |
| `firestore` | `bug-diagnosis-agent` |
| `firestore` | `docs-update-agent` |
| `firestore` | `openstatus-alert-agent` |
| `firestore` | `pr-review-eligibility-agent` |
| `firestore` | `user-addition-agent` |
| `bucket` | `dev-tfstate-skilled-script-469819-f2` |
| `bucket` | `host-portal-db-backups-development` |
| `bucket` | `host-portal-public-assets` |
| `bucket` | `northamerica-northeast1.deploy-artifacts.skilled-script-469819-f2.appspot.com` |
| `bucket` | `pr-review-eligibility-agent-claims` |
| `bucket` | `terraform-state-bucket-npe` |
| `bucket` | `terraform-state-skilled-script-prod` |
| `secret` | `branch-drift-agent-asana-gateway-pat` |
| `secret` | `bug-diagnosis-agent-api-key` |
| `secret` | `bug-diagnosis-agent-asana-pat` |
| `secret` | `bug-diagnosis-agent-gateway-pat` |
| `secret` | `bug-diagnosis-agent-webhook-secret` |
| `secret` | `bug-diagnosis-reasoner-gateway-pat` |
| `secret` | `bug-diagnosis-reasoner-github-pat` |
| `secret` | `docs-update-agent-api-key` |
| `secret` | `docs-update-agent-gateway-pat` |
| `secret` | `email-health-agent-asana-gateway-pat` |
| `secret` | `env-audit-agent-asana-gateway-pat` |
| `secret` | `form-engine-bump-monitor-gateway-pat` |
| `secret` | `gke-workload-health-agent-api-key` |
| `secret` | `gke-workload-health-agent-asana-gateway-pat` |
| `secret` | `gke-workload-health-agent-asana-token` |
| `secret` | `globus-asana-alliance-api-key` |
| `secret` | `globus-dev-hubspot-api-key` |
| `secret` | `globus-dev-hubspot-auth-header` |
| `secret` | `globus-dev-netsuite-access-token` |
| `secret` | `globus-dev-netsuite-account-id` |
| `secret` | `globus-dev-netsuite-consumer-key` |
| `secret` | `globus-dev-netsuite-consumer-secret` |
| `secret` | `globus-dev-netsuite-realm` |
| `secret` | `globus-dev-netsuite-token-secret` |
| `secret` | `globus-development-environment` |
| `secret` | `globus-development-posthog-host` |
| `secret` | `globus-development-sandbox-mode` |
| `secret` | `globus-development-translation-glossary-id` |
| `secret` | `globus-docai-processor-id` |
| `secret` | `globus-n8n-sandbox-api-key` |
| `secret` | `globus-n8n-webhook-url-job-order` |
| `secret` | `globus-sendgrid-api-key` |
| `secret` | `n8n-dev-deploy-api-key` |
| `secret` | `n8n-dev-hubspot-webhook-secret` |
| `secret` | `n8n-dev-owner-password` |
| `secret` | `n8n-globus-api-callback-key` |
| `secret` | `n8n-qa-pipeline-webhook-token` |
| `secret` | `n8n-sandbox-deploy-api-key` |
| `secret` | `n8n-sandbox-globus-callback-key` |
| `secret` | `n8n-sandbox-owner-password` |
| `secret` | `n8n-sandbox-template-admin-harness-key` |
| `secret` | `onepassword-mcp-vault-admin-token` |
| `secret` | `openstatus-alert-agent-api-key` |
| `secret` | `openstatus-alert-agent-gateway-pat` |
| `secret` | `openstatus-alert-agent-known-issues` |
| `secret` | `openstatus-alert-agent-openstatus-key` |
| `secret` | `platform-bot-asana-pat` |
| `secret` | `ppp2-globus-api-key` |
| `secret` | `ppp2-keycloak-admin-client-secret` |
| `secret` | `ppp2-passport-name-sync-secret` |
| `secret` | `pr-hygiene-agent-api-key` |
| `secret` | `pr-hygiene-agent-gateway-pat` |
| `secret` | `pr-hygiene-agent-known-issues` |
| `secret` | `pr-latency-agent-api-key` |
| `secret` | `pr-latency-agent-gateway-pat` |
| `secret` | `pr-review-agent-gateway-pat` |
| `secret` | `pr-review-eligibility-agent-api-key` |
| `secret` | `pr-review-eligibility-agent-asana-gateway-pat` |
| `secret` | `pr-review-eligibility-agent-cycle-state` |
| `secret` | `pr-review-eligibility-agent-gateway-pat` |
| `secret` | `pr-review-eligibility-agent-webhook-secret` |
| `secret` | `secrets-drift-agent-api-key` |
| `secret` | `secrets-drift-agent-state` |
| `secret` | `security-agent-asana-gateway-pat` |
| `secret` | `vertex-reviewer-private-key` |
| `service_account` | `branch-drift-agent-sa` |
| `service_account` | `branch-drift-scheduler` |
| `service_account` | `bug-diagnosis-agent` |
| `service_account` | `bug-diagnosis-reasoner` |
| `service_account` | `cloudbuild-teams-notifier` |
| `service_account` | `data-lake-bigquery` |
| `service_account` | `dev-to-qa-sync-agent-sa` |
| `service_account` | `domain-admin-sa` |
| `service_account` | `env-audit-agent-sa` |
| `service_account` | `gke-workload-health-agent-sa` |
| `service_account` | `observer-agent-v2-sa` |
| `service_account` | `openstatus-alert-agent-sa` |
| `service_account` | `openstatus-mcp-sa` |
| `service_account` | `overseer-agent-sa` |
| `service_account` | `posthog-agent-sa` |
| `service_account` | `pr-hygiene-agent` |
| `service_account` | `pr-latency-agent-sa` |
| `service_account` | `pr-review-eligibility-agent` |
| `service_account` | `secrets-drift-agent-sa` |
| `service_account` | `sevis-sdk-reader` |
| `service_account` | `skilled-script-469819-f2` |
| `service_account` | `vertex-sync-agent-sa` |
| `service_account` | `volume-testing-agent-sa` |
| `wif_pool` | `github-actions-sandbox` |
| `artifact_registry` | `globus-npm` |
| `pubsub_topic` | `cloud-builds` |
| `pubsub_topic` | `secret-rotation-notifications` |
| `scheduler_job` | `docs-update-agent-drift-check` |
| `scheduler_job` | `docs-update-agent-sweep` |
| `domain_mapping` | `dev-1.sandbox.allianceabroad.com` |
| `domain_mapping` | `dev-2.sandbox.allianceabroad.com` |
| `domain_mapping` | `dev-3.sandbox.allianceabroad.com` |
| `domain_mapping` | `dev.apply.allianceabroad.com` |
| `domain_mapping` | `development.apply.allianceabroad.com` |
| `domain_mapping` | `development.apply.wildpacks.com` |
| `domain_mapping` | `nexus.allianceabroad.com` |

### In Terraform but not found live

| Resource type | Name | Terraform address | Defined in |
| --- | --- | --- | --- |
| `secret` | `n8n-monitors` | `module.secrets_bulk_development` | `main.tf:2624` |

### Created by GCP or GKE

These are created by the platform itself (default network rules, GKE firewall rules, default compute service accounts, Cloud Build buckets, container analysis topics) and are not drift.

| Resource type | Name |
| --- | --- |
| `bucket` | `481e243513174cba93c5a766e5db6d40_clouddeploy` |
| `bucket` | `gcf-v2-sources-382570452229-us-central1` |
| `bucket` | `gcf-v2-uploads-382570452229.us-central1.cloudfunctions.appspot.com` |
| `bucket` | `run-sources-skilled-script-469819-f2-us-central1` |
| `bucket` | `skilled-script-469819-f2_cloudbuild` |
| `service_account` | `382570452229-compute` |
| `artifact_registry` | `gcf-artifacts` |
| `pubsub_topic` | `container-analysis-notes-v1` |
| `pubsub_topic` | `container-analysis-notes-v1beta1` |
| `pubsub_topic` | `container-analysis-occurrences-v1` |
| `pubsub_topic` | `container-analysis-occurrences-v1beta1` |
| `firewall_rule` | `gke-globus-cluster-development-5c06a123-all` |
| `firewall_rule` | `gke-globus-cluster-development-5c06a123-exkubelet` |
| `firewall_rule` | `gke-globus-cluster-development-5c06a123-inkubelet` |
| `firewall_rule` | `gke-globus-cluster-development-5c06a123-vms` |
| `firewall_rule` | `k8s-fw-l7--9845bf8df74ff07a` |

### Terraform items whose name is computed at plan time

These could not be matched by name, so they are not counted as matched or missing.

| Resource type | Terraform address | Defined in |
| --- | --- | --- |
| `firestore` | `module.docs_update_agent_firestore` | `docs-update-agent-firestore.tf:1` |
| `firestore` | `module.openstatus_alert_agent_firestore` | `openstatus-alert-agent-firestore.tf:1` |
| `firestore` | `module.pr_review_eligibility_agent_firestore` | `pr-review-eligibility-agent-firestore.tf:1` |
| `firestore` | `module.user_addition_agent_firestore` | `user-addition-agent-firestore.tf:1` |
| `secret` | `module.secrets_bulk_development` | `main.tf:2624` |
| `wif_pool` | `google_iam_workload_identity_pool.sandbox` | `branching-sandbox.tf:65` |

### Resource types not compared

_None._

### Live reads that were denied or unavailable

| Read attempted | Result |
| --- | --- |
| first combined gcloud call (services+project describe+billing) via gcp_gcp_shell_exec | backend request failed (transient, retried successfully in split calls) |
| combined python inventory call (jobs+sql+redis+firestore+buckets) via gcp_gcp_shell_exec | backend request failed (likely timeout; retried successfully in split calls) |
| gcloud iam workload-identity-pools providers loop + artifacts list combined call | backend request failed (retried successfully in split calls) |

### Collection notes

Caveats recorded when the live snapshot was read.

- Dedicated gateway read tools were not loaded; all data gathered with read-only gcloud list/describe/get-iam-policy via gcp_gcp_shell_exec (no writes, no secret values, no kubectl).
- IAM member strings are abbreviated: '.SA' = '.iam.gserviceaccount.com', '@P' = '@skilled-script-469819-f2', '@developer' = '@developer.gserviceaccount.com'.
- collected_at is the date (2026-10-01); exact time not captured.
- Secret replication: all 234 secrets are automatic replication; names list is complete (count 234).
- Cloud Deploy targets list returned empty in northamerica-northeast1 for the ppp2 pipeline; targets ppp2-dev and ppp2-dev-client inferred from Cloud Run labels.
- Cloud Run services list contains no nexus-hub service in this project though domain mapping nexus.allianceabroad.com -> nexus-hub exists (dangling). nexus-hub-runtime-sa exists.
- Dev project hosts references to prod/test resources by name: buckets globus-documents-prod, globus-profile-photos-prod, globus-vertex-agent-prod/-staging, terraform-state-skilled-script-prod; a globus-prod NEG; IAM for production-499116 and quality-assurance-496022 SAs. Also resources with 'staging' naming (stg-globus-maps-rot key, globus-vertex-agent-staging).
- Stale/deleted principals in IAM: vi-gke-nodes, virtual-interviews-sa, ci-failure-alert-agent (all 'deleted:'). Stale virtual-interviews resources remain (cert mcrt-f9efe9d8, NEG, Cloud Armor policy virtual-interviews-security-policy).
- External human principals with project access: [user account] (bigquery.admin, iam.serviceAccountCreator), [user account] (viewer, browser), [user account] and [user account] (storage.admin), [user account]. Owners: soregan, bmishkin37, manus-agent-sa.
- Basic roles in use: roles/editor on default compute SA and cloudservices SA; roles/owner on manus-agent-sa.
- Public/exposure: globus-db-development and mcp-db-development have public IPv4 enabled; every Cloud Run service has ingress=all; default-allow-ssh limited to 75.40.188.183/32; GKE exkubelet rule source 0.0.0.0/0.
- Redis instances: both BASIC tier, no persistence/HA; keycloackparticipant transit encryption DISABLED.
- dev-globus-maps-rot-20260314-v3 API key has no API target restriction.
- Cloud Build triggers: pr-review-trigger and host-company-portal-server-development are disabled; ParticipantPortalPrototype trigger still active though that repo is archived.
- Firestore bug-diagnosis-agent database is in us-central1 with delete protection off; others nam5 with protection on.
- GCP project-level labels: none. No GKE ExternalSecret/kubectl data collected (kubectl prohibited).

## mcp

### Terraform compared with live state

| Resource type | Live | In Terraform | Matched | Live only (unmanaged) | Platform-created | Terraform only | Name not resolvable |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `api` | 49 | 0 | 0 | 49 | 0 | 0 | 0 |
| `cloud_run_service` | 23 | 20 | 20 | 3 | 0 | 0 | 0 |
| `cloud_run_job` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `secret` | 119 | 122 | 103 | 16 | 0 | 0 | 0 |
| `service_account` | 34 | 33 | 32 | 1 | 1 | 0 | 0 |
| `cloudbuild_trigger` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `gke_cluster` | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| `domain_mapping` | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| `firewall_rule` | 6 | 0 | 0 | 0 | 6 | 0 | 0 |
| `vpc_network` | 1 | 0 | 0 | 0 | 1 | 0 | 0 |

### Live but not in Terraform

71 resources of the compared types exist in the project without a matching Terraform declaration.

| Resource type | Name |
| --- | --- |
| `api` | `analyticsadmin` |
| `api` | `analyticsdata` |
| `api` | `analyticshub` |
| `api` | `artifactregistry` |
| `api` | `autoscaling` |
| `api` | `bigquery` |
| `api` | `bigqueryconnection` |
| `api` | `bigquerydatapolicy` |
| `api` | `bigquerydatatransfer` |
| `api` | `bigquerymigration` |
| `api` | `bigqueryreservation` |
| `api` | `bigquerystorage` |
| `api` | `binaryauthorization` |
| `api` | `cloudapis` |
| `api` | `cloudbilling` |
| `api` | `cloudbuild` |
| `api` | `cloudresourcemanager` |
| `api` | `cloudshell` |
| `api` | `cloudtrace` |
| `api` | `compute` |
| `api` | `container` |
| `api` | `containeranalysis` |
| `api` | `containerfilesystem` |
| `api` | `containerregistry` |
| `api` | `dataform` |
| `api` | `dataplex` |
| `api` | `datastore` |
| `api` | `dns` |
| `api` | `file` |
| `api` | `gkebackup` |
| `api` | `iam` |
| `api` | `iamcredentials` |
| `api` | `iap` |
| `api` | `logging` |
| `api` | `monitoring` |
| `api` | `networkconnectivity` |
| `api` | `orgpolicy` |
| `api` | `oslogin` |
| `api` | `pubsub` |
| `api` | `run` |
| `api` | `secretmanager` |
| `api` | `servicemanagement` |
| `api` | `serviceusage` |
| `api` | `sql-component` |
| `api` | `sqladmin` |
| `api` | `storage` |
| `api` | `storage-api` |
| `api` | `storage-component` |
| `api` | `telemetry` |
| `cloud_run_service` | `itrequest-mcp` |
| `cloud_run_service` | `replitmcp` |
| `cloud_run_service` | `wordpress-mcp` |
| `secret` | `auth0-mcp-hostportal-dev-audience` |
| `secret` | `auth0-mcp-hostportal-dev-client-id` |
| `secret` | `auth0-mcp-hostportal-dev-client-secret` |
| `secret` | `auth0-mcp-hostportal-dev-domain` |
| `secret` | `auth0-mcp-hostportal-qa-audience` |
| `secret` | `auth0-mcp-hostportal-qa-client-id` |
| `secret` | `auth0-mcp-hostportal-qa-client-secret` |
| `secret` | `auth0-mcp-hostportal-qa-domain` |
| `secret` | `domain-admin-sa-key` |
| `secret` | `google-workspace-mcp-admin` |
| `secret` | `google-workspace-mcp-domain` |
| `secret` | `google-workspace-mcp-sa-key` |
| `secret` | `mcp-gateway-oauth-asana-client-id` |
| `secret` | `mcp-gateway-oauth-asana-client-secret` |
| `secret` | `mcp-gateway-skill-directive-signing-key` |
| `secret` | `posthog-mcp-personal-api-key` |
| `service_account` | `openstatus-mcp-deploy` |
| `gke_cluster` | `openstatus-cluster` |
| `domain_mapping` | `teams-mcp.mcp.allianceabroad.com` |

### In Terraform but not found live

_None._

### Created by GCP or GKE

These are created by the platform itself (default network rules, GKE firewall rules, default compute service accounts, Cloud Build buckets, container analysis topics) and are not drift.

| Resource type | Name |
| --- | --- |
| `service_account` | `627350954379-compute` |
| `firewall_rule` | `default-allow-internal` |
| `firewall_rule` | `gke-openstatus-cluster-e2bda491-all` |
| `firewall_rule` | `gke-openstatus-cluster-e2bda491-exkubelet` |
| `firewall_rule` | `gke-openstatus-cluster-e2bda491-inkubelet` |
| `firewall_rule` | `gke-openstatus-cluster-e2bda491-vms` |
| `firewall_rule` | `k8s-fw-l7--e0f2d94e66fa6a36` |
| `vpc_network` | `default` |

### Resource types not compared

| Resource type | Reason | Declared in Terraform |
| --- | --- | --- |
| `cloud_sql` | snapshot section unreadable (denied, API disabled or not collected) | 1 |
| `redis` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `firestore` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `bucket` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `wif_pool` | snapshot section unreadable (denied, API disabled or not collected) | 7 |
| `artifact_registry` | snapshot section unreadable (denied, API disabled or not collected) | 4 |
| `pubsub_topic` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `scheduler_job` | snapshot section unreadable (denied, API disabled or not collected) | 0 |

### Live reads that were denied or unavailable

| Read attempted | Result |
| --- | --- |
| gcloud projects get-iam-policy (project IAM bindings) | does not have permission to access projects instance [alliance-mcp-services:getIamPolicy] |
| gcloud iam workload-identity-pools list | PERMISSION_DENIED iam.workloadIdentityPools.list |
| gcloud sql instances list / databases list | The client is not authorized to make this request (sqladmin enabled; dev env token lacks access) |
| gcloud storage buckets list | 403 manus-agent-sa@skilled-script-469819-f2 lacks storage.buckets.list on project |
| gcloud artifacts repositories list | artifactregistry.locations.list denied |
| gcloud builds triggers list | PERMISSION_DENIED |
| gcloud builds connections list (northamerica-northeast1, us-central1) | cloudbuild.connections.list denied |
| gcloud pubsub topics list / subscriptions list | pubsub.topics.list / pubsub.subscriptions.list denied (pubsub API enabled) |
| gcloud dns managed-zones list | Forbidden (dns API enabled) |
| gcloud services api-keys list | apikeys.keys.list denied |
| gcloud iap settings get | iap.projects.getSettings denied |
| gcloud redis instances list | redis.googleapis.com not enabled (no Redis) |
| gcloud firestore databases list | firestore.googleapis.com not enabled (datastore.googleapis.com is enabled; not checked) |
| gcloud scheduler jobs list | cloudscheduler.googleapis.com not enabled |
| VPC access connectors | vpcaccess.googleapis.com not enabled (none exist) |
| Cloud Deploy / Certificate Manager | clouddeploy.googleapis.com / certificatemanager.googleapis.com not enabled |
| gcloud projects describe / most calls via environment=prod and agents | prod env token: no permission on alliance-mcp-services; agents env: backend request failed. All successful reads used environment=development. |
| gcloud run jobs list | returned [] (no error) |

### Collection notes

Caveats recorded when the live snapshot was read.

- alliance-mcp-services is not a selectable gateway environment; all reads were made with environment=development, whose token (manus-agent-sa@skilled-script-469819-f2) has partial read access to this project.
- Only read-only list/describe commands were run. No secret values accessed.
- Cloud Run: 24 services; 3 in northamerica-northeast1 (gateway, admin, itrequest-mcp), rest us-central1. Several images pull from the skilled-script-469819-f2 (dev) Artifact Registry.
- Secret-backed env 'HUBSPOT_TOKEN' in hubspot-mcp references secret wildp-1efe771b-76e7-11f1-95a0-9c65eb2e83c5 which is absent from the project's Secret Manager list.
- Secret names mcp-production-* exist in this project alongside mcp-development-*; MCP servers should be non-environment-specific.
- platform-hub-neg exists in both NE1 and us-central1 but the platform-hub service is us-central1 only.
- domain mapping teams-mcp.mcp.allianceabroad.com has Ready condition False.
- openstatus runs on GKE Autopilot cluster openstatus-cluster in this project (kubectl not used).
- Subnet list was truncated at 20 rows of the auto-mode default network.
- Firewall list: exkubelet rule shows source 0.0.0.0/0 with no allowed protocols returned (GKE-managed).
- cloud_sql, redis, firestore, buckets, iam_bindings, wif_pools, artifact_registry, pubsub, dns, api_keys, scheduler set to null because unreadable or API disabled (see denied).

## platform-services

### Live state

No live snapshot could be read for `alliance-platform-services` through the gateway. Everything on this page for this project comes from Terraform only and is **not verified against the running project**.

| Read attempted | Result |
| --- | --- |
| gcloud projects describe alliance-platform-services | does not have permission to access projects instance (or it may not exist): The caller does not have permission |
| gcloud services list --enabled | Permission denied to list services for consumer container [projects/283996200641] (serviceusage.services.list) |
| gcloud run services list | PERMISSION_DENIED: run.services.list denied on namespaces/alliance-platform-services/services |
| all other sections | not attempted: gateway gcp_* tools only expose environments development, qa, prod, agents; none resolves to alliance-platform-services, and the agents-scoped id |

## production

### Terraform compared with live state

| Resource type | Live | In Terraform | Matched | Live only (unmanaged) | Platform-created | Terraform only | Name not resolvable |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `api` | 63 | 53 | 53 | 10 | 0 | 0 | 0 |
| `cloud_run_service` | 9 | 9 | 9 | 0 | 0 | 0 | 0 |
| `cloud_run_job` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `cloud_sql` | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
| `redis` | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| `bucket` | 8 | 4 | 4 | 3 | 1 | 0 | 0 |
| `secret` | 97 | 96 | 96 | 1 | 0 | 0 | 0 |
| `service_account` | 25 | 21 | 21 | 3 | 1 | 0 | 0 |
| `wif_pool` | 4 | 4 | 3 | 1 | 0 | 0 | 1 |
| `artifact_registry` | 9 | 9 | 9 | 0 | 0 | 0 | 0 |
| `cloudbuild_trigger` | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
| `pubsub_topic` | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| `gke_cluster` | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| `domain_mapping` | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| `firewall_rule` | 5 | 2 | 2 | 0 | 3 | 0 | 0 |
| `vpc_network` | 2 | 2 | 2 | 0 | 0 | 0 | 0 |

### Live but not in Terraform

20 resources of the compared types exist in the project without a matching Terraform declaration.

| Resource type | Name |
| --- | --- |
| `api` | `anthos` |
| `api` | `apikeys` |
| `api` | `certificatemanager` |
| `api` | `cloudasset` |
| `api` | `cloudkms` |
| `api` | `containersecurity` |
| `api` | `distance-matrix-backend` |
| `api` | `iap` |
| `api` | `memorystore` |
| `api` | `orgpolicy` |
| `bucket` | `host-portal-db-backups-prod` |
| `bucket` | `production-499116-db-migration` |
| `bucket` | `terraform-state-bucket-produ` |
| `secret` | `n8n-prod-hubspot-webhook-secret` |
| `service_account` | `data-lake-bigquery` |
| `service_account` | `manus-agent-sa` |
| `service_account` | `ocr-service-prod-deployer` |
| `wif_pool` | `github-actions-sandbox` |
| `pubsub_topic` | `secret-rotation-notifications` |
| `domain_mapping` | `sandbox.allianceabroad.com` |

### In Terraform but not found live

| Resource type | Name | Terraform address | Defined in |
| --- | --- | --- | --- |
| `cloudbuild_trigger` | `wildpacks-prod` | `module.trigger_wildpacks_prod` | `main.tf:2038` |

### Created by GCP or GKE

These are created by the platform itself (default network rules, GKE firewall rules, default compute service accounts, Cloud Build buckets, container analysis topics) and are not drift.

| Resource type | Name |
| --- | --- |
| `bucket` | `production-499116_cloudbuild` |
| `service_account` | `445487831874-compute` |
| `firewall_rule` | `gke-globus-cluster-prod-c4b72319-all` |
| `firewall_rule` | `gke-globus-cluster-prod-c4b72319-vms` |
| `firewall_rule` | `k8s-fw-l7--ccab3f00c36e3a86` |

### Terraform items whose name is computed at plan time

These could not be matched by name, so they are not counted as matched or missing.

| Resource type | Terraform address | Defined in |
| --- | --- | --- |
| `wif_pool` | `google_iam_workload_identity_pool.sandbox` | `branching-sandbox.tf:62` |

### Resource types not compared

| Resource type | Reason | Declared in Terraform |
| --- | --- | --- |
| `firestore` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `scheduler_job` | snapshot section unreadable (denied, API disabled or not collected) | 0 |

### Live reads that were denied or unavailable

| Read attempted | Result |
| --- | --- |
| gcloud firestore databases list | firestore.googleapis.com not enabled on project (SERVICE_DISABLED) - treated as no Firestore |
| gcloud scheduler jobs list | cloudscheduler.googleapis.com not enabled (SERVICE_DISABLED) - treated as none |
| gcloud deploy delivery-pipelines list | clouddeploy.googleapis.com not enabled - treated as none |
| gcloud billing projects describe | call returned 'backend request failed' (grouped with project describe); billing state not captured |

### Collection notes

Caveats recorded when the live snapshot was read.

- Run via gateway gcp_shell_exec env=prod as manus-agent-sa; several multi-command calls returned 'backend request failed' and were retried split into smaller calls.
- apis list is names only, all *.googleapis.com.
- Cloud Build triggers checked in global scope only (regional triggers not enumerated); GitHub connection found in us-central1 only.
- Cloud Run list covered all regions via --platform=managed; domain mappings checked only in northamerica-northeast1 and us-central1.
- Cloud Run jobs: none (empty list).
- IAP settings readable only at project level (no per-resource settings enumerated).
- GKE workloads not inspected (no kubectl). GKE ingress LBs for globus, n8n, wildpacks exist in this project.
- No secret values read.

## qa

### Terraform compared with live state

| Resource type | Live | In Terraform | Matched | Live only (unmanaged) | Platform-created | Terraform only | Name not resolvable |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `api` | 59 | 53 | 53 | 6 | 0 | 0 | 0 |
| `cloud_run_service` | 11 | 8 | 10 | 1 | 0 | 0 | 0 |
| `cloud_run_job` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `cloud_sql` | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
| `redis` | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| `firestore` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `bucket` | 8 | 4 | 4 | 2 | 2 | 0 | 0 |
| `secret` | 97 | 93 | 93 | 4 | 0 | 0 | 0 |
| `service_account` | 21 | 17 | 17 | 3 | 1 | 0 | 0 |
| `wif_pool` | 4 | 4 | 3 | 1 | 0 | 0 | 1 |
| `artifact_registry` | 8 | 7 | 7 | 1 | 0 | 0 | 0 |
| `cloudbuild_trigger` | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| `pubsub_topic` | 5 | 0 | 0 | 1 | 4 | 0 | 0 |
| `scheduler_job` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `gke_cluster` | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| `domain_mapping` | 5 | 1 | 1 | 4 | 0 | 0 | 0 |
| `firewall_rule` | 7 | 2 | 2 | 0 | 5 | 0 | 0 |
| `vpc_network` | 2 | 2 | 2 | 0 | 0 | 0 | 0 |

### Live but not in Terraform

23 resources of the compared types exist in the project without a matching Terraform declaration.

| Resource type | Name |
| --- | --- |
| `api` | `apikeys` |
| `api` | `cloudasset` |
| `api` | `cloudkms` |
| `api` | `cloudscheduler` |
| `api` | `distance-matrix-backend` |
| `api` | `orgpolicy` |
| `cloud_run_service` | `db-query-proxy-qa` |
| `bucket` | `host-portal-db-backups-qa` |
| `bucket` | `host-portal-public-assets-qa` |
| `secret` | `db-query-proxy-qa-db-password` |
| `secret` | `db-query-proxy-qa-token` |
| `secret` | `globus-qa-template-admin-sendgrid-key` |
| `secret` | `n8n-qa-hubspot-webhook-secret` |
| `service_account` | `db-query-proxy-qa-runtime` |
| `service_account` | `karin-proxy-caller-qa` |
| `service_account` | `manus-agent-sa` |
| `wif_pool` | `github-actions-sandbox` |
| `artifact_registry` | `db-query-proxy` |
| `pubsub_topic` | `secret-rotation-notifications` |
| `domain_mapping` | `qa-1.sandbox.allianceabroad.com` |
| `domain_mapping` | `qa-2.sandbox.allianceabroad.com` |
| `domain_mapping` | `qa-3.sandbox.allianceabroad.com` |
| `domain_mapping` | `qa.apply.wildpacks.com` |

### In Terraform but not found live

_None._

### Created by GCP or GKE

These are created by the platform itself (default network rules, GKE firewall rules, default compute service accounts, Cloud Build buckets, container analysis topics) and are not drift.

| Resource type | Name |
| --- | --- |
| `bucket` | `qa-cloudbuild-staging-496022` |
| `bucket` | `quality-assurance-496022_cloudbuild` |
| `service_account` | `735345320299-compute` |
| `pubsub_topic` | `container-analysis-notes-v1` |
| `pubsub_topic` | `container-analysis-notes-v1beta1` |
| `pubsub_topic` | `container-analysis-occurrences-v1` |
| `pubsub_topic` | `container-analysis-occurrences-v1beta1` |
| `firewall_rule` | `gke-globus-cluster-qa-0b3cf4aa-all` |
| `firewall_rule` | `gke-globus-cluster-qa-0b3cf4aa-exkubelet` |
| `firewall_rule` | `gke-globus-cluster-qa-0b3cf4aa-inkubelet` |
| `firewall_rule` | `gke-globus-cluster-qa-0b3cf4aa-vms` |
| `firewall_rule` | `k8s-fw-l7--2188e7542740cb43` |

### Terraform items whose name is computed at plan time

These could not be matched by name, so they are not counted as matched or missing.

| Resource type | Terraform address | Defined in |
| --- | --- | --- |
| `wif_pool` | `google_iam_workload_identity_pool.sandbox` | `branching-sandbox.tf:60` |

### Resource types not compared

_None._

### Live reads that were denied or unavailable

| Read attempted | Result |
| --- | --- |
| billing info (gcloud billing projects describe) | cloudbilling.googleapis.com not enabled on project 735345320299; billing linked state unknown |
| Firestore databases list | firestore.googleapis.com not enabled on quality-assurance-496022 (treated as none; datastore.googleapis.com is enabled) |
| Certificate Manager certificates/maps | certificatemanager.googleapis.com not enabled (none) |
| Cloud Deploy pipelines | clouddeploy.googleapis.com not enabled (none) |
| IAP settings | iap.googleapis.com not enabled (none) |

### Collection notes

Caveats recorded when the live snapshot was read.

- Cloud Run jobs: none listed. Cloud Scheduler: none in us-central1 or northamerica-northeast1. Cloud Armor: none. Pub/Sub subscriptions: none.
- Cloud Build triggers: global region empty; the only trigger is wildpacks-qa in us-central1. Connection repos include ParticipantPortalPrototype (archived repo).
- Cloud SQL globus-db-qa contains a database named globus_staging (naming only).
- IAM contains a deleted SA member (db-query-proxy-qa-sa) on roles/cloudsql.client, and a temp external user [user account] with viewer/logging.viewer/cloudsql.instanceUser.
- mishkin-db-export-import SA holds roles/owner on the project.
- Cert mcrt-4bc55357 (qa.hosts.allianceabroad.com) on the GKE globus ingress proxy is PROVISIONING; host-portal-qa-cert (LB) is ACTIVE for the same domain.
- Host portal has both a Cloud Run + external-managed LB path (host-portal-qa-*) and a GKE ingress cert for qa.hosts.allianceabroad.com.
- Artifact Registry locations were not captured per repo (list output omitted location); inferred from image paths where marked.
- VPC connector regions were not captured; inferred from service usage.
- Subnet list: 46 total = 42 auto-mode default-network subnets + 4 custom on skilled-script-vpc-qa.
- Run via gcp_gcp_shell_exec (environment=qa); only read-only list/describe commands used. No secret values read.
- collected_at is date-only approximate (2026-10-01).

## vertex

### Terraform compared with live state

| Resource type | Live | In Terraform | Matched | Live only (unmanaged) | Platform-created | Terraform only | Name not resolvable |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `api` | 40 | 36 | 35 | 5 | 0 | 1 | 0 |
| `cloud_run_service` | 11 | 0 | 0 | 11 | 0 | 0 | 0 |
| `cloud_run_job` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `cloud_sql` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `firestore` | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| `bucket` | 3 | 0 | 0 | 1 | 2 | 0 | 0 |
| `secret` | 35 | 3 | 2 | 33 | 0 | 1 | 0 |
| `service_account` | 15 | 10 | 7 | 7 | 1 | 3 | 0 |
| `wif_pool` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `artifact_registry` | 2 | 0 | 0 | 1 | 1 | 0 | 0 |
| `cloudbuild_trigger` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| `pubsub_topic` | 5 | 1 | 1 | 0 | 4 | 0 | 0 |
| `scheduler_job` | 2 | 0 | 0 | 2 | 0 | 0 | 0 |
| `domain_mapping` | 0 | 0 | 0 | 0 | 0 | 0 | 0 |

### Live but not in Terraform

61 resources of the compared types exist in the project without a matching Terraform declaration.

| Resource type | Name |
| --- | --- |
| `api` | `cloudasset` |
| `api` | `dlp` |
| `api` | `firebaserules` |
| `api` | `firestore` |
| `api` | `recommender` |
| `cloud_run_service` | `asana-hygiene-agent` |
| `cloud_run_service` | `branch-drift-agent` |
| `cloud_run_service` | `cloudbuild-teams-notifier` |
| `cloud_run_service` | `dev-to-qa-sync-agent` |
| `cloud_run_service` | `env-audit-agent` |
| `cloud_run_service` | `github-token-minter` |
| `cloud_run_service` | `posthog-agent` |
| `cloud_run_service` | `pr-hygiene-agent` |
| `cloud_run_service` | `qa-to-prod-sync-agent` |
| `cloud_run_service` | `security-agent` |
| `cloud_run_service` | `vertex-sync-agent` |
| `firestore` | `(default)` |
| `bucket` | `platform-agents-tfstate-alliance-platform-agents` |
| `secret` | `POSTHOG_PERSONAL_API_KEY` |
| `secret` | `asana-hygiene-agent-api-key` |
| `secret` | `asana-hygiene-agent-gateway-pat` |
| `secret` | `branch-drift-agent-api-key` |
| `secret` | `branch-drift-agent-gateway-pat` |
| `secret` | `branch-drift-agent-known-issues` |
| `secret` | `dev-to-qa-sync-agent-api-key` |
| `secret` | `dev-to-qa-sync-agent-gateway-pat` |
| `secret` | `dev-to-qa-sync-agent-state` |
| `secret` | `env-audit-agent-api-key` |
| `secret` | `env-audit-agent-gateway-pat` |
| `secret` | `globus-development-asana-access-token` |
| `secret` | `n8n-api-key` |
| `secret` | `observer-agent-v2-api-key` |
| `secret` | `observer-agent-v2-gateway-pat` |
| `secret` | `overseer-agent-api-key` |
| `secret` | `overseer-agent-gateway-pat` |
| `secret` | `overseer-agent-known-issues` |
| `secret` | `overseer-agent-n8n-sync-state` |
| `secret` | `overseer-agent-openai-api-key` |
| `secret` | `platform-bot-github-pat` |
| `secret` | `posthog-agent-api-key` |
| `secret` | `posthog-agent-gateway-pat` |
| `secret` | `pr-hygiene-agent-asana-pat` |
| `secret` | `qa-to-prod-sync-agent-api-key` |
| `secret` | `qa-to-prod-sync-agent-gateway-pat` |
| `secret` | `security-agent-api-key` |
| `secret` | `security-agent-gateway-pat` |
| `secret` | `security-agent-iac-scan-github-token` |
| `secret` | `security-agent-openai-api-key` |
| `secret` | `teams-platform-pulse-webhook-url` |
| `secret` | `vertex-sync-agent-api-key` |
| `secret` | `vertex-sync-agent-gateway-pat` |
| `service_account` | `cloudbuild-teams-notifier-sa` |
| `service_account` | `github-token-minter-sa` |
| `service_account` | `manus-agent-sa` |
| `service_account` | `observer-agent-v2-sa` |
| `service_account` | `overseer-agent-sa` |
| `service_account` | `pr-hygiene-agent-sa` |
| `service_account` | `qa-to-prod-sync-agent-sa` |
| `artifact_registry` | `alliance-abroad` |
| `scheduler_job` | `branch-drift-agent-scan` |
| `scheduler_job` | `vertex-sync-agent-hourly` |

### In Terraform but not found live

| Resource type | Name | Terraform address | Defined in |
| --- | --- | --- | --- |
| `api` | `container` | `module.project_services_agents` | `main.tf:159` |
| `secret` | `pr-hygiene-agent-known-issues` | `module.pr_hygiene_agent_known_issues` | `main.tf:466` |
| `service_account` | `pr-hygiene-agent` | `module.pr_hygiene_agent_sa` | `main.tf:299` |
| `service_account` | `branch-drift-scheduler` | `module.branch_drift_scheduler` | `main.tf:322` |
| `service_account` | `cloudbuild-teams-notifier` | `module.cloudbuild_teams_notifier_development` | `main.tf:380` |

### Created by GCP or GKE

These are created by the platform itself (default network rules, GKE firewall rules, default compute service accounts, Cloud Build buckets, container analysis topics) and are not drift.

| Resource type | Name |
| --- | --- |
| `bucket` | `alliance-platform-agents_cloudbuild` |
| `bucket` | `run-sources-alliance-platform-agents-us-central1` |
| `service_account` | `668649570162-compute` |
| `artifact_registry` | `cloud-run-source-deploy` |
| `pubsub_topic` | `container-analysis-notes-v1` |
| `pubsub_topic` | `container-analysis-notes-v1beta1` |
| `pubsub_topic` | `container-analysis-occurrences-v1` |
| `pubsub_topic` | `container-analysis-occurrences-v1beta1` |

### Resource types not compared

| Resource type | Reason | Declared in Terraform |
| --- | --- | --- |
| `redis` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `gke_cluster` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `firewall_rule` | snapshot section unreadable (denied, API disabled or not collected) | 0 |
| `vpc_network` | snapshot section unreadable (denied, API disabled or not collected) | 0 |

### Live reads that were denied or unavailable

| Read attempted | Result |
| --- | --- |
| gcloud billing projects describe | cloudbilling.googleapis.com not enabled on project 668649570162 (SERVICE_DISABLED) |
| gcloud redis instances list | redis.googleapis.com not enabled (treated as no Redis) |
| gcloud compute networks/subnets/firewall/etc. (network, load_balancing) | compute.googleapis.com not enabled; networking not enumerable. No vpc connector on any Cloud Run service. |
| gcloud dns managed-zones list | dns.googleapis.com not enabled |
| gcloud container clusters list | container.googleapis.com not enabled (no GKE) |
| gcloud services api-keys list | apikeys.googleapis.com not enabled on project 668649570162 |
| gcloud deploy delivery-pipelines list | clouddeploy.googleapis.com not enabled |
| first combined gcloud projects describe + services list call | gateway: backend request failed (retried OK as separate calls) |

### Collection notes

Caveats recorded when the live snapshot was read.

- Run via gateway env=agents (read-only). Cloud Run listed across all regions: all 11 in us-central1.
- WIF pools, build triggers, Cloud Build connections (us-central1 only checked), Cloud SQL, Cloud Run jobs, domain mappings (us-central1 only checked) are empty.
- Cloud Run secret env refs recorded as names only; some secrets referenced cross-project (projects/382570452229/secrets/...) via run.googleapis.com/secrets annotation.
- Secrets have no labels, automatic replication.
- SAs overseer-agent-sa and observer-agent-v2-sa exist (with secrets) but no Cloud Run service for them is deployed.
- Project owner is user [user account]; cross-project principals gcp-mcp-sa@alliance-mcp-services and github-actions-deploy@skilled-script-469819-f2 hold run.developer/storage.admin etc.

## Reading the tables

Start with the summary table: one row per environment with live, matched, unmanaged, Terraform-only and platform-created counts, and the number of types not compared. Then use the per-environment tables.

- A large live-only count in one type (secrets, service accounts) usually means a group of resources created together outside Terraform, not many unrelated accidents. Read the names for the shared prefix.
- Terraform-only items are worth a look first. They are either never applied (the apply is gated, as in production and mcp), already deleted by hand, or named differently from what the comparison derives.
- The "not compared" table lists the resource types that were not checked in that project. Compare it with the denied-reads table before trusting a project's totals.
- Collection notes are caveats written when the snapshot was taken. They are facts about the project, not findings of the comparison.

The matching is by name only. It does not compare settings (a bucket's lifecycle, a service's ingress or scaling, an IAM binding). A matched resource can still differ from its declaration. IAM bindings, DNS records, secret values, database schemas and users are outside the comparison entirely, and the first two are only partly visible in the snapshots.

## How much to trust each result

All reads were made through the gateway, whose GCP tools expose only the development, qa, prod and agents environments.

| Project | Environment in this report | What was readable | Confidence |
|---|---|---|---|
| `skilled-script-469819-f2` | development | Almost everything, including IAM. GKE contents (kubectl) were not read. Three combined calls failed and were retried in pieces. | High for names, none for in-cluster state |
| `quality-assurance-496022` | qa | Almost everything. Billing, Firestore (API off), Certificate Manager, Cloud Deploy and IAP are not enabled or readable. | High |
| `production-499116` | production | Most types. Firestore and Scheduler are not enabled and treated as none. Cloud Build triggers were checked in the global scope only, and domain mappings in two regions. | High, with two types not compared |
| `alliance-mcp-services` | mcp | Read with a development-environment token. Project IAM, WIF pools, Cloud SQL, buckets, Artifact Registry, Pub/Sub, DNS, API keys and Cloud Build triggers were denied. | Partial: Cloud Run, secrets, service accounts, GKE, firewall only |
| `alliance-platform-agents` | vertex | Read through the agents environment. Compute, GKE, DNS and API keys are not enabled. | Good for Cloud Run, secrets, service accounts, Pub/Sub, Scheduler |
| `alliance-platform-services` | platform-services | Nothing. The project could not be read at all. | None |

For `alliance-platform-services` every Terraform-declared item shows as "Terraform only" only because there is no live data. That is not evidence it is missing. The same caution applies to the unreadable mcp types: their declared items (for example Cloud SQL, WIF pools and Artifact Registry repositories) are unchecked.

## Main patterns of drift

### Development

The development project has the most drift and the widest gap between what runs and what is declared.

- **Agent services deployed outside Terraform.** Nine of the eighteen Cloud Run services have no declaration, and they are the scheduled and event-driven agents (bug diagnosis, docs update, GKE workload health, OpenStatus alert, PR latency, PR review eligibility, secrets drift, user addition) plus the GCP MCP server. Many of their service accounts (23 service accounts in total are live-only) and five Firestore databases follow the same pattern. Four Terraform Firestore modules are declared but their names are computed, so they appear as unresolved rather than matched.
- **Prod- and staging-named resources in the development project.** The project holds buckets and a network endpoint group with `prod` or `staging` in the name, a state bucket named for prod, and IAM bindings for the production and qa service accounts. There is no staging environment (see `/docs/gcp-naming-conventions`), so these are leftovers or cross-wiring to be reviewed.
- **Stale virtual-interviews leftovers.** A certificate, a network endpoint group and a Cloud Armor policy remain from the decommissioned virtual-interviews system, along with deleted IAM principals.
- **Missing domain-mapping declarations.** All seven live domain mappings (the sandbox slots, the apply hosts and the nexus host) have no Terraform declaration. One of them points at a service that does not exist in the project.
- **Secrets.** 65 live secrets have no matching declaration and one declared bulk-secret module is unresolved.
- **Certificates stuck PROVISIONING.** Two certificates are stuck in provisioning, one unattached and one belonging to the decommissioned virtual-interviews system.

### QA

QA is close to its declaration. The live-only items include the `db-query-proxy-qa` Cloud Run service with its runtime service account, secrets and Artifact Registry repository, three service accounts in all, four sandbox and wildpacks domain mappings, four secrets and two buckets. The certificate `mcrt-4bc55357` for `qa.hosts.allianceabroad.com` on the GKE ingress is PROVISIONING while the load-balancer certificate for the same domain is ACTIVE, because the host portal exists on both a Cloud Run path and a GKE path (see `/docs/gcp-env-qa`).

### Production

Production has the least drift: every Cloud Run service, database, Redis instance and GKE cluster is matched. Remaining differences are small: three buckets, three service accounts (including the Manus agent account and the data-lake account), one secret, the `github-actions-sandbox` WIF pool (the sandbox module declares a pool whose name is computed, so it is unresolved rather than matched), the sandbox domain mapping and a Pub/Sub topic. Two Certificate Manager certificates for the host portal domains are PROVISIONING. A declared Cloud Build trigger (`wildpacks-prod`) is not found live, but triggers were checked in the global scope only (the GitHub connection is in us-central1), so this may be a read gap.

### MCP

The unmanaged Cloud Run services are `itrequest-mcp`, `replitmcp` and `wordpress-mcp`, plus the GKE cluster that runs OpenStatus, one domain mapping (not Ready) and 16 secrets. Secret names with a `mcp-production-` prefix exist next to `mcp-development-` ones even though MCP servers are meant to be a single, non-environment-specific instance.

### Agents project

All eleven Cloud Run services in `alliance-platform-agents` are live-only: none is declared. Seven of fifteen service accounts and 33 of 35 secrets are also live-only, while three declared service accounts are not found live. Two agent service accounts have secrets but no deployed service. The existing Firestore database, two Scheduler jobs and an Artifact Registry repository are also unmanaged.

### Platform services

No pattern can be stated. See the trust table above.

## The standing rule

Everything must be in Terraform. Resources created through the console, `gcloud`, an agent or a one-off script are drift by definition, even when they work. Terraform for development and qa applies on merge, so a missing declaration is a pull request away. Production and mcp apply only by manual dispatch with a typed phrase. The pull request plan check is read-only and does not fail its job when `terraform plan` errors (the failure is only reported in the comment it posts), so a green plan check can hide a failed plan (see `/docs/gcp-terraform-workflows`). Do not treat a clean plan as proof of no drift: this comparison is the only check that looks for resources Terraform does not know about.

The standing way to close a live-only item is one of three actions: add a declaration (import it if it must not be recreated), delete the resource, or record a reason it cannot be managed. Secret values, database schemas and users, and runtime bootstrap are not Terraform's job and are not drift.

## Re-running the check

From the root of the `nexus-parity` workspace, with the repo cloned under `code/alliance-gcp-infra` and fresh snapshots in `data/gcp/live`:

```
node harness/gcp/iac.mjs      # parse the Terraform repo -> data/gcp/iac-inventory.json
node harness/gcp/diff.mjs     # compare with live snapshots -> data/gcp/drift.json
node harness/gcp/gen.mjs      # assemble the generated pages -> data/gcp/out
node harness/gcp/check.mjs    # validate the generated output
```

Refresh the live snapshots first, or the comparison reports the old state. Snapshot files hold names only and must never contain secret values. A project with no readable snapshot is reported as not verified, not as clean.

## Security observations

These are facts taken from the collection notes of the snapshots, not conclusions. They should be reviewed by someone who can confirm each against the live project.

- **Development, external access.** Several users from external company domains hold project roles: one with BigQuery admin and service-account creator, two from another domain with storage admin, and one with viewer and browser. A temporary-domain Google account also has project access. Owner is held by named staff users and by the Manus agent service account, and the default compute and cloud-services service accounts hold the editor role.
- **Development, exposure.** The `globus-db-development` and `mcp-db-development` Cloud SQL instances have public IPv4 enabled. Every Cloud Run service has ingress set to all. One firewall rule allows SSH from a single address, and the GKE-managed kubelet rule has source `0.0.0.0/0`.
- **Development, keys and stores.** The `dev-globus-maps-rot-20260314-v3` API key has no API restriction. Both Redis instances are BASIC tier with no persistence or HA, and the `keycloackparticipant` instance has transit encryption disabled. The `bug-diagnosis-agent` Firestore database has delete protection off.
- **Development, stale access.** Deleted principals remain in IAM (`vi-gke-nodes`, `virtual-interviews-sa`, `ci-failure-alert-agent`). Two Cloud Build triggers are disabled and the trigger for the archived participant portal repo is still active.
- **QA.** A temporary-domain account holds viewer, logging viewer and Cloud SQL instance user. A database export/import service account holds the owner role. A deleted principal (`db-query-proxy-qa-sa`) still holds `roles/cloudsql.client`. The Cloud SQL instance `globus-db-qa` contains a database named `globus_staging`.
- **MCP.** `hubspot-mcp` references a secret that is absent from the project's Secret Manager list. The `teams-mcp.mcp.allianceabroad.com` mapping is not Ready. Several images are pulled from the development Artifact Registry, so the mcp project depends on the development project. Project IAM could not be read.
- **Agents project.** The project owner is a user account, and service accounts from the mcp and development projects hold `run.developer` and `storage.admin`. Some Cloud Run services reference secrets in another project by path. Secrets carry no labels.
- **Production.** No security findings were recorded in the snapshot notes, but project IAM was not summarised there. Absence of notes is not absence of findings.

## Known gaps

- `alliance-platform-services` could not be read at all, and `alliance-mcp-services` was read through a development token with many sections denied. Their results are partial or empty.
- Comparison is by name only. Attribute drift, IAM and DNS drift are not measured.
- The repo `README.md` still says development and production are not under Terraform. That is stale: both have `.tf` files, workflows and matched resources above.
- See `/docs/repo-inventory` for the repo's role. Snapshot dates are in the provenance line of the tables.
