Secure storage vault for secrets in git repositories (SOPS alike)
Project description
xvault
xvault is a CLI for keeping secrets inside your real config and notes files, while staying Git-friendly.
Your files remain readable and reviewable, and only the values you explicitly mark as secret are encrypted.
The core idea is a single source of truth: store secrets, notes, and configuration together in a small set of canonical files (.json, .jsonc, .yaml, .env, .md), and let xvault handle safe editing, encryption, and export.
From these files, you can derive/export/resolve the exact formats your tooling expects (e.g., .env, JSON config, certificate files) without duplicating plaintext secrets across multiple files or repositories.
To minimize cognitive load, xvault keeps the workflow intentionally simple: secure defaults, straightforward commands, and optional OS key caching (no servers to run, no KMS to configure, and no complex policy systems). It’s optimized for solo developers and small teams who want a local-first vault that integrates cleanly with Git.
Intro
Motivation: single source of truth for developer secrets
Most developer workflows end up with friction such as:
- a config file plus a separate secrets file
- manual merging before deployment / resolving secrets at runtime
- ugly diffs (whole files encrypted)
- accidental leaks when exporting plaintext
xvault is designed to keep your notes and configs as the source of truth, with inline secrets that stay encrypted on disk.
Comparison: SOPS and git-crypt
xvault overlaps with tools like SOPS and git-crypt, but it targets a slightly different “developer ergonomics” space:
-
SOPS shines for GitOps/Kubernetes workflows and KMS-backed key management. It’s great when your infra pipeline is already built around SOPS + KMS/PGP/age.
xvaultis not trying to replace that ecosystem; it focuses on editing arbitrary files (.json, .jsonc, .env, .yml, .md) with minimal ceremony and clean diffs. -
git-crypt is effective for encrypting entire files transparently in Git.
xvaulttakes a more explicit approach: secrets are marked withenc:or${enc:...}and only those values are encrypted, keeping the rest of the document readable.
If your main need is “encrypt a whole directory of files in git”, git-crypt may be enough.
If your main need is “keep notes/config readable while only encrypting secret values”, xvault is a better fit.
Design philosophy
- Explicit by default: only values marked with
enc:or${enc:...}are treated as secrets. - Git diffs matter: keep secrets stored as single-line ciphertext.
- Stay close to real formats: work with .json, .jsonc, .yaml, .env, .md, without forcing a rigid schema.
- Developer UX first:
editis the primary workflow; everything else supports it. - Safe defaults: prefer failing loudly over producing ambiguous output.
Usage
xvault is designed for two main workflows. Both rely on the same core idea: keep secrets inside the files you already use, encrypt only what you explicitly mark as secret (enc: or ${enc:...}), and derive/export the exact outputs when needed.
1) Application config files with embedded secrets
Use xvault directly on configuration files that your applications and tooling already understand:
.envfiles- JSON / JSONC
- YAML
- md files
You keep the config readable, and only encrypt values marked as secrets (enc:... or ${enc:...}).
Example (dev.env):
DB_HOST=localhost
DB_USER=enc:admin
DB_PASS=enc:"my password with spaces"
DATABASE_URL=postgres://${var:DB_USER}:${var:DB_PASS}@localhost/app
Typical workflow:
xvault edit ./dev.envto safely edit secrets and non-secret config togetherxvault export ./dev.envto materialize a decrypted output for scripts/CI/runtimexvault get ./dev.env DB_PASSto extract a decrypted value from file
2) Personal vault notes (Markdown)
Use xvault as a local-first personal vault where you store notes, runbooks, logs, credentials, and key material inside Markdown files.
A common pattern is:
- one Markdown file per topic (e.g., servers.md, accounts.md, infra.md)
- secrets stored inside standard fenced blocks like ```env
Example (servers.md):
## prod-api-01
Notes and runbook steps in plain text...
```env
SSH_HOST=prod-api-01.example.com
SSH_USER=enc:admin
SSH_PASS=${enc:my password with spaces}
SSH_KEY_PEM_B64=enc:LS0tLS1CRUdJTiBPU...
```
Guidelines:
- Use
enc:...or${enc:...}for secret values. - Use *_B64 variables for multi-line or binary material (PEM/PFX/PDF/PNG) encoded as base64.
- Keep everything else (notes, procedures, logs) in plain text for excellent Git diffs and searchability.
Features
- Formats: .json, .jsonc, .yaml, .env, .md
- Inline secret marking:
enc:...and${enc:...}indicate secret values - Single-line ciphertext for clean Git diffs
- Optional variable substitution: resolve
${var:VARNAME}placeholders (xvault get file.json secret_name --resolve) - Key caching (optional):
unlockstores a derived key in the OS key storelockremoves it--no-cache-keydisables cache read/write per command
- Crypto (v1):
- Password-based key derivation: Argon2id
- Encryption: AES-256-GCM (authenticated encryption)
- Rekey support: rotate secrets to a new password (
xvault rekey) - Validation: sanity checks for file structure and encrypted markers (
xvault validate)
Security Model
What xvault protects against
- Accidental commits of plaintext secrets by keeping secrets encrypted on disk
- “Diff leakage”: avoids storing whole plaintext configs; only
enc:.../${enc:...}values become ciphertext - Backup leakage: encrypted vault files are safe to back up as ciphertext
- Tampering detection: AES-GCM provides integrity/authentication for secret values (wrong key or modified ciphertext fails to decrypt)
- By default, xvault edit uses an in-terminal editor and does not write plaintext temp files.
Threats it does NOT fully solve (limitations)
- Weak passwords: your vault is only as strong as the password you choose. Use a strong passphrase (e.g., 12–16+ characters, preferably more).
- Compromised machine: if an attacker owns your box while you edit, they can read memory, or use a keylogger, or inspect terminal buffers. Or if an attacker gains access to your machine, they may be able to extract the cached key from the OS key store and decrypt your vault without ever needing to wait for you to edit.
- Plaintext exports:
exportcan produce decrypted content. Handle it carefully (gitignore, temporary locations). - OS key cache availability: keyring/credential storage may fail in some contexts (e.g., Windows over SSH). Use
--no-cache-keyor alternative cache strategies.
Threat mitigations (practical)
- Use a strong, unique password (prefer long passphrases).
- Keep repositories private; avoid cloning vault repos on untrusted machines.
- Prefer
--no-cache-keyin sensitive environments (remote sessions, servers, CI). - Run
xvault validatebefore committing.
Example file (conceptual)
xvault stores a small metadata header (e.g. _xvault) and secrets as enc:/${enc:...} values:
{
"_xvault": "xvault:<opaque-metadata-blob>",
"db": {
"host": "...",
"user": "enc:...",
"password": "enc:...",
"url": "https://login:${enc:...}@server/path/to/resource"
}
}
_xvault="xvault:<opaque-metadata-blob>"
DB_HOST=...
DB_USER=enc:...
DB_PASSWORD=enc:...
Installation
Install from PyPI:
pip install xvault
xvault version
Install from source (development)
Clone the repository:
# clone the repository:
git clone https://github.com/marcdp/xvault.git
# run the CLI:
python -m xvault
# or install as a command:
pip install .
Roadmap
Short-term (quality and UX):
- Improve TUI editor UX (colors, navigation, safer save guards, undo-redo)
- Better Markdown conventions for multi-line secrets and binary references
- Safer export modes (explicit confirmations)
Mid-term (developer workflows):
- Export filtering by section/scope in Markdown (e.g., server.var)
- SSH-agent helpers (load selected keys with TTL)
- A "blob store" for large binary secrets (PFX/PDF/PNG) with manifest + encrypted blobs
Long-term:
- VS Code virtual filesystem provider (xvault:/...) backed by xvault (no plaintext temp files)
- Optional policy validation hooks (pre-commit integration)
- Optional alternative key caching backends (more reliable across SSH / WSL)
License
MIT License
See the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 xvault-0.0.38.tar.gz.
File metadata
- Download URL: xvault-0.0.38.tar.gz
- Upload date:
- Size: 24.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbc667fc8751e647f4e8514af7f39b06e17d9cf84a309677c76b2071d2695f51
|
|
| MD5 |
809dbcb573917f7f31aa757a1582664f
|
|
| BLAKE2b-256 |
2c8f4283b5781e41df2c963ef228306deac87afae32e12cec8884089a5c4c635
|
File details
Details for the file xvault-0.0.38-py3-none-any.whl.
File metadata
- Download URL: xvault-0.0.38-py3-none-any.whl
- Upload date:
- Size: 14.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4209870ec7daaf3bd8beec5e722f65d97e91b2ed079ad5d9a9b2cb9bb2dabda
|
|
| MD5 |
21d550f38be94f2f373ab6c24fa1c662
|
|
| BLAKE2b-256 |
5b18a9df5a2239c0efc2e708375bed4efe3751e70782f1a6d6330d411331bfda
|