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  }