Skip to content

Secrets and Environment

mdeguzis edited this page Jul 8, 2026 · 2 revisions

Secrets and Environment

Every secret this project uses, where it lives, what it's for, and how to (re-)provision it. If you spin up a fresh clone, a new maintainer, or rotate a compromised credential, this is the checklist.

Secrets live in three places:

  1. Supabase edge-function secrets -- read by Deno edge functions via Deno.env.get(...).
  2. GitHub repository secrets on mdeguzis/proton-pulse-web -- read by GitHub Actions workflows via secrets.NAME.
  3. GitHub repository secrets on mdeguzis/proton-pulse-web-staging -- one PAT so the main-repo workflow can push shell files there.

Nothing sensitive is ever stored in the codebase or in memory. If you find a value hardcoded, treat it as a bug and rotate.


Supabase edge-function secrets

Managed via the Supabase CLI or dashboard. The project ref is ilsgdshkaocrmibwdezk.

Set with:

supabase secrets set NAME=value --project-ref ilsgdshkaocrmibwdezk

List with:

supabase secrets list --project-ref ilsgdshkaocrmibwdezk
Secret Where to get it Used by
STEAM_API_KEY https://steamcommunity.com/dev/apikey (domain: proton-pulse.com) steam-callback (OpenID login), sync-steam-library (owned games sync), steam-library-lookup (admin API Explorer)
SGDB_API_KEY https://www.steamgriddb.com/profile/preferences/api image-refetch (SteamGridDB box-art fallback)
SITE_URL https://www.proton-pulse.com steam-callback (OAuth redirect target)
STAGING_URL https://mdeguzis.github.io/proton-pulse-web-staging steam-callback (staging redirect when linked via ?staging=1)
SUPABASE_URL Built-in -- injected automatically by the Supabase runtime Every edge fn
SUPABASE_ANON_KEY Built-in -- injected automatically Every edge fn using createRequestAuthClient
SUPABASE_SERVICE_ROLE_KEY Built-in -- injected automatically image-refetch (bucket writes), steam-callback (user creation)

Rule: reuse an existing secret name before inventing a new one. When adding an edge fn that needs the Steam Web API key, read STEAM_API_KEY -- not STEAM_WEB_API_KEY, not STEAMWORKS_KEY. The list above is the canonical vocabulary.


GitHub Actions secrets on mdeguzis/proton-pulse-web

Set at https://github.com/mdeguzis/proton-pulse-web/settings/secrets/actions or with:

gh secret set NAME --repo mdeguzis/proton-pulse-web

Deploy + data pipeline (update-data.yml, gh-pages publishing)

Secret Purpose Notes
STAGING_DEPLOY_TOKEN Push shell files to mdeguzis/proton-pulse-web-staging from the main-repo workflow Fine-grained PAT scoped to proton-pulse-web-staging, Contents: Read and write
SUPABASE_URL REST base URL used by pipeline scripts to fetch Pulse rows Same value as the edge-fn built-in
SUPABASE_ANON_KEY Anon key for the pipeline's Supabase reads Same value as the edge-fn built-in
SUPABASE_SERVICE_ROLE_KEY Service-role key for pipeline writes (e.g. data-versions.json bookkeeping) Sensitive -- rotate immediately if leaked
SUPABASE_TOKEN Personal access token so the deploy-functions workflow can push edge fn code From https://supabase.com/dashboard/account/tokens, no expiry
STEAM_API_KEY Some pipeline steps hit api.steampowered.com directly (e.g. Steam catalog fetches) Same value as the Supabase secret; keep in sync
SGDB_API_KEY Nightly box-art enrichment Same value as the Supabase secret
OPENAI_API_KEY content-moderation.yml runs a moderation pass on flagged phrases Optional -- workflow degrades to rule-based when unset
VT_API_KEY scan-issue-attachments.yml hash-lookups suspicious attachments against VirusTotal (#228, see Security-Guardrails) Optional -- free tier gives 500 lookups/day. Register at https://www.virustotal.com/gui/join-us. When unset, the scanner still applies extension-only policy

CI + backups

Secret Purpose Notes
CODECOV_TOKEN Upload Jest + pytest coverage from ci.yml to Codecov Not required for CI to pass -- coverage upload is best-effort
BACKUP_REPO_TOKEN backup.yml uses this to push nightly Supabase dumps to a private mirror Fine-grained PAT on the backup repo, Contents: RW
BACKUP_HMAC_SECRET HMAC signature on the dump so we can detect tampering on restore Any random 32+ byte string

Discord webhooks

Discord webhook URLs are treated as secrets so we can rotate them without editing workflows. Each of these is the full webhook URL, including the token portion.

Secret Channel purpose
DISCORD_WEBHOOK_BUILDS CI success / failure notifications
DISCORD_WEBHOOK_ISSUES New issue + issue-comment mentions
DISCORD_WEBHOOK_PULL_REQUESTS PR opened / merged pings
DISCORD_WEBHOOK_RELEASES Release-published announcements
DISCORD_WEBHOOK_BACKUPS Nightly backup success + digest

If a webhook is leaked, revoke it in the Discord server settings and set the new URL under the same secret name -- workflows don't need to change.

Built-in

GITHUB_TOKEN is injected automatically by GitHub Actions -- do not set it manually. It's scoped to the repo it runs in.


GitHub Actions secrets on mdeguzis/proton-pulse-web-staging

The staging repo has no workflows of its own -- everything is pushed to gh-pages from the main-repo workflow using STAGING_DEPLOY_TOKEN. No secrets need to be set on the staging repo itself.


Local development

The site + pipeline are designed to work without any local secrets:

  • make serve reads only public data from the production origin.
  • make test-js and make test-py don't need network.
  • make pre-push runs a headless smoke test against a local staged copy -- no secrets.

If you want to run a pipeline step that hits Supabase or Steam directly (rare), export the same env vars the workflow uses:

export SUPABASE_URL=https://ilsgdshkaocrmibwdezk.supabase.co
export SUPABASE_ANON_KEY=<from dashboard>
export STEAM_API_KEY=<from dashboard>

.env files are gitignored so a stray file cannot leak into a commit.


Rotation checklist

When rotating a shared secret (Steam / SGDB / OpenAI / Supabase service role):

  1. Generate the new value at the source (Steam dev page, SGDB profile, Supabase dashboard).
  2. Set the new value under the same secret name in every location listed above:
    • Supabase edge-function secrets (if applicable).
    • mdeguzis/proton-pulse-web repo secrets (if applicable).
  3. Redeploy the edge functions if the secret is server-side (git push a no-op change touching any supabase/functions/** file, or trigger deploy-functions.yml via workflow_dispatch).
  4. Trigger update-data.yml with staging_only=true to confirm the pipeline still runs cleanly.
  5. Revoke the old value at the source once you confirm nothing depends on it.

Related pages

Clone this wiki locally