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