ownlock 0.1.0__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.
- ownlock-0.1.0/.github/workflows/ci.yml +80 -0
- ownlock-0.1.0/.gitignore +24 -0
- ownlock-0.1.0/CHANGELOG.md +29 -0
- ownlock-0.1.0/LICENSE +21 -0
- ownlock-0.1.0/PKG-INFO +96 -0
- ownlock-0.1.0/README.md +72 -0
- ownlock-0.1.0/SECURITY.md +25 -0
- ownlock-0.1.0/ownlock/__init__.py +3 -0
- ownlock-0.1.0/ownlock/cli.py +425 -0
- ownlock-0.1.0/ownlock/crypto.py +55 -0
- ownlock-0.1.0/ownlock/keyring_util.py +84 -0
- ownlock-0.1.0/ownlock/redactor.py +77 -0
- ownlock-0.1.0/ownlock/resolver.py +92 -0
- ownlock-0.1.0/ownlock/vault.py +137 -0
- ownlock-0.1.0/pyproject.toml +39 -0
- ownlock-0.1.0/tests/__init__.py +0 -0
- ownlock-0.1.0/tests/test_cli.py +234 -0
- ownlock-0.1.0/tests/test_crypto.py +49 -0
- ownlock-0.1.0/tests/test_redactor.py +62 -0
- ownlock-0.1.0/tests/test_resolver.py +117 -0
- ownlock-0.1.0/tests/test_vault.py +104 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
include:
|
|
16
|
+
- os: ubuntu-latest
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- os: ubuntu-latest
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
- os: macos-latest
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
- os: windows-latest
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
|
|
25
|
+
runs-on: ${{ matrix.os }}
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
31
|
+
uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: ${{ matrix.python-version }}
|
|
34
|
+
|
|
35
|
+
- name: Install dependencies
|
|
36
|
+
run: |
|
|
37
|
+
python -m pip install --upgrade pip
|
|
38
|
+
pip install -e .
|
|
39
|
+
pip install pytest
|
|
40
|
+
|
|
41
|
+
- name: Run tests
|
|
42
|
+
run: pytest tests/ -v --tb=short
|
|
43
|
+
|
|
44
|
+
build:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Set up Python
|
|
50
|
+
uses: actions/setup-python@v5
|
|
51
|
+
with:
|
|
52
|
+
python-version: "3.12"
|
|
53
|
+
|
|
54
|
+
- name: Install build
|
|
55
|
+
run: pip install build
|
|
56
|
+
|
|
57
|
+
- name: Build package
|
|
58
|
+
run: python -m build
|
|
59
|
+
|
|
60
|
+
- name: Upload distributions
|
|
61
|
+
uses: actions/upload-artifact@v4
|
|
62
|
+
with:
|
|
63
|
+
name: dist
|
|
64
|
+
path: dist/
|
|
65
|
+
|
|
66
|
+
publish:
|
|
67
|
+
needs: build
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
70
|
+
permissions:
|
|
71
|
+
id-token: write
|
|
72
|
+
steps:
|
|
73
|
+
- name: Download distributions
|
|
74
|
+
uses: actions/download-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: dist
|
|
77
|
+
path: dist/
|
|
78
|
+
|
|
79
|
+
- name: Publish to PyPI
|
|
80
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
ownlock-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Vault data
|
|
2
|
+
.ownlock/
|
|
3
|
+
*.db
|
|
4
|
+
|
|
5
|
+
.DS_Store
|
|
6
|
+
# Python
|
|
7
|
+
.venv/
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
*.egg
|
|
14
|
+
|
|
15
|
+
# Testing
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
# IDE
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ownlock will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-02-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **CLI**: `ownlock` — lightweight secrets manager
|
|
13
|
+
- `init` — create global or project vault
|
|
14
|
+
- `set` / `get` / `list` / `delete` — manage secrets
|
|
15
|
+
- `run` — resolve `.env`, inject secrets, redact stdout
|
|
16
|
+
- `export` — print resolved KEY=VALUE pairs
|
|
17
|
+
- `import` — bulk import from plaintext `.env`
|
|
18
|
+
- `scan` — find leaked secrets in files
|
|
19
|
+
- **Encryption**: AES-256-GCM, PBKDF2-HMAC-SHA256 (200K iterations)
|
|
20
|
+
- **Storage**: SQLite vault at `~/.ownlock/vault.db` (global) or `.ownlock/vault.db` (project)
|
|
21
|
+
- **Keyring**: macOS Keychain / GNOME Keyring for passphrase
|
|
22
|
+
- **`.env` format**: `vault("key-name")` references with optional `env=` and `project=true`
|
|
23
|
+
- **Redaction**: Automatically redact secret values in subprocess stdout/stderr
|
|
24
|
+
- **Hardening**:
|
|
25
|
+
- Path validation (env files and scan dir must stay under cwd when relative)
|
|
26
|
+
- Secret name validation (alphanumeric, hyphen, underscore only)
|
|
27
|
+
- Scan limits (max 10K files, depth 20 by default)
|
|
28
|
+
- Clean error messages (no tracebacks for expected errors)
|
|
29
|
+
- Export value quoting for docker format
|
ownlock-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ownly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ownlock-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ownlock
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight secrets manager — encrypted vault, env injection, stdout redaction. No Docker, no server, no account.
|
|
5
|
+
Project-URL: Repository, https://github.com/thebscolaro/ownlock
|
|
6
|
+
Author: Ownly
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: cli,encryption,env,secrets,vault
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Requires-Dist: cryptography>=44.0
|
|
19
|
+
Requires-Dist: keyring>=25.0
|
|
20
|
+
Requires-Dist: python-dotenv>=1.0
|
|
21
|
+
Requires-Dist: rich>=13.0
|
|
22
|
+
Requires-Dist: typer>=0.15.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# ownlock
|
|
26
|
+
|
|
27
|
+
Lightweight secrets manager — encrypted local vault, `.env` injection, stdout redaction.
|
|
28
|
+
|
|
29
|
+
No Docker. No server. No account. Just `pip install ownlock`.
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install ownlock
|
|
35
|
+
|
|
36
|
+
# Create a vault (passphrase saved to system keyring)
|
|
37
|
+
ownlock init
|
|
38
|
+
|
|
39
|
+
# Store secrets
|
|
40
|
+
ownlock set anthropic-api-key
|
|
41
|
+
> Enter value: ****
|
|
42
|
+
|
|
43
|
+
# In your .env, use vault() instead of plain values:
|
|
44
|
+
# ANTHROPIC_API_KEY=vault("anthropic-api-key")
|
|
45
|
+
|
|
46
|
+
# Run commands with secrets injected and stdout redacted
|
|
47
|
+
ownlock run -- python app.py
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## .env format
|
|
51
|
+
|
|
52
|
+
Plain values pass through unchanged. Secrets stay in the vault and are resolved at runtime:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Non-sensitive config (stored as plain text)
|
|
56
|
+
OLLAMA_BASE_URL=http://localhost:11434
|
|
57
|
+
DEFAULT_WORKER_MODEL=anthropic:claude-opus-4-6
|
|
58
|
+
|
|
59
|
+
# Secrets (resolved from vault at runtime)
|
|
60
|
+
ANTHROPIC_API_KEY=vault("anthropic-api-key")
|
|
61
|
+
OPENAI_API_KEY=vault("openai-api-key", env="production")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Commands
|
|
65
|
+
|
|
66
|
+
| Command | Description |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `ownlock init` | Create a vault (global or `--project` local) |
|
|
69
|
+
| `ownlock set KEY` | Store a secret in global vault (use `--project` for project vault) |
|
|
70
|
+
| `ownlock set KEY=VALUE` | Store inline |
|
|
71
|
+
| `ownlock get KEY` | Print decrypted value |
|
|
72
|
+
| `ownlock list` | Show secret names (never values) |
|
|
73
|
+
| `ownlock delete KEY` | Remove a secret |
|
|
74
|
+
| `ownlock run -- CMD` | Resolve `.env`, inject secrets, redact stdout |
|
|
75
|
+
| `ownlock export` | Print resolved `KEY=VALUE` pairs |
|
|
76
|
+
| `ownlock import .env` | Bulk import from plaintext `.env` |
|
|
77
|
+
| `ownlock scan .` | Scan files for leaked secret values |
|
|
78
|
+
|
|
79
|
+
Add `--project` to any command to use the project vault (`.ownlock/vault.db`) instead of the global vault.
|
|
80
|
+
|
|
81
|
+
## How it works
|
|
82
|
+
|
|
83
|
+
- Secrets are encrypted with **AES-256-GCM** and stored in a local SQLite database
|
|
84
|
+
- Key derivation: PBKDF2-HMAC-SHA256 with 200,000 iterations
|
|
85
|
+
- Vault passphrase stored in your system keyring (macOS Keychain, GNOME Keyring, etc.)
|
|
86
|
+
- `ownlock run` resolves `vault()` references, injects env vars into the subprocess, and redacts any secret values that appear in stdout/stderr
|
|
87
|
+
- Zero network calls. Everything is local.
|
|
88
|
+
|
|
89
|
+
## Storage
|
|
90
|
+
|
|
91
|
+
- **Global vault**: `~/.ownlock/vault.db` — default for all commands
|
|
92
|
+
- **Project vault**: `.ownlock/vault.db` — use `--project` flag
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
ownlock-0.1.0/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ownlock
|
|
2
|
+
|
|
3
|
+
Lightweight secrets manager — encrypted local vault, `.env` injection, stdout redaction.
|
|
4
|
+
|
|
5
|
+
No Docker. No server. No account. Just `pip install ownlock`.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install ownlock
|
|
11
|
+
|
|
12
|
+
# Create a vault (passphrase saved to system keyring)
|
|
13
|
+
ownlock init
|
|
14
|
+
|
|
15
|
+
# Store secrets
|
|
16
|
+
ownlock set anthropic-api-key
|
|
17
|
+
> Enter value: ****
|
|
18
|
+
|
|
19
|
+
# In your .env, use vault() instead of plain values:
|
|
20
|
+
# ANTHROPIC_API_KEY=vault("anthropic-api-key")
|
|
21
|
+
|
|
22
|
+
# Run commands with secrets injected and stdout redacted
|
|
23
|
+
ownlock run -- python app.py
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## .env format
|
|
27
|
+
|
|
28
|
+
Plain values pass through unchanged. Secrets stay in the vault and are resolved at runtime:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Non-sensitive config (stored as plain text)
|
|
32
|
+
OLLAMA_BASE_URL=http://localhost:11434
|
|
33
|
+
DEFAULT_WORKER_MODEL=anthropic:claude-opus-4-6
|
|
34
|
+
|
|
35
|
+
# Secrets (resolved from vault at runtime)
|
|
36
|
+
ANTHROPIC_API_KEY=vault("anthropic-api-key")
|
|
37
|
+
OPENAI_API_KEY=vault("openai-api-key", env="production")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Commands
|
|
41
|
+
|
|
42
|
+
| Command | Description |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `ownlock init` | Create a vault (global or `--project` local) |
|
|
45
|
+
| `ownlock set KEY` | Store a secret in global vault (use `--project` for project vault) |
|
|
46
|
+
| `ownlock set KEY=VALUE` | Store inline |
|
|
47
|
+
| `ownlock get KEY` | Print decrypted value |
|
|
48
|
+
| `ownlock list` | Show secret names (never values) |
|
|
49
|
+
| `ownlock delete KEY` | Remove a secret |
|
|
50
|
+
| `ownlock run -- CMD` | Resolve `.env`, inject secrets, redact stdout |
|
|
51
|
+
| `ownlock export` | Print resolved `KEY=VALUE` pairs |
|
|
52
|
+
| `ownlock import .env` | Bulk import from plaintext `.env` |
|
|
53
|
+
| `ownlock scan .` | Scan files for leaked secret values |
|
|
54
|
+
|
|
55
|
+
Add `--project` to any command to use the project vault (`.ownlock/vault.db`) instead of the global vault.
|
|
56
|
+
|
|
57
|
+
## How it works
|
|
58
|
+
|
|
59
|
+
- Secrets are encrypted with **AES-256-GCM** and stored in a local SQLite database
|
|
60
|
+
- Key derivation: PBKDF2-HMAC-SHA256 with 200,000 iterations
|
|
61
|
+
- Vault passphrase stored in your system keyring (macOS Keychain, GNOME Keyring, etc.)
|
|
62
|
+
- `ownlock run` resolves `vault()` references, injects env vars into the subprocess, and redacts any secret values that appear in stdout/stderr
|
|
63
|
+
- Zero network calls. Everything is local.
|
|
64
|
+
|
|
65
|
+
## Storage
|
|
66
|
+
|
|
67
|
+
- **Global vault**: `~/.ownlock/vault.db` — default for all commands
|
|
68
|
+
- **Project vault**: `.ownlock/vault.db` — use `--project` flag
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## Reporting vulnerabilities
|
|
4
|
+
|
|
5
|
+
If you discover a security vulnerability in ownlock, please report it responsibly:
|
|
6
|
+
|
|
7
|
+
1. **Do not** open a public GitHub issue.
|
|
8
|
+
2. Email the maintainers or open a [private security advisory](https://github.com/thebscolaro/ownlock/security/advisories/new) on GitHub.
|
|
9
|
+
3. Include a description of the vulnerability, steps to reproduce, and any suggested fixes.
|
|
10
|
+
4. We will respond promptly and work with you to address the issue.
|
|
11
|
+
|
|
12
|
+
## Security model
|
|
13
|
+
|
|
14
|
+
- **Encryption**: Secrets are encrypted with AES-256-GCM before storage. Key derivation uses PBKDF2-HMAC-SHA256 with 200,000 iterations.
|
|
15
|
+
- **Passphrase**: Stored in the system keyring (macOS Keychain, GNOME Keyring) when possible. Can also be provided via `OWNLOCK_PASSPHRASE` or interactively.
|
|
16
|
+
- **No network**: ownlock never makes network requests. All data stays local.
|
|
17
|
+
- **Path safety**: Relative paths for `.env` files and scan directories are validated to stay within the current directory.
|
|
18
|
+
- **Subprocess**: `ownlock run` passes the command as a list to the OS exec APIs. No shell interpretation. Secrets are injected as environment variables.
|
|
19
|
+
- **Redaction**: Known secret values are replaced with `[REDACTED:NAME]` in subprocess stdout/stderr.
|
|
20
|
+
|
|
21
|
+
## Known limitations
|
|
22
|
+
|
|
23
|
+
- Decrypted secrets exist in process memory while commands run.
|
|
24
|
+
- Environment variables are visible to child processes and can appear in process listings.
|
|
25
|
+
- The system keyring can be accessed by other applications running as the same user.
|