Metadata-Version: 2.4
Name: secure-vault-cli
Version: 0.1.4
Summary: A local private document vault CLI with a polished interactive shell.
Author: Luis696969
License-Expression: MIT
Keywords: cli,vault,notes,documents,sqlite,typer,rich
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: platformdirs<5.0,>=4.0
Requires-Dist: prompt_toolkit<4.0,>=3.0
Requires-Dist: rich<14.0,>=13.7
Requires-Dist: typer<1.0,>=0.12
Requires-Dist: cryptography<46.0,>=44.0
Requires-Dist: argon2-cffi<26.0,>=23.1
Provides-Extra: dev
Requires-Dist: build<2.0,>=1.2; extra == "dev"
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
Requires-Dist: twine<7.0,>=6.0; extra == "dev"
Dynamic: license-file

# vault-cli

`vault-cli` is a local, private, terminal-first vault for ideas, notes, and project documents. It keeps the interactive shell and polished CLI flow of the original base project, but swaps the domain entirely to an encrypted document library designed for single-user local use.

PyPI package: `secure-vault-cli`

Quick links: [Contributing](./CONTRIBUTING.md) · [Contributors](./CONTRIBUTORS.md) · [License](./LICENSE)

Public command:

```bash
vault
```

## Highlights

- Local-only encrypted vault backed by SQLite
- Functional metadata encrypted at rest
- Integrated shell with `help`, `man`, and command completion
- Integrated multiline editor by default
- Optional export, clipboard copy, and external editor with explicit privacy warnings
- Cross-platform target: Windows and Linux
- Ready for `pipx`

## Installation

Recommended:

```bash
pipx install secure-vault-cli
```

Development install:

```bash
python -m pip install -e .[dev]
python -m pytest
```

## PyPI publishing

The repository includes a GitHub Actions workflow for PyPI publishing via Trusted Publishing.

It is designed to:

- build the distributions in a dedicated job
- run `twine check` before upload
- pass the built artifacts to a separate publish job
- publish to PyPI using GitHub OIDC instead of a long-lived API token

Before the workflow can upload anything, configure `secure-vault-cli` on PyPI with this repository as a Trusted Publisher and use the `pypi` environment in GitHub.

## Commands

- `vault init`
- `vault unlock`
- `vault lock`
- `vault new <id>`
- `vault edit <id>`
- `vault view <id>`
- `vault list`
- `vault delete <id>`
- `vault export <id> <path>`
- `vault copy <id>`
- `vault purge`
- `vault help`
- `vault man`
- `vault shell`

Running `vault` with no subcommand starts the interactive shell.

## Data paths

Default per-user paths are resolved with `platformdirs`.

- Vault config: `config_dir / vault.json`
- Vault database: `data_dir / vault.db`

For tests or custom local runs you can override the root with:

```bash
VAULT_CLI_HOME=/custom/root
```

Inside that root, the app uses:

- `config/vault.json`
- `data/vault.db`

## Security model

### What is encrypted

The full functional payload of every document is encrypted:

- `id`
- `title`
- `created_at`
- `updated_at`
- `folder`
- `tags`
- `template_name`
- `body`

Outside the encrypted payload, the database stores only:

- `lookup_key`
- `payload_version`
- `encrypted_payload`
- technical metadata that is not functionally sensitive

IDs are never stored in cleartext.

### Cryptography v1

- Passphrase KDF: `Argon2id`
- `master_key`: 32 bytes
- `index_key`: 32 bytes derived from `master_key` using `HKDF`
- Per-document cipher: `AESGCM`
- Nonce size: 12 bytes
- `encrypted_payload` format: `nonce(12 bytes) || ciphertext+tag`
- Authenticated additional data includes:
  - `payload_version`
  - stable type identifier `document-v1`

`lookup_key` is defined exactly as:

```text
HMAC-SHA256(index_key, normalized_id.encode("utf-8"))
```

The full binary digest is stored as fixed-length `BLOB` and indexed uniquely. It is not reversible.

### vault.json schema

`vault.json` contains only technical material:

```json
{
  "schema_version": 1,
  "kdf": {
    "algorithm": "argon2id",
    "time_cost": 3,
    "memory_cost": 65536,
    "parallelism": 4,
    "hash_len": 32,
    "salt_b64": "..."
  },
  "wrapping": {
    "algorithm": "AESGCM",
    "nonce_b64": "...",
    "wrapped_master_key_b64": "..."
  }
}
```

Units and semantics:

- `memory_cost` is expressed in `KiB`
- `time_cost`, `parallelism`, and `hash_len` are integers

No functional metadata is stored in `vault.json`.

### SQLite behavior

In v1 the SQLite connection uses:

- `PRAGMA journal_mode=DELETE`
- `PRAGMA temp_store=MEMORY`

This reduces auxiliary artifacts compared with WAL, but it does not replace the cryptographic erase model or guarantee absence of filesystem traces.

## Query UX

### `vault list`

Default columns:

- `id`
- `title`
- `updated_at`

Verbose mode:

```bash
vault list --verbose
```

Adds:

- `folder`
- `tags`

Stable JSON output:

```bash
vault list --json
```

Public stable shape:

```json
{
  "items": [
    {
      "id": "example-id",
      "title": "Example",
      "updated_at": "2026-04-13T12:00:00Z",
      "folder": "inbox",
      "tags": ["one", "two"]
    }
  ]
}
```

This JSON format is treated as stable for v1. Timestamps are emitted in ISO 8601 UTC.

### `vault view`

`view`, `export` by default, and `copy --full` all share the same canonical full render with this fixed order:

1. `ID`
2. `Title`
3. `Created At`
4. `Updated At`
5. `Folder`
6. `Tags`
7. body

## Editing

The integrated editor is the default. It supports:

- `.save`
- `.cancel`
- `.print`
- `.help`

The app always controls:

- `id`
- `created_at`
- `updated_at`
- `template_name`

The editor is intended for:

- `title`
- `folder`
- `tags`
- `body`

## Privacy warnings

### Export

`vault export` writes plaintext outside the encrypted perimeter.

- Default output: canonical full render
- `--body-only`: only the body
- No overwrite without `--force`

### Clipboard

`vault copy` is best-effort and intentionally avoids extra dependencies.

- Default: copy `body`
- `--full`: copy canonical full render
- Windows: `clip`
- Linux: `wl-copy`, `xclip`, or `xsel`

Clipboard contents are outside the encrypted perimeter and may be visible to other local processes.

### External editor

`vault edit --external-editor` is opt-in only. It may create plaintext artifacts such as temp files, swap, MRU entries, or editor history.

## IDs and normalization

IDs are normalized predictably:

- trimmed
- lowercased
- internal whitespace converted to `-`
- only `[a-z0-9._-]` allowed after normalization

Examples:

- `My Idea` -> `my-idea`
- `  Project_1  ` -> `project_1`

If normalization changes the ID, the CLI reports it before persistence. Empty IDs after normalization are rejected. Collisions after normalization are rejected.

## Exit codes

- `0` success
- `1` generic error
- `2` invalid usage
- `3` locked vault / auth required
- `4` not found
- `5` already exists
- `6` destructive action aborted

## Examples

```bash
vault init
vault unlock
vault new idea-one
vault view idea-one
vault list --verbose
vault export idea-one ./idea-one.txt
vault copy idea-one --full
vault delete idea-one
vault purge
```

## Threats and limits

- The session key lives only in process memory, but Python memory cleanup is best-effort and not a forensic guarantee.
- `list` and filters decrypt documents in memory in v1; this is an explicit privacy/functionality trade-off.
- No full-text search is implemented in v1.
- No passphrase by CLI argument or environment variable in v1.
- `purge` destroys key/config material and app-managed files as application-level cryptographic erase, but cannot guarantee physical erasure on modern SSDs or all filesystems.

## Manual

Use the built-in manual:

```bash
vault man
vault man new
vault man purge
```

## Contributors

- Luis Romero ([Luis696969](https://github.com/Luis696969)) — creator and maintainer

See also [CONTRIBUTORS.md](./CONTRIBUTORS.md).

## License

This project is licensed under the MIT License. See [LICENSE](./LICENSE).
