github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/ruby/parse_gemfile_lock.go (about) 1 package ruby 2 3 import ( 4 "bufio" 5 "context" 6 "strings" 7 8 "github.com/scylladb/go-set/strset" 9 10 "github.com/anchore/syft/syft/artifact" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/pkg" 13 "github.com/anchore/syft/syft/pkg/cataloger/generic" 14 ) 15 16 var _ generic.Parser = parseGemFileLockEntries 17 18 var sectionsOfInterest = strset.New("GEM", "GIT", "PATH", "PLUGIN SOURCE") 19 20 // parseGemFileLockEntries is a parser function for Gemfile.lock contents, returning all Gems discovered. 21 func parseGemFileLockEntries(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 22 var pkgs []pkg.Package 23 scanner := bufio.NewScanner(reader) 24 25 var currentSection string 26 27 for scanner.Scan() { 28 line := scanner.Text() 29 sanitizedLine := strings.TrimSpace(line) 30 31 if len(line) > 1 && line[0] != ' ' { 32 // start of section 33 currentSection = sanitizedLine 34 continue 35 } else if !sectionsOfInterest.Has(currentSection) { 36 // skip this line, we're in the wrong section 37 continue 38 } 39 40 if isDependencyLine(line) { 41 candidate := strings.Fields(sanitizedLine) 42 if len(candidate) != 2 { 43 continue 44 } 45 pkgs = append(pkgs, 46 newGemfileLockPackage( 47 candidate[0], 48 strings.Trim(candidate[1], "()"), 49 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 50 ), 51 ) 52 } 53 } 54 if err := scanner.Err(); err != nil { 55 return nil, nil, err 56 } 57 return pkgs, nil, nil 58 } 59 60 func isDependencyLine(line string) bool { 61 if len(line) < 5 { 62 return false 63 } 64 return strings.Count(line[:5], " ") == 4 65 }