Repository navigation
Secrets
Secrets never go in the repo, and preferably not in ~/.zshrc.local either: plain-text files end up in backups, screen shares and shell history. Bitwarden is the source of truth; a tool gets a secret only when it starts, so it never sits in a file or in every shell's environment.
bw is a wrapper (bw.zsh): the session key lives in a root-only file, so the first bw in a shell asks for Touch ID (sudo) and later ones reuse it, without the master password. It needs export BW_USER=<email> in ~/.zshrc.local; bw --regenerate-session-key starts a new session. The key reaches the CLI through BW_SESSION, never on the command line (ps would show it).
A tool that needs a token, in ~/.zshrc.local:
mytool() {
local token
token=$(bw get password <item>) || return
MYTOOL_TOKEN=$token command mytool "$@"
}Several values in one item: bw get item <item> | jq -r '.fields[] | select(.name == "<field>").value'. Never fetch secrets at the top level of .zshrc*: every new shell would block on the vault.
secret T # asks without echoing it
secret T <item> # or from Bitwarden
claude mcp add ... --header "Authorization: Bearer $T"$T is cleared after the next command and never exported. Lines that look like they hold a token (GitHub / GitLab / Slack / OpenAI / Anthropic keys, AWS access keys, JWTs, a long Bearer, --password=...) are not saved to the history; a leading space keeps any command out of it.
The keys for SOPS-encrypted files live in one Bitwarden secure note, SOPS age keys, never on disk by default.
| Command | |
|---|---|
sops-on [60m] |
writes them to sops's keys file for a while (90, 90m, 30s, 2h; default SOPS_ON_MINUTES, else 60), then removes them with a notice and a macOS notification |
sops-off |
removes them now |
sops-status |
the time left |
sops-save [FILE] |
puts a keys file in the note |
sops-login [on|off] |
the clean-up at login on this machine (below) |
- A keys file
sops-ondid not create is never overwritten or removed. -
A log out or restart removes them: the timer dies with the session, so a LaunchAgent (
.config/dotfiles/launchd) cleans up at login, whatever time was left.sops-login offturns that off on a machine where it makes no sense (macOS keeps the choice across reboots and syncs),sops-login onback on. - Neovim opens SOPS files decrypted and re-encrypts on
:w(sops.nvim), with undo history and swap off for them.
- gitleaks scans every commit's staged changes (global hook), and CI scans the whole history.
-
sops-guard stops a commit of a file sops should have encrypted but that is staged in cleartext: named
*.sops.*/*.enc.*, or matched by apath_regexof a.sops.yaml(read as Go regexes, as sops does). See Git. -
The global gitignore keeps
.envand.env.*out (not.env.example;git add -foverrides). - Claude Code is blocked from reading keys, credentials and env files (Claude Code).
- Check by hand:
git grep -nIE '(token|secret|password|api_?key)\s*='.