github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/ruby/parse_gemfile_lock.go (about)

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