noctivault


Namenoctivault JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummarySecure secret handler with cloud platform
upload_time2025-09-15 01:35:23
maintainerNone
docs_urlNone
authorricky-rehivo
requires_python>=3.10
licenseMIT
keywords secret secret-manager vault security
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # noctivault

[![PyPI](https://img.shields.io/pypi/v/noctivault.svg)](https://pypi.org/project/noctivault/)
[![Python Versions](https://img.shields.io/pypi/pyversions/noctivault.svg)](https://pypi.org/project/noctivault/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Wheel](https://img.shields.io/pypi/wheel/noctivault.svg)](https://pypi.org/project/noctivault/)

Noctivault loads secrets from cloud Secret Managers into process memory without going through environment variables. Values are masked by default, and configuration is clearly separated from execution.

- Safe by default: in‑memory resolution, masked string representations
- Operational clarity: two files — references (refs) and mock values (mocks)
- Flexible: local encrypted store and remote (GCP) fetch supported

## Why Noctivault

- Avoids env‑vars; secrets are handled via explicit API calls
- Lighter than Vault/SOPS for Python apps; DX focused
- Two‑file split clarifies “what to use” (refs) vs “where values come from” (mocks)
- Commit `.yaml.enc`, distribute the key separately for safer, reproducible setups

## Support & Requirements

- Python: >= 3.10
- Local encrypted store: extra `local-enc` (`cryptography`, `argon2-cffi`)
- Remote (GCP): `google-cloud-secret-manager` (also available as extra `gcp`)
- Remote platform support: Google only for now (AWS/Azure on roadmap)

## Install

- pip:
  - `pip install noctivault`
  - Local encrypted store: `pip install 'noctivault[local-enc]'`
  - GCP remote: `pip install google-cloud-secret-manager` (or `pip install 'noctivault[gcp]'`)
- Poetry:
  - `poetry add noctivault`
  - Local encrypted store: `poetry add "noctivault[local-enc]"`
  - GCP remote: `poetry add google-cloud-secret-manager` (or `poetry add "noctivault[gcp]"`)

## Quickstart (Local, two‑file layout)

1) Mocks (plaintext or encrypted source): `noctivault.local-store.yaml`

```yaml
platform: google
gcp_project_id: demo

secret-mocks:
  - name: db-password
    value: s3cr3t
    version: 2
  - name: db-port
    value: "5432"
    version: 1
```

2) Refs (plaintext; do not encrypt): `noctivault.yaml`

```yaml
platform: google
gcp_project_id: demo

secret-refs:
  - key: database
    children:
      - cast: password
        ref: db-password
        version: latest
        type: str
      - cast: port
        ref: db-port
        version: 1
        type: int
```

3) Encrypt mocks (recommended)

- Generate key: `noctivault key gen` (default `~/.config/noctivault/local.key`, chmod 600)
- Create encrypted file: `noctivault local seal . --key-file ~/.config/noctivault/local.key --rm-plain`
  - Commit `.yaml.enc`; keep plaintext `.yaml` and `local.key` out of VCS

4) Load (Python)

```python
from noctivault import NoctivaultSettings
import noctivault

nv = noctivault.noctivault(settings=NoctivaultSettings(source="local"))
secrets = nv.load(local_store_path="./")  # prefers .enc; falls back to .yaml

print(secrets.database.password)        # -> ***
print(secrets.database.password.get())  # -> "s3cr3t"
print(secrets.database.port.get())      # -> 5432
```

Restore plaintext from `.enc` when needed:

```bash
noctivault local unseal noctivault.local-store.yaml.enc --key-file ~/.config/noctivault/local.key > noctivault.local-store.yaml
```

## Quickstart (Remote, GCP)

Prereqs

- Dependency: `poetry add google-cloud-secret-manager` (or `poetry add "noctivault[gcp]"`)
- Auth (ADC)
  - Service account JSON: `export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json`
  - Or: `gcloud auth application-default login`
- Permission: `roles/secretmanager.secretAccessor`, etc.

`noctivault.yaml` (refs only)

```yaml
platform: google
gcp_project_id: my-gcp-project

secret-refs:
  - key: database
    children:
      - cast: password
        ref: db-password
        version: latest
        type: str
```

Load (Python)

```python
from noctivault import NoctivaultSettings
import noctivault

nv = noctivault.noctivault(settings=NoctivaultSettings(source="remote"))
secrets = nv.load(local_store_path=".")  # reads ./noctivault.yaml
print(secrets.database.password)         # -> ***
print(secrets.database.password.get())   # -> UTF-8 string from GCP
```

Common errors and fixes

- MissingDependencyError: add `google-cloud-secret-manager`
- AuthorizationError: fix ADC/permissions
- MissingRemoteSecretError: check project/ref/version in `noctivault.yaml`

## CLI

- Key: `noctivault key gen [--out PATH]`
- Seal: `noctivault local seal <dir|file> (--key-file PATH | --passphrase PW | --prompt) [--out PATH] [--rm-plain] [--force]`
- Unseal: `noctivault local unseal <enc_file> (--key-file PATH | --passphrase PW | --prompt)`
- Verify: `noctivault local verify <enc_file> (--key-file PATH | --passphrase PW | --prompt)`

When a directory is given, `.yaml.enc` is preferred; otherwise falls back to `.yaml`. You can pass file paths directly as well.

## Settings & Precedence

- `NoctivaultSettings(source="local"|"remote")`
- Local encrypted store key material (in this order):
  - `settings.local_enc.key_file_path`
  - `NOCTIVAULT_LOCAL_KEY_FILE`
  - `./local.key` next to `.enc`
  - `~/.config/noctivault/local.key`
- Passphrase mode
  - `settings.local_enc.passphrase` or `NOCTIVAULT_LOCAL_PASSPHRASE`, or CLI `--prompt`

## Schema Summary

- Mocks (`noctivault.local-store.yaml`)
  - Top‑level `platform`, `gcp_project_id` are required; entries inherit if omitted
  - `secret-mocks`: `name`, `value` (str), `version` (int)
- Refs (`noctivault.yaml`)
  - Top‑level `platform`, `gcp_project_id` required
  - `secret-refs`: entries or grouped by `key`/`children`
  - `type`: `str|int` (default `str`), `version`: `latest|int`

See `docs/api.md` for full details.

## Security

- Masked by default (`repr/str` -> `***`); call `.get()` to reveal
- Encryption format (NVLE1)
  - AES‑256‑GCM; Argon2id (for passphrase); KDF params stored in header
  - Tamper detection via GCM tag; invalid tag -> decryption failure
- Operational guidance
  - Keep plaintext `.yaml` and `local.key` out of VCS (use `.gitignore`)
  - Key files should be mode 600; distribute via secure channels

## Troubleshooting

- CombinedConfigNotAllowedError: don’t mix mocks and refs in one file
- MissingLocalMockError / MissingRemoteSecretError: name/version/project mismatch
- TypeCastError: e.g., `type=int` for non‑numeric values
- InvalidEncHeaderError / DecryptError: bad header / wrong key
- RemoteUnavailableError: transient GCP issues; retry later

## FAQ

- Why two files?
  - Separate intent (refs) from value sources (mocks); simpler reviews and switching between local/remote
- Which file is preferred?
  - Local: `.yaml.enc` > `.yaml`; Remote uses `noctivault.yaml` only
- How to migrate from a single file?
  - Move `secret-mocks` into `noctivault.local-store.yaml`, and `secret-refs` into `noctivault.yaml`

## Roadmap

- Remote drivers for AWS/Azure
- Cache/TTL/force‑refresh
- Pluggable providers; HMAC option for `display_hash`

## Contributing

- PRs welcome. Please keep Ruff/Mypy clean and maintain high test coverage
- For security reports, please use responsible disclosure

## License

MIT — see `LICENSE`.


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "noctivault",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "secret, secret-manager, vault, security",
    "author": "ricky-rehivo",
    "author_email": "ricky.rehivo@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/b7/c3/0e8e681c95d24f2f493b9b88e126e699d11ed3d68ee407c14ef0ed399931/noctivault-0.1.0.tar.gz",
    "platform": null,
    "description": "# noctivault\n\n[![PyPI](https://img.shields.io/pypi/v/noctivault.svg)](https://pypi.org/project/noctivault/)\n[![Python Versions](https://img.shields.io/pypi/pyversions/noctivault.svg)](https://pypi.org/project/noctivault/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Wheel](https://img.shields.io/pypi/wheel/noctivault.svg)](https://pypi.org/project/noctivault/)\n\nNoctivault loads secrets from cloud Secret Managers into process memory without going through environment variables. Values are masked by default, and configuration is clearly separated from execution.\n\n- Safe by default: in\u2011memory resolution, masked string representations\n- Operational clarity: two files \u2014 references (refs) and mock values (mocks)\n- Flexible: local encrypted store and remote (GCP) fetch supported\n\n## Why Noctivault\n\n- Avoids env\u2011vars; secrets are handled via explicit API calls\n- Lighter than Vault/SOPS for Python apps; DX focused\n- Two\u2011file split clarifies \u201cwhat to use\u201d (refs) vs \u201cwhere values come from\u201d (mocks)\n- Commit `.yaml.enc`, distribute the key separately for safer, reproducible setups\n\n## Support & Requirements\n\n- Python: >= 3.10\n- Local encrypted store: extra `local-enc` (`cryptography`, `argon2-cffi`)\n- Remote (GCP): `google-cloud-secret-manager` (also available as extra `gcp`)\n- Remote platform support: Google only for now (AWS/Azure on roadmap)\n\n## Install\n\n- pip:\n  - `pip install noctivault`\n  - Local encrypted store: `pip install 'noctivault[local-enc]'`\n  - GCP remote: `pip install google-cloud-secret-manager` (or `pip install 'noctivault[gcp]'`)\n- Poetry:\n  - `poetry add noctivault`\n  - Local encrypted store: `poetry add \"noctivault[local-enc]\"`\n  - GCP remote: `poetry add google-cloud-secret-manager` (or `poetry add \"noctivault[gcp]\"`)\n\n## Quickstart (Local, two\u2011file layout)\n\n1) Mocks (plaintext or encrypted source): `noctivault.local-store.yaml`\n\n```yaml\nplatform: google\ngcp_project_id: demo\n\nsecret-mocks:\n  - name: db-password\n    value: s3cr3t\n    version: 2\n  - name: db-port\n    value: \"5432\"\n    version: 1\n```\n\n2) Refs (plaintext; do not encrypt): `noctivault.yaml`\n\n```yaml\nplatform: google\ngcp_project_id: demo\n\nsecret-refs:\n  - key: database\n    children:\n      - cast: password\n        ref: db-password\n        version: latest\n        type: str\n      - cast: port\n        ref: db-port\n        version: 1\n        type: int\n```\n\n3) Encrypt mocks (recommended)\n\n- Generate key: `noctivault key gen` (default `~/.config/noctivault/local.key`, chmod 600)\n- Create encrypted file: `noctivault local seal . --key-file ~/.config/noctivault/local.key --rm-plain`\n  - Commit `.yaml.enc`; keep plaintext `.yaml` and `local.key` out of VCS\n\n4) Load (Python)\n\n```python\nfrom noctivault import NoctivaultSettings\nimport noctivault\n\nnv = noctivault.noctivault(settings=NoctivaultSettings(source=\"local\"))\nsecrets = nv.load(local_store_path=\"./\")  # prefers .enc; falls back to .yaml\n\nprint(secrets.database.password)        # -> ***\nprint(secrets.database.password.get())  # -> \"s3cr3t\"\nprint(secrets.database.port.get())      # -> 5432\n```\n\nRestore plaintext from `.enc` when needed:\n\n```bash\nnoctivault local unseal noctivault.local-store.yaml.enc --key-file ~/.config/noctivault/local.key > noctivault.local-store.yaml\n```\n\n## Quickstart (Remote, GCP)\n\nPrereqs\n\n- Dependency: `poetry add google-cloud-secret-manager` (or `poetry add \"noctivault[gcp]\"`)\n- Auth (ADC)\n  - Service account JSON: `export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json`\n  - Or: `gcloud auth application-default login`\n- Permission: `roles/secretmanager.secretAccessor`, etc.\n\n`noctivault.yaml` (refs only)\n\n```yaml\nplatform: google\ngcp_project_id: my-gcp-project\n\nsecret-refs:\n  - key: database\n    children:\n      - cast: password\n        ref: db-password\n        version: latest\n        type: str\n```\n\nLoad (Python)\n\n```python\nfrom noctivault import NoctivaultSettings\nimport noctivault\n\nnv = noctivault.noctivault(settings=NoctivaultSettings(source=\"remote\"))\nsecrets = nv.load(local_store_path=\".\")  # reads ./noctivault.yaml\nprint(secrets.database.password)         # -> ***\nprint(secrets.database.password.get())   # -> UTF-8 string from GCP\n```\n\nCommon errors and fixes\n\n- MissingDependencyError: add `google-cloud-secret-manager`\n- AuthorizationError: fix ADC/permissions\n- MissingRemoteSecretError: check project/ref/version in `noctivault.yaml`\n\n## CLI\n\n- Key: `noctivault key gen [--out PATH]`\n- Seal: `noctivault local seal <dir|file> (--key-file PATH | --passphrase PW | --prompt) [--out PATH] [--rm-plain] [--force]`\n- Unseal: `noctivault local unseal <enc_file> (--key-file PATH | --passphrase PW | --prompt)`\n- Verify: `noctivault local verify <enc_file> (--key-file PATH | --passphrase PW | --prompt)`\n\nWhen a directory is given, `.yaml.enc` is preferred; otherwise falls back to `.yaml`. You can pass file paths directly as well.\n\n## Settings & Precedence\n\n- `NoctivaultSettings(source=\"local\"|\"remote\")`\n- Local encrypted store key material (in this order):\n  - `settings.local_enc.key_file_path`\n  - `NOCTIVAULT_LOCAL_KEY_FILE`\n  - `./local.key` next to `.enc`\n  - `~/.config/noctivault/local.key`\n- Passphrase mode\n  - `settings.local_enc.passphrase` or `NOCTIVAULT_LOCAL_PASSPHRASE`, or CLI `--prompt`\n\n## Schema Summary\n\n- Mocks (`noctivault.local-store.yaml`)\n  - Top\u2011level `platform`, `gcp_project_id` are required; entries inherit if omitted\n  - `secret-mocks`: `name`, `value` (str), `version` (int)\n- Refs (`noctivault.yaml`)\n  - Top\u2011level `platform`, `gcp_project_id` required\n  - `secret-refs`: entries or grouped by `key`/`children`\n  - `type`: `str|int` (default `str`), `version`: `latest|int`\n\nSee `docs/api.md` for full details.\n\n## Security\n\n- Masked by default (`repr/str` -> `***`); call `.get()` to reveal\n- Encryption format (NVLE1)\n  - AES\u2011256\u2011GCM; Argon2id (for passphrase); KDF params stored in header\n  - Tamper detection via GCM tag; invalid tag -> decryption failure\n- Operational guidance\n  - Keep plaintext `.yaml` and `local.key` out of VCS (use `.gitignore`)\n  - Key files should be mode 600; distribute via secure channels\n\n## Troubleshooting\n\n- CombinedConfigNotAllowedError: don\u2019t mix mocks and refs in one file\n- MissingLocalMockError / MissingRemoteSecretError: name/version/project mismatch\n- TypeCastError: e.g., `type=int` for non\u2011numeric values\n- InvalidEncHeaderError / DecryptError: bad header / wrong key\n- RemoteUnavailableError: transient GCP issues; retry later\n\n## FAQ\n\n- Why two files?\n  - Separate intent (refs) from value sources (mocks); simpler reviews and switching between local/remote\n- Which file is preferred?\n  - Local: `.yaml.enc` > `.yaml`; Remote uses `noctivault.yaml` only\n- How to migrate from a single file?\n  - Move `secret-mocks` into `noctivault.local-store.yaml`, and `secret-refs` into `noctivault.yaml`\n\n## Roadmap\n\n- Remote drivers for AWS/Azure\n- Cache/TTL/force\u2011refresh\n- Pluggable providers; HMAC option for `display_hash`\n\n## Contributing\n\n- PRs welcome. Please keep Ruff/Mypy clean and maintain high test coverage\n- For security reports, please use responsible disclosure\n\n## License\n\nMIT \u2014 see `LICENSE`.\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Secure secret handler with cloud platform",
    "version": "0.1.0",
    "project_urls": {
        "Changelog": "https://github.com/stellavoid-org/noctivault/releases",
        "Issues": "https://github.com/stellavoid-org/noctivault/issues",
        "Repository": "https://github.com/stellavoid-org/noctivault"
    },
    "split_keywords": [
        "secret",
        " secret-manager",
        " vault",
        " security"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c770b2ebef5dd6c8b24b52a7ce1b75a64a56a6fe6b6967df8d29d2401e006686",
                "md5": "726bb31aab0c1d0eedd84889d3618b0e",
                "sha256": "7ac1378e6aed1f4571cc4a517cd3081463aa1626b5a9138e859921d1f143bc66"
            },
            "downloads": -1,
            "filename": "noctivault-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "726bb31aab0c1d0eedd84889d3618b0e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 20349,
            "upload_time": "2025-09-15T01:35:21",
            "upload_time_iso_8601": "2025-09-15T01:35:21.723920Z",
            "url": "https://files.pythonhosted.org/packages/c7/70/b2ebef5dd6c8b24b52a7ce1b75a64a56a6fe6b6967df8d29d2401e006686/noctivault-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b7c30e8e681c95d24f2f493b9b88e126e699d11ed3d68ee407c14ef0ed399931",
                "md5": "98980258e9b2139cdb34920e8e37be1e",
                "sha256": "28d06321b439cad30729ed542db52854bb1308354d3f4ec647874d3a3be2aff5"
            },
            "downloads": -1,
            "filename": "noctivault-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "98980258e9b2139cdb34920e8e37be1e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 18342,
            "upload_time": "2025-09-15T01:35:23",
            "upload_time_iso_8601": "2025-09-15T01:35:23.414206Z",
            "url": "https://files.pythonhosted.org/packages/b7/c3/0e8e681c95d24f2f493b9b88e126e699d11ed3d68ee407c14ef0ed399931/noctivault-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-15 01:35:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "stellavoid-org",
    "github_project": "noctivault",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "noctivault"
}
        
Elapsed time: 3.73261s