Secrets¶
Purpose¶
The difference between a GitHub Actions secret and a Cloudflare Worker secret, and how to rotate
each safely. Sourced primarily from docs/DEPLOYMENT.md §2 and §6.
Two different secret stores - do not confuse them¶
| GitHub Actions secrets | Cloudflare Worker secrets | |
|---|---|---|
| Where set | Repo → Settings → Secrets and variables → Actions | wrangler secret put <NAME> --config <path> |
| Who/what reads them | Workflow runs only (ci.yml, deploy-cloudflare.yml) |
The deployed Worker at runtime, via env.<NAME> |
Visible in wrangler.jsonc? |
No - never appear in any committed file | Only the name appears (if referenced in vars/bindings docs); value is never in git |
| Example | CLOUDFLARE_API_TOKEN |
any secret the API Worker reads at request time (none beyond the Cloudflare credentials are currently defined - NOTIFICATION_EMAIL is a plain vars entry, not a secret, see Cloudflare → Workers) |
A GitHub Actions secret gets a deploy run; a Cloudflare secret gets a deployed Worker's own code something to read. Setting one does not set the other.
GitHub Actions secrets used in this repository¶
| Secret | Purpose | Scope needed |
|---|---|---|
CLOUDFLARE_API_TOKEN |
Auth for every wrangler call in both workflows |
Workers Scripts: Edit, D1: Edit, R2: Edit, Zone: Read (relevant zone only) |
CLOUDFLARE_ACCOUNT_ID |
Which Cloudflare account to target | N/A (identifier, not a credential - low sensitivity, still kept as a secret rather than a plain repo variable) |
CLOUDFLARE_D1_DATABASE_ID |
Used only by deploy-cloudflare.yml's now-no-op sed step, see Deployment |
N/A (identifier) |
Set these at Settings → Secrets and variables → Actions → New repository secret. Never in a workflow file, never in a commit.
Rotating CLOUDFLARE_API_TOKEN¶
From docs/DEPLOYMENT.md §6, reproduced here:
- Cloudflare dashboard → My Profile → API Tokens → create a new token with the same scopes as the one being replaced (see the scope list above).
- GitHub repo → Settings → Secrets and variables → Actions →
CLOUDFLARE_API_TOKEN→ Update → paste the new token value. - Revoke the old token in the Cloudflare dashboard after confirming a workflow run succeeds with the new one - don't revoke first, or an in-flight/queued run fails mid-deploy.
- Trigger
validate(any push, orworkflow_dispatch) to confirm the new token authenticates correctly before relying on it for a realdeploy-productionrun.
Setting a Cloudflare Worker secret¶
Prompts interactively for the value (not passed as an argument, so it never lands in shell history). Applies to the production Worker immediately - there is no separate secrets store per environment, since this repository has no staging environment (see Infrastructure → Environments).What is not a secret in this repository¶
NOTIFICATION_EMAIL and ALLOWED_ORIGINS are plain vars in workers/api/wrangler.jsonc -
visible in git, not sensitive. Resource identifiers like a database_id are treated as
non-secret per docs/DEPLOYMENT.md's own framing (they identify a resource, they don't
authenticate anything) - see Cloudflare → D1 for where one is written
literally with a timestamped caveat.
Least privilege¶
- Scope
CLOUDFLARE_API_TOKENto only the permissions in the table above - not the account-wide "Edit Cloudflare Workers" template, which grants far more than this repository's workflows use. - Only repository Settings → Secrets grants workflow access - branch protection rules don't
restrict secret access by branch in this repository's current configuration; treat any
contributor with push access to any branch as able to trigger a workflow that reads these
secrets (though only a push to
maintriggers an actualdeploy-production, see Deployment).
Security considerations¶
- Never place a real secret value in a commit, a workflow log via
echo, or this documentation - placeholders (<CLOUDFLARE_API_TOKEN>,<SECRET_VALUE>) only. - If a secret value is ever committed by mistake: rotate it immediately (a
git revertdoes not invalidate a leaked value already visible in history/forks/CI logs) - see Operations → Incident Response.