github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/common/cpe/apk.go (about)

     1  package cpe
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strings"
     7  
     8  	"github.com/anchore/syft/internal"
     9  	"github.com/anchore/syft/syft/pkg"
    10  )
    11  
    12  var (
    13  	prefixesToPackageType = map[string]pkg.Type{
    14  		"py-":   pkg.PythonPkg,
    15  		"ruby-": pkg.GemPkg,
    16  	}
    17  	streamVersionPkgNamePattern = regexp.MustCompile(`^(?P<stream>[a-zA-Z][\w-]*?)(?P<streamVersion>\-?\d[\d\.]*?)($|-(?P<subPackage>[a-zA-Z][\w-]*?)?)$`)
    18  )
    19  
    20  type upstreamCandidate struct {
    21  	Name string
    22  	Type pkg.Type
    23  }
    24  
    25  func upstreamCandidates(m pkg.ApkMetadata) (candidates []upstreamCandidate) {
    26  	// Do not consider OriginPackage variations when generating CPE candidates for the child package
    27  	// because doing so will result in false positives when matching to vulnerabilities in Grype since
    28  	// it won't know to lookup apk fix entries using the OriginPackage name.
    29  
    30  	name := m.Package
    31  	groups := internal.MatchNamedCaptureGroups(streamVersionPkgNamePattern, m.Package)
    32  	stream, ok := groups["stream"]
    33  
    34  	if ok && stream != "" {
    35  		sub, ok := groups["subPackage"]
    36  
    37  		if ok && sub != "" {
    38  			name = fmt.Sprintf("%s-%s", stream, sub)
    39  		} else {
    40  			name = stream
    41  		}
    42  	}
    43  
    44  	for prefix, typ := range prefixesToPackageType {
    45  		if strings.HasPrefix(name, prefix) {
    46  			t := strings.TrimPrefix(name, prefix)
    47  			if t != "" {
    48  				candidates = append(candidates, upstreamCandidate{Name: t, Type: typ})
    49  				return candidates
    50  			}
    51  		}
    52  	}
    53  
    54  	if name != "" {
    55  		candidates = append(candidates, upstreamCandidate{Name: name, Type: pkg.UnknownPkg})
    56  		return candidates
    57  	}
    58  
    59  	return candidates
    60  }
    61  
    62  func candidateVendorsForAPK(p pkg.Package) fieldCandidateSet {
    63  	metadata, ok := p.Metadata.(pkg.ApkMetadata)
    64  	if !ok {
    65  		return nil
    66  	}
    67  
    68  	vendors := newFieldCandidateSet()
    69  	candidates := upstreamCandidates(metadata)
    70  
    71  	for _, c := range candidates {
    72  		switch c.Type {
    73  		case pkg.UnknownPkg:
    74  			vendors.addValue(c.Name)
    75  			vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, pkg.ApkPkg, c.Name, c.Name)...)
    76  			vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, pkg.ApkPkg, c.Name)...)
    77  		case pkg.PythonPkg:
    78  			vendors.addValue(c.Name)
    79  			vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, c.Type, c.Name, c.Name)...)
    80  			vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, c.Type, c.Name)...)
    81  			for _, av := range additionalVendorsForPython(c.Name) {
    82  				vendors.addValue(av)
    83  				vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, pkg.PythonPkg, av, av)...)
    84  				vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, pkg.PythonPkg, av)...)
    85  			}
    86  		default:
    87  			vendors.addValue(c.Name)
    88  			vendors.addValue(findAdditionalVendors(defaultCandidateAdditions, c.Type, c.Name, c.Name)...)
    89  			vendors.removeByValue(findVendorsToRemove(defaultCandidateRemovals, c.Type, c.Name)...)
    90  		}
    91  	}
    92  
    93  	vendors.union(candidateVendorsFromURL(metadata.URL))
    94  
    95  	for v := range vendors {
    96  		v.disallowDelimiterVariations = true
    97  		v.disallowSubSelections = true
    98  	}
    99  
   100  	return vendors
   101  }
   102  
   103  func candidateProductsForAPK(p pkg.Package) fieldCandidateSet {
   104  	metadata, ok := p.Metadata.(pkg.ApkMetadata)
   105  	if !ok {
   106  		return nil
   107  	}
   108  
   109  	products := newFieldCandidateSet()
   110  	candidates := upstreamCandidates(metadata)
   111  
   112  	for _, c := range candidates {
   113  		switch c.Type {
   114  		case pkg.UnknownPkg:
   115  			products.addValue(c.Name)
   116  			products.addValue(findAdditionalProducts(defaultCandidateAdditions, pkg.ApkPkg, c.Name)...)
   117  			products.removeByValue(findProductsToRemove(defaultCandidateRemovals, pkg.ApkPkg, c.Name)...)
   118  		default:
   119  			products.addValue(c.Name)
   120  			products.addValue(findAdditionalProducts(defaultCandidateAdditions, c.Type, c.Name)...)
   121  			products.removeByValue(findProductsToRemove(defaultCandidateRemovals, c.Type, c.Name)...)
   122  		}
   123  	}
   124  
   125  	for p := range products {
   126  		p.disallowDelimiterVariations = true
   127  		p.disallowSubSelections = true
   128  	}
   129  
   130  	return products
   131  }