Skip to content

perf(pm): reduce utoo-pm binary size - #3183

Merged
fireairforce merged 1 commit into
nextfrom
codex/pm-binary-size
Jun 19, 2026
Merged

fireairforce merged 1 commit into
nextfrom
codex/pm-binary-size

Conversation

@elrrrrrrr

@elrrrrrrr elrrrrrrr commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Remove the gix/gitoxide HTTP transport from utoo-ruborist native git resolution by delegating clone/checkout to the system git executable, while keeping the existing cache layout, token injection, dedup cache, manifest finalization, and atomic cache commit protocol.
  • Trim utoo-pm/utoo-ruborist release features: drop reqwest http2, hickory-dns, and stream; remove the macOS aws-lc TLS override; keep socks proxy support; replace tokio/full with the features the PM code actually uses; align PM on workspace dirs.
  • Add a utoopm-binary-size GitHub Actions job that asserts h2, hickory-resolver, gix, and aws-lc-rs stay out of the Linux release dependency tree and reports the release binary size.
  • Address git fallback hardening by passing -- before clone positional args and accepting both 40-char SHA-1 and 64-char SHA-256 full hashes.

Local Size Result

Measured in this worktree with cargo build -p utoo-pm --release --bin utoo on macOS:

  • Baseline from origin/next: 10,419,376 bytes
  • Optimized: 6,319,232 bytes
  • Delta: -4,100,144 bytes (-39.35%)

The local Linux-target release-tree assertion also passes:

cargo tree -p utoo-pm --target x86_64-unknown-linux-gnu -e normal,build --prefix none
# no h2 / hickory-resolver / gix / aws-lc-rs entries

Reqwest / Tokio Alternatives Notes

  • reqwest is still the lowest-risk fit for the async registry clients because the code relies on async requests, shared client builders, proxy handling, socks proxy support, gzip/json, rustls, and custom DNS resolver policy. The important win here is feature diet rather than replacing it. Reqwest docs also call out socks as an explicit feature for socks proxy envs, so this PR keeps it: https://docs.rs/reqwest/
  • ureq is a plausible future experiment for isolated blocking download paths, but it is blocking by design and would need spawn_blocking plus new pooling/proxy/retry integration for the resolver: https://docs.rs/ureq
  • minreq is even smaller/minimal, but too bare for the current registry client behavior without rebuilding much of the HTTP policy stack: https://docs.rs/minreq
  • tokio should stay; PM uses process, fs, net, sync, time, select, and the multi-thread runtime. The size win is replacing full with a concrete feature list. Tokio's feature list shows full includes extras such as io-std, parking_lot, and signal that PM release code does not need: https://docs.rs/crate/tokio/latest/features

Validation

  • cargo fmt
  • tombi format Cargo.toml crates/pm/Cargo.toml crates/ruborist/Cargo.toml
  • cargo clippy --all-targets -- -D warnings --no-deps
  • cargo test -p utoo-ruborist --features native-git -- --nocapture (201 passed before the follow-up hardening)
  • cargo test -p utoo-ruborist --features native-git full_sha_detection_accepts_sha1_and_sha256 -- --nocapture
  • cargo test -p utoo-ruborist --features native-git ensure_repo_cached_clones_local_repo -- --nocapture
  • cargo test -p utoo-pm -- --nocapture (272 passed, 3 ignored)
  • cargo build -p utoo-pm --release --bin utoo
  • Local copy of the new GHA release dependency assertion

@elrrrrrrr elrrrrrrr changed the title [codex] perf(pm): reduce utoo-pm binary size perf(pm): reduce utoo-pm binary size Jun 18, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request replaces the gix library with the system git executable for cloning and checking out git dependencies, significantly reducing the dependency tree by removing crates like gix, hickory-resolver, and moka. It also removes the macOS-specific aws-lc-rs TLS configuration, standardizing on reqwest's default rustls provider across all native platforms. Feedback on these changes highlights a critical argument injection vulnerability in the git clone execution that can be mitigated by using -- to separate options from positional arguments, as well as a future-proofing suggestion to support 64-character SHA-256 commit hashes in the is_full_sha helper.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/ruborist/src/resolver/git.rs Outdated
clone_args.extend(["--branch", ref_name]);
}
}
clone_args.extend([effective_url.as_str(), checkout_str]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-critical critical

Security Vulnerability: Argument Injection in git clone

If effective_url starts with a dash (-), it can be interpreted as a command-line option by git clone (e.g., --config or -u), potentially leading to arbitrary command execution.

To prevent this, use -- to separate options from positional arguments (the repository URL and destination directory).

Suggested change
clone_args.extend([effective_url.as_str(), checkout_str]);
clone_args.push("--");
clone_args.extend([effective_url.as_str(), checkout_str]);

Comment on lines +240 to +242
fn is_full_sha(commit_ish: Option<&str>) -> bool {
commit_ish.is_some_and(|c| c.len() == 40 && c.chars().all(|ch| ch.is_ascii_hexdigit()))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Future-proofing: Support SHA-256 Commit Hashes

Git is transitioning to SHA-256, where full commit hashes are 64 hex characters instead of 40. Updating is_full_sha to accept both 40 and 64 character hex strings ensures compatibility with SHA-256 repositories.

Suggested change
fn is_full_sha(commit_ish: Option<&str>) -> bool {
commit_ish.is_some_and(|c| c.len() == 40 && c.chars().all(|ch| ch.is_ascii_hexdigit()))
}
fn is_full_sha(commit_ish: Option<&str>) -> bool {
commit_ish.is_some_and(|c| {
(c.len() == 40 || c.len() == 64) && c.chars().all(|ch| ch.is_ascii_hexdigit())
})
}

@elrrrrrrr
elrrrrrrr force-pushed the codex/pm-binary-size branch from 4173edc to 000232f Compare June 18, 2026 18:04
@elrrrrrrr

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 000232f2be

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

clone_args.extend(["--branch", ref_name]);
}
}
clone_args.extend(["--", effective_url.as_str(), checkout_str]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid passing git auth tokens in argv

When GITHUB_TOKEN/GH_TOKEN is set for an HTTPS git dependency, effective_url contains x-access-token:<token>@..., and passing that value directly as the git clone command-line argument exposes the secret through process listings such as /proc/*/cmdline or ps while the clone is running. Use a credential helper, askpass, or an http.extraHeader/stdin-based mechanism so private-repo installs do not leak tokens to other local processes.

Useful? React with 👍 / 👎.

@elrrrrrrr

Copy link
Copy Markdown
Contributor Author

Empirical backing for dropping the macOS aws-lc-rs override

The aws-lc-rs special-case existed for a "~40% faster M-series cold resolve" claim. I A/B-tested that on a separate branch before this PR existed — sharing the data here since it justifies the TLS change with numbers (the perf claim did not reproduce).

Method: same machine (macOS arm64, M-series), two release binaries differing only in the rustls provider at runtime (ring vs aws-lc-rs — DNS/h2 unused at runtime in both). Cold resolve of an ant-design-sized tree (~659 pkgs, caret ranges), manifest cache cleared each run, 5 interleaved runs.

registry ring (median / min) aws-lc-rs (median / min) aws-lc vs ring
registry.npmmirror.com 1.47s / 1.32s 1.87s / 1.83s +27% slower
registry.antgroup-inc.cn 2.59s / 2.26s 2.84s / 2.19s +10% median / tied at min (noisy)

cold resolve is network-bound, so aws-lc's crypto edge is invisible, while its per-client load_native_certs + install_default adds fixed overhead. So unifying to ring is a size win and a small perf win on China registries — no tradeoff on the registries that matter here. (The original ~40% likely came from npmjs.org / a different setup.)

Superseding my #3182 in favor of this PR — it's a superset (also trims tokio/full → concrete features + stream, plus SHA-256 / -- clone hardening). Closing #3182.

@killagu killagu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@fireairforce
fireairforce merged commit ec7768f into next Jun 19, 2026
43 of 65 checks passed
@fireairforce
fireairforce deleted the codex/pm-binary-size branch June 19, 2026 14:13
killagu pushed a commit that referenced this pull request Jun 21, 2026
…e::chunk` (#3188)

#3142 added live install progress using `response.bytes_stream()`, which
requires reqwest's `stream` feature. #3183 (binary slimming) had removed
that feature on a base that predated the call site, so once both landed on
`next` the combination failed to compile (`E0599: no method bytes_stream`).
#3187 fixed the breakage by re-adding the `stream` feature.

But download progress never needed `stream`. `Response::chunk()` reads the
body frame-by-frame with no feature gate, so it feeds the same per-chunk
`DOWNLOADED_BYTES` counter the spinner renders. The body is still fully
buffered before return (the extractor is not streaming), so this only buys
the progress signal, not lower peak memory — identical behavior, one fewer
feature.

Revert #3187's `stream` feature (drops the wasm-only `wasm-streams` dep
from the lock) and rewrite the download loop to use `chunk()`, dropping the
`futures::StreamExt` import.

Verified: cargo check -p utoo-pm, cargo clippy --all-targets -D warnings,
cargo fmt all clean; Cargo.lock diff is the exact inverse of #3187.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

3 participants