Skip to content

Lock inventory reads only Gemfile.lock, so a gems.rb project's gems.locked is invisible and a stale Gemfile.lock is read instead #736

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.

Kind: bug. Source: new finding, register E56 (related to review Part 5.4 on gem section models, E19).

Problem

Bundler loads one manifest/lock pair. When there is no BUNDLE_GEMFILE, that is gems.rb + gems.locked if gems.rb exists, and Gemfile + Gemfile.lock otherwise. socket-patch has a shared resolver for this, LoadedManifest::pair.`` Hosted mode uses it through keep_bundler_loaded_gem_files, which also works over a memory view. The vendored refusal (`gem_manifest_refusal`) and the crawler use it as well.

Two other readers each choose the lock their own way:

  • Lock inventory reads only Gemfile.lock: lock_inventory/gem.rs#L46-L53 (view.read_text("Gemfile.lock")). gem_remotes does the same.
  • VEX discovery reads both locks whatever Bundler loads: vex/discover/gem.rs#L133-L138 (for file in BUNDLER_LOCKS).

That makes three rules for one question.

Proof by execution (a unit probe at 045d7ec, run twice, not committed). The project has gems.rb (gem "rack", "2.2.8") and a valid gems.locked locking rack (2.2.8):

gems.locked only:                  inventory_project = []
same text via GemfileLock::parse:  ["pkg:gem/rack@2.2.8"]
bundler_loaded_manifest().pair():  ("gems.rb", "gems.locked")
+ stale Gemfile.lock (rack 2.0.0): inventory_project = ["pkg:gem/rack@2.0.0"]

Consumers that see the wrong set

  • The in-memory hosted engine builds its purl set from this inventory (hosted/memory/mod.rs#L571-L578).`` So for a gems.rb project it finds no gems, even though its own gem rewriter would edit `gems.locked`. With a leftover `Gemfile.lock`, it plans versions Bundler doesn't use.
  • Scan's lockfile supplement (scan/discovery.rs#L71-L95) and apply's lockfile_resolved (apply.rs#L2304-L2306) miss lockfile-only gems, or count stale ones.
  • VEX ledger liveness (vex/discover/mod.rs#L1611-L1613) judges a hosted gem pin against the wrong lock.

Symptoms

None filed. #341 and #390 fixed the same "wrong pair" class for the vendored and hosted writers but not for the readers.

Impact

Medium for gems.rb projects, which are Bundler's documented alternate spelling. For a stale-twin project it is incorrect data rather than missing data.

Proposed change

  • Move the pair selection that keep_bundler_loaded_gem_files does into formats::gem::manifest as loaded_lock(view: &ProjectView) -> Option<&'static str> (disk: bundler_loaded_manifest; memory: .bundle/config only, as today).
  • Make inventory_gemfile_lock_raw_in, gem_remotes and VEX discovery's extract read only that lock. VEX may still diagnose the ignored twin.
  • Delete the hard-coded "Gemfile.lock" reads in lock_inventory/gem.rs and the BUNDLER_LOCKS loop's both-locks rule.

Size and scope

4 files and under 120 changed production lines. Out of scope: the three gem section models (E19) and BUNDLE_GEMFILE pointing outside the root, which stays unsupported.

Acceptance criteria

  • inventory_project on a gems.rb + gems.locked project returns its gems.
  • With a stale Gemfile.lock beside gems.rb + gems.locked, inventory and VEX discovery read only gems.locked.
  • .bundle/config BUNDLE_GEMFILE: Gemfile beside a gems.rb reads Gemfile.lock (disk and memory views).
  • In-memory hosted engine regression: a gems.rb project yields a gem candidate.
  • Existing lock_inventory, vex::discover::gem, formats::gem::manifest and hosted gem tests stay green.

Dependencies

None. It touches files near open #712, #684 and #621 (gem settings), but not the same functions.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:claimedagent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpm:bundlerBundler (RubyGems)priority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions