Answer
Every key Brew uses lives in Google Secret Manager in project squareup-492617 and reaches a service only by name at deploy time, production has its own copies of the four that protect sign-ins and data, and this page names each secret and where it is used, never its value; who rotates what is still Param's call.
Today
Where secrets live
- Google Secret Manager, project squareup-492617. Services read them as
NAME:latestat deploy. brew/deploy.sh:42 brew/tools/prod-env.sh:10 - Production runs as
brew-prod-runtime@; staging, the demo and the ops jobs run asbrew-runtime@and cannot read production's secrets or data. brew/tools/prod-env.sh:5-6 - Brands' own sign-ins are not secrets in Secret Manager: they are encrypted with the vault key and stored per brand under
private/vault/. brew/db/connector-ping.mjs:11 memory brew-storage - Locally, keys come from
../ugc-factory/.env, or the file named inENV_FILE. brew/README.md
Secrets by site
| Secret | What it is for | Staging | Production | Demo | Source |
|---|---|---|---|---|---|
BREW_STAGING_DATABASE_URL |
Staging Postgres | yes | brew/deploy.sh:42 | ||
BREW_PROD_DATABASE_URL |
Production Postgres | yes | brew/tools/prod-env.sh:10 | ||
FEED_SESSION_SECRET / _PROD |
Signs sign-in sessions | plain | _PROD |
plain | brew/deploy.sh:42 brew/tools/prod-env.sh:10 brew/tools/deploy-demo.sh:17 |
HANDOFF_SECRET / _PROD |
Signs hand-off links | plain | _PROD |
plain | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
FEED_VAULT_KEY / _PROD |
Encrypts each brand's stored sign-ins | plain | _PROD |
brew/deploy.sh:42 brew/tools/prod-env.sh:10 | |
ANTHROPIC_API_KEY |
Claude | yes | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
OPENAI_API_KEY |
OpenAI fallback for media | yes | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
TREG_TOKEN |
treg data calls | yes | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
YOUTUBE_API_KEY |
YouTube comments for listening | yes | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
PAGESPEED_API_KEY |
Site speed reads | yes | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
RESEND_API_KEY |
Team emails | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 | |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET |
Google sign-in | yes | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 |
GOOGLE_ADS_OAUTH_CLIENT_ID, _SECRET, GOOGLE_ADS_DEVELOPER_TOKEN |
Google Ads and GA4 connect | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 | |
META_ADS_OAUTH_CLIENT_ID, _SECRET |
Meta connect | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 | |
FEED_SHOPIFY_CLIENT_ID, _SECRET |
Shopify app | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 | |
SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRET |
Slack app | yes | yes | brew/deploy.sh:42 brew/tools/prod-env.sh:10 | |
APIFY_TOKEN |
Apify, added only if the secret exists | yes | yes | brew/deploy.sh:38 brew/tools/prod-env.sh:11 | |
HF_API_KEY_ID, HF_API_KEY_SECRET |
Higgsfield, added only if both exist | yes | yes | brew/deploy.sh:37 brew/tools/prod-env.sh:12 | |
CLOUDFLARE_DNS_ONBOARDING_TOKEN |
Cloudflare DNS changes by script | ops only | memory brew-demo-mode |
Ops jobs
brew-partner-copyruns as its own service account and reads both vault keys and both database URLs; it refuses to run if the two vault keys are equal. brew/tools/partner-copy.sh:13-16 brew/db/migrate-to-prod.mjs:19-20brew-prod-migrateandbrew-prod-cleanread onlyBREW_PROD_DATABASE_URL. brew/tools/promote.sh:65-66 brew/tools/promote.sh:85-86brew-backuphas a custom export-only role. memory brew-prod-backend
Known key history
| When | What | Source |
|---|---|---|
| 20 Oct | New Anthropic key, ANTHROPIC_API_KEY version 3; the key ran out of credit the same morning |
memory brew-pro-switch-and-flush |
| about 23 Oct | Old treg key died with 401s; TREG_TOKEN version 2 is an agent key brew-live on team squareup, capped at 20k calls a day; version 1 disabled |
memory brew-apify-watch |
| 23 Oct | APIFY_TOKEN added with the Apify Starter plan |
memory brew-apify-watch |
| 25 Oct | Production got its own session, vault and hand-off secrets | memory brew-prod-backend |
The handbook's own
- Deploys of the docs and the handbook use the person's own gcloud sign-in token, nothing stored. brand-directions/_tools/deploy-handbook.py:61-62
- The comments service checks Cloudflare Access's signed identity; it needs
CF_TEAM_DOMAIN,CF_ACCESS_AUDandALLOWED_EMAILS, which are settings, not secrets. It reads Firestore as its runtime account. handbook/comments/server.mjs:1-15 - Claude's side reads the same Firestore through Google sign-in on the Mac. handbook/tools/comments.mjs:1-13
A known gap
The default compute service account has project-wide secret access and Cloud Run admin, which reaches about 15 other services. Raised as open for Param on 25 Oct. memory brew-prod-backend
Tomorrow
| Item | Version | Tag |
|---|---|---|
| Secret Manager, names only in code, production's own copies of the four | v1 | Stays |
| One named owner and a rotation date per secret | v1 | New |
| Separate production keys for Anthropic, OpenAI and treg, so spend and leaks are told apart | v2 | New |
| Default compute account stripped of project-wide secret access | v1 | Changes |
How we do it
- Never paste a secret value in chat, code, the handbook or a log. Refer to it by name.
- Add a new key:
printf '%s' "<value>" | gcloud secrets create <NAME> --data-file=- --project=squareup-492617
- Rotate a key: add a version, deploy staging, promote production, then disable the old version.
printf '%s' "<new value>" | gcloud secrets versions add <NAME> --data-file=- --project=squareup-492617
gcloud secrets versions disable <old version> --secret=<NAME> --project=squareup-492617
- Never rotate
FEED_VAULT_KEYorFEED_VAULT_KEY_PRODby adding a version alone: every stored brand sign-in is encrypted with it. A vault key change needs a re-encrypt job like the partner copy, and Arata's sign-ins must survive it. brew/db/migrate-to-prod.mjs:19-20 brew/connectors/protected.js:1-4 - Rotating
FEED_SESSION_SECRET_PRODsigns everyone out of production; tell the partners first.
Numbers
| Metric | Definition | Where measured |
|---|---|---|
| Secrets without an owner | Names in the table with no owner set | This page, Proposed; all of them today |
| Oldest secret version in use | Days since the serving version was made | gcloud secrets versions list, Proposed |
Open
- Who rotates which secret? No source names anyone. Proposal: Param owns every secret for now; Claude may add versions only when Param asks in chat; a review every quarter starting January 2027.
- Should production have its own AI and data keys? Today staging, production and the demo share
ANTHROPIC_API_KEY,OPENAI_API_KEYandTREG_TOKEN. Proposal: yes for treg and Anthropic before the first paying partner, so a staging leak or runaway test cannot spend production's balance. - Fix the default compute account's access? Proposal: yes, remove project-wide secret accessor and give each of the 15 services its own account, in one planned session.