github.com/anchore/syft@v1.38.2/syft/pkg/rpm.go (about)

     1  package pkg
     2  
     3  import (
     4  	"sort"
     5  	"strings"
     6  
     7  	"github.com/scylladb/go-set/strset"
     8  
     9  	"github.com/anchore/syft/syft/file"
    10  )
    11  
    12  // RpmDBGlob is the glob pattern used to find RPM DB files. Where:
    13  // - /var/lib/rpm/... is the typical path for most distributions
    14  // - /usr/share/rpm/... is common for rpm-ostree distributions (coreos-like)
    15  // - Packages is the legacy Berkeley db based format
    16  // - Packages.db is the "ndb" format used in SUSE
    17  // - rpmdb.sqlite is the sqlite format used in fedora + derivates
    18  const RpmDBGlob = "**/{var/lib,usr/share,usr/lib/sysimage}/rpm/{Packages,Packages.db,rpmdb.sqlite}"
    19  
    20  // RpmManifestGlob is used in CBL-Mariner distroless images
    21  const RpmManifestGlob = "**/var/lib/rpmmanifest/container-manifest-2"
    22  
    23  var _ FileOwner = (*RpmDBEntry)(nil)
    24  
    25  // RpmArchive represents package metadata extracted directly from a .rpm archive file, containing the same information as an RPM database entry.
    26  type RpmArchive RpmDBEntry
    27  
    28  // RpmDBEntry represents all captured data from a RPM DB package entry.
    29  type RpmDBEntry struct {
    30  	// Name is the RPM package name as found in the RPM database.
    31  	Name string `json:"name"`
    32  
    33  	// Version is the upstream version of the package.
    34  	Version string `json:"version"`
    35  
    36  	// Epoch is the version epoch used to force upgrade ordering (null if not set).
    37  	Epoch *int `json:"epoch"  cyclonedx:"epoch" jsonschema:"nullable"`
    38  
    39  	// Arch is the target CPU architecture (e.g., "x86_64", "aarch64", "noarch").
    40  	Arch string `json:"architecture"`
    41  
    42  	// Release is the package release number or distribution-specific version suffix.
    43  	Release string `json:"release" cyclonedx:"release"`
    44  
    45  	// SourceRpm is the source RPM filename that was used to build this package.
    46  	SourceRpm string `json:"sourceRpm" cyclonedx:"sourceRpm"`
    47  
    48  	// Signatures contains GPG signature metadata for package verification.
    49  	Signatures []RpmSignature `json:"signatures,omitempty" cyclonedx:"signatures"`
    50  
    51  	// Size is the total installed size of the package in bytes.
    52  	Size int `json:"size" cyclonedx:"size"`
    53  
    54  	// Vendor is the organization that packaged the software.
    55  	Vendor string `json:"vendor"`
    56  
    57  	// ModularityLabel identifies the module stream for modular RPM packages (e.g., "nodejs:12:20200101").
    58  	ModularityLabel *string `json:"modularityLabel,omitempty" cyclonedx:"modularityLabel"`
    59  
    60  	// Provides lists the virtual packages and capabilities this package provides.
    61  	Provides []string `json:"provides,omitempty"`
    62  
    63  	// Requires lists the dependencies required by this package.
    64  	Requires []string `json:"requires,omitempty"`
    65  
    66  	// Files are the file records for all files owned by this package.
    67  	Files []RpmFileRecord `json:"files"`
    68  }
    69  
    70  // RpmSignature represents a GPG signature for an RPM package used for authenticity verification.
    71  type RpmSignature struct {
    72  	// PublicKeyAlgorithm is the public key algorithm used for signing (e.g., "RSA").
    73  	PublicKeyAlgorithm string `json:"algo"`
    74  
    75  	// HashAlgorithm is the hash algorithm used for the signature (e.g., "SHA256").
    76  	HashAlgorithm string `json:"hash"`
    77  
    78  	// Created is the timestamp when the signature was created.
    79  	Created string `json:"created"`
    80  
    81  	// IssuerKeyID is the GPG key ID that created the signature.
    82  	IssuerKeyID string `json:"issuer"`
    83  }
    84  
    85  func (s RpmSignature) String() string {
    86  	if s.PublicKeyAlgorithm == "" && s.HashAlgorithm == "" && s.Created == "" && s.IssuerKeyID == "" {
    87  		return ""
    88  	}
    89  	// mimics the output you would see from rpm -q --qf "%{RSAHEADER}"
    90  	// e.g."RSA/SHA256, Mon May 16 12:32:55 2022, Key ID 702d426d350d275d"
    91  	return strings.Join([]string{s.PublicKeyAlgorithm + "/" + s.HashAlgorithm, s.Created, "Key ID " + s.IssuerKeyID}, ", ")
    92  }
    93  
    94  // RpmFileRecord represents the file metadata for a single file attributed to a RPM package.
    95  type RpmFileRecord struct {
    96  	// Path is the absolute file path where the file is installed.
    97  	Path string `json:"path"`
    98  
    99  	// Mode is the file permission mode bits following Unix stat.h conventions.
   100  	Mode RpmFileMode `json:"mode"`
   101  
   102  	// Size is the file size in bytes.
   103  	Size int `json:"size"`
   104  
   105  	// Digest contains the hash algorithm and value for file integrity verification.
   106  	Digest file.Digest `json:"digest"`
   107  
   108  	// UserName is the owner username for the file.
   109  	UserName string `json:"userName"`
   110  
   111  	// GroupName is the group name for the file.
   112  	GroupName string `json:"groupName"`
   113  
   114  	// Flags indicates the file type (e.g., "%config", "%doc", "%ghost").
   115  	Flags string `json:"flags"`
   116  }
   117  
   118  // RpmFileMode is the raw file mode for a single file. This can be interpreted as the linux stat.h mode (see https://pubs.opengroup.org/onlinepubs/007908799/xsh/sysstat.h.html)
   119  type RpmFileMode uint16
   120  
   121  func (m RpmDBEntry) OwnedFiles() (result []string) {
   122  	s := strset.New()
   123  	for _, f := range m.Files {
   124  		if f.Path != "" {
   125  			s.Add(f.Path)
   126  		}
   127  	}
   128  	result = s.List()
   129  	sort.Strings(result)
   130  	return result
   131  }