Module: StillActive::LockfileIndexer

Extended by:
LockfileIndexer
Included in:
LockfileIndexer
Defined in:
lib/helpers/lockfile_indexer.rb

Overview

Maps gem names to line numbers in a Bundler-generated Gemfile.lock. Used by SARIF output so findings annotate the correct lockfile line.

We hand-roll the parsing rather than delegating to Bundler::LockfileParser because the latter is not side-effect-free —it tries to resolve PLUGIN SOURCE blocks against the installed plugin registry and raises Bundler::Plugin::UnknownSourceError if a plugin isn’t present in the consuming environment. We just want names + lines.

Constant Summary collapse

TOP_LEVEL_SPEC =

Bundler indents top-level specs with exactly 4 spaces; nested deps get 6+. S+ matches what Bundler’s own parser accepts (any non-space).

/\A    (\S+) \(/
BLOCK_HEADER =

Source blocks Bundler emits — see bundler/lockfile_parser.rb SOURCE constant.

/\A(GEM|GIT|PATH|PLUGIN SOURCE)\b/
SECTION_BREAK =
/\A[A-Z]/

Instance Method Summary collapse

Instance Method Details

#gem_line_index(content) ⇒ Object

Returns a Hash mapping gem name -> 1-based line number in ‘content`. When a gem appears as both a top-level spec and a nested dep, the top-level entry wins. Lines outside GEM/GIT/PATH/PLUGIN SOURCE blocks are ignored.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/helpers/lockfile_indexer.rb', line 26

def gem_line_index(content)
  index = {}
  in_block = false
  content.each_line.with_index(1) do |line, lineno|
    if line.match?(BLOCK_HEADER)
      in_block = true
      next
    end
    if line.match?(SECTION_BREAK)
      in_block = false
      next
    end
    next unless in_block

    match = line.match(TOP_LEVEL_SPEC)
    index[match[1]] = lineno if match
  end
  index
end

#ruby_version_line(content) ⇒ Object

Returns the 1-based line number of the Ruby version inside the RUBY VERSION block (the line after the header). Falls back to 1.



48
49
50
51
52
53
# File 'lib/helpers/lockfile_indexer.rb', line 48

def ruby_version_line(content)
  content.each_line.with_index(1) do |line, lineno|
    return lineno + 1 if line.start_with?("RUBY VERSION")
  end
  1
end