Enhance installation, upgrade, and documentation processes#13
Open
plyght wants to merge 75 commits into
Open
Conversation
Add a note to standardize time to action and include a flag.
Hardlink targets with absolute paths or .. components could escape the extraction destination. Add pre-check before canonicalization to catch these cases early.
http:// tap URLs are vulnerable to man-in-the-middle attacks. Require https://, git@, or local paths instead.
Missing sha256 tools or missing .sha256 files now abort instead of silently skipping. WAX_NO_VERIFY=1 required to install without integrity check.
Allows skipping automatic post-install hooks on install/cask commands. Plumbs run_scripts through all install code paths. Defaults to enabled.
Formulas with only URL now parse successfully with empty url/sha256 fields. Source build path rejects empty URLs with a clear --head suggestion instead of crashing.
Update repo URLs to plyght/wax. Document --no-script, WAX_NO_VERIFY, head-only formulas. Update limitation descriptions to match current behavior. Reference correct test and lint commands.
Formula upgrades use a producer-consumer channel so each bottle can uninstall/install as soon as it is ready while other downloads continue. Cask upgrades run in a JoinSet concurrently with the formula pipeline. CaskState add/remove take a shared async lock so parallel cask installs cannot corrupt installed_casks.json. Co-authored-by: Cursor <cursoragent@cursor.com>
Replaced the use of `dunce::canonicalize` with a simple path absolutization that does not resolve symlinks. This fixes a Time-of-Check to Time-of-Use (TOCTOU) vulnerability where an attacker could exploit the path resolution before executing `sudo rm -rf`. By not resolving symlinks, we ensure that when a path points to a symlink, `sudo rm -rf` acts on the symlink itself and not its target. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaced unsafe `unwrap()` calls on `file_name()` in `src/commands/services.rs` with safe `ok_or_else` that maps to a `WaxError::ServiceError`. This prevents panics when handling unexpected paths and ensures errors are correctly bubbled up. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Replaced `unwrap()` with proper error handling inside `sync.rs`. - Task early-exits and returns `WaxError::InstallError` properly on Semaphore Acquisition failures. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaced blocking `std::fs::File::create` and `set_len` with `tokio::fs` equivalents inside `download_multipart`. This prevents blocking Tokio's executor thread during file pre-allocation. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaces `!candidates.contains(&cask_index)` with a `last() != Some(&cask_index)` check. Because the outer loop uses `.enumerate()` and provides strictly increasing indices, any previously inserted `cask_index` is guaranteed to be at the end of the `candidates` vector, turning an O(N) array scan into an O(1) tail check. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replaced the slow `.contains` push loop with `extend`, `sort_unstable`, and `dedup` to lower complexity to O(N log N). Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Optimize leaves filtering by avoiding String allocations The `depended_on` `HashSet` currently clones `String` names from formula dependencies. This changes it to hold `&str` references directly pointing to the dependency strings from the formulae in the cache, eliminating unnecessary allocations in the `leaves` function hot loop. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> * Remove broken benchmark config; keep leaves HashSet optimization only --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit adds unit tests for the `Formula::full_version` method in `src/api.rs`. It ensures that the version string is properly formatted when a revision number is absent (0) and when it is present. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added a single sequential test to `src/signal.rs` to verify that `set_active_multi` and `clear_active_multi` appropriately update the active multi progress state. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This adds tests in `src/system_pm.rs` for: - The `name()` method on `SystemPm` variants. - The `which` and `find_in_path` binary utility functions. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Adds a comprehensive unit test suite for the `detect_artifact_type` function in `src/cask.rs`. The new tests cover: - Direct file extensions (.dmg, .pkg, .zip) - All supported tarball variants (which map to .tar.gz) - URLs with query parameters - URLs with fragments - Unsupported extensions - Extension-less URLs Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Added a new asynchronous test, `test_get_outdated_packages`, to improve testing coverage for the upgrade command's business logic. This test accurately mocks the filesystem (by redirecting the HOME environment variable to a temporary directory) and safely tests the logic using a global mutex lock to prevent concurrent testing race conditions. The test verifies that the `get_outdated_packages` function properly identifies packages that are: - Version outdated - Bottle rebuild outdated - Bottle SHA256 outdated And ensures it ignores packages that are pinned or already up to date. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Merge bottle_rebuild, sudo error helper, signal shutdown/critical-section, and ui dirs/copy_dir_all tests that could not auto-merge after earlier PRs.
There was a problem hiding this comment.
Pull request overview
This PR broadens Wax’s installation/upgrade ergonomics and reliability: it adds self-update and timing support in the CLI, improves cask state/metadata handling, tightens security constraints around taps and filesystem paths, and refreshes documentation/scripts to match the new workflows.
Changes:
- Add
self-update,--time-to-actionoutput, and richer help/diagnostics coverage (includingdoctor --full). - Improve install/upgrade plumbing: safer tap handling, better bottle/platform resolution, improved relocation/runtime validation, and more robust sudo + progress interactions.
- Expand cask support: metadata repair, safer artifact destinations, and better discovery of manually installed apps.
Reviewed changes
Copilot reviewed 42 out of 43 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| todo.md | Adds a tracking note for system package manager parity. |
| tests/cli.rs | Extends CLI integration coverage for new flags/subcommands and behavioral constraints. |
| src/ui.rs | Progress UI tweaks and macOS clonefile optimization for directory copy. |
| src/timing.rs | Adds global timing toggle + formatting helpers. |
| src/tap.rs | Rejects insecure http:// taps; improves parent-dir error handling. |
| src/system_pm.rs | Replaces which subprocess usage with PATH scanning; pre-acquires sudo for visible sudo runs. |
| src/sudo.rs | Improves sudo prompting/TTY handling; adds progress suspension hook; changes path normalization strategy. |
| src/signal.rs | Adds with_suspended_progress and expands unit tests. |
| src/main.rs | Adds self-update, --time-to-action, doctor --full, and refactors self-update path. |
| src/install.rs | Avoids unwrap on empty version lists when syncing state. |
| src/formula_parser.rs | Adds bin_install_targets, supports bin.install ... => ..., and head-only formula parsing improvements. |
| src/discovery.rs | Improves macOS cask discovery resolution using bundle metadata scoring. |
| src/deps.rs | Removes reverse-deps helper and adds tests for dependency graph sorting/cycles. |
| src/commands/version_install.rs | Switches timing output to new timing helpers; avoids epoch unwrap panic. |
| src/commands/update.rs | Switches timing output to new timing helpers. |
| src/commands/uninstall.rs | Switches timing output to new timing helpers; avoids epoch unwrap panic. |
| src/commands/sync.rs | Uses file_for_platform; improves semaphore error handling; switches timing output; avoids epoch unwrap panic. |
| src/commands/services.rs | Replaces unwrap() on filenames with proper errors. |
| src/commands/self_update.rs | Updates canonical repo URL; increases HTTP timeout; adds test. |
| src/commands/reinstall.rs | Adds “not installed” failure behavior; switches timing output; improves --all handling. |
| src/commands/outdated.rs | Switches timing output to new timing helpers. |
| src/commands/leaves.rs | Uses &str sets to reduce allocations. |
| src/commands/install.rs | Adds tap auto-add/update for qualified packages; adds --no-script; improves bottle selection; adjusts concurrency; adds linkage checking; registers progress globally for nested prompts; adds multiple helpers/tests. |
| src/commands/info.rs | Shows tap slug for qualified packages; improves installed lookups; adds tests. |
| src/commands/doctor.rs | Adds --full / quick mode; adds cask metadata checks/repair; refactors slow checks; improves cellar scanning. |
| src/commands/bundle.rs | Propagates run_scripts flag; switches timing output. |
| src/cask.rs | Adds Homebrew-compatible metadata generation/repair, safer artifact destinations, and serialized cask-state writes. |
| src/cache.rs | Avoids epoch unwrap panic. |
| src/builder.rs | Replaces which with PATH scanning; factors CPU core calculation and adds tests. |
| src/bottle.rs | Improves extraction safety around links; expands relocation placeholders; adds Linux runtime validation and more tests; async preallocation. |
| src/api.rs | Adds BottleStable::file_for_platform (incl. arm64/aarch64 Linux aliasing) and tests. |
| README.md | Updates install/usage docs for new features and workflows. |
| install.sh | Switches repo; makes checksum verification mandatory unless explicitly disabled. |
| docs/TROUBLESHOOTING.md | Updates support links and documents new behavioral expectations. |
| docs/PHASE2_SUMMARY.md | Updates narrative to reflect relocation and post-install behavior. |
| docs/DEVELOPMENT.md | Updates test/quality guidance and repo URLs. |
| docs/CLI.md | Documents --time-to-action and --no-script. |
| docs/ARCHITECTURE.md | Updates limitations/future plans to match current behavior. |
| Cargo.toml | Version bump; repo/homepage updates; adds rustls-webpki. |
| benchmark.sh | Major benchmarking script overhaul (CLI options, download probes, reporting). |
| .gitignore | Ignores AGENTS.md and .poc/. |
| .github/workflows/release.yml | Reworks release triggers/tagging flow and release-note generation conditions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+101
to
+102
| let src_c = CString::new(src.as_os_str().as_bytes())?; | ||
| let dst_c = CString::new(dst.as_os_str().as_bytes())?; |
Comment on lines
1304
to
+1310
| fn reject_traversal(path: &Path) -> Result<()> { | ||
| if path.as_os_str().as_encoded_bytes().contains(&0) { | ||
| return Err(WaxError::InstallError(format!( | ||
| "Path contains NUL byte: {}", | ||
| path.display() | ||
| ))); | ||
| } |
Comment on lines
+416
to
+418
| pub async fn sync_from_caskrooms(&self) -> Result<HashSet<String>> { | ||
| let mut casks = self.load().await?; | ||
| let mut synced_names = HashSet::new(); |
Comment on lines
972
to
+976
| let multi = MultiProgress::new(); | ||
| let owns_formula_multi = crate::signal::clone_active_multi().is_none(); | ||
| if owns_formula_multi { | ||
| set_active_multi(multi.clone()); | ||
| } |
Comment on lines
+36
to
+38
| if [[ "${{ github.ref_type }}" == "tag" ]]; then | ||
| VERSION="${github.ref_name#v}" | ||
| echo "Tag push for v$VERSION" |
|
|
||
| ```bash | ||
| curl -fsSL https://raw.githubusercontent.com/plyght/wax/master/install.sh | bash | ||
| curl -fsSL https://raw.githubusercontent.com/tschk/wax/master/install.sh | bash |
|
|
||
| ```bash | ||
| git clone https://github.com/plyght/wax.git | ||
| git clone https://github.com/tschk/wax.git |
|
|
||
| ```bash | ||
| git clone https://github.com/plyght/wax.git | ||
| git clone https://github.com/tschk/wax.git |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.