github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/ruby/parse_gemfile_lock.go (about)

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