ProxSave v0.17.0
🧭 Unified installer semantics, context-aware TUI flows, and safer atomic restore/write paths
This release is a broad quality and safety upgrade across ProxSave’s interactive workflows (CLI + TUI). It aligns installer and new-install behavior across entrypoints, makes TUI execution fully context-aware (cancellation and timeouts work end-to-end), hardens several file operations with atomic writes/extraction, and improves correctness in storage usage reporting and notification defaults. It also substantially expands test coverage (including true end-to-end decrypt TUI coverage) and reduces flakiness across CI.
-
Installer parity (CLI + TUI): one set of rules, everywhere
- Existing
backup.envhandling aligned with four explicit actions: Overwrite, Edit existing, Keep existing & continue, and Cancel (same semantics in CLI and TUI). - “Keep existing” now consistently means continue, not abort, and runner errors are propagated instead of swallowed.
- Post-config steps are skipped consistently when the config wizard is skipped (AGE setup, post-install audit, Telegram pairing), while finalization steps still run.
--new-installconfirmation flow aligned via a shared reset plan and a single source of truth for preserved entries (build/env/identity). CLI confirmation is CLI-only; TUI confirmation is a pure adapter.- Secondary storage disable semantics aligned: disabling secondary now always writes the canonical cleared state:
SECONDARY_ENABLED=false,SECONDARY_PATH=,SECONDARY_LOG_PATH=- Prevents stale secondary paths surviving TUI edits.
- Secondary path validation centralized across config load, CLI install, and TUI:
- Enforces absolute local-path rules, rejects remote/UNC-style paths,
- Keeps
SECONDARY_LOG_PATHoptional, - CLI installer retries invalid input instead of aborting.
- Cron scheduling aligned across CLI and TUI: shared parsing/normalization and consistent precedence rules so wizard-selected/default cron values are honored reliably in both modes.
- AGE setup consistency fixes: shared private-key validation to prevent silent retry loops; clearer “saved vs reused” messaging and explicit outcome reporting.
- Telegram setup aligned across CLI and TUI: shared bootstrap eligibility rules, consistent skip behavior and centralized skip-reason logging (no more TUI-only fallback logic).
- Existing
-
Decrypt workflow consistency + true end-to-end TUI coverage
- Secret prompt semantics aligned:
"0"is now an explicit abort in both CLI and TUI, with clear messaging andErrDecryptAbortedmapping. - Destination prompts hardened: reject unchanged destination paths (including normalized-equivalent paths) and require a real change before continuing.
- Passphrases are preserved exactly: decrypt prompts no longer trim user input; leading/trailing spaces are preserved (trimming is used only for validation and the
"0"token check). - End-to-end decrypt TUI smoke tests now cover the real production path from entrypoint through bundle creation, including:
- success path validation (bundle contents, metadata, checksum),
- clean abort at the secret prompt,
- flake reduction and stabilization under coverage/CI load.
- Secret prompt semantics aligned:
-
Context-aware TUI across the board (cancellation and timeouts now “just work”)
- Introduced
App.RunWithContext(ctx)and migrated wizard runners and orchestrator prompts to honor context cancellation/timeouts. - Propagated context through:
- install and new-install TUI,
- Telegram setup and post-install audit wizards,
- decrypt and restore prompts (including network commit flows),
- AGE setup flows and confirmation dialogs (no more
context.Background()in modals).
- Added context-aware identity and filesystem operations (
DetectWithContext, immutable attribute ops, identity writes, base-dir resets) usingexec.CommandContextandctx.Err()checks. - Improved cancellation correctness in notification paths (email/relay/webhook) and made retry backoffs context-aware.
- Introduced
-
Safety and correctness hardening (atomic operations + better error handling)
- Atomic restore extraction for regular files: extract to a sibling temp file and rename into place only after successful copy + close, preventing partial/clobbered targets on failure.
- Restore temp files now created with
CreateTempin the target directory to avoidENAMETOOLONGcollisions while preserving atomic rename semantics. - Restored directories are opened before applying final restrictive modes, preventing non-root flows from being blocked by early permission tightening.
- Backup bundle creation is now atomic: write to a temp file, sync, rename into place, sync directory, and clean up reliably on error.
- Bundle/restore close handling hardened: avoided duplicate
Close()calls while preserving explicit close error reporting. - AGE recipient overwrite flow made safe and atomic:
- backups are created via copy-to-
.bak-*at commit time, - new recipients written atomically,
- backup/write failures propagate (abort leaves existing recipients intact),
- backup filenames are collision-resistant (nanosecond precision).
- backups are created via copy-to-
-
Security and integrity improvements
- Executable integrity checks hardened:
- reject symlinked executables via
Lstat, - close TOCTOU swap gaps by verifying
os.SameFile()betweenLstatand the opened file, - apply permission fixes via file descriptor (fd-based
chmod/chown) only after SameFile validation.
- reject symlinked executables via
- TUI output safety: escaped user/runtime-provided strings with
tview.Escapeacross screens, prompts, and headers to prevent markup interpretation. - Telegram CLI output sanitized: strips terminal escape/control characters from registration status text before printing.
- Added a cap on Telegram CLI verification retries to prevent infinite loops.
- Executable integrity checks hardened:
-
Storage reporting and retention correctness
- Fixed UsedSpace calculation (use
Blocks - Bfree, notTotal - Bavail) so reserved blocks aren’t misreported as “used”. - Propagated UsedSpace consistently through orchestrator and notifications (no recomputation from free/total).
- Cloud retry backoff bounded (2s, 4s, 8s, 16s, capped at 30s) and made context-aware to honor cancellation during backoff.
- Normalized GFS retention so
RETENTION_DAILY <= 0consistently yields an effective daily minimum of 1 across all paths (prevents misclassification/deletion). - Normalized bundle path handling to avoid double-suffix artifacts like
*.bundle.tar.bundle.tar, and prevented duplicate cloud uploads when a bundle exists.
- Fixed UsedSpace calculation (use
-
Notification config defaults + legacy compatibility
- Aligned notification defaults with templates/docs:
EMAIL_ENABLEDnow defaults to false when unset. - Restored runtime and migration compatibility with legacy
*_ENABLEenv flags (including env override precedence) and added missing Gotify overrides.
- Aligned notification defaults with templates/docs:
-
Robustness, UX, and test reliability
- Fixed nil-bootstrap logger panics in install/newkey/new-install flows (nil-safe bootstrap behavior with stdout fallback).
- Improved rollback countdown internals without behavioral change, and synchronized TUI teardown paths to avoid goroutine leaks.
- Hardened FakeFS sandbox mapping to prevent
../traversal escaping the test root. - Migrated env-based tests to
t.Setenvfor safer cleanup and reduced flakiness. - Expanded and stabilized TUI simulation tooling (startup synchronization, cancellation timing, builder propagation, screen shell unification, primitive text detection).
-
Dependencies
- Bumped
golang.org/x/cryptoto 0.49.0.
- Bumped
Behavior changes to note:
- Secondary storage validation now applies only when
SECONDARY_ENABLED=true, and disabling secondary always clears saved secondary paths. - Decrypt secret entry treats
"0"as an explicit abort consistently in CLI and TUI. EMAIL_ENABLEDdefaults to false when unset; legacy*_ENABLEaliases remain supported and now override canonical settings consistently.
Overall: a more predictable installer (one shared decision model), fully context-aware TUI workflows, safer atomic restore/write behavior, and stronger correctness/security guarantees—backed by substantially expanded and stabilized test coverage.