This repo helps with local secret hygiene. It is not a complete secret-management system.
The SOPS + age + Keychain pattern reduces risk from:
- plaintext
.envfiles sitting in local repos for months - accidental commits of plaintext secrets
- broad local search, indexing, or agent inspection over repo contents
- backups and sync tools sweeping up long-lived plaintext dotenv files
- clone workflows where developers need the repo but should not receive a copied private identity file
This repo does not fully protect you from:
- malware or an attacker already running as your macOS user
- secrets leaking into logs, shell history, crash reports, or test output
- plaintext
.envfiles that already exist in git history - team-wide sharing, revocation, RBAC, or audit requirements
- production or CI secret delivery on its own
Once a command is running under sops exec-env or the wrapper, the secrets are in process environment space. That is better than a long-lived plaintext file on disk, but it is not the same thing as a hardware-backed or centrally governed secret-management system.
If you adopt this repo publicly, pair it with:
- one recipient per person or per device where possible
- secret rotation after migration, especially if plaintext may have leaked before
- GitHub push protection or equivalent host-side secret scanning
- repo-by-repo validation instead of blind bulk rewrites
- explicit smoke commands in migration instructions
The built-in validate-repo secret scan is a high-signal spot check for common prefixes. It is useful, but it is not comprehensive enough to replace host-side secret scanning or a dedicated scanner.
This repo intentionally stops before central secret management. When you need more than local workflow hardening, add one of these layers:
- 1Password for friendlier human-facing secret storage and sharing
- macOS Keychain if you only need local single-user storage on one machine
- HashiCorp Vault for dynamic secrets, leases, and deeper policy control
- Infisical for a friendlier open-source team secret workflow
- Doppler for centralized developer and environment secret management
- AWS Secrets Manager, GCP Secret Manager, or Azure Key Vault for cloud-native delivery
- GitHub secret scanning
- GitHub push protection
- organization rules or CI checks that reject committed plaintext dotenv files
This repo is primarily a local macOS workflow. CI is secondary and should not reuse the macOS Keychain helper.
If CI must decrypt SOPS files:
- use a dedicated CI recipient or cloud KMS, not a developer's personal Keychain identity
- store that identity in the CI secret manager
- inject it through
SOPS_AGE_KEYor a file-backed equivalent
Minimal GitHub Actions example:
jobs:
test:
runs-on: ubuntu-latest
env:
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
steps:
- uses: actions/checkout@v4
- run: sops exec-env .env -- uv run pytestFor .env.sops, use the repo's wrapper boundary instead of the macOS Keychain helper:
- run: scripts/sops-env .env.sops -- npm run test:rawIf you do not need encrypted dotenvs in CI, keep CI out of scope and document the local-only boundary clearly.
Rotate recipients when a device is retired, a private identity may have leaked, or you are moving from a single-user bootstrap to per-person recipients.
Typical flow:
- create the new age identity
- update
.sops.yamlwith the new recipient list - run
sops updatekeys -y ENV_FILE - validate with
scripts/validate-repo ... -- smoke command - rotate the underlying application secrets too if the old recipient may have exposed them
Use this repo when you want:
- a macOS-friendly local workflow
- better defaults for repos that currently rely on plaintext dotenv files
- agent-assisted migration help
- a publishable, explainable pattern for one repo at a time
Use a central secret manager when you want:
- shared production access
- audited team onboarding and offboarding
- dynamic credentials
- environment-level rotation and policy
- service-to-service secret delivery