Skip to content

setup:full does not sync Supabase service role keys to GitHub Actions secrets #382

@ZappoMan

Description

@ZappoMan

What happened?

After running npm run setup:full (including the GitHub secrets sync phase), production deploy fails at billing:sync-stripe with:

Missing STRIPE_SECRET_KEY, SUPABASE_URL, or SUPABASE_SERVICE_ROLE_KEY

CI shows STRIPE_SECRET_KEY and SUPABASE_URL are set, but SUPABASE_SERVICE_ROLE_KEY is empty because secrets.PRODUCTION_SUPABASE_SERVICE_ROLE_KEY was never pushed to GitHub.

Expected: setup:full syncs all secrets required by deploy workflows, including Supabase service role keys for staging, production, and PR preview.

Actual: Service role keys are fetched during the Supabase setup phase and written to local generated env (.env.cloud.generated.local), but they are not synced to GitHub Actions secrets.

Root cause

In scripts/lib/setup-manifest.mjs:

  • setup-full.mjs stores {STAGING,PRODUCTION,PREVIEW}_SUPABASE_SERVICE_ROLE_KEY (and PR_TESTING_SUPABASE_SERVICE_ROLE_KEY for preview) in the setup accumulator after supabase projects api-keys.
  • Those keys are listed in EXTRA_MERGEABLE_ENV_KEYS (local merge only).
  • They are missing from GITHUB_SECRETS, so the GitHub sync step never runs gh secret set for them.

Deploy workflows do require these secrets, e.g. in .github/workflows/deploy-production.yml:

SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.PRODUCTION_SUPABASE_SERVICE_ROLE_KEY }}

Used by billing:sync-stripe, edge function deploy, and related steps. Staging (deploy-staging.yml) and PR preview (pr-preview-environment.ymlPR_TESTING_SUPABASE_SERVICE_ROLE_KEY) have the same dependency.

env.example documents PRODUCTION_SUPABASE_SERVICE_ROLE_KEY, but docs/reference/github-actions-secrets.md (generated from the manifest) does not list any *_SUPABASE_SERVICE_ROLE_KEY entries — consistent with the manifest gap.

Steps to reproduce

  1. Fork BeakerStack and run npm run setup:full through Supabase + GitHub phases (or inspect secrets after a completed setup on a fresh adopter repo).
  2. Run gh secret list on the adopter repo — note PRODUCTION_SUPABASE_URL, PRODUCTION_SUPABASE_ANON_KEY, etc. are present, but PRODUCTION_SUPABASE_SERVICE_ROLE_KEY is absent.
  3. Push to main to trigger deploy-production.yml.
  4. Workflow passes Supabase db push, then fails at Sync Stripe prices to billing_plans (npm run billing:sync-stripe).

Suggested fix

Add to GITHUB_SECRETS in scripts/lib/setup-manifest.mjs:

Secret name envKeys group
STAGING_SUPABASE_SERVICE_ROLE_KEY STAGING_SUPABASE_SERVICE_ROLE_KEY staging
PRODUCTION_SUPABASE_SERVICE_ROLE_KEY PRODUCTION_SUPABASE_SERVICE_ROLE_KEY production
PR_TESTING_SUPABASE_SERVICE_ROLE_KEY PR_TESTING_SUPABASE_SERVICE_ROLE_KEY, PREVIEW_SUPABASE_SERVICE_ROLE_KEY preview

Then regenerate docs: npm run docs:actions-secrets.

Workaround

Manually set the missing secrets from Supabase Dashboard → Project Settings → API → service_role, or from the values already in .env.cloud.generated.local:

gh secret set PRODUCTION_SUPABASE_SERVICE_ROLE_KEY
gh secret set STAGING_SUPABASE_SERVICE_ROLE_KEY
gh secret set PR_TESTING_SUPABASE_SERVICE_ROLE_KEY

Environment

  • Template: BeakerStack 2026.001 (fork/adopter setup)
  • Observed on: GitHub Actions deploy-production.yml
  • Node 20, macOS (local setup); Ubuntu (CI)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions