OctoWiki

Secrets & Configuration

Where every credential, secret, and config value lives across the platform — and how to rotate each one.

This page inventories every secret store so the repo is self-contained: a new operator can find (and rotate) any credential without tribal knowledge. No live secret values are copied here — instead each entry says exactly where the value lives and how it's generated/rotated.

A live credential is committed in this repo

.claude/settings.local.json contains a real sandbox Postgres password in plaintext (inside pre-approved PGPASSWORD=… psql -h 94.130.137.222 … allow-list entries), and frontend/grasshopper/wrangler.jsonc commits several sandbox worker secrets under env.sandbox.vars. These are documented here deliberately (so the repo is self-contained), but they should be rotated and future secrets should never be committed. See rotation.

The secret stores at a glance

1. Backend env files (/etc/octopus{,-sandbox}/octopus.env)

Generated once by deploy/setup-octopus-service.sh (prod) / setup-octopus-sandbox-service.sh (sandbox), which mint random secrets with openssl. File perms 640, dir root:octopus 750. update-octopus.sh appends any missing keys ("drift-fix") but never overwrites existing values.

KeyPurposeSource / rotation
JWT_SECRETSigns API + portal + G2A JWTsopenssl rand -base64 64 at setup. Rotating invalidates all live tokens.
APP_KEYAES key for encrypting Shopify tokens & voucher dataopenssl rand -base64 32. Rotating breaks decryption of existing encrypted DB values — re-encrypt first.
PG_PASSPostgres password (octopus user)openssl rand -base64 24 at setup; must match the local_postgres container.
VALKEY_PASSValkey auth (often empty locally)set at setup if used.
OTEL_EXPORTER_OTLP_TOKENsignoz-access-token for telemetry ingestfrom SigNoz; paste into env.
SENDGRID_API_KEY / SMTP_*Email deliveryadded manually to the env file (not written by setup); from SendGrid.
WEBAUTHN_RP_ID / _ORIGINSPasskey relying-party configdomain-derived; sandbox uses octopuscards.io.

Other (non-secret) keys in the same file: APP_ENV, PORT (:8081/:8082), PG_HOST/PORT/USER/DB/SSLMODE, CACHE_TYPE, CACHE_PREFIX (sandbox:), VALKEY_ADDR, QUEUE_* (sandbox: app.sandbox), FEATURE_*_ENABLED, OTEL_ENABLED, OTEL_EXPORTER_OTLP_ENDPOINT, INSECURE_MODE, COOKIE_DOMAIN, CLIENT_PORTAL_ORIGINS.

2. Client-portal env files (/etc/octopus{,-sandbox}/octopus-client.env)

All keys are NEXT_PUBLIC_* and inlined at build time (changing one needs a rebuild via update-octopus-client.sh): NEXT_PUBLIC_API_URL, NEXT_PUBLIC_APP_NAME, NEXT_PUBLIC_BRAND (default/octopus-cards), NEXT_PUBLIC_ASSET_BASE_URL, NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN, NEXT_PUBLIC_OTEL_*, NEXT_PUBLIC_DEBUG_LOGS. The only real secret here is the Mapbox token (public-scoped, but rotate via Mapbox). The docs site has an analogous /etc/octopus/octopus-docs.env with APP_*/FEATURE_* build vars.

3. Docker data-plane credentials (root docker-compose.yaml)

  • Postgres: POSTGRES_USER=octopus, POSTGRES_PASSWORD=${PG_PASS:-octopus}, REPLICATION_PASSWORD=${REPLICATION_PASSWORD:-replicator}.
  • RabbitMQ: octopus/octopus (mgmt UI on :15672).
  • MySQL: root rootpassword, db/user/pass octopus.

These default to weak values (octopus/octopus, rootpassword) and the ports are published on the public interface — security relies entirely on the host firewall. In prod, PG_PASS/REPLICATION_PASSWORD come from the env; set strong values and lock the firewall.

4. Vendor credentials — vendor_attributes table

All upstream vendor API credentials live in the database, not env. Rows are (vendor_id, key, value); factories map host/username/password/api_key/callback_url and pass everything else through Extra/Credentials. To rotate a vendor key, update the vendor_attributes row (via the admin UI / a migration — never an ad-hoc SQL write on prod). See Vendors → credentials.

Channel-specific credential stores:

  • Shopifyclients.ShopifyAccessToken, AES-encrypted with APP_KEY, decrypted per-tenant at client build.
  • G2Ag2a_credentials table: bcrypt-hashed client secret + webhook secret, per client.

5. Cloudflare secrets

  • grasshopper (prod) — real Wrangler secrets (wrangler secret put): OCTOPUS_API_URL, OCTOPUS_CLIENT_USERNAME, OCTOPUS_CLIENT_PASSWORD, ENCRYPTION_KEY (AES-256-GCM PII field encryption — the worker crashes without it), ADMIN_TOKEN, CLAIM_NONCE_SECRET, TURNSTILE_SECRET_KEY, OTEL_INGEST_TOKEN.
  • grasshopper (sandbox) — the same names are committed as plaintext in wrangler.jsonc env.sandbox.vars. Rotate these.
  • KV octopus_token — runtime cache of the Octopus JWT (not a managed secret; self-heals on expiry).
  • Cloudflare API token — used by CI + local wrangler; issue a scoped token from the CF dashboard.
  • Local devfrontend/grasshopper/.dev.vars (gitignored; template .dev.vars.example).

6. GitHub Actions secrets

CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID (used by every deploy-*.yml). Rotate the token in the CF dashboard and update the repo secret. The backend test workflow uses only static, non-sensitive test values.

7. AI-agent config — .claude/settings.local.json

A Claude Code permission allow-list. Contains a leaked sandbox Postgres password (see the top-of-page warning). It should list command shapes, never literal secrets.

Rotation checklist

Rotating APP_KEY or JWT_SECRET has blast radius — plan it.

  1. Sandbox Postgres password (leaked in .claude/settings.local.json): change the octopus DB password on 94.130.137.222, update /etc/octopus-sandbox/octopus.env + the container, and scrub the PGPASSWORD= entries from the settings file. Because it's in git history, treat it as compromised regardless.
  2. grasshopper sandbox secrets (in wrangler.jsonc): move to real wrangler secret put values, delete the committed ones.
  3. JWT_SECRET: rotating logs everyone out (all tokens invalid). Do it during a maintenance window.
  4. APP_KEY: do not rotate blindly — it decrypts Shopify tokens & voucher data. Re-encrypt existing values with the new key first, or you'll lose access to them.
  5. Vendor keys: update the vendor_attributes row via admin UI / migration; no redeploy needed.
  6. Cloudflare API token: rotate in dashboard → update GitHub secret + local wrangler.

On this page