fix(vendor): vendor pure-ruby (?platform=ruby) gems, gate on the purl not the staging dir - #172
Open
Mikola Lysenko (mikolalysenko) wants to merge 1 commit into
Open
Conversation
… not the staging dir The gem vendor gate refused any install whose dir name was not `<name>-<version>`, using that as a proxy for "platform-specific build". That proxy is wrong for the registry auto-fetch ladder: a lockfile- resolvable-but-not-installed gem is staged into a private tempdir named literally `gem` (registry_fetch::fetch_gem), so a pure-ruby gem like `activestorage` (whose production patch purl is `?platform=ruby`, the DEFAULT portable platform) was refused with `platform_gem_unsupported`. #157 (find_packages_for_rollback) already fixed the runtime behavior for gems the crawler finds installed (qualified `?platform=ruby` now maps to the installed base dir), so `scan --mode vendored` vendors cleanly when the gem is installed under `vendor/bundle` or a gem home. But the auto-fetch path (fresh clone / uninstalled but lock-resolvable) still hit the bug with the identical error. Gate on the authoritative signal instead: the purl's own `?platform=` qualifier. `ruby` (and a bare, unqualified purl) is the portable build and vendors; only a genuine native platform (`x86_64-linux`, `arm64-darwin`, `java`, `x64-mingw32`, …) is refused. A defense-in-depth dir check still refuses a locally-resolved platform-suffixed install dir (`<name>-<version>-<suffix>`), which the auto-fetch `gem` dir is not. Adds a reusable `purl_qualifier(purl, key)` to utils::purl (the other ecosystems only ever strip qualifiers) and hermetic regression tests: `?platform=ruby` from a `gem`-named staging dir now vendors; a native `?platform=x86_64-linux` is refused even from a clean leaf dir. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
enabled auto-merge (squash)
August 14, 2026 00:20
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.
Problem
Vendoring a pure-ruby gem whose production patch purl is platform-qualified —
pkg:gem/activestorage@7.0.2.2?platform=ruby— was refused withplatform_gem_unsupported("installed dirgemdoes not equalactivestorage-7.0.2.2"). Therubyplatform is the DEFAULT, portable RubyGems platform, not a native build, so this refusal is wrong.The gem vendor gate used
installed_dir.file_name() != "<name>-<version>"as a proxy for "platform-specific build". That proxy breaks on the registry auto-fetch ladder: a lockfile-resolvable-but-not-installed gem is staged into a private tempdir named literallygem(registry_fetch::fetch_gem), sodir_nameisgemand every pure-ruby auto-fetched gem tripped the gate.What #157 already fixed vs. what remained (verified against current
main, real production API + rubygems.org,SOCKET_NO_CONFIG=true):bundle config set --local path vendor/bundle,bundle install,scan --mode vendored): fix(vendor): resolve installed packages via the qualified-purl-aware lookup #157'sfind_packages_for_rollbackmaps the qualified?platform=rubypurl back to the installed base dir, so no auto-fetch happens and it vendors cleanly — 8/8 runs,applied: 1, exit 0. fix(vendor): resolve installed packages via the qualified-purl-aware lookup #157 fixed this runtime path.main, refusing with the identicalplatform_gem_unsupportederror (eventvendor_fetched_missing→ stagedgemdir → refused). This is what this PR fixes.Fix
Gate on the authoritative signal — the purl's own
?platform=qualifier — instead of the staging dir name:?platform=ruby(and a bare, unqualified purl) is the portable build and vendors normally.x86_64-linux,arm64-darwin,java,x64-mingw32, …) is refused, with the same clearplatform_gem_unsupportedcode.<name>-<version>-<suffix>) is still refused (preserving the downstream invariant that platform installs never reach the copy/lock edit). The auto-fetchgemdir is not such a suffix, so it passes.Adds a small reusable
purl_qualifier(purl, key)toutils::purl(the other ecosystems only ever strip qualifiers) rather than hand-rolling the parse. Change is scoped to the gem vendor path.Test
installed dir gem does not equal rack-3.2.6symptom):test_platform_ruby_gem_from_autofetch_staging_dir_vendors— a?platform=rubygem from agem-named auto-fetch staging dir now vendors successfully.test_refuses_native_platform_qualifier— a native?platform=x86_64-linuxpurl is still refused even from a clean leaf dir.test_refuses_platform_suffixed_dir(existing) stays green via the defense-in-depth dir check.test_purl_qualifier— unit coverage for the new helper.SOCKET_NO_CONFIG=true, live prod + rubygems.org):applied: 1, exit 0), viavendor_fetched_missing→vendor_prebuilt_downloaded.bundle installfrom the committed.socket/vendor/tree succeeds (exit 0) andbundle info activestorageresolves7.0.2.2from the vendored (patched) path.cargo build+cargo clippy(both crates) clean; the only clippy warnings are pre-existingdoc_lazy_continuationine2e_vendored_production.rs(untouched).Note (separate, pre-existing, out of scope): with the default
--vendor-source auto/service, the patch-servicegem-stub-gemspecfor activestorage omitss.summary, which RubyGems' validation rejects onbundle install. This is a converter/service-side artifact defect, not in the gem vendor CLI path — it affects the installed and auto-fetch paths equally and was simply never reached before because vendoring failed first. Delivery via the local-build stub (a valid gemspec) works, as shown above. The live-ignoredgem_bundler_vendored_known_platform_defecte2e leg will now take its built-in "vendor succeeds" branch; promoting it to a full frozen-install delivery proof is a follow-up gated on that stub-summary fix.🤖 Generated with Claude Code
Note
Medium Risk
Changes gem vendor gating logic on production patch paths; scope is limited to platform detection with added tests, but incorrect classification could still allow or block vendoring incorrectly.
Overview
Fixes incorrect
platform_gem_unsupportedrefusals for pure-ruby gems whose patch PURL is?platform=ruby(or unqualified), especially on the registry auto-fetch path where content is staged in a tempdir namedgemrather than<name>-<version>.Adds
purl_qualifierinutils/purlto read qualifier values (case-insensitive keys, stops at#subpath). Gem vendor logic now treats?platform=rubyand bare purls as portable and vendors them; only non-empty, non-rubyplatform values (e.g.x86_64-linux) are refused viaplatform_gem_unsupported.Defense in depth: platform-suffixed install dirs (
<name>-<version>-<suffix>) are still refused viadir_name.starts_with("{leaf}-")instead ofdir_name != leaf, so the literalgemstaging dir is not mistaken for a native build.New unit tests cover
purl_qualifier, native platform refusal from a clean leaf dir, and the auto-fetchgemstaging regression.Reviewed by Cursor Bugbot for commit ed3688f. Configure here.