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

     1  package rpm
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	rpmdb "github.com/knqyf263/go-rpmdb/pkg"
     9  
    10  	"github.com/anchore/packageurl-go"
    11  	"github.com/anchore/syft/syft/file"
    12  	"github.com/anchore/syft/syft/linux"
    13  	"github.com/anchore/syft/syft/pkg"
    14  )
    15  
    16  func newPackage(dbOrRpmLocation file.Location, pd parsedData, distro *linux.Release) pkg.Package {
    17  	p := pkg.Package{
    18  		Name:         pd.Name,
    19  		Version:      toELVersion(pd.RpmMetadata),
    20  		Licenses:     pkg.NewLicenseSet(pd.Licenses...),
    21  		PURL:         packageURL(pd.RpmMetadata, distro),
    22  		Locations:    file.NewLocationSet(dbOrRpmLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
    23  		Type:         pkg.RpmPkg,
    24  		MetadataType: pkg.RpmMetadataType,
    25  		Metadata:     pd.RpmMetadata,
    26  	}
    27  
    28  	p.SetID()
    29  	return p
    30  }
    31  
    32  type parsedData struct {
    33  	Licenses []pkg.License
    34  	pkg.RpmMetadata
    35  }
    36  
    37  func newParsedDataFromEntry(licenseLocation file.Location, entry rpmdb.PackageInfo, files []pkg.RpmdbFileRecord) parsedData {
    38  	return parsedData{
    39  		Licenses: pkg.NewLicensesFromLocation(licenseLocation, entry.License),
    40  		RpmMetadata: pkg.RpmMetadata{
    41  			Name:            entry.Name,
    42  			Version:         entry.Version,
    43  			Epoch:           entry.Epoch,
    44  			Arch:            entry.Arch,
    45  			Release:         entry.Release,
    46  			SourceRpm:       entry.SourceRpm,
    47  			Vendor:          entry.Vendor,
    48  			Size:            entry.Size,
    49  			ModularityLabel: entry.Modularitylabel,
    50  			Files:           files,
    51  		},
    52  	}
    53  }
    54  
    55  func newMetadataFromManifestLine(entry string) (*parsedData, error) {
    56  	parts := strings.Split(entry, "\t")
    57  	if len(parts) < 10 {
    58  		return nil, fmt.Errorf("unexpected number of fields in line: %s", entry)
    59  	}
    60  
    61  	versionParts := strings.Split(parts[1], "-")
    62  	if len(versionParts) != 2 {
    63  		return nil, fmt.Errorf("unexpected version field: %s", parts[1])
    64  	}
    65  	version := versionParts[0]
    66  	release := versionParts[1]
    67  
    68  	converted, err := strconv.Atoi(parts[8])
    69  	var epoch *int
    70  	if err != nil || parts[5] == "(none)" {
    71  		epoch = nil
    72  	} else {
    73  		epoch = &converted
    74  	}
    75  
    76  	converted, err = strconv.Atoi(parts[6])
    77  	var size int
    78  	if err == nil {
    79  		size = converted
    80  	}
    81  	return &parsedData{
    82  		RpmMetadata: pkg.RpmMetadata{
    83  			Name:      parts[0],
    84  			Version:   version,
    85  			Epoch:     epoch,
    86  			Arch:      parts[7],
    87  			Release:   release,
    88  			SourceRpm: parts[9],
    89  			Vendor:    parts[4],
    90  			Size:      size,
    91  		},
    92  	}, nil
    93  }
    94  
    95  // packageURL returns the PURL for the specific RHEL package (see https://github.com/package-url/purl-spec)
    96  func packageURL(m pkg.RpmMetadata, distro *linux.Release) string {
    97  	var namespace string
    98  	if distro != nil {
    99  		namespace = distro.ID
   100  	}
   101  
   102  	qualifiers := map[string]string{
   103  		pkg.PURLQualifierArch: m.Arch,
   104  	}
   105  
   106  	if m.Epoch != nil {
   107  		qualifiers[pkg.PURLQualifierEpoch] = strconv.Itoa(*m.Epoch)
   108  	}
   109  
   110  	if m.SourceRpm != "" {
   111  		qualifiers[pkg.PURLQualifierUpstream] = m.SourceRpm
   112  	}
   113  
   114  	return packageurl.NewPackageURL(
   115  		packageurl.TypeRPM,
   116  		namespace,
   117  		m.Name,
   118  		// for purl the epoch is a qualifier, not part of the version
   119  		// see https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst under the RPM section
   120  		fmt.Sprintf("%s-%s", m.Version, m.Release),
   121  		pkg.PURLQualifiers(
   122  			qualifiers,
   123  			distro,
   124  		),
   125  		"",
   126  	).ToString()
   127  }