Skip to main content

Lightweight secrets manager — encrypted vault, env injection, stdout redaction. Optional MCP (stdio) delegates to CLI. No Docker, no cloud account.

Project description

ownlock

Lightweight secrets manager — encrypted local vault, .env injection, stdout redaction.

No Docker. No cloud account. Just pip install ownlock.


Quick start

pip install ownlock
ownlock init

Have a plaintext .env? Run ownlock auto to import secrets and rewrite the file to use vault().

Otherwise: set a secret, add one line to .env, then run your app:

ownlock set api-key
# Add to .env: MY_APP_KEY=vault("api-key")
ownlock run -- python app.py

MCP (Model Context Protocol)

Optional integration for assistants (e.g. Cursor): the MCP server does not decrypt the vault in its own process. It spawns the ownlock CLI; passphrase and secrets are handled only in that subprocess.

pip install 'ownlock[mcp]'

Run the stdio server (configure your client to launch this command):

ownlock-mcp

Tools:

  • ownlock_run — same as ownlock run -f <file> -e <vault_env> -- <command...>; returns exit code and captured stdout/stderr (redaction applies in the child as usual).
  • ownlock_list_secret_names — same as ownlock list (names only, never values).
  • ownlock_version — installed package version.

get and export are intentionally not exposed via MCP.

Cursor example (.cursor/mcp.json or global MCP settings):

{
  "mcpServers": {
    "ownlock": {
      "command": "ownlock-mcp",
      "args": []
    }
  }
}

Use the full path to ownlock-mcp if it is not on your PATH (e.g. ~/.local/bin/ownlock-mcp or your venv’s bin).


Guided setup (ownlock auto)

ownlock auto discovers .env and common variants (.env.local, etc.), lets you choose which file and keys to import, then optionally rewrites the file so matching keys use vault("..."). After that you can use ownlock run -- your-command without editing .env by hand.

ownlock auto

For CI or non-interactive use:

ownlock auto -f .env --yes

Initialize a vault

Command Effect
ownlock init Project vault at ./.ownlock/vault.db. First run also creates the global vault and stores the passphrase in the keyring.
ownlock init --global Global vault only at ~/.ownlock/vault.db (passphrase in keyring).
ownlock init
# or global only:
ownlock init --global

Store, list, delete

ownlock set my-secret
ownlock set api-key=your-value
ownlock set database-url --env production
ownlock list
ownlock get my-secret
ownlock delete my-secret

set and import overwrite any existing value for the same key (and env).


Which vault is used?

Situation Vault used
Inside a directory with .ownlock/vault.db (or a parent) Project vault
No project vault found Global vault
--global Global vault
--project Project vault at current directory

Commands that accept --global / --project: set, get, list, delete, import, scan. run and export read vault references from your .env file.


.env format

Use vault("name") for secrets; they are resolved when you run commands.

API_KEY=vault("api-key")
DATABASE_URL=vault("database-url")
SUPABASE_SERVICE_KEY=vault("supabase-service-key", env="production")

To force the global vault: vault("name", global=true).


Run and export

ownlock run -- python app.py
ownlock run -f .env.local -- python app.py
ownlock export --format docker

get and export print secrets to stdout. Use only in trusted environments; prefer ownlock run to inject secrets into a process without printing them.


Import, rewrite-env, scan

ownlock import secrets.env
ownlock rewrite-env -f .env
ownlock scan .

Command reference

Command Description
ownlock init Create project vault (first run also creates global + keyring)
ownlock init --global Create global vault only
ownlock set KEY / KEY=VALUE Store secret
ownlock get KEY Print decrypted value
ownlock list List secret names
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 env file to use vault()
ownlock auto Guided import + rewrite
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 (200,000 iterations).
  • Passphrase is stored in the system keyring when you use init (global or first project init).
  • ownlock run resolves vault() in .env, injects env vars, and redacts secret values from stdout/stderr. No network; everything stays local.

Security

  • Encryption: Each secret is encrypted with AES-256-GCM; the vault stores ciphertext only.
  • Passphrase: Required to decrypt; keep it safe. Keyring avoids typing it every time.
  • get / export: Both print secrets to stdout. Use in trusted environments only; prefer ownlock run to inject without printing.
  • Overwrite: set and import overwrite existing values for the same key (and env); no append.
  • File permissions: Restrict permissions on ~/.ownlock/ and .ownlock/. Project init adds .ownlock/ to .gitignore.
  • Automated checks: Bandit, pip-audit, security-focused tests, and subprocess smoke tests (pytest -m smoke) — see SECURITY_TESTING.md.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ownlock-0.1.8.tar.gz (30.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ownlock-0.1.8-py3-none-any.whl (19.9 kB view details)

Uploaded Python 3

File details

Details for the file ownlock-0.1.8.tar.gz.

File metadata

  • Download URL: ownlock-0.1.8.tar.gz
  • Upload date:
  • Size: 30.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ownlock-0.1.8.tar.gz
Algorithm Hash digest
SHA256 9ce02fc18f5056ecbda4e1a99596a2289af8ce9fb273d57cb36fb9b906c12703
MD5 d8f4d308ff6017f0e516229a2c81b06b
BLAKE2b-256 280925e5146b335dfb0481a1f0ebe89314b311523f4dcaff9b2d0da86a8b4259

See more details on using hashes here.

Provenance

The following attestation bundles were made for ownlock-0.1.8.tar.gz:

Publisher: ci.yml on thebscolaro/ownlock

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ownlock-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: ownlock-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 19.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ownlock-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 a7b9a248d14437d7ed482bbbd8042b0789b93f8f0b117ba380b3f56025b26fd0
MD5 b16a2503a5ef0aa406ad74a6de69fc8f
BLAKE2b-256 60ae2f528909a5a65ff12c9ea0a26fd1c4b35b64c66891f252debfdb959e36b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for ownlock-0.1.8-py3-none-any.whl:

Publisher: ci.yml on thebscolaro/ownlock

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page