A secret is an encrypted value that workflows read as ${{ secrets.NAME }}. The gh 29 CLI encrypts it locally with the repository's public key (a libsodium sealed box), so nobody, the owner included, can read it back. Repository secrets (up to 100, 48 KB each) reach every workflow; environment secrets reach only jobs that name the environment (Staging and Production), after its rules pass; organization secrets are not run here (no organization). On a name clash, environment beats repository beats organization. The demo key exists twice, read from openssl so it never enters the shell history:
openssl rand -hex 12 | gh secret set SHELF_API_KEY
openssl rand -hex 12 | gh secret set SHELF_API_KEY --env production
gh secret list; gh secret list --env productionSHELF_API_KEY 2026-09-25T12:14:57Z SHELF_API_KEY 2026-09-25T12:15:16Z
Listings never show values. Pull requests from forks get no secrets, and if: cannot test a secret directly.