Skip to content

Feat/resumable uploads - #24

Merged
Sparkleeop merged 16 commits into
mainfrom
feat/resumable-uploads
Aug 22, 2026
Merged

Feat/resumable uploads#24
Sparkleeop merged 16 commits into
mainfrom
feat/resumable-uploads

Conversation

@Sparkleeop

Copy link
Copy Markdown
Owner

Summary
This PR implements resumable uploads for Stash, allowing interrupted uploads to be resumed from where they left off. This is a major feature that significantly improves the user experience for large file uploads over unreliable connections.
🎯 Features Implemented
Core Functionality

  • --resume flag for stash put command to resume interrupted uploads
  • --file-id option to explicitly specify which incomplete upload to resume
  • Automatic detection of incomplete uploads by filename when --resume is used without --file-id
  • Chunk-level resume: Skips already-uploaded chunks, only re-uploads missing chunks
  • Incremental manifest saving: Manifest is saved after each chunk upload for crash recovery
  • File integrity verification: Verifies file size and first-chunk checksum before resuming
  • File change detection: Fails gracefully with clear error if file content changed since initial upload
    Key Management Integration
  • stash key-commands lock: Removes RMK from OS keyring (locks repository)
  • stash key-commands unlock --recovery-key : Restores RMK from recovery key (new device setup)
  • stash key-commands status: Shows key management status
  • stash key-commands recovery: Displays recovery key (RMK) for backup
    📝 Changes Summary
    File Changes
    src/stash/core/manifest.py Added ChunkStatus & UploadStatus enums; extended ChunkInfo & FileManifest with status tracking fields; updated serialization/deserialization
    src/stash/core/keymanager.py New KeyManager class for RMK management using OS keyring
    src/stash/core/crypto.py Added derive_file_key_from_rmk() method for RMK-based key derivation
    src/stash/core/exceptions.py Added KeyManagementError exception
    src/stash/cli/commands/put.py Added --resume/--file-id flags; resume logic with incremental manifest saving
    src/stash/cli/commands/key.py New key_commands group (lock, unlock, status, recovery)
    src/stash/cli/main.py Registered key_commands group
    src/stash/cli/commands/init.py Generates RMK on init, stores in keyring, displays recovery key
    Testing
    All 40 tests pass (34 unit + 6 integration):
  • 6 new integration tests for resumable uploads:
  • test_new_upload_creates_partial_manifest ✅
  • test_resume_upload_after_interruption ✅
  • test_resume_with_explicit_file_id ✅
  • test_resume_fails_when_file_changed ✅
  • test_multiple_resume_cycles ✅
  • test_corrupted_manifest_handling ✅
  • All 40 tests pass (34 unit + 6 integration)
  • Ruff linting: ✅ clean
  • MyPy type checking: ✅ clean
    UX Flow
    First device:
    stash init # Generates RMK, stores in OS keyring, shows recovery key
    stash put file.zip # No password prompt - uses RMK from keyring
    New device / recovery:
    stash key-commands unlock --recovery-key # Restore RMK from recovery key
    stash put file.zip # No password prompt
    Interruption recovery:
    stash put bigfile.zip --resume # Auto-detects by filename
    stash put bigfile.zip --resume --file-id abc123 # Explicit file ID
    Configuration
    No new config required. Uses existing ~/.config/stash/config.json for provider settings. RMK stored in OS credential store:
  • Windows: Credential Manager
  • macOS: Keychain
  • Linux: secret-service (GNOME Keyring, KWallet, etc.)
    Breaking Changes
  • No more password prompts on put/get — uses RMK from keyring
  • Old repositories with password-wrapped keys need migration (not yet implemented)
  • stash put no longer accepts --password flag
    Dependencies
  • Added keyring>=25.0 to pyproject.toml and requirements.txt
    Documentation Updates
  • README.md: Added Key Management section with UX flows
  • docs/cli-reference.md: Added key-commands reference
  • docs/security.md: Updated key hierarchy documentation
  • docs/architecture.md: Updated key hierarchy diagram
  • docs/troubleshooting.md: Added RMK/keyring troubleshooting section
    Checklist
  • All tests pass (40/40)
  • Ruff linting clean
  • MyPy type checking clean
  • Documentation updated
  • CHANGELOG/RELEASING guide updated
    Related Issues
  • Closes #key-management (RMK hierarchy implementation)
  • Enables future: #resumable-uploads, #multi-provider-routing, #replication
    Reviewer Notes
  • The core logic is in src/stash/cli/commands/put.py:_put_async (resume logic) and src/stash/core/keymanager.py (key management)
  • Tests use mocked providers — no real API credentials needed
  • Integration tests cover 6 scenarios including edge cases (file change detection, multiple cycles, corrupted manifests)

@Sparkleeop
Sparkleeop merged commit 478ceaa into main Aug 22, 2026
6 checks passed
@Sparkleeop
Sparkleeop deleted the feat/resumable-uploads branch August 22, 2026 10:18
@Sparkleeop
Sparkleeop restored the feat/resumable-uploads branch August 22, 2026 10:23
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