Lightweight secrets manager — encrypted vault, env injection, stdout redaction. No Docker, no server, no account.
Project description
ownlock
Lightweight secrets manager — encrypted local vault, .env injection, stdout redaction.
No Docker. No server. No account. Just pip install ownlock.
Quick start
# Install
pip install ownlock
# Create your first vault (project vault at ./.ownlock/; use --global for ~/.ownlock/)
ownlock init
# Store a secret (interactive prompt)
ownlock set anthropic-api-key
# Or inline
ownlock set openai-api-key=sk-xxxx
# Reference secrets in .env — they’re resolved at runtime
echo 'ANTHROPIC_API_KEY=vault("anthropic-api-key")' >> .env
# Run your app: secrets are injected and redacted from stdout
ownlock run -- python app.py
Full usage guide
1. Initialize a vault
You need a vault before storing secrets. Pick one of two locations:
| Vault type | Command | Location | When to use |
|---|---|---|---|
| Project | ownlock init |
./.ownlock/vault.db |
One vault per project (adds .ownlock/ to .gitignore) |
| Global | ownlock init --global |
~/.ownlock/vault.db |
Shared across all projects (passphrase in keyring) |
# Project vault — good for repo-specific secrets (default)
ownlock init
# Global vault — good for personal API keys you reuse
ownlock init --global
2. Store and retrieve secrets
# Store (prompts for value)
ownlock set my-secret
# Store inline
ownlock set DATABASE_URL=postgres://localhost/mydb
# Different environments (default, production, staging, etc.)
ownlock set api-key --env production
# Retrieve
ownlock get my-secret
# List all (names only, never values)
ownlock list
# Delete
ownlock delete my-secret
3. Which vault is used?
| Situation | Vault used |
|---|---|
You're inside a directory that has .ownlock/vault.db (or a parent does) |
Project vault (closest one found) |
| No project vault found | Global vault |
You pass --global |
Global vault (always) |
You pass --project |
Project vault at current directory (always) |
Commands that accept --global and --project: set, get, list, delete, import, scan.
run and export don’t use these flags — they read vault references from your .env file.
4. .env format
Plain values go through as-is. Secrets use vault("name") and are resolved when you run commands.
Example .env:
# Plain config (not secret)
OLLAMA_BASE_URL=http://localhost:11434
DEFAULT_MODEL=anthropic:claude-opus
# Secrets from vault
# If a project vault exists, these come from the project vault by default;
# otherwise they come from the global vault.
SUPABASE_URL=vault("supabase-url")
SUPABASE_SERVICE_KEY=vault("supabase-service-key")
ANTHROPIC_API_KEY=vault("anthropic-api-key")
OPENAI_API_KEY=vault("openai-api-key", env="production")
To force the global vault even when a project vault exists, use global=true:
# Always read from global vault
GLOBAL_ONLY_SECRET=vault("global-only-secret", global=true)
5. Run and export
# Resolve .env, inject secrets, run command, redact secret values from stdout
ownlock run -- python app.py
# Custom .env path
ownlock run -f .env.local -- python app.py
# Print resolved KEY=VALUE pairs (e.g. for Docker)
ownlock export --format docker
6. Bulk import and scanning
# Import from a plaintext .env
ownlock import secrets.env
# Scan for leaked secret values
ownlock scan .
7. Guided setup (ownlock auto)
# After init, run a guided import + rewrite:
ownlock auto
ownlock auto(project-first) discovers common env files (.env,.env.local, etc.), lets you pick which to import from, and loads validKEY=VALUEpairs into the vault.- It can then rewrite your env file (by default
.env) so matching keys usevault("KEY")references, making it easy to go from plaintext env to vault-backed env in one flow. - For non-interactive or CI, use flags like:
ownlock auto -f .env --yes
ownlock rewrite-env -f .env --yes
Command reference
| Command | Description |
|---|---|
ownlock init |
Create project vault at ./.ownlock/vault.db |
ownlock init --global |
Create global vault at ~/.ownlock/vault.db |
ownlock set KEY |
Store secret (prompts for value) |
ownlock set KEY=VALUE |
Store secret inline |
ownlock get KEY |
Print decrypted value |
ownlock list |
List secret names (never values) |
ownlock delete KEY |
Remove a secret |
ownlock run -- CMD |
Resolve .env, inject secrets, redact stdout |
ownlock export |
Print resolved KEY=VALUE pairs |
ownlock import FILE |
Bulk import from plaintext .env |
ownlock rewrite-env |
Rewrite an env file to use vault() references |
ownlock auto |
Guided import + rewrite for env files |
ownlock scan DIR |
Scan for leaked secret values |
Add --global or --project to set, get, list, delete, import, scan to override vault selection.
How it works
- Secrets are encrypted with AES-256-GCM before storage
- Key derivation: PBKDF2-HMAC-SHA256 with 200,000 iterations
- Passphrase stored in your system keyring (macOS Keychain, GNOME Keyring, etc.)
ownlock runresolvesvault()in.env, injects env vars, and redacts secret values from stdout/stderr- Zero network calls. Everything stays local.
Security
- Value-level encryption: Each secret is encrypted separately with AES-256-GCM. The SQLite file stores ciphertext, not plaintext.
- Passphrase: Required to decrypt. Without it, the vault is unusable.
- No RLS: SQLite does not support row-level security (RLS). RLS is a multi-tenant feature (e.g. PostgreSQL) that restricts which rows a role can see. ownlock is single-user and local; security comes from per-value encryption and file permissions on
vault.db. - File permissions: Keep
~/.ownlock/and.ownlock/with restrictive permissions. Add.ownlock/to.gitignorefor project vaults (done automatically withinit --project).
License
MIT
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 ownlock-0.1.3.tar.gz.
File metadata
- Download URL: ownlock-0.1.3.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f04a4260e1bdc73afa65d1d05c3471ced65faeb7de047a2d678fea7945cc587e
|
|
| MD5 |
96b1eded19e77374ac83dac2fc519aa3
|
|
| BLAKE2b-256 |
a4d8e675494f043de5180125088368017fbec86f944ab83549d687bff4f9ecdf
|
Provenance
The following attestation bundles were made for ownlock-0.1.3.tar.gz:
Publisher:
ci.yml on thebscolaro/ownlock
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ownlock-0.1.3.tar.gz -
Subject digest:
f04a4260e1bdc73afa65d1d05c3471ced65faeb7de047a2d678fea7945cc587e - Sigstore transparency entry: 1097006978
- Sigstore integration time:
-
Permalink:
thebscolaro/ownlock@bbf3598c4d2bb9c2f243c562f60451ef22062d13 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/thebscolaro
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@bbf3598c4d2bb9c2f243c562f60451ef22062d13 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ownlock-0.1.3-py3-none-any.whl.
File metadata
- Download URL: ownlock-0.1.3-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b3d8cc8ec9de5c509c4f4134ebced01d9de0defdd931a7118eb7f4c11a93ada
|
|
| MD5 |
d9e1bc67be5200ebf0d704ea80ca52b8
|
|
| BLAKE2b-256 |
5d13c4357accd38c0234764eac9ba8659f81b21f82e6bdb7f28df58b10b3df3e
|
Provenance
The following attestation bundles were made for ownlock-0.1.3-py3-none-any.whl:
Publisher:
ci.yml on thebscolaro/ownlock
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ownlock-0.1.3-py3-none-any.whl -
Subject digest:
1b3d8cc8ec9de5c509c4f4134ebced01d9de0defdd931a7118eb7f4c11a93ada - Sigstore transparency entry: 1097006979
- Sigstore integration time:
-
Permalink:
thebscolaro/ownlock@bbf3598c4d2bb9c2f243c562f60451ef22062d13 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/thebscolaro
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@bbf3598c4d2bb9c2f243c562f60451ef22062d13 -
Trigger Event:
push
-
Statement type: