Snapshots

Arata's Meta and Shopify are never disconnected, and code refuses to try

Waiting on you
  • PROTECTED_CONNECTIONS makes the code refuse disconnect, reconnect and re-select for listed brands.
  • Arata is connected on both sites because the vault was copied, never reconnected.
  • The guard cannot stop revoking the app at Meta or Shopify itself.
  • Ping jobs read the sign-ins without printing any token.
  • Only Arata is protected today; the other four partners are not.
22 OctParam's rule on Arata's Meta
Your call

Protect the other four partners too, and keep force on production?

Ops and infrastructure · 8.10

Protected connections

DraftLast checked 2026-10-26Owner Param

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.sh and tools/flush-live.sh still have no protected check, but since 26 Oct they exit 3 unless STORAGE=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 force path 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

  1. Before any script that touches private/vault/, connections.json or a disconnect, check it skips every protected brand.
  2. 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

  1. 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.
  2. Should force exist at all on production? Proposal: keep it for Param only, log every use, and require a note saying why.
Sources
  • brew origin/main d6154b3: db/brand-wipe.js:8-32, 235, db/delete-brand.mjs:10, test/brand-wipe-pg.test.js:61-79, connectors/protected.js:1-4, connectors/index.js:70, 148, 269, 429, vault.js:27, tools/prod-env.sh:9, db/connector-ping.mjs:1-24, db/status.mjs:1-15, db/reset-jams.mjs:7, 18-19, db/partner-copy.js:6-8, test/qv1-roles-security.test.js
  • brew/.wt-prod/docs/production.md:21, 50
  • memory never-disconnect-arata-meta, brew-shopify-connector-qa, brew-prod-backend, brew-live-stores, brew-wipe-data, brew-meta-connector-qa (index line)

Source file content/ops-and-infrastructure/protected-connections.md · For agents: Markdown · JSON