Multi-Environment Bootstrap
|
Operator only. This runbook is for the PepperCheck project operator provisioning Firebase / GCP / GitHub Secrets infrastructure. Day-to-day developers and external contributors can skip this page — local Flutter dev only needs the |
Operator-only runbook for provisioning the Phase 1 multi-environment setup — Firebase projects, service accounts, per-flavor configs, and the matching GitHub Secrets. Run these scripts once per fresh workstation; they are all idempotent.
Background: see docs/superpowers/specs/2026-06-05-android-flavor-split-design.md and the umbrella roadmap issue #418.
When to use
Use these scripts when:
-
Bootstrapping a new operator workstation for releasing PepperCheck.
-
Re-provisioning after a Firebase project rebuild or service-account key rotation.
-
Re-downloading per-flavor
google-services.json/GoogleService-Info-*.plistto a fresh clone.
Day-to-day Flutter development does NOT need these. Once the dev flavor configs are in place, regular flutter run --flavor dev -t lib/main_dev.dart works against local Supabase + the peppercheck-dev Firebase project.
Scripts overview
| Script | Purpose | When to (re-)run |
|---|---|---|
|
Idempotently creates the two non-production Firebase projects ( |
Once per organization; safe to re-run (skips existing projects). |
|
Registers Android + iOS apps in the target Firebase project (creates them if absent) and downloads |
Once per env per workstation. Re-run to re-download configs after a Firebase app rebuild or to refresh a stale local config. |
|
Creates a |
Once per operator workstation. Re-running creates an additional key (previous keys stay active); rotate manually with |
|
Sets four GitHub Secrets at once via STDIN redirect (values never appear on stdout, in the process list, or in shell history): |
Once per credential refresh. Re-run to update any of the four secrets after a service-account key rotation or staging app re-registration. |
Order of operations
Run these in order on a fresh workstation:
# 0. Pre-flight: `firebase login`, `gcloud auth login <email>`, `gh auth login`,
# and confirm `jq` is on PATH.
# 1. Create the two non-production Firebase projects.
./scripts/setup/bootstrap-firebase-projects.sh
# 2. Register Android + iOS apps in each project and download the
# per-flavor Firebase config files (`google-services.json` and
# `GoogleService-Info-*.plist`).
./scripts/setup/register-firebase-apps.sh dev
./scripts/setup/register-firebase-apps.sh staging
./scripts/setup/register-firebase-apps.sh production (1)
# 3. Provision the staging service account (FCM + FAD admin roles) and
# download its JSON key into `~/.config/peppercheck/`.
./scripts/setup/bootstrap-peppercheck-staging-sa.sh
# 4. Push the four BETA_*/PROD_* secrets to GitHub.
./scripts/setup/setup-deploy-secrets.sh ~/.config/peppercheck/peppercheck-staging-sa.json
| 1 | The production Firebase project (peppercheck) and its Android/iOS apps already exist; the script skips creation and only re-downloads configs. |
After step 4, also visit the Firebase Console once to enable App Distribution on peppercheck-staging and to create the peppercheck-staging-testers group (this part has no API). See deploy-beta.yml for the literal group name the CI invokes.
Generated files
| Path | Source script | Notes |
|---|---|---|
|
|
dev flavor Firebase config; gitignored. CI does not regenerate this in current workflows — dev is local-only. |
|
|
staging flavor Firebase config; gitignored. CI regenerates from |
|
|
production flavor Firebase config; gitignored. CI regenerates from |
|
|
iOS Firebase configs pre-positioned for future #424 / #425 Xcode wiring; currently unread by Xcode. |
|
|
Service account JSON key for the staging FAD upload + Edge Function FCM. Mode 0600 inside a mode 0700 directory. Source of truth for |
Secrets set by step 4
setup-deploy-secrets.sh sets exactly four secrets in the cloveclovedev/peppercheck repo:
| Secret name | Value |
|---|---|
|
The verbatim contents of the SA JSON path passed to the script. Consumed by |
|
Auto-resolved via |
|
Verbatim contents of |
|
Verbatim contents of |
Other Firebase / Play SA secrets (PROD_FIREBASE_SERVICE_ACCOUNT_JSON, BETA_/PROD_GOOGLE_PLAY_SERVICE_ACCOUNT_JSON) are NOT touched by this script — they are set manually per the commands documented in scripts/github-secrets.example.
JSON secret convention
All JSON-shaped GitHub Secrets store the raw file contents (multi-line is fine). The deploy workflows normalize the value to single-line via jq -c . at each env-file write site (see deploy-beta.yml / deploy-production.yml around the printf "FIREBASE_SERVICE_ACCOUNT_JSON='%s'\n" line). This gives operators a single rule:
gh secret set NAME < /path/to/file.json
regardless of how the value is later consumed.
Re-running and idempotency
All four scripts are safe to re-run.
| Script | Re-run behavior |
|---|---|
|
Prints |
|
Prints |
|
Skips SA creation and IAM grants if they already exist. Always creates a NEW JSON key — old keys remain active until manually deleted via |
|
Overwrites all four secrets every time; no skip logic. |
Pre-requisites
-
firebaseCLI logged in (firebase login) with access to the parent Firebase organization. -
gcloudCLI authenticated to a Google account with IAM permissions onpeppercheck-staging. The script auto-detects which authenticated account has access, so being logged into multiple accounts is fine. -
ghCLI authenticated tocloveclovedev/peppercheckwith secrets:write scope. -
jqon PATH (pre-installed on macOS via Homebrew, orapt install jqon Debian/Ubuntu).