Keychain backend¶
The keychain backend stores credentials in the OS-native secret store via the keyring library. On macOS this is the Keychain (backed by Security.framework); on Linux, it can be gnome-keyring, kwallet, or any other backend keyring.get_keyring() resolves.
When to use it¶
- Personal long-lived credentials that survive repo deletion (GitHub OAuth, Bitwarden-style PATs used outside of Bitwarden, SSH key passphrases).
- macOS-primary workflows where Keychain is the obvious source of truth.
- Anywhere you want "not in git" to be a hard guarantee — nothing on disk in plaintext, nothing encrypted in the repo, nothing readable without the user's session.
Requirements¶
- The
[keychain]optional extra:pip install 'himitsubako[keychain]'. Without it, calling any keychain backend operation raisesBackendErrorwith a clear install hint. - On Linux, a usable keyring daemon (gnome-keyring, kwallet, or a properly configured secret-service implementation). himitsubako refuses to run against
Null,PlaintextKeyring,EncryptedKeyring, orfail.Keyring— see Insecure backend deny-list.
Configuration¶
default_backend: keychain
keychain:
service: my-project # keyring service name; defaults to "himitsubako"
The service name is the string passed to keyring.get_password(service, key) and keyring.set_password(service, key, value). Pick something distinctive per project so entries do not collide in the system keyring UI.
Capabilities¶
get(key)—keyring.get_password(service, key).set(key, value)—keyring.set_password(service, key, value).delete(key)—keyring.delete_password(service, key). RaisesSecretNotFoundErrorwhen the key does not exist (sohmb delete --missing-okworks correctly).list_keys()— raisesBackendError. Thekeyringpublic API does not expose enumeration. Returning an empty list would silently mislead callers; an explicit error is more honest.hmb listcatches this and prints a friendly message pointing users at their project's secrets registry.check_availability()— thehmb statusping, added in HMB-S019. Importskeyring, callsget_keyring(), walks the MRO against the deny-list. Does not touch any stored credential.
Insecure backend deny-list¶
On a misconfigured Linux host, keyring.get_keyring() can silently fall back to Null (drops writes on the floor) or PlaintextKeyring (stores secrets in the clear under ~/.local/share/python_keyring/). Both would be catastrophic for a credential manager, so the keychain backend rejects them. The check walks the resolved class MRO, so a subclass like class SafeWrapper(PlaintextKeyring) cannot bypass the gate by renaming the leaf class.
When the deny-list hits, you get:
keychain: unavailable (keyring resolved to insecure backend 'PlaintextKeyring' (MRO matches ['PlaintextKeyring']); install gnome-keyring (Linux), use macOS Keychain (Darwin), or set keyring's preferred backend explicitly)
Fix it by installing a real keyring daemon (gnome-keyring or kwallet on Linux), ensuring the D-Bus session is running for your user, or setting keyring.set_keyring(...) in a startup hook before any himitsubako call.
Minimal working example¶
pip install 'himitsubako[keychain]'
cat > .himitsubako.yaml <<'EOF'
default_backend: keychain
keychain:
service: my-project
EOF
hmb set GITHUB_OAUTH_TOKEN
# Value: (hidden prompt)
hmb get GITHUB_OAUTH_TOKEN | cat
hmb delete GITHUB_OAUTH_TOKEN
Threat model summary¶
- T-020 — insecure keyring backend. Mitigated by the MRO-walking deny-list above (M-015).
- T-021 — missing keyring optional dependency. Mitigated by converting
ImportErrorto aBackendErrorwith a clear install hint. - Enumeration. Intentionally unsupported. This is neither a security property nor a leak, just an API limitation of
keyring.hmb listprints a friendly message and exits 0.
See Security for the user-facing summary.