Skip to content

Mole parity P2–P6 - #2

Merged
baroitrung merged 21 commits into
mainfrom
quaqua/mu-integ
Oct 19, 2026
Merged

baroitrung merged 21 commits into
mainfrom
quaqua/mu-integ

Conversation

@baroitrung

Copy link
Copy Markdown
Owner

Mole parity phases P2–P6 accepted on mu-integ (plan: docs/plans/active/mole-parity.md).

  • P2 a4b78ad · P3 d8fcbd8 · P4 7cad4aa · P5 213c5f7 · P6 122313e
  • make test: 432 + 52 green
  • Known open: LOWs in runs/pipeline-mufix-p{2..6}.md; clippy red in src/optimize.rs (pre-existing)

from therealTINHTUTE with love ❤️❤️❤️

…gration (Phase 6)

- Implement mu sudo (enable|disable|status) with pam_fprintd, backups, and lockout protection
- Implement mu update with SHA-256 checksum verification against checksums.txt, atomic replacement, and --dry-run
- Implement mu remove with safe FreeDesktop trash deletion via trash::SafeDelete and --dry-run sentinel verification
- Implement mu completion --install for auto-installing shell completion scripts
- Implement interactive whitelist editor (mu clean|optimize --whitelist) in Ratatui
- Add biometric status hint and update notice banner to TUI main menu
- Add golden help fixtures for sudo, update, and remove subcommands
- Add comprehensive unit and integration acceptance tests (351 passed)
- Implement `mu history` reading operations.log with tabular and --json formatting
- Implement `mu purge` safely trashing project build artifacts with --paths and --dry-run
- Implement `mu installer` inspecting and removing .deb/.AppImage/.iso/archive packages
- Add post-clean advisory hint in `mu clean` when build artifacts exceed 2 GB
- Update golden help fixtures and add cli integration tests
- uninstall CLI: always print removal plan; add -y/--yes fail-closed
  confirmation gate for direct removal (no unprompted apt-get purge)
- uninstall CLI: reject ambiguous bare names across apt/snap/flatpak,
  require a source prefix
- Steam: never trash appmanifests via substring match; parse appid/name
  and delegate to 'steam steam://uninstall/<id>' on exact name match
- clean: implement --external <PATH> external-volume target (trashes
  .Trash-*/.directory via SafeDelete, fail-closed on unsafe roots)
- system-trash: fail closed when gio is missing instead of silently
  reporting freed bytes
- system-trash: show item count in the interactive preview via
  CleanTarget::display_label
- browser-cache: make PWA protection functional (component-based domain
  match + recursive delete plan that never removes protected
  ServiceWorker/IndexedDB storage)

Tests added for each fixed behaviour; golden help fixtures updated.
make test: 336 unit + 29 integration pass.
- external-volume: empty '.Trash-*' in place via FreeDesktop traversal
  instead of SafeDelete (which moved the trash into itself: EINVAL for the
  caller's uid, 0 bytes freed for others); '.directory' still SafeDeleted.
  Scan now reports dir_size errors (no 'let (sz, _)').
- add negative tests for --external root validation (/ , /etc, relative).
- browser-cache: drop redundant is_protected_pwa_path checks (the delete
  plan never contains a protected path by construction).
- flow: cache display labels at FlowModel construction so count_fn does not
  read the trash dir on every render tick.
- Steam games are now first-class candidates reached by name
  (mu uninstall "<game>"), printed in the plan and gated like any package;
  remove_package handles source=steam via steam://uninstall/<appid> with a
  look_path check and error propagation. Removed the hidden apt/snap
  side-effect that fired on a name collision.
- the direct-CLI confirmation gate takes an injected ConfirmFn instead of
  reading the real process stdin, so tests never block on a TTY and the
  y/N/EOF answers are covered.
- dry-run header printed before the plan it introduces (output order).
empty_trash_dir read_dir'd <mount>/.Trash-<uid>/files directly, so a
symlinked files/ (or info/, expunged/) pointing outside the mount made
--external permanently delete outside the volume, bypassing SafeDelete.
lstat each subdir and refuse a symlink/non-directory before read_dir;
entries inside are still unlinked without following symlinks.

Test: external_volume_refuses_symlinked_trash_subdir.
Keep both phases' clean targets (system-trash + the four Phase 3 opt-in
targets) and both test blocks. Phase 3's new CleanTarget literals predate
the Phase 2 count_fn field, so add count_fn: None to the four new targets
to keep the auto-merge compiling. make test green at this commit.
- orphaned-app-data: fail closed when package discovery fails, and add a
  per-path preview with the review's named user-data dirs protected (f1, f2).
- podman: report reclaimable size from `podman system df` and preview the
  stopped containers / dangling images prune would remove (f3).
- optimize state step: resolve XDG_STATE_HOME fail-closed, validate the
  cleanup root and every candidate, surface SafeDelete errors, and never
  touch live state (nvim/wireplumber/mpv, $HISTFILE) (f4).
- orphaned-services: recurse *.wants/ under the configured config home,
  report the real symlink size, and relabel to user-scope (f5).
- dns/systemd: run the polkit-gated system scope with sudo (f6).
- align the Phase 3 spec text and add a test per fixed behaviour.
- state step: protect shell history by name (history, *_history, lesshst)
  and match HISTFILE by base name, since HISTFILE is a shell variable and
  is almost never exported (r1 f1).
- podman: preview now propagates podman ls failures as preview_err and also
  lists created containers; the comment no longer claims an exact list (r1 f2).
- orphaned-app-data: execute discovers packages through the same runner as
  scan/preview (the trash runner is only for SafeDelete), so the delete set
  matches the previewed set (r1 f3).
- add a test per fixed behaviour.
F1 (HIGH): purge/installer never opened operations.log; add an injectable
Deps seam that calls oplog::init_logger_at before any log_outcome, with a
test asserting a log line is written.
F2 (MEDIUM): generic artifact names (target/dist/build) now require a project
manifest in the parent dir; strong names stay name-only.
F3 (MEDIUM): installer defaults to ~/Downloads only and the archive heuristic
no longer treats any .sh/.bin/.run or setup.py as an installer.
F4 (MEDIUM spec gap): interactive multi-select for purge/installer (new
src/tui/select.rs) on a TTY, menu entries + dispatch, headless --yes and the
non-TTY gate unchanged; all deletions still go through trash::safe_delete.
…, CPU%, duration parsing, page size, disk partitions)
…ed remove, arch update, pam unique backup/rollback)
@baroitrung
baroitrung merged commit 2727c73 into main Oct 19, 2026
0 of 2 checks passed
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