Summary
Re-submission of #43 (Matt Van Horn's RubyGems registry support), rebased onto current main with the remove.rs fix the review bot flagged on the original PR, plus two follow-on fixes surfaced during review.
Adds gem:, ruby:, and rubygems: prefixes to fetch Ruby gem source code via rubygems.org API. Same shape as npm, PyPI, and crates.io.
Usage
opensrc path gem:rails
opensrc path ruby:sidekiq
opensrc path gem:nokogiri@1.16.0Also adds --rubygems to opensrc clean and shows RubyGems in opensrc list.
What changed vs #43
- Rebased onto current main. #56's structured-error refactor (April 30) replaced
Box<dyn std::error::Error>with the crate's typedError/Resultacross all registries.rubygems.rsnow usesError::PackageNotFound,Error::HttpStatus, andError::NoRepoUrlto match the other registry modules. - Resolved the list.rs conflict introduced by #53's
opensrc fetchsubcommand. The empty-state hint usesfetchexamples to match the post-#53 style. - Added
Registry::RubyGemsto the fallback registry scan in remove.rs, the issue the review bot flagged on #43. Without it, RubyGems packages could only be removed by an explicitgem:prefix. - Tightened the remove.rs prefix scoping. The cross-registry fallback now only fires when the user did not supply an explicit prefix, so
opensrc remove gem:railsno longer risks deleting a cached npm/PyPI/cratesrailswhen no gemrailsis present. Added awas_explicit: boolfield toDetectedRegistryto carry the prefix information out of detection. - Collapsed the rubygems.rs error variant. The single-call V2 endpoint can't distinguish "gem missing" from "version missing", so a misleading
VersionNotFoundwas replaced with a singlePackageNotFoundreporting the user's spec verbatim.
Known limitations (out of scope here)
Three concerns surfaced during review that exist in current main for every registry, not just RubyGems. Flagging for maintainer visibility; happy to open separate PRs if helpful:
-
Substring-based host validation.
is_git_repo_urlincore/registries/mod.rsusesurl.contains("github.com"), andauthenticated_clone_urlrewrites credentials viastr::replace. A malicious package whose repository URL contains a known host as a substring (e.g.https://github.com.evil.example/owner/repo) passes validation and would receiveGITHUB_TOKEN. Fix: parse withurl::Urland require exact host match. -
Default-branch fallback silently mislabels cache.
clone_at_tagincore/git.rstreats a tagless default-branch clone as success afterv{version}and{version}both miss.sources.jsonthen records the package at the requested version while the cache holds default-branch HEAD. RubyGems is more likely to hit this than npm/crates because gem repos don't uniformly tag with thevprefix. -
URL encoding inconsistency.
npm.rsencodes package names withurlencoding::encode;pypi.rs,crates.rs, and this PR'srubygems.rsinterpolate raw. Probably benign for the constrained name characters these registries allow, but worth aligning.
Testing
cargo fmt --manifest-path packages/opensrc/cli/Cargo.toml --check
cargo clippy --manifest-path packages/opensrc/cli/Cargo.toml -- -D warnings
cargo test --manifest-path packages/opensrc/cli/Cargo.toml -- --test-threads=1All 107 tests pass. fmt and clippy clean.
Credit
Original work by @mvanhorn in #43. The squashed commit keeps Matt as Author. I'm listed as Co-author for the rebase, error-pattern port, remove.rs scoping fix, and error-variant collapse.
This PR was AI-generated and human-reviewed. The rebase, error refactor, and remove.rs fixes were prepared with Claude Code under my review, with adversarial review from Codex and Gemini before submission.
Activity
3Thanks for picking this up @kylesnowschwartz -- happy to see #43's work landed under your stewardship with the co-authorship credit preserved. Two of the changes you added are real improvements I missed:
- The
was_explicit: boolfield onDetectedRegistryis the right scoping for the remove.rs fallback. Without it,opensrc remove gem:railscould nuke a cached npm rails. Glad you caught that. - The
PackageNotFoundcollapse is more honest than the originalVersionNotFound/PackageNotFoundsplit given that the V2 endpoint can't distinguish the two.
The three out-of-scope concerns all look legitimate to me on a re-read of core/registries/mod.rs and core/git.rs. The substring host validation in particular (url.contains("github.com")) is worth tightening soon -- happy to take any of those if maintainers want them split.
LGTM as a contributor; deferring to vercel-labs on the merge call.
@mvanhorn is attempting to deploy a commit to the Vercel Labs Team on Vercel.
A member of the Team first needs to authorize it.