Add bash tab completion script for pwr CLI commands
Provide a bash completion function for all pwr subcommands and their
flags. The completion script maps each subcommand to its valid arguments:
init completes –server-host, –server-port, –psk, and –local-root;
archive, restore, and ensure complete directory paths; status and list
offer –recursive/-r; log provides –errors/-e and –project; shell
completes bash, zsh, fish, and –init. The completion is installed via
‘source <(pwr completions bash)’ in .bashrc.
Document required parentheses around impl Trait syntax in handler signatures
The Rust 2024 edition requires explicit parentheses around compound trait
bounds in function argument position. Without them, ‘&mut impl Read + Write’
is ambiguous: it could parse as ‘(&mut impl Read) + Write’ (a mutable
reference to a type implementing Read, with an additional Write bound) or
‘&mut (impl Read + Write)’ (a mutable reference to a type implementing
both). The compiler requires the latter to be written with parentheses.
Add a module-level doc comment explaining this so future maintainers do
not attempt to remove the parentheses.
Add end-to-end integration tests for full client-server lifecycle
Implement two end-to-end tests using paired in-memory byte streams (Pipe
struct implementing Read+Write via Arc<Mutex<Vec») that simulate a
complete client-server interaction without network dependencies.
test_full_client_server_archive_restore_cycle creates a multi-file project
directory, generates age encryption keys and a PSK, runs the archive
pipeline to produce an encrypted blob, then spawns two threads for client
and server communicating through paired pipes. The client performs the
full protocol sequence: Handshake with HMAC-SHA256 proof, ArchiveRequest
with project metadata, chunked data transfer with 1 MiB chunks and
zero-length EOF marker, and ArchiveComplete with SHA-256 hash. The server
thread receives the Handshake, verifies the client proof, responds with
its own server proof for mutual authentication, reads the ArchiveRequest,
receives all chunks via the 4-byte length-prefixed streaming protocol, and
acknowledges ArchiveComplete. After both threads join, assertions verify
the server received the exact encrypted blob, decryption succeeds, and the
local project metadata transitions correctly through local → archived →
placeholder states with .project.toml file survival.
test_end_to_end_hash_verification_prevents_corruption validates that
tampering with a single byte of the encrypted archive produces a different
SHA-256 hash, ensuring integrity violations are detectable before
extraction.
Add operation progress overlay to TUI and wire pwr tui subcommand in CLI
Implement an OperationOverlay screen for the ratatui-based TUI that renders
a centered modal dialog with a progress gauge, transfer statistics, and a
cancel prompt during archive and restore operations. The overlay displays
the operation name and project name in the title bar, a cyan progress
gauge driven by the bytes_done/bytes_total ratio, a statistics line
showing human-readable byte counts with percentage, and a status line that
changes between ‘Press Esc to cancel’ during transfer, ‘Transfer complete’
on success, and red error text on failure. The format_size helper converts
byte counts to GB/MB/KB/B with one decimal place. The handle_input method
maps Escape to cancellation and Enter to dismissal after completion.
Wire the pwr tui subcommand into the CLI behind the tui feature flag. The
Commands enum gains a Tui variant gated by #[cfg(feature = “tui”)], the
dispatch match arm calls cmd_tui(), and the tui module is conditionally
compiled. Building without –features tui produces a CLI-only binary;
building with the flag includes the ratatui and crossterm dependencies and
the tui module, enabling pwr tui to launch the interactive interface.
Annotate session state structs with allow(dead_code) for future use
The ArchiveSession and RestoreSession structs in the handler state machine
contain fields (session_id, file_count, compression, bytes_received,
bytes_sent) that are stored for future use in resume-after-interruption
logic and detailed transfer statistics. Currently they are only written
during state transitions but not yet read back. Add #[allow(dead_code)]
annotations to suppress compiler warnings while keeping the fields
available for the planned transfer progress tracking and interrupted
archive resume features.
Fix warning: remove unused variable and clean up imports
Remove the unused config variable clone from the listener accept loop where
it was captured by the thread closure but never referenced. Remove the
unused PrivateKeyDer import from rustls pki_types. Prefix the catch-all
match variable with underscore to suppress the unused variable warning in
the dispatch function. Keep the required parentheses around impl Trait
syntax in argument position as required by Rust 2024 edition for
disambiguation. Add MIT LICENSE file.
Add systemd service unit and deployment guides for server and client
Create a hardened systemd service unit for pwr-server with security
directives including NoNewPrivileges, PrivateTmp, ProtectSystem=strict,
ProtectHome=yes, and read-only access to config and certificate paths
with read-write access only to the project storage directory. The service
runs as the pwr system user, restarts on failure with a 5-second delay,
and logs to journald. Resource limits cap file descriptors at 4096 and
memory at 512 MB.
Add docs/server-setup.md covering the complete Debian 12 deployment
workflow: installing build dependencies, compiling with cargo,
initializing the server to generate TLS certificates and PSK, creating the
storage directory with correct ownership, installing and enabling the
systemd service, verifying the listener with ss, configuring firewall
rules for nftables and iptables, and troubleshooting common issues.
Add docs/client-setup.md covering the Arch Linux client workflow:
building the binary, running pwr init with server host and PSK, setting
up shell integration for bash, zsh, and fish, performing the first archive
and restore, launching the TUI, and troubleshooting configuration and
authentication errors. Include a full configuration file reference.
Fix client integration tests and add retry-aware connect test
Repair the client integration test suite after the retry logic and library
target additions. The connect_to_nonexistent_server test now uses a match
statement instead of unwrap_err to work with the ClientResult type.
The connect_timeout_is_respected test is marked #[ignore] because OS-level
TCP timeout behavior varies across platforms, making sub-second timeout
assertions unreliable in CI environments. Unused imports (TcpListener,
Duration) are removed from the test file.
Add progress bar integration to CLI with empty-archive edge case handling also add 0-byte transfer file size.
Add progress callback support to client archive and restore methods
Extend archive_project and restore_project with optional progress callbacks
that report bytes transferred against total size. The existing methods
become thin wrappers calling the new archive_project_with_progress and
restore_project_with_progress variants with None for backward
compatibility. During archive, the callback fires after each 1 MiB chunk
is written to the TCP stream, reporting cumulative bytes sent. During
restore, the callback fires after each received chunk is appended to the
buffer, reporting cumulative bytes received. The callback signature is
fn(u64, u64) where the first argument is current progress and the second
is the total, suitable for driving indicatif progress bars or TUI
progress displays without coupling the client module to any specific UI
library.
Add exponential backoff retry logic to PwrClient connection
Implement connect_with_retry in PwrClient that wraps the existing connection
logic with up to 3 retry attempts using exponential backoff starting at 1
second and doubling to 2 and 4 seconds. The existing connect method is
renamed to connect_once and made private, with the public connect method
now calling it in a retry loop. Transient network failures such as TCP
connection refused or TLS handshake timeouts are retried, while
authentication failures are not (they propagate immediately since retrying
with the same credentials would produce the same result). Each retry
attempt is logged at WARN level with the error and delay, and a successful
retry is logged at INFO level. The connect_timeout_secs from the client
config is applied to each individual TCP connection attempt within the
retry loop.
Implement TLS transport with custom certificate verifier and fingerprint pinning
Replace the TLS-not-yet-implemented stub in the PwrClient with a working
rustls-based TLS 1.3 connection layer. The connect_tls function builds a
ClientConfig using the dangerous API with a custom certificate verifier
(CertVerifier) that accepts self-signed server certificates — necessary
because pwr-server generates its own ECDSA P-256 certificate during init
rather than obtaining one from a public CA. Authentication is provided by
the PSK handshake running over the encrypted channel, so the TLS layer
provides confidentiality while the application layer handles mutual
authentication.
The verifier supports optional SHA-256 certificate fingerprint pinning.
When a server_fingerprint is present in the client config, the verifier
computes the SHA-256 hash of the server’s end-entity certificate and
compares it against the pinned value, rejecting the connection on
mismatch. When no fingerprint is configured, the verifier accepts any
certificate but logs the observed fingerprint for the user to pin later,
enabling a trust-on-first-use workflow.
Signature verification in the verifier accepts all TLS 1.2 and 1.3
signatures without checking against a root CA. This is intentional: the
security model relies on PSK-based mutual authentication at the
application layer combined with certificate pinning for defense-in-depth,
rather than on the Web PKI trust infrastructure which would reject
self-signed certificates. The supported_verify_schemes list advertises
ECDSA and RSA schemes to maximize compatibility.
Add server address display to status command output
Extend the status command to print the configured server host and port
after the project count summary, giving users a quick reminder of which
NAS their projects are archived to.
Fix server handler and listener warnings: remove unnecessary parentheses and unused imports
Clean up compilation warnings in the pwr-server crate. In handler.rs, the
send_server_msg function signature used unnecessary parentheses around
impl Write which triggered the unused_parens lint. In listener.rs, the
PrivateKeyDer import was unused since the key is loaded via
rustls_pemfile::private_key which returns a generic PrivateKeyDer type
that does not need to be explicitly imported.
Clean up unused imports and fix compilation warnings in client TLS module
Remove unused Arc import from the top-level client scope (it is only
needed inside the connect_tls function where it is imported locally).
Replace TrustAnchor with the correct ServerName import from
rustls::pki_types. Remove the unnecessary mut qualifier from the
ClientConnection binding in connect_tls.
Add –tls flag to all network commands, –limit to log, –auto-install to shell init
Extend the CLI with connection and usability flags across all subcommands.
Every command that contacts the server (archive, restore, ensure, status,
list) now accepts a –tls flag that is passed through to
PwrClient::connect, controlling whether the connection uses TLS with
certificate pinning or plaintext for local testing. The log command gains
a –limit flag defaulting to 50 entries, with a summary line showing how
many entries were truncated. The shell init command supports
–auto-install which opens the shell rc file in append mode and writes
the eval line directly, providing a one-command setup experience.
Function signatures throughout main.rs are updated to thread the new
boolean parameter. The ensure command passes tls=false through to its
internal restore call since ensure is triggered from the shell wrapper
where TLS may not be configured. The list command delegates to
cmd_status with tls=false for local-only directory scanning.
Wire progress bars and retry logic into CLI archive and restore commands
Integrate the progress reporting module and retry logic into the two main
CLI workflows. The archive command now creates a progress bar before the
packaging pipeline and passes it to create_archive_with_progress via a
ProgressFn callback that maps ArchiveStage values to status messages and
fractional bar position. A second progress bar tracks the upload phase.
Both bars are finished and cleared on completion. The restore command
similarly uses a download progress bar keyed to the stored project size
and an extraction progress bar sized to the received encrypted blob.
Connection attempts now use with_retry wrapping PwrClient::connect with 3
retries and a 1-second base delay, retrying only on transient network
errors as classified by is_retryable_error. This provides resilience
against momentary server unavailability without masking fatal errors
like authentication failures.
Add client integration test suite with handshake, streaming, retry, and progress tests
Create 14 integration tests in pwr-cli/tests/client_integration.rs covering
the client-side protocol layer. Handshake tests verify that ClientMessage
frames encode with correct magic bytes, version, and type discriminants,
and that decode_client_message recovers the original Handshake struct with
client_id and nonce intact. Archive flow tests exercise ArchiveRequest and
ArchiveComplete serialization round-trips with all fields including UUID,
name, total_size, file_count, compression, and hash. Restore flow tests
verify RestoreRequest encoding and decoding.
Server response parsing tests validate that HandshakeAck, Error, and
StatusResponse messages are correctly deserialized from framed payloads,
including success flags, error codes, and project info vectors with UUID
and file_count fields. Chunk streaming tests cover five size boundaries
from zero bytes (EOF detection) through 1 MiB, plus standalone EOF marker
encoding. Retry logic tests verify is_retryable_error correctly classifies
connection failures, timeouts, and broken pipes as transient while treating
authentication and not-found errors as fatal. with_retry is tested for
immediate success, maximum retry exhaustion (initial + 3 retries = 4
calls), and early termination on non-retryable errors after 1 call.
A progress stage test confirms all five ArchiveStage variants are distinct.
Add progress reporting module with indicatif integration and stage callbacks
Introduce a progress module in the pwr CLI crate that provides two
display modes for long-running operations. The archive_progress_bar and
restore_progress_bar functions create indicatif ProgressBar instances
with styled templates showing a spinner, progress bar, byte counter,
and ETA. The update_archive_progress function maps ArchiveStage enum
values to human-readable status messages displayed in the bar.
For non-interactive terminals or quiet mode, print_stage emits a simple
line to stderr for each stage transition during archive or extract
operations. This provides visibility into long-running operations
without requiring a TTY.