Python bindings for the dotvault public client API (read per-user Vault secrets dotvault enrols)
Project description
dotvault — Python bindings
Python bindings for dotvault's public client API. They let a Python program read the per-user secrets a dotvault daemon enrolled and keeps current — talking to the same Vault, resolving a token the same way, and reading from the exact kv/users/<user>/... path dotvault writes to.
The package is a thin ctypes wrapper over dotvault's Go client package compiled to a shared library with go build -buildmode=c-shared. Connectivity, token precedence, the OS-user identity convention, and the path layout all come from the one canonical Go implementation rather than being re-derived in Python, so a consumer can't silently diverge from the daemon. The native bridge imports only the public Go client package — never dotvault's internals.
Scope
This first release exposes the read-only + cached-auth subset of the Go facade:
Client(config_path=None, identity=None)— load config, build the client.authenticate_cached(timeout=None)— resolve a token (DOTVAULT_TOKEN→ token file → peer socket borrow whenvault.token_socketis configured) and validate it. The socket borrow is a plain read with no browser or prompt, so a host with no local token but a live peer socket authenticates without an interactive login. Never prompts.identity_name(),token().read_user_secret(service, field, timeout=None),read_kv_field(mount, path, field, timeout=None).
Interactive login (OIDC browser pop, LDAP password + MFA terminal prompts) is deliberately out of scope — driving it across an FFI boundary from inside a Python process is awkward and not what a library caller wants. Provision a token out of band (dotvault login, or the daemon) and these bindings consume it.
Install
Released wheels are published to PyPI (Linux manylinux_2_28, macOS arm64, Windows x86_64):
pip install dotvault # or: uv pip install dotvault
The wheel is tagged py3-none-<platform>: it carries a native shared library (so it is platform-specific) but contains no CPython C-extension — it is pure ctypes — so a single wheel per OS installs on any Python ≥ 3.9, not one wheel per interpreter version. Its version is derived from the repo's git tags by setuptools-scm (the same tags that version the daemon); dotvault.__version__ reports it.
Wheels are built for glibc Linux x86_64 (manylinux_2_28), Apple-Silicon macOS, and Windows x86_64. There are currently no wheels for Linux aarch64, musl/Alpine, Intel macOS, or Windows arm64 — pip install on those reports "no matching distribution"; build from a checkout instead.
To build from a checkout instead — the tooling is uv:
make python-wheel # -> python/dist/dotvault-*.whl (runs `uv build`)
uv pip install python/dist/dotvault-*.whl
or an editable install (requires Go on PATH, since the bridge is compiled on install):
cd python && uv pip install -e .
Building from source needs the Go toolchain and a C compiler — go build -buildmode=c-shared is the one place dotvault uses cgo (CGO_ENABLED=1). The main dotvault binaries remain pure-Go static builds; only this binding links libc. On Windows the C compiler must be a mingw-w64 gcc (the c-shared build does not work with MSVC); GitHub's windows-latest runners ship one, but a local Windows build needs it on PATH.
Concurrency note: set DOTVAULT_TOKEN before the first use of a Client, not concurrently with reads from another thread. The bridge re-reads the facade's env vars from libc on each token-resolving call; that read/write is serialised internally, but it cannot be made safe against the host process mutating its own environment from another thread.
Quick start
import dotvault
# Defaults: dotvault's system config path, identity = the OS user.
with dotvault.Client() as c:
try:
c.authenticate_cached(timeout=5) # env -> token file; no prompt
except dotvault.LoginRequired:
raise SystemExit("run `dotvault login` first")
except dotvault.Unreachable:
raise SystemExit("vault is unreachable; retry later")
token = c.read_user_secret("gh", "oauth_token") # -> str | None
if token is None:
raise SystemExit("github enrolment not present")
use(token)
A read returns the field value, or None when the secret or field is absent — a missing path and a missing field are not distinguished (both are "not there"), matching the Go facade. Transport/authorisation failures raise instead.
Identity is the OS user, not the Vault token
dotvault derives the <user> segment of kv/users/<user>/... from the OS account the process runs as (with any DOMAIN\ prefix stripped), not from the Vault token's display_name or entity. By default a consumer must therefore run as the same OS user as the dotvault that populated the secrets — normally true for a per-user daemon.
If your process runs as a different user (a service account, a container), pass identity= to read that user's secrets:
dotvault.Client(identity="alice")
A wrong identity reads a non-existent path, which surfaces as a None read — not an error.
Errors
Every failure is a DotvaultError or a subclass:
| Exception | Meaning | What to do |
|---|---|---|
LoginRequired |
No usable cached token. | Provision a token (dotvault login). |
Unreachable |
Vault down / 5xx / timeout. | Retry, back off. |
Denied |
Vault rejected the read (401/403). | Fail closed; the token lacks the policy. |
AuthFailed |
A login ran but failed. | Surface the auth problem (rare on this surface). |
DotvaultError |
Anything else (config load, closed client). | Fail closed. |
A not-found read is None, never an exception.
Environment variables
The bindings honour the same variables as dotvault: DOTVAULT_TOKEN (a token supplied via the environment) and VAULT_NAMESPACE. VAULT_TOKEN is deliberately ignored — it belongs to the vault CLI and must not leak into dotvault's session; use DOTVAULT_TOKEN.
The Go runtime snapshots its environment at load time, so the bridge re-reads these two variables from the live process environment on each call. That means setting os.environ["DOTVAULT_TOKEN"] after import dotvault works as you'd expect.
Development
make python-lib # build the native bridge into the package for local use
make python-test # build the bridge + run the Python test suite (via `uv run`)
go test ./python/bridge/... # the Go-side bridge unit tests
make python-test and make python-wheel shell out to uv, which provisions Python and the test/build dependencies; only the Go toolchain and a C compiler need to be present beforehand.
The Python tests run fully offline — they point at a closed Vault port and assert the error categorisation — so no live Vault is needed.
Releasing
Publishing a GitHub Release with a vX.Y.Z tag drives both the Go release (release.yml) and the Python wheels: the .github/workflows/python.yml publish job builds the per-OS wheels and uploads them to PyPI via the official pypa/gh-action-pypi-publish action using Trusted Publishing (OIDC — no stored token). One-time setup before the first release: register a pending publisher on PyPI for project dotvault pointing at this repository, workflow python.yml, and environment pypi. A dev/untagged build produces a PEP 440 local version that PyPI rejects, so only exact tagged releases publish. Consider a one-off TestPyPI dry run (temporarily pointing the action at TestPyPI) before the first real release to validate the OIDC/publisher wiring.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dotvault-0.26.0-py3-none-win_amd64.whl.
File metadata
- Download URL: dotvault-0.26.0-py3-none-win_amd64.whl
- Upload date:
- Size: 10.7 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fd0ea5b4a7d6317d7d9438003c51630a59040daa636dd84023b7e736f522a73
|
|
| MD5 |
698a18d566737b2f9ac3e6c538b32bec
|
|
| BLAKE2b-256 |
795d5e64b857a71f60467c1a86a8dea5ce2b635f7b411b1b15067ac09e7f4b92
|
Provenance
The following attestation bundles were made for dotvault-0.26.0-py3-none-win_amd64.whl:
Publisher:
python.yml on goodtune/dotvault
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotvault-0.26.0-py3-none-win_amd64.whl -
Subject digest:
3fd0ea5b4a7d6317d7d9438003c51630a59040daa636dd84023b7e736f522a73 - Sigstore transparency entry: 2030492701
- Sigstore integration time:
-
Permalink:
goodtune/dotvault@75a2ea8ff4bfabfc0857fd21a8590460d2fc2fe0 -
Branch / Tag:
refs/tags/v0.26.0 - Owner: https://github.com/goodtune
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python.yml@75a2ea8ff4bfabfc0857fd21a8590460d2fc2fe0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dotvault-0.26.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: dotvault-0.26.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 10.9 MB
- Tags: Python 3, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f8bdd85c07e026146f84a5c4893c2df0c7945f12294c8465f502d5d17df3d9d
|
|
| MD5 |
10b2bbd0b5d9fa30634a81847b84f4cc
|
|
| BLAKE2b-256 |
f3f5ebf697b57e118a09c32b4cbf622dfc8bced90a3fd08a6ef7e4db10a51d8d
|
Provenance
The following attestation bundles were made for dotvault-0.26.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl:
Publisher:
python.yml on goodtune/dotvault
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotvault-0.26.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl -
Subject digest:
9f8bdd85c07e026146f84a5c4893c2df0c7945f12294c8465f502d5d17df3d9d - Sigstore transparency entry: 2030492991
- Sigstore integration time:
-
Permalink:
goodtune/dotvault@75a2ea8ff4bfabfc0857fd21a8590460d2fc2fe0 -
Branch / Tag:
refs/tags/v0.26.0 - Owner: https://github.com/goodtune
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python.yml@75a2ea8ff4bfabfc0857fd21a8590460d2fc2fe0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dotvault-0.26.0-py3-none-macosx_26_0_arm64.whl.
File metadata
- Download URL: dotvault-0.26.0-py3-none-macosx_26_0_arm64.whl
- Upload date:
- Size: 5.5 MB
- Tags: Python 3, macOS 26.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54271dbe9daba1183a0d0e0eb179b4f2dc65bb8a0be60e05b0be96c88414b4f8
|
|
| MD5 |
3ba07a829c6682696725e75775367799
|
|
| BLAKE2b-256 |
92c150241913b18846d437e8b04823f0cb2471dc5ea75929ae4f45bb4aacd8a6
|
Provenance
The following attestation bundles were made for dotvault-0.26.0-py3-none-macosx_26_0_arm64.whl:
Publisher:
python.yml on goodtune/dotvault
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotvault-0.26.0-py3-none-macosx_26_0_arm64.whl -
Subject digest:
54271dbe9daba1183a0d0e0eb179b4f2dc65bb8a0be60e05b0be96c88414b4f8 - Sigstore transparency entry: 2030492837
- Sigstore integration time:
-
Permalink:
goodtune/dotvault@75a2ea8ff4bfabfc0857fd21a8590460d2fc2fe0 -
Branch / Tag:
refs/tags/v0.26.0 - Owner: https://github.com/goodtune
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python.yml@75a2ea8ff4bfabfc0857fd21a8590460d2fc2fe0 -
Trigger Event:
release
-
Statement type: