Answer
Arata's Meta and Shopify connections are never disconnected, reconnected, re-selected or revoked, on either site, and the code refuses those actions for any brand listed in PROTECTED_CONNECTIONS; this page says what the guard covers, what it does not, and how to check the connections are still alive.
Today
The rule
- Never disconnect, reconnect or re-select Arata's Meta connector, in any case. Param, 22 Oct. memory never-disconnect-arata-meta
- Never disconnect Arata's Shopify. memory brew-shopify-connector-qa
- Never revoke Meta grants. memory brew-meta-connector-qa
- Arata stays connected on both staging and production: the vault was copied, never reconnected. memory brew-prod-backend brew/.wt-prod/docs/production.md:21
- Disconnect and reconnect tests run only on Cozy Snugglet. memory never-disconnect-arata-meta memory brew-live-stores
What Arata has connected
| Account | How | Why it can be shared by both sites | Source |
|---|---|---|---|
| Meta Ads, ad account act_2942894532542334 | OAuth on the SquareUp Meta app, connected 22 Oct | Meta token never refreshes | memory never-disconnect-arata-meta brew/db/partner-copy.js:6-8 |
| Shopify | Arata's own app, route own-oauth, offline token |
Token never expires or refreshes | memory brew-shopify-connector-qa brew/db/partner-copy.js:6-8 |
If Arata's Shopify token ever starts rotating, production becomes the only refresher and staging uses a token broker. memory brew-prod-backend
The guard in code
| Layer | What it refuses | Source |
|---|---|---|
PROTECTED_CONNECTIONS |
List of protected brands; default arata-in when unset; production sets it to arata-in |
brew/connectors/protected.js:1-4 brew/tools/prod-env.sh:9 |
| Connector routes | disconnect, select, key, connect on an existing protected connection, unless a root admin sends force: true |
brew/connectors/index.js:429 |
| Replacing a connection | Refused for a protected brand unless forced by a root admin | brew/connectors/index.js:148 |
| Disconnect function | Refused for a protected brand unless forced | brew/connectors/index.js:269 |
| Vault | A protected brand's stored sign-in is never replaced, except a refresh or a force | brew/vault.js:27 |
| Jam reset | Refuses to write connections, vault or live paths | brew/db/reset-jams.mjs:7 brew/db/reset-jams.mjs:18-19 |
Brand reset, db/reset-brand.mjs |
Keeps connections, vault, live numbers and the connected ledger, and fails the run if they changed by a byte | brew/db/brand-wipe.js:15-17, 235 |
Data request deletion, db/delete-brand.mjs |
Refuses any brand in PROTECTED_CONNECTIONS; take it out of the setting first, deliberately |
brew/db/brand-wipe.js:27; brew/db/delete-brand.mjs:10 |
| Both brand tools | Refuse the five design partners unless --partner-override --confirm-slug <slug> |
brew/db/brand-wipe.js:28-30; brew/test/brand-wipe-pg.test.js:61 |
| Shopify webhooks | Uninstall and redact disconnect only app:'brew' connections, so Arata's own app is untouched |
memory brew-shopify-connector-qa |
| Tests | QV round 1 found the guard could be bypassed and fixed it with a test | memory brew-prod-backend brew/test/qv1-roles-security.test.js |
What the guard does not cover
- Provider-side grants: revoking the app at Meta or Shopify is outside our code. memory brew-wipe-data
- The bucket scripts
tools/reset-brand.shandtools/flush-live.shstill have no protected check, but since 26 Oct they exit 3 unlessSTORAGE=gcs, so they cannot run against what the sites read. brew/tools/reset-brand.sh:11-19; brew/tools/flush-live.sh:17-26 - A deletion never revokes a platform grant; it prints the grants the brand revokes itself. brew/db/brand-wipe.js:7, 240
- The
forcepath is open to root admins. brew/connectors/index.js:429
Tomorrow
| Item | Version | Tag |
|---|---|---|
| Arata protected on both sites | v1 | Stays |
| Every design partner protected once its accounts are connected | v1 | Changes, see Open |
| Wipe tools that refuse protected brands in code, on origin/main since 26 Oct | v1 | Stays |
| A daily ping of protected sign-ins, alerting when one stops reading | v1 | New |
| Token broker for rotating tokens shared by two sites | v2 | New, only if a token starts rotating |
How we do it
- Before any script that touches
private/vault/,connections.jsonor a disconnect, check it skips every protected brand. - Check the connections still read, read only, no token printed:
gcloud run jobs execute brew-prod-ping --region=asia-south1 --wait
gcloud run jobs execute brew-staging-ping --region=asia-south1 --wait
gcloud run jobs execute brew-ops --region=asia-south1 --wait
The ping jobs run db/connector-ping.mjs arata-in; brew-ops runs db/status.mjs, which lists every protected brand's connection states. brew/db/connector-ping.mjs:1-4 brew/db/status.mjs:1-2 memory brew-prod-backend
3. After a database restore, run the production ping. Never reconnect Arata to fix a failed ping; tell Param. brew/.wt-prod/docs/production.md:50
4. To protect another brand, add its slug to PROTECTED_CONNECTIONS in tools/prod-env.sh and deploy.sh, then deploy and promote.
Numbers
| Metric | Definition | Where measured |
|---|---|---|
| Protected sign-ins reading | Protected accounts whose ping succeeds, out of all | db/connector-ping.mjs; Proposed as a daily job |
| Forced actions | Times a root admin used force on a protected brand |
Proposed: access log |
Open
- Protect the other four partners too? Today only Arata is listed. Proposal: add each partner the day it connects its first real account, starting with Nutrova.
- Should
forceexist at all on production? Proposal: keep it for Param only, log every use, and require a note saying why.