Skip to content

feat: implement Repository Master Key (RMK) hierarchy with OS keyring storage - #20

Merged
Sparkleeop merged 19 commits into
mainfrom
feat/repository-master-key
Aug 20, 2026
Merged

feat: implement Repository Master Key (RMK) hierarchy with OS keyring storage#20
Sparkleeop merged 19 commits into
mainfrom
feat/repository-master-key

Conversation

@Sparkleeop

Copy link
Copy Markdown
Owner

Summary

This PR implements a Repository Master Key (RMK) hierarchy to replace the password-based encryption flow. The RMK is generated once during stash init, stored securely in the OS credential store (Windows Credential Manager, macOS Keychain, Linux secret-service) via the keyring library, and used to derive per-file and per-chunk encryption keys.

Key Changes

Core Implementation

  • src/stash/core/keymanager.py (new) — RMK generation, storage, retrieval using OS keyring
  • src/stash/core/crypto.py — Rewritten for RMK-based hierarchy:
    • generate_file_key(rmk) — per-file key from RMK
    • derive_file_key_from_rmk(rmk, file_id) — deterministic derivation
    • encrypt_filename/decrypt_filename — dedicated filename encryption
    • Removed password-based key wrapping (encrypt_file_key/decrypt_file_key)
  • src/stash/core/manifest.py — Updated for RMK system (removed file_key_wrapped)
  • src/stash/core/exceptions.py — Added KeyManagementError

CLI Commands

  • stash init — Generates RMK, stores in keyring, displays recovery key (RMK hex)
  • stash put / stash get — Use RMK from keyring (no password prompt)
  • stash key-commands (new group):
    • lock — remove RMK from keyring
    • unlock --recovery-key <hex> — restore RMK from recovery key
    • status — show key management status
    • recovery — display RMK for backup

Documentation & Tests

  • Updated all docs (README, docs/, cli-reference, security, architecture, troubleshooting)
  • Added requirements.txt with keyring>=25.0
  • Updated 34 unit tests for new RMK API

UX Flow

First device:                    New device:
stash init                       stash unlock --recovery-key <hex>
  ↓                                 ↓
Generate RMK                     Restore RMK to keyring
  ↓                                 ↓
Store in OS keyring              Ready to use
  ↓
Show recovery key (SAVE!)

Testing

  • All 34 unit tests pass
  • Ruff linting clean
  • Mypy type checking clean
  • Local integration tested: init → lock → unlock → put/get cycle

Breaking Changes

  • No more password prompts on put/get — uses RMK from keyring
  • Recovery key (RMK hex) shown once at stash init — must be saved
  • Old repositories with password-wrapped keys need migration (not yet implemented)

Dependencies

  • Added keyring>=25.0 to pyproject.toml and requirements.txt

Closes: #key-management

@Sparkleeop
Sparkleeop merged commit b2a4ccd into main Aug 20, 2026
6 checks passed
@Sparkleeop
Sparkleeop deleted the feat/repository-master-key branch August 20, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant