Skip to content

VEX gemspec product detection reads commented-out # spec.name = / # spec.version = lines, so the document names the wrong product or version #1573

Closed

Description

[agent] Found by the scheduled Bundler (RubyGems) bug-hunt routine (ledger #316).

Summary

vex (and scan/apply/vendor --vex without --vex-product) names the top-level product of a gem library project from its root *.gemspec (parse_gemspec, probe 9). The parser takes the first line whose =-left side ends in .name / .version and whose right side starts with a quote. It never skips Ruby comments, so a commented-out assignment wins over the live one:

  • # spec.version = "0.0.1" above spec.version = Acme::VERSION → product pkg:gem/acme@0.0.1 (the real version is 2.3.4; a computed version should be dropped, giving pkg:gem/acme).
  • # spec.name = "acme-legacy" above spec.name = "acme" → product pkg:gem/acme-legacy.

No warning is printed. Ruby (Gem::Specification.load) gives acme-2.3.4 for both files.

Impact

The OpenVEX document's products[].@id names a product or version that doesn't exist, so consumers that match VEX statements to their SBOM by product purl won't apply them (or will apply them to the wrong release). The run reports success. Leaving old assignments commented out is a common edit when a gem moves its version into a VERSION constant, or after a gem is renamed.

Repro (Linux, Ruby 3.3.6, Bundler 2.5.22 / 4.0.18; main e76cb9b)

mkdir -p acme/lib/acme && cd acme
echo 'module Acme; VERSION = "2.3.4"; end' > lib/acme/version.rb
cat > acme.gemspec <<'E'
require_relative "lib/acme/version"
Gem::Specification.new do |spec|
  spec.name = "acme"
  # spec.version = "0.0.1" # pinned before the VERSION constant existed
  spec.version = Acme::VERSION
  spec.authors = ["x"]
  spec.summary = "x"
  spec.files = []
  spec.add_dependency "colorize", "0.8.1"
end
E
printf 'source "https://rubygems.org"\ngemspec\n' > Gemfile
bundle install
# any applied gem patch in .socket/manifest.json (hand-written colorize@0.8.1 manifest + `apply --offline` here)
socket-patch apply --offline
socket-patch vex | grep '"@id": "pkg:gem/acme'
#   "@id": "pkg:gem/acme@0.0.1"
ruby -e 'puts Gem::Specification.load("acme.gemspec").full_name'
#   acme-2.3.4

The name variant: put # spec.name = "acme-legacy" above Gem::Specification.new (and drop the commented version). vex then gives "@id": "pkg:gem/acme-legacy". Each shape reproduced twice.

Expected vs actual

  • Expected: parse_gemspec's own doc says the product comes "from literal <spec>.name = "…" / <spec>.version = "…" assignments; a version computed from a constant (Foo::VERSION) is dropped" (crates/socket-patch-core/src/vex/product.rs:363-366). A comment is not an assignment, so this file should give pkg:gem/acme (version dropped). vex.rs:66 documents probe 9 as pkg:gem/<name>[@<version>].
  • Actual: pkg:gem/acme@0.0.1 / pkg:gem/acme-legacy.

Matrix

OS Ruby / Bundler Commented version Commented name
Linux (sandbox) 3.3.6 / 2.5.22 reproduces (×2) reproduces (×2)

The parser is OS- and Bundler-independent (pure text), so macOS / Windows aren't probed.

Suspect code

crates/socket-patch-core/src/vex/product.rs:367-380: the literal closure trims the line and checks lhs.ends_with(".name") without first dropping lines that start with # (or text after a # outside a string). =begin/=end blocks and heredocs are also read as code, though those are rarer.

First bad version: not bisected (the sandbox clone is shallow). parse_gemspec has had this shape since gemspec detection was added.

Activity

  1. mikolalysenko commented on Oct 15, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged: priority:p1 (RubyGems/Bundler). Confirmed on main e76cb9b by reading parse_gemspec (crates/socket-patch-core/src/vex/product.rs:367-381): the literal closure splits each trimmed line on the first = and only checks that the left side ends with .name / .version, so # spec.version = "0.0.1" matches (left side # spec.version) before the live spec.version = Acme::VERSION line. No duplicate or existing fix PR found. Not clustered: no other open issue shares this parser.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 15, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (single-issue cluster; root cause: parse_gemspec reads Ruby comments as assignments). Branch: agent/fix-gemspec-comment-parse. Claim-ID: 2026-10-15T16:20:57Z-e577a2


    Generated by Claude Code

  3. mikolalysenko commented on Oct 15, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Fix in progress: #1582


    Generated by Claude Code

  4. added a commit that references this issue on Oct 15, 2026
    d2b3976
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions