Skip to main content

credstore

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

A standalone secret manager that ships with Slife but does not depend on it. Only two lightweight dependencies: keyring and keyrings-cryptfile. Available both as a standalone PyPI package and bundled with Slife.

Install

Standalone (PyPI)

pip install credstore

Or with uv:

uv tool install credstore

Bundled with Slife

Installing Slife gives you the credstore command automatically — no extra step.

uv tool install git+https://github.com/juzcn/slife.git

In a development checkout, run via uv:

uv run credstore <command>

Verify

credstore status

No configuration needed — the OS keyring is used automatically. Run credstore set-password to enable encrypted backup.


CLI

Setup (first time)

credstore set-password

Creates ~/.credstore/credentials.crypt and sets a master password (dev: ./credentials.crypt). Path configurable via CREDSTORE_FILE env var.

Command Reference

Command Master key Description
set-password sets it Create/change master key, init cryptfile
set KEY enters it Atomic dual-write (cryptfile + keyring). Rolls back on keyring failure
get KEY no Keyring only, masked output (sk-5f…b722)
get KEY -p enters it Dual-query keyring + cryptfile, plaintext. Fails on mismatch
delete KEY enters it Remove from keyring + cryptfile
list enters it Triple-read: keyring + cryptfile + env vars
inject KEY... no Persist to system env: registry (Windows) or shell profile (Unix)
uninject KEY... no Remove from system env: registry (Windows) or shell profile (Unix)
reset-keyring enters it Restore keyring from cryptfile backup
reset-backup enters it Sync system keyring → cryptfile
status no Show backend status
credstore set-password                   # first-time setup
credstore set DEEPSEEK_API_KEY           # store (masked, atomic dual-write)
credstore get DEEPSEEK_API_KEY           # retrieve, masked output
credstore get DEEPSEEK_API_KEY -p        # retrieve plaintext (dual-query)
credstore list                           # triple-read: keyring + cryptfile + env
credstore delete OLD_KEY                 # delete from keyring + cryptfile

# System environment injection (persistent)
credstore inject DEEPSEEK_API_KEY        # Windows → registry, Unix → shell profile
Invoke-Expression (credstore inject KEY) # PowerShell: activate in current shell
eval "$(credstore inject KEY)"           # Bash/Zsh: activate in current shell
credstore uninject DEEPSEEK_API_KEY      # remove from registry/profile

credstore reset-keyring                  # restore keyring from cryptfile backup
credstore reset-backup                   # sync keyring → cryptfile
credstore status                         # show backend status

List Output

credstore list performs a triple-read — checking the system keyring, encrypted cryptfile backup, and current environment variables simultaneously:

  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, — = missing
CRYPTFILE ✔ = stored in encrypted backup, — = missing
ENV ✔ = currently set as environment variable, — = not set
STATUS synced (both stores match), keyring only, cryptfile only, or MISMATCH ⚠

The ENV column uses os.environ — it checks whether the credential key is currently exported as an environment variable. No secret values are decoded during the check.

Environment Variable Injection

inject reads a secret from the keyring and persists it to the system environment. On Windows, it writes directly to the registry (HKCU\Environment); on Unix, it appends to the shell profile. New shells load it automatically.

# Persist + activate in current shell
credstore inject DEEPSEEK_API_KEY        # persist to registry/profile
Invoke-Expression (credstore inject KEY) # PowerShell: activate now
eval "$(credstore inject KEY)"           # Bash/Zsh: activate now

# Remove
credstore uninject DEEPSEEK_API_KEY      # remove from registry/profile

Secret never appears on the terminal — inject detects TTY and prints only a hint. The actual export command flows through a pipe when wrapped in Invoke-Expression / eval.

No master password required (keyring only).

Disaster Recovery

When the OS keyring loses data (e.g. after a Windows password change):

credstore reset-keyring               # restore all from cryptfile backup

Design: Memory Safety

Secrets are immutable Python str objects — they cannot be zeroed in place. credstore mitigates memory leaks through three design rules:

Rule Mechanism
Never batch-load list collects only key names from keyring, cryptfile, and os.environ. Sync comparison fetches one value at a time and immediately del-s it
Prefer existence checks exists_credential() / list_credential_keys() never retrieve secret content
Explicit cleanup Every CLI handler del-s secret references after last use. set, get, reset, set-password all clean up on every exit path — including error branches

Operations that read/transport secrets

Operation How memory is cleaned
get Caller is responsible for del-ing the returned value
set del secret + del master_pw after dual-write (all code paths)
list Values fetched one-at-a-time, compared, del-ed immediately. Env vars checked via os.environ — no secret values decoded
inject Value read → persisted → del-ed. TTY: no secret on stdout. Pipe: secret through pipe only
uninject No secrets involved — registry/profile cleanup only
reset-keyring Each value del-ed after writing to keyring
reset-backup Batch load unavoidable, del entries + del master_pw after sync
set-password old_data dict del-ed after re-encryption; all password strings cleaned up

The masked_input() terminal helper echoes * for each keystroke — paste works but the actual value is never displayed or logged.

Python API

import credstore

# Read / check / write / 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

# Shell formatting (for env var injection)
credstore.format_export("MY_KEY", "secret", "bash")   # → "export MY_KEY='secret'"
credstore.format_unset("MY_KEY", "bash")              # → "unset MY_KEY"

# keyring: URI resolution
credstore.is_keyring_uri("keyring:myapp/k")    # → True
credstore.resolve_uri("keyring:myapp/k")       # → the secret value

# Backend info
credstore.check_backend()       # → {"available": True, "backend": "…", …}
credstore.is_cryptfile_ready()  # → True if master key is set

Memory rule: callers of get_credential() and resolve_uri() MUST del the returned value after use. Prefer exists_credential() or list_credential_keys() when you only need to know whether a credential exists.

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

Metadata

Release files for credstore 0.3.16

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.3.16
File Size Uploaded
credstore-0.3.16.tar.gz 40.3 kB Details

Built distribution (wheel)

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

Total release size: 66.5 kB

Release files / credstore-0.3.16.tar.gz

Download URL credstore-0.3.16.tar.gz
Size 40.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8b4d5ab09aeecba35931f7b6e91cccf075cdd118fdb7a0472aea474e445aed4e
BLAKE2b-256 checksum
How to use checksums
4c8dfd8e9b4cfca5ae3c1d0e82507388edc65507a159f33bfee3b375afc845e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.2.0 CPython/3.13.14

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

Download URL credstore-0.3.16-py3-none-any.whl
Size 26.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
53db1459a94ab3fccf93d0ee7e7e39d670e565738a1243e367fe5dda83825a80
BLAKE2b-256 checksum
How to use checksums
68748b7cde1dc4ed76023a58a39e287fce8f3aacb416c58f9d4cd514a3b320dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.2.0 CPython/3.13.14

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

0.9.4

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

This release

0.3.16 This release

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