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  }