Skip to main content

credstore

Cross-platform credential storage — OS keyring with AES-encrypted file backup.

A standalone secret manager that ships with Slife but has no dependency on it. Depends only on keyring, keyring-wincred, and keyrings-cryptfile.

Supports Windows, macOS, Linux (desktop + headless), and WSL (Windows Credential Manager via PowerShell bridge).

Install

pip install credstore
# or bundled with Slife:
uv tool install git+https://github.com/juzcn/slife.git

Verify: credstore status

No configuration needed. Run credstore set-password to enable encrypted backup.

CLI

Setup

credstore set-password    # creates ~/.credstore/credentials.crypt

Path overridable via CREDSTORE_FILE env var or credstore.json5.

Commands

Command Auth Description
set-password sets it Create or change master key (≥8 chars)
status — Show backend health
set KEY master + secret Atomic dual-write: cryptfile → keyring. Rolls back on keyring failure
get KEY — Keyring only, masked output (sk-5f…b722)
get KEY -p master Dual-query keyring + cryptfile, plaintext. Fails on mismatch
delete KEY master Remove from both stores
copy SOURCE DEST master Idempotent copy (keyring + cryptfile). Re-injects dest to env if previously injected
list master¹ Triple-read: keyring + cryptfile + env. Shows sync status per key
inject KEY… [--shell] — Persist to system env: registry (Win) or shell profile (Unix)
uninject KEY… [--shell] — Remove from system env
reset-keyring master Restore all from cryptfile → keyring (disaster recovery)
reset-backup master Sync keyring → cryptfile

¹ Master password required only if cryptfile exists.

get Modes

Mode Reads from Output Use case
get KEY Keyring only Masked Quick check, safe for screen sharing
get KEY -p Keyring + cryptfile Plaintext Verify consistency, pipe to another tool

-p mode performs a dual-query consistency check:

  • Both stores have the value AND they match → prints plaintext
  • One store missing → error with recovery instructions
  • Values differ → error, tells you which tool to run

inject / uninject

inject reads a secret from the keyring and persists it to the system environment:

Platform Persistence Activation
Windows Registry (HKCU\Environment) + broadcast Restart shell, or Invoke-Expression (credstore inject KEY)
Unix Shell profile (~/.bashrc) New shell, or eval "$(credstore inject KEY)"

When stdout is a TTY, inject prints an activation hint instead of the secret. The actual export command only flows through a pipe.

eval "$(credstore inject DEEPSEEK_API_KEY)"           # Bash/Zsh — activate now
Invoke-Expression (credstore inject DEEPSEEK_API_KEY)  # PowerShell — activate now

uninject reverses the operation — removes from registry or profile and prints the unset command.

list Output

  KEY                  SYSTEM KEYRING   CRYPTFILE        ENV    STATUS
  ────────             ──────────────   ──────────────   ────   ──────
  ANTHROPIC_API_KEY    ✔                ✔                —      synced
  DEEPSEEK_API_KEY     ✔                ✔                ✔      synced
  OPENAI_API_KEY       —                ✔                —      cryptfile only
  ────────             ──────────────   ──────────────   ────   ──────
  3 credential(s) — synced: 2, cryptfile only: 1, env: 1
Column Meaning
SYSTEM KEYRING ✔ = stored in OS keyring
CRYPTFILE ✔ = stored in encrypted backup
ENV ✔ = currently set as environment variable
STATUS synced, keyring only, cryptfile only, or MISMATCH ⚠

Memory Safety

Secrets are immutable Python str objects — they cannot be zeroed in place. Mitigations:

  1. Never batch-load — list collects only key names. Sync comparison fetches one value at a time and immediately dels it.
  2. Prefer existence checks — exists_credential() / list_credential_keys() never retrieve secret content.
  3. Explicit cleanup — every CLI handler dels secret references on all exit paths including error branches.
Operation Cleanup
get / get_credential() Caller must del the returned value
set del secret + del master_pw after dual-write
copy Same as set. Idempotent: skips if dest matches source. Re-injects dest to env if previously persisted
list Values fetched one-at-a-time, compared, deled immediately
inject Value read → persisted → deled. TTY: no secret on stdout
reset-keyring Each value deled after writing to keyring
reset-backup Batch load unavoidable; del entries + del master_pw after sync

masked_input() echoes * per keystroke — paste works, actual value never displayed.

Python API

import credstore

# Read / check / delete (system keyring only, no prompt)
credstore.get_credential("myapp/api_key")      # → str | None
credstore.exists_credential("myapp/api_key")   # → bool  (NEVER returns secret)
credstore.list_credential_keys()               # → list[str]  (NEVER returns values)
credstore.set_credential("myapp/api_key", "sk-…")
credstore.delete_credential("myapp/api_key")   # → bool

# keyring: URI resolution
credstore.is_keyring_uri("keyring:myapp/k")    # → True
credstore.resolve_uri("keyring:myapp/k")       # → the secret value (or KeyError)
credstore.parse_keyring_uri("keyring:srv/k")   # → ("srv", "k") | None

# Shell formatting
credstore.format_export("KEY", "secret", "bash")   # → "export KEY='secret'"
credstore.format_unset("KEY", "bash")              # → "unset KEY"

# Diagnostics
credstore.check_backend()      # → {"available": True, "backend": "…", …}
credstore.get_backend_name()   # → "system keyring + cryptfile (dual-write)"

Python API talks to system keyring only — no master password, no prompt. Dual-write (keyring + cryptfile) is handled by the CLI.

Callers of get_credential() and resolve_uri() must del the returned value after use. Prefer exists_credential() when you only need to know if a credential exists.

Configuration

Optional credstore.json5 (searched at ./credstore.json5 then ~/.credstore/config.json5):

{
  // Override default cryptfile path
  cryptfile_path: "/custom/path/credentials.crypt",
}

Priority: CREDSTORE_FILE env var → credstore.json5 → ~/.credstore/credentials.crypt (or ./credentials.crypt in Slife dev mode).

Architecture

Backend Matrix

Credstore auto-selects the best available backend via keyring's priority system:

Platform Backend Priority Mechanism
Windows WinCredKeyring 9.0 Windows Credential Manager (pywin32)
WSL WslBackend 9.5 PowerShell → advapi32.dll CredReadW/CredWriteW (C# P/Invoke)
macOS Keychain 5.0 macOS Keychain
Linux desktop SecretService 5.0 D-Bus Secret Service (GNOME Keyring / KWallet)
Linux headless KeyutilsBackend 1.5 Kernel keyring via add_key/keyctl syscalls (ctypes, zero deps)

Dual-Write Flow

┌──────────────────────────────────────────────────┐
│  CLI (__main__.py)                               │
│  Interactive: masked_input(), master password     │
│  Atomic dual-write: cryptfile → keyring           │
│  Rollback on keyring failure                      │
├──────────────────────────────────────────────────┤
│  Python API (__init__.py)                        │
│  Programmatic: no prompt, system keyring only     │
├────────────────────┬─────────────────────────────┤
│  System Keyring    │  Cryptfile Backup           │
│  (primary)         │  (encrypted)                │
│  ────────────────  │  ───────────────────────    │
│  Win CredMan       │  keyrings.cryptfile         │
│  WSL (PowerShell)  │  AES-encrypted INI          │
│  macOS Keychain    │  Survives OS pw changes     │
│  Linux Secret Svc  │                             │
│  Linux keyutils    │                             │
└────────────────────┴─────────────────────────────┘

WSL Backend

On WSL, no Linux desktop keyring is available. WslBackend bridges to Windows Credential Manager by calling powershell.exe with embedded C# that P/Invokes advapi32.dll (CredReadW, CredWriteW, CredDeleteW). Priority 9.5 beats WinCredKeyring (9.0) when both are installed — our backend fixes target-format and encoding issues.

Keyutils Backend

On headless Linux (no D-Bus session), KeyutilsBackend stores credentials in the Linux kernel's persistent keyring (@p). Calls add_key and keyctl syscalls directly through ctypes — zero Python dependencies beyond stdlib. Each credential is a "user" key with description "credstore:<service>/<key>".

Credential Enumeration

credstore list reads keys from the OS credential store using platform-specific APIs:

Platform API
Windows win32cred.CredEnumerate
WSL powershell.exe + inline C# CredEnumerateW via advapi32.dll
Other Unsupported — re-run credstore set <KEY> to populate cryptfile

Enumeration retrieves key names only — secret values are never batch-loaded. Sync comparison fetches one value at a time and immediately discards it.

License

MIT

Metadata

Release files for credstore 0.9.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for credstore 0.9.4
File Size Uploaded
credstore-0.9.4.tar.gz 58.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for credstore 0.9.4
File Interpreter ABI Platform
credstore-0.9.4-py3-none-any.whl Python 3 none any Details

Total release size: 94.1 kB

Release files / credstore-0.9.4.tar.gz

Download URL credstore-0.9.4.tar.gz
Size 58.0 kB
Tags Source
SHA-256 checksum
How to use checksums
8d4e68c3dcbd2dd8afae98e19b45ae470fe80dd12b4e397764cb6b763588b216
BLAKE2b-256 checksum
How to use checksums
65e6a879847fe6ba1277017b3ad4142d6621b208484e7189112eab0bac450921
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / credstore-0.9.4-py3-none-any.whl

Download URL credstore-0.9.4-py3-none-any.whl
Size 36.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1837c37d7112f3b91727aca791a2df3c76afde30acd40e7ab3357ca17bd75a6d
BLAKE2b-256 checksum
How to use checksums
aaabf1a305ff08648e72f09f9de5cd53a975acc586222d3e16a4140fa27cda7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.15

Release history Release notifications | RSS feed

0.10.6

2 release files

0.10.5

2 release files

0.10.2

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.9

2 release files

0.9.8

2 release files

0.9.7

2 release files

0.9.6

2 release files

0.9.5

2 release files

This release

0.9.4 This release

2 release files

0.9.0

2 release files

0.3.23

2 release files

0.3.22

2 release files

0.3.21

2 release files

0.3.20

2 release files

0.3.19

2 release files

0.3.18

2 release files

0.3.17

2 release files

0.3.16

2 release files

0.3.7

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page