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

     1  package rpm
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"io"
     7  	"strings"
     8  
     9  	"github.com/anchore/syft/internal/log"
    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  // Parses an RPM manifest file, as used in Mariner distroless containers, and returns the Packages listed
    17  func parseRpmManifest(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    18  	r := bufio.NewReader(reader)
    19  	allPkgs := make([]pkg.Package, 0)
    20  
    21  	for {
    22  		line, err := r.ReadString('\n')
    23  		if err != nil {
    24  			if errors.Is(err, io.EOF) {
    25  				break
    26  			}
    27  			return nil, nil, err
    28  		}
    29  
    30  		if line == "" {
    31  			continue
    32  		}
    33  
    34  		p, err := parseRpmManifestEntry(strings.TrimSuffix(line, "\n"), reader.Location)
    35  		if err != nil {
    36  			log.Warnf("unable to parse RPM manifest entry: %w", err)
    37  			continue
    38  		}
    39  
    40  		if !pkg.IsValid(p) {
    41  			continue
    42  		}
    43  
    44  		p.SetID()
    45  		allPkgs = append(allPkgs, *p)
    46  	}
    47  
    48  	return allPkgs, nil, nil
    49  }
    50  
    51  // Parses an entry in an RPM manifest file as used in Mariner distroless containers
    52  // Each line is the output of :
    53  // rpm --query --all --query-format "%{NAME}\t%{VERSION}-%{RELEASE}\t%{INSTALLTIME}\t%{BUILDTIME}\t%{VENDOR}\t%{EPOCH}\t%{SIZE}\t%{ARCH}\t%{EPOCHNUM}\t%{SOURCERPM}\n"
    54  // https://github.com/microsoft/CBL-Mariner/blob/3df18fac373aba13a54bd02466e64969574f13af/toolkit/docs/how_it_works/5_misc.md?plain=1#L150
    55  func parseRpmManifestEntry(entry string, location file.Location) (*pkg.Package, error) {
    56  	metadata, err := newMetadataFromManifestLine(entry)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	if metadata == nil {
    62  		return nil, nil
    63  	}
    64  
    65  	p := newPackage(location, *metadata, nil)
    66  
    67  	return &p, nil
    68  }