Skip to content

Enhance installation, upgrade, and documentation processes#13

Open
plyght wants to merge 75 commits into
plyght:masterfrom
tschk:master
Open

Enhance installation, upgrade, and documentation processes#13
plyght wants to merge 75 commits into
plyght:masterfrom
tschk:master

Conversation

@plyght

@plyght plyght commented Jun 12, 2026

Copy link
Copy Markdown
Owner

No description provided.

undivisible and others added 30 commits April 30, 2026 12:55
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>
undivisible and others added 25 commits June 7, 2026 23:59
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.
Copilot AI review requested due to automatic review settings June 12, 2026 18:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-action output, and richer help/diagnostics coverage (including doctor --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 thread src/ui.rs
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 thread src/cask.rs
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 thread src/cask.rs
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 thread src/commands/install.rs
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"
Comment thread README.md

```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
Comment thread README.md

```bash
git clone https://github.com/plyght/wax.git
git clone https://github.com/tschk/wax.git
Comment thread README.md

```bash
git clone https://github.com/plyght/wax.git
git clone https://github.com/tschk/wax.git
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.

4 participants