credstore 0.3.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,232 @@
1
+ # Credential store encrypted backup
2
+ credentials.crypt
3
+
4
+ # WeChat session files (contain auth tokens)
5
+ wechat_*.json5
6
+
7
+ # Runtime logs
8
+ logs/
9
+
10
+ # Byte-compiled / optimized / DLL files
11
+ __pycache__/
12
+ *.py[codz]
13
+ *$py.class
14
+
15
+ # C extensions
16
+ *.so
17
+
18
+ # Distribution / packaging
19
+ .Python
20
+ build/
21
+ develop-eggs/
22
+ dist/
23
+ downloads/
24
+ eggs/
25
+ .eggs/
26
+ lib/
27
+ lib64/
28
+ parts/
29
+ sdist/
30
+ var/
31
+ wheels/
32
+ share/python-wheels/
33
+ *.egg-info/
34
+ .installed.cfg
35
+ *.egg
36
+ MANIFEST
37
+
38
+ # PyInstaller
39
+ # Usually these files are written by a python script from a template
40
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
41
+ *.manifest
42
+ *.spec
43
+
44
+ # Installer logs
45
+ pip-log.txt
46
+ pip-delete-this-directory.txt
47
+
48
+ # Unit test / coverage reports
49
+ htmlcov/
50
+ .tox/
51
+ .nox/
52
+ .coverage
53
+ .coverage.*
54
+ .cache
55
+ nosetests.xml
56
+ coverage.xml
57
+ *.cover
58
+ *.py.cover
59
+ .hypothesis/
60
+ .pytest_cache/
61
+ cover/
62
+
63
+ # Translations
64
+ *.mo
65
+ *.pot
66
+
67
+ # Django stuff:
68
+ *.log
69
+ local_settings.py
70
+ db.sqlite3
71
+ db.sqlite3-journal
72
+
73
+ # Flask stuff:
74
+ instance/
75
+ .webassets-cache
76
+
77
+ # Scrapy stuff:
78
+ .scrapy
79
+
80
+ # Sphinx documentation
81
+ docs/_build/
82
+
83
+ # PyBuilder
84
+ .pybuilder/
85
+ target/
86
+
87
+ # Jupyter Notebook
88
+ .ipynb_checkpoints
89
+
90
+ # IPython
91
+ profile_default/
92
+ ipython_config.py
93
+
94
+ # pyenv
95
+ # For a library or package, you might want to ignore these files since the code is
96
+ # intended to run in multiple environments; otherwise, check them in:
97
+ # .python-version
98
+
99
+ # pipenv
100
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
101
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
102
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
103
+ # install all needed dependencies.
104
+ # Pipfile.lock
105
+
106
+ # UV
107
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
108
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
109
+ # commonly ignored for libraries.
110
+ # uv.lock
111
+
112
+ # poetry
113
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
114
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
115
+ # commonly ignored for libraries.
116
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
117
+ # poetry.lock
118
+ # poetry.toml
119
+
120
+ # pdm
121
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
122
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
123
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
124
+ # pdm.lock
125
+ # pdm.toml
126
+ .pdm-python
127
+ .pdm-build/
128
+
129
+ # pixi
130
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
131
+ # pixi.lock
132
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
133
+ # in the .venv directory. It is recommended not to include this directory in version control.
134
+ .pixi
135
+
136
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
137
+ __pypackages__/
138
+
139
+ # Celery stuff
140
+ celerybeat-schedule
141
+ celerybeat.pid
142
+
143
+ # Redis
144
+ *.rdb
145
+ *.aof
146
+ *.pid
147
+
148
+ # RabbitMQ
149
+ mnesia/
150
+ rabbitmq/
151
+ rabbitmq-data/
152
+
153
+ # ActiveMQ
154
+ activemq-data/
155
+
156
+ # SageMath parsed files
157
+ *.sage.py
158
+
159
+ # Environments
160
+ .env
161
+ .envrc
162
+ .venv
163
+ env/
164
+ venv/
165
+ ENV/
166
+ env.bak/
167
+ venv.bak/
168
+
169
+ # Spyder project settings
170
+ .spyderproject
171
+ .spyproject
172
+
173
+ # Rope project settings
174
+ .ropeproject
175
+
176
+ # mkdocs documentation
177
+ /site
178
+
179
+ # mypy
180
+ .mypy_cache/
181
+ .dmypy.json
182
+ dmypy.json
183
+
184
+ # Pyre type checker
185
+ .pyre/
186
+
187
+ # pytype static type analyzer
188
+ .pytype/
189
+
190
+ # Cython debug symbols
191
+ cython_debug/
192
+
193
+ # PyCharm
194
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
195
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
196
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
197
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
198
+ # .idea/
199
+
200
+ # Abstra
201
+ # Abstra is an AI-powered process automation framework.
202
+ # Ignore directories containing user credentials, local state, and settings.
203
+ # Learn more at https://abstra.io/docs
204
+ .abstra/
205
+
206
+ # Visual Studio Code
207
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
208
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
209
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
210
+ # you could uncomment the following to ignore the entire vscode folder
211
+ # .vscode/
212
+ # Temporary file for partial code execution
213
+ tempCodeRunnerFile.py
214
+
215
+ # Ruff stuff:
216
+ .ruff_cache/
217
+
218
+ # PyPI configuration file
219
+ .pypirc
220
+
221
+ # Marimo
222
+ marimo/_static/
223
+ marimo/_lsp/
224
+ __marimo__/
225
+
226
+ # Streamlit
227
+ .streamlit/secrets.toml
228
+
229
+ # SQLite database files (may appear anywhere in the project)
230
+ *.db
231
+ *.db-shm
232
+ *.db-wal
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.4
2
+ Name: credstore
3
+ Version: 0.3.7
4
+ Summary: Cross-platform credential storage — OS keyring with AES-encrypted file backup
5
+ Project-URL: Homepage, https://github.com/juzcn/slife
6
+ Project-URL: Repository, https://github.com/juzcn/slife
7
+ Project-URL: Documentation, https://github.com/juzcn/slife/blob/main/credstore/README.md
8
+ Author-email: juzcn <zhangjun@cueb.edu.cn>
9
+ License: MIT
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Security
20
+ Classifier: Topic :: System :: Systems Administration
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: keyring>=25.0.0
23
+ Requires-Dist: keyrings-cryptfile>=1.3.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ # credstore
27
+
28
+ Cross-platform credential storage — OS keyring + AES-encrypted file backup.
29
+
30
+ A standalone secret manager that ships with [Slife](https://github.com/juzcn/slife)
31
+ but does **not** depend on it. Only two lightweight dependencies: `keyring` and
32
+ `keyrings-cryptfile`.
33
+
34
+ ## Install
35
+
36
+ ### One-click (recommended)
37
+
38
+ ```bash
39
+ pip install credstore
40
+ ```
41
+
42
+ Or with uv:
43
+
44
+ ```bash
45
+ uv tool install credstore
46
+ ```
47
+
48
+ ### Verify
49
+
50
+ ```bash
51
+ credstore status
52
+ ```
53
+
54
+ No configuration needed — the OS keyring is used automatically.
55
+ Run `credstore set-password` to enable encrypted backup.
56
+
57
+ ---
58
+
59
+ ## CLI
60
+
61
+ ### Setup (first time)
62
+
63
+ ```bash
64
+ credstore set-password
65
+ ```
66
+
67
+ Creates `~/.credstore/credentials.crypt` and sets a master password (dev: `./credentials.crypt`). Path configurable via `CREDSTORE_FILE` env var.
68
+
69
+ ### Command Reference
70
+
71
+ | Command | Master key | Description |
72
+ |---------|:----------:|-------------|
73
+ | `set-password` | sets it | Create/change master key, init cryptfile |
74
+ | `set KEY` | enters it | Atomic dual-write (cryptfile + keyring). Rolls back on keyring failure |
75
+ | `get KEY` | no | Keyring only, masked output (`sk-5f…b722`) |
76
+ | `get KEY -p` | enters it | Dual-query keyring + cryptfile, plaintext. Fails on mismatch |
77
+ | `delete KEY` | enters it | Remove from keyring + cryptfile |
78
+ | `list` | enters it | List all stored credential keys |
79
+ | `inject KEY...` | no | Persist to system env: registry (Windows) or shell profile (Unix) |
80
+ | `uninject KEY...` | no | Remove from system env: registry (Windows) or shell profile (Unix) |
81
+ | `reset-keyring` | enters it | Restore keyring from cryptfile backup |
82
+ | `reset-backup` | enters it | Sync system keyring → cryptfile |
83
+ | `status` | no | Show backend status |
84
+
85
+ ```bash
86
+ credstore set-password # first-time setup
87
+ credstore set DEEPSEEK_API_KEY # store (masked, atomic dual-write)
88
+ credstore get DEEPSEEK_API_KEY # retrieve, masked output
89
+ credstore get DEEPSEEK_API_KEY -p # retrieve plaintext (dual-query)
90
+ credstore list # list all stored keys
91
+ credstore delete OLD_KEY # delete from keyring + cryptfile
92
+
93
+ # System environment injection (persistent)
94
+ credstore inject DEEPSEEK_API_KEY # Windows → registry, Unix → shell profile
95
+ Invoke-Expression (credstore inject KEY) # PowerShell: activate in current shell
96
+ eval "$(credstore inject KEY)" # Bash/Zsh: activate in current shell
97
+ credstore uninject DEEPSEEK_API_KEY # remove from registry/profile
98
+
99
+ credstore reset-keyring # restore keyring from cryptfile backup
100
+ credstore reset-backup # sync keyring → cryptfile
101
+ credstore status # show backend status
102
+ ```
103
+
104
+ ### Environment Variable Injection
105
+
106
+ `inject` reads a secret from the keyring and persists it to the system
107
+ environment. On Windows, it writes directly to the registry (`HKCU\Environment`);
108
+ on Unix, it appends to the shell profile. New shells load it automatically.
109
+
110
+ ```bash
111
+ # Persist + activate in current shell
112
+ credstore inject DEEPSEEK_API_KEY # persist to registry/profile
113
+ Invoke-Expression (credstore inject KEY) # PowerShell: activate now
114
+ eval "$(credstore inject KEY)" # Bash/Zsh: activate now
115
+
116
+ # Remove
117
+ credstore uninject DEEPSEEK_API_KEY # remove from registry/profile
118
+ ```
119
+
120
+ Secret never appears on the terminal — `inject` detects TTY and prints only
121
+ a hint. The actual export command flows through a pipe when wrapped in
122
+ `Invoke-Expression` / `eval`.
123
+
124
+ No master password required (keyring only).
125
+
126
+ ### Disaster Recovery
127
+
128
+ When the OS keyring loses data (e.g. after a Windows password change):
129
+
130
+ ```bash
131
+ credstore reset-keyring # restore all from cryptfile backup
132
+ ```
133
+
134
+ ## Design: Memory Safety
135
+
136
+ Secrets are immutable Python `str` objects — they cannot be zeroed in place.
137
+ credstore mitigates memory leaks through three design rules:
138
+
139
+ | Rule | Mechanism |
140
+ |------|-----------|
141
+ | **Never batch-load** | `list` collects only key names. Sync comparison fetches one value at a time and immediately `del`-s it |
142
+ | **Prefer existence checks** | `exists_credential()` / `list_credential_keys()` never retrieve secret content |
143
+ | **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 |
144
+
145
+ ### Operations that read/transport secrets
146
+
147
+ | Operation | How memory is cleaned |
148
+ |-----------|----------------------|
149
+ | `get` | Caller is responsible for `del`-ing the returned value |
150
+ | `set` | `del secret` + `del master_pw` after dual-write (all code paths) |
151
+ | `list` | Values fetched one-at-a-time, compared, `del`-ed immediately |
152
+ | `inject` | Value read → persisted → `del`-ed. TTY: no secret on stdout. Pipe: secret through pipe only |
153
+ | `uninject` | No secrets involved — registry/profile cleanup only |
154
+ | `reset-keyring` | Each value `del`-ed after writing to keyring |
155
+ | `reset-backup` | Batch load unavoidable, `del entries` + `del master_pw` after sync |
156
+ | `set-password` | `old_data` dict `del`-ed after re-encryption; all password strings cleaned up |
157
+
158
+ The `masked_input()` terminal helper echoes `*` for each keystroke — paste works but the
159
+ actual value is never displayed or logged.
160
+
161
+ ## Python API
162
+
163
+ ```python
164
+ import credstore
165
+
166
+ # Read / check / write / delete (system keyring only, no prompt)
167
+ credstore.get_credential("myapp/api_key") # → str | None
168
+ credstore.exists_credential("myapp/api_key") # → bool (NEVER returns secret)
169
+ credstore.list_credential_keys() # → list[str] (NEVER returns values)
170
+ credstore.set_credential("myapp/api_key", "sk-…")
171
+ credstore.delete_credential("myapp/api_key") # → bool
172
+
173
+ # Shell formatting (for env var injection)
174
+ credstore.format_export("MY_KEY", "secret", "bash") # → "export MY_KEY='secret'"
175
+ credstore.format_unset("MY_KEY", "bash") # → "unset MY_KEY"
176
+
177
+ # keyring: URI resolution
178
+ credstore.is_keyring_uri("keyring:myapp/k") # → True
179
+ credstore.resolve_uri("keyring:myapp/k") # → the secret value
180
+
181
+ # Backend info
182
+ credstore.check_backend() # → {"available": True, "backend": "…", …}
183
+ credstore.is_cryptfile_ready() # → True if master key is set
184
+ ```
185
+
186
+ Memory rule: callers of `get_credential()` and `resolve_uri()` MUST `del` the
187
+ returned value after use. Prefer `exists_credential()` or `list_credential_keys()`
188
+ when you only need to know whether a credential exists.
189
+
190
+ The Python API talks to the system keyring only — no master password, no prompt. Dual-write (keyring + cryptfile) is handled by the CLI.
@@ -0,0 +1,165 @@
1
+ # credstore
2
+
3
+ Cross-platform credential storage — OS keyring + AES-encrypted file backup.
4
+
5
+ A standalone secret manager that ships with [Slife](https://github.com/juzcn/slife)
6
+ but does **not** depend on it. Only two lightweight dependencies: `keyring` and
7
+ `keyrings-cryptfile`.
8
+
9
+ ## Install
10
+
11
+ ### One-click (recommended)
12
+
13
+ ```bash
14
+ pip install credstore
15
+ ```
16
+
17
+ Or with uv:
18
+
19
+ ```bash
20
+ uv tool install credstore
21
+ ```
22
+
23
+ ### Verify
24
+
25
+ ```bash
26
+ credstore status
27
+ ```
28
+
29
+ No configuration needed — the OS keyring is used automatically.
30
+ Run `credstore set-password` to enable encrypted backup.
31
+
32
+ ---
33
+
34
+ ## CLI
35
+
36
+ ### Setup (first time)
37
+
38
+ ```bash
39
+ credstore set-password
40
+ ```
41
+
42
+ Creates `~/.credstore/credentials.crypt` and sets a master password (dev: `./credentials.crypt`). Path configurable via `CREDSTORE_FILE` env var.
43
+
44
+ ### Command Reference
45
+
46
+ | Command | Master key | Description |
47
+ |---------|:----------:|-------------|
48
+ | `set-password` | sets it | Create/change master key, init cryptfile |
49
+ | `set KEY` | enters it | Atomic dual-write (cryptfile + keyring). Rolls back on keyring failure |
50
+ | `get KEY` | no | Keyring only, masked output (`sk-5f…b722`) |
51
+ | `get KEY -p` | enters it | Dual-query keyring + cryptfile, plaintext. Fails on mismatch |
52
+ | `delete KEY` | enters it | Remove from keyring + cryptfile |
53
+ | `list` | enters it | List all stored credential keys |
54
+ | `inject KEY...` | no | Persist to system env: registry (Windows) or shell profile (Unix) |
55
+ | `uninject KEY...` | no | Remove from system env: registry (Windows) or shell profile (Unix) |
56
+ | `reset-keyring` | enters it | Restore keyring from cryptfile backup |
57
+ | `reset-backup` | enters it | Sync system keyring → cryptfile |
58
+ | `status` | no | Show backend status |
59
+
60
+ ```bash
61
+ credstore set-password # first-time setup
62
+ credstore set DEEPSEEK_API_KEY # store (masked, atomic dual-write)
63
+ credstore get DEEPSEEK_API_KEY # retrieve, masked output
64
+ credstore get DEEPSEEK_API_KEY -p # retrieve plaintext (dual-query)
65
+ credstore list # list all stored keys
66
+ credstore delete OLD_KEY # delete from keyring + cryptfile
67
+
68
+ # System environment injection (persistent)
69
+ credstore inject DEEPSEEK_API_KEY # Windows → registry, Unix → shell profile
70
+ Invoke-Expression (credstore inject KEY) # PowerShell: activate in current shell
71
+ eval "$(credstore inject KEY)" # Bash/Zsh: activate in current shell
72
+ credstore uninject DEEPSEEK_API_KEY # remove from registry/profile
73
+
74
+ credstore reset-keyring # restore keyring from cryptfile backup
75
+ credstore reset-backup # sync keyring → cryptfile
76
+ credstore status # show backend status
77
+ ```
78
+
79
+ ### Environment Variable Injection
80
+
81
+ `inject` reads a secret from the keyring and persists it to the system
82
+ environment. On Windows, it writes directly to the registry (`HKCU\Environment`);
83
+ on Unix, it appends to the shell profile. New shells load it automatically.
84
+
85
+ ```bash
86
+ # Persist + activate in current shell
87
+ credstore inject DEEPSEEK_API_KEY # persist to registry/profile
88
+ Invoke-Expression (credstore inject KEY) # PowerShell: activate now
89
+ eval "$(credstore inject KEY)" # Bash/Zsh: activate now
90
+
91
+ # Remove
92
+ credstore uninject DEEPSEEK_API_KEY # remove from registry/profile
93
+ ```
94
+
95
+ Secret never appears on the terminal — `inject` detects TTY and prints only
96
+ a hint. The actual export command flows through a pipe when wrapped in
97
+ `Invoke-Expression` / `eval`.
98
+
99
+ No master password required (keyring only).
100
+
101
+ ### Disaster Recovery
102
+
103
+ When the OS keyring loses data (e.g. after a Windows password change):
104
+
105
+ ```bash
106
+ credstore reset-keyring # restore all from cryptfile backup
107
+ ```
108
+
109
+ ## Design: Memory Safety
110
+
111
+ Secrets are immutable Python `str` objects — they cannot be zeroed in place.
112
+ credstore mitigates memory leaks through three design rules:
113
+
114
+ | Rule | Mechanism |
115
+ |------|-----------|
116
+ | **Never batch-load** | `list` collects only key names. Sync comparison fetches one value at a time and immediately `del`-s it |
117
+ | **Prefer existence checks** | `exists_credential()` / `list_credential_keys()` never retrieve secret content |
118
+ | **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 |
119
+
120
+ ### Operations that read/transport secrets
121
+
122
+ | Operation | How memory is cleaned |
123
+ |-----------|----------------------|
124
+ | `get` | Caller is responsible for `del`-ing the returned value |
125
+ | `set` | `del secret` + `del master_pw` after dual-write (all code paths) |
126
+ | `list` | Values fetched one-at-a-time, compared, `del`-ed immediately |
127
+ | `inject` | Value read → persisted → `del`-ed. TTY: no secret on stdout. Pipe: secret through pipe only |
128
+ | `uninject` | No secrets involved — registry/profile cleanup only |
129
+ | `reset-keyring` | Each value `del`-ed after writing to keyring |
130
+ | `reset-backup` | Batch load unavoidable, `del entries` + `del master_pw` after sync |
131
+ | `set-password` | `old_data` dict `del`-ed after re-encryption; all password strings cleaned up |
132
+
133
+ The `masked_input()` terminal helper echoes `*` for each keystroke — paste works but the
134
+ actual value is never displayed or logged.
135
+
136
+ ## Python API
137
+
138
+ ```python
139
+ import credstore
140
+
141
+ # Read / check / write / delete (system keyring only, no prompt)
142
+ credstore.get_credential("myapp/api_key") # → str | None
143
+ credstore.exists_credential("myapp/api_key") # → bool (NEVER returns secret)
144
+ credstore.list_credential_keys() # → list[str] (NEVER returns values)
145
+ credstore.set_credential("myapp/api_key", "sk-…")
146
+ credstore.delete_credential("myapp/api_key") # → bool
147
+
148
+ # Shell formatting (for env var injection)
149
+ credstore.format_export("MY_KEY", "secret", "bash") # → "export MY_KEY='secret'"
150
+ credstore.format_unset("MY_KEY", "bash") # → "unset MY_KEY"
151
+
152
+ # keyring: URI resolution
153
+ credstore.is_keyring_uri("keyring:myapp/k") # → True
154
+ credstore.resolve_uri("keyring:myapp/k") # → the secret value
155
+
156
+ # Backend info
157
+ credstore.check_backend() # → {"available": True, "backend": "…", …}
158
+ credstore.is_cryptfile_ready() # → True if master key is set
159
+ ```
160
+
161
+ Memory rule: callers of `get_credential()` and `resolve_uri()` MUST `del` the
162
+ returned value after use. Prefer `exists_credential()` or `list_credential_keys()`
163
+ when you only need to know whether a credential exists.
164
+
165
+ The Python API talks to the system keyring only — no master password, no prompt. Dual-write (keyring + cryptfile) is handled by the CLI.
@@ -0,0 +1,10 @@
1
+ {
2
+ // credstore configuration.
3
+ // Lookup order: ./credstore.json5 → ~/.credstore/config.json5
4
+ // Env var CREDSTORE_FILE overrides both.
5
+ //
6
+ // If no config is found, defaults to ~/.credstore/credentials.crypt
7
+
8
+ // Custom path for the encrypted credential file:
9
+ // cryptfile_path: "~/.credstore/credentials.crypt",
10
+ }
@@ -0,0 +1,75 @@
1
+ """credstore — secure credential storage via OS keyring.
2
+
3
+ Cross-platform API for retrieving secrets stored in the OS keyring
4
+ with keyrings.cryptfile encrypted backup. Secrets are *stored* only
5
+ via the CLI (``credstore set``) which reads from masked stdin — never
6
+ through Python function arguments.
7
+
8
+ Modules::
9
+
10
+ _store.py CredentialStore + module-level API
11
+ _shell.py Shell formatting helpers
12
+ _backend.py Dual-write backends (system keyring + cryptfile)
13
+ _enumerate.py Platform-specific credential enumeration
14
+ _config.py Config file loading
15
+ _resolver.py keyring: URI resolution
16
+ _tty.py Masked terminal input
17
+ __main__.py CLI (entry point)
18
+
19
+ Usage::
20
+
21
+ import credstore
22
+
23
+ # Retrieve a secret
24
+ value = credstore.get_credential("myapp/api_key")
25
+
26
+ # Resolve keyring: URIs in config values
27
+ resolved = credstore.resolve_uri("keyring:myapp/api_key")
28
+
29
+ # Delete
30
+ credstore.delete_credential("myapp/api_key")
31
+
32
+ # Shell formatting
33
+ credstore.format_export("KEY", "value", "bash") # → export statement
34
+
35
+ # Check backend
36
+ info = credstore.check_backend()
37
+ """
38
+
39
+ from credstore._shell import format_export, format_unset
40
+ from credstore._store import (
41
+ get_credential,
42
+ exists_credential,
43
+ list_credential_keys,
44
+ set_credential,
45
+ delete_credential,
46
+ get_backend_name,
47
+ check_backend,
48
+ init_store,
49
+ )
50
+ from credstore._resolver import (
51
+ resolve_uri,
52
+ is_keyring_uri,
53
+ parse_keyring_uri,
54
+ )
55
+
56
+ __all__ = [
57
+ # Read / write / delete
58
+ "get_credential",
59
+ "exists_credential",
60
+ "list_credential_keys",
61
+ "set_credential",
62
+ "delete_credential",
63
+ # URI resolution
64
+ "is_keyring_uri",
65
+ "parse_keyring_uri",
66
+ "resolve_uri",
67
+ # Shell formatting
68
+ "format_export",
69
+ "format_unset",
70
+ # Diagnostics
71
+ "get_backend_name",
72
+ "check_backend",
73
+ "init_store",
74
+ ]
75
+ __version__ = "0.3.6"