A scheduled cadence + an emergency drill.
- At least annually per platform.
- Immediately on suspected compromise: stolen laptop,
committed-then-reverted
.env, departed maintainer. - Quarterly for high-impact secrets (PyPI, GHCR, Docker Hub).
The rotation table in
release_kit.workflows.rotate_tokens
names each platform's URL + the env-var/keyring slot the runner
uses.
release-kit rotate-tokens --list # show known platforms
release-kit rotate-tokens --platform pypi # rotate one
release-kit rotate-tokens # walk every platformFor each platform:
- The CLI prints the management URL — open it.
- Create the new token in the registry/host UI.
- Paste it at the prompt (input is hidden).
- The new value is written to the OS keyring under
service
release-kit, account<slug>. - Old token: revoke it in the same UI before closing the tab.
Re-run release-kit doctor to confirm the new token resolves.
When you believe a token is leaked:
- Revoke first, ask questions later. Use the platform UI's "revoke" / "delete" button on the suspected token. The platform refuses subsequent calls within seconds.
- Create a replacement.
release-kit rotate-tokens --platform <slug>to store it.- Re-run any in-flight CI jobs that depended on the old token.
- Audit the platform's audit log for unexpected pushes / pulls while the token was valid.
- Post-mortem: how did it leak? Was it in a log, a
.envchecked into git history, a screenshot?
Rotation in the OS keyring doesn't touch the CI secret store. Two options:
- OIDC-capable targets: drop the long-lived token entirely
(
oidc-bootstrap.md). - Token-only targets: rotate via the platform UI, then update
the CI secret. GitHub:
Settings → Secrets and variables → Actions → <SECRET> → Update.
After a rotation:
unset PYPI_TOKEN # ensure env doesn't shadow keyring
release-kit doctor # target should show GREEN with auth from keyringIf GREEN: the keyring lookup found the new value.
If RED with token-not-found: the keyring write failed or the
slot name doesn't match. Re-run release-kit rotate-tokens --platform <slug>.
Every token resolution emits a structlog event with the source:
INFO resolve-token source=keyring:release-kit:pypi
Ship the structured logs to your audit pipeline (Loki, Datadog,
CloudWatch) and alert on resolution from sources you didn't
expect (e.g. source=env:RELEASE_KIT_TOKEN_PYPI from a CI job
that's supposed to use OIDC).
- Don't commit a
.env(or any file containing tokens) to git.release-kit initadds.envto.gitignorefor you. - Don't share an automation token with a human session. Maintainer tokens and CI tokens are separate.
- Don't store production tokens in a personal password manager that other people can see by sharing a vault.