This is a public repository. Every secret here must be one of:
kind: ExternalSecret— a reference resolved at runtime by External Secrets Operator from Bitwarden/Vaultwarden. No secret value is ever in git.- A gitignored dotfile —
.env,*.local.yaml,*.pem,kubeconfig, etc. (see.gitignore). Real values live only on disk / in the cluster.
A plaintext kind: Secret with a data: / stringData: block is forbidden.
base64 is encoding, not encryption — a committed Secret is a public credential.
| Gate | Where | What it blocks |
|---|---|---|
scripts/check-no-inline-secrets.sh |
pre-commit + CI | any kind: Secret with populated data |
gitleaks (.gitleaks.toml) |
pre-commit + CI | high-entropy secrets, keys, tokens in tree + history |
.gitignore dotfile patterns |
local | stops real-value files being staged |
Enable the local hooks once:
pipx install pre-commit
pre-commit installCI runs both scanners on every push and PR (.github/workflows/secret-scan.yml)
on GitHub-hosted runners — never the in-cluster arc-chem runners.
- Store the value in Bitwarden. For multi-field secrets use custom fields and
the
bitwarden-fieldsClusterSecretStore; for a simple login usebitwarden-loginwithusername/password. - Write a
kind: ExternalSecretreferencing the item UUID. Examples in-repo:- multi-field:
rke2/longhorn-system/b2-back-secret.yaml - login:
rke2/authentik/github-oauth-secret.yaml - rendered file (e.g. a datasource):
rke2/monitor/spotify-postgres/grafana-datasource.yaml
- multi-field:
- Rotate first — assume any value that reached this public repo is compromised and already scraped. Rotate at the source (Garage key, Postgres role, etc.). Rotation is the real fix; git cleanup is secondary.
- Convert the manifest to
ExternalSecret. - Purge from history (
git filter-repo), force-push, and ask GitHub Support to evict cached blob views.