# 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: ```bash supabase secrets set NAME=value --project-ref ilsgdshkaocrmibwdezk ``` List with: ```bash 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: ```bash 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: ```bash export SUPABASE_URL=https://ilsgdshkaocrmibwdezk.supabase.co export SUPABASE_ANON_KEY= export STEAM_API_KEY= ``` `.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 - [[Web-Deploy-Workflow]] -- staging + prod deploy mechanics - [[Data-Pipeline]] -- what the pipeline reads / writes - [[Steam-Auth-Flow]] -- how `STEAM_API_KEY` is used during login - [[Store-APIs-and-Images]] -- how `SGDB_API_KEY` is used by `image-refetch`