github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/redhat/parse_rpm_archive.go (about) 1 package redhat 2 3 import ( 4 "fmt" 5 "strconv" 6 7 rpmdb "github.com/knqyf263/go-rpmdb/pkg" 8 "github.com/sassoftware/go-rpmutils" 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 // parseRpmArchive parses a single RPM 17 func parseRpmArchive(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 18 rpm, err := rpmutils.ReadRpm(reader) 19 if err != nil { 20 return nil, nil, fmt.Errorf("RPM file found but unable to read: %s (%w)", reader.Location.RealPath, err) 21 } 22 23 nevra, err := rpm.Header.GetNEVRA() 24 if err != nil { 25 return nil, nil, err 26 } 27 28 licenses, _ := rpm.Header.GetStrings(rpmutils.LICENSE) 29 sourceRpm, _ := rpm.Header.GetString(rpmutils.SOURCERPM) 30 vendor, _ := rpm.Header.GetString(rpmutils.VENDOR) 31 digestAlgorithm := getDigestAlgorithm(rpm.Header) 32 size, _ := rpm.Header.InstalledSize() 33 files, _ := rpm.Header.GetFiles() 34 35 metadata := pkg.RpmArchive{ 36 Name: nevra.Name, 37 Version: nevra.Version, 38 Epoch: parseEpoch(nevra.Epoch), 39 Arch: nevra.Arch, 40 Release: nevra.Release, 41 SourceRpm: sourceRpm, 42 Vendor: vendor, 43 Size: int(size), 44 Files: mapFiles(files, digestAlgorithm), 45 } 46 47 return []pkg.Package{newArchivePackage(reader.Location, metadata, licenses)}, nil, nil 48 } 49 50 func getDigestAlgorithm(header *rpmutils.RpmHeader) string { 51 digestAlgorithm, _ := header.GetString(rpmutils.FILEDIGESTALGO) 52 if digestAlgorithm != "" { 53 return digestAlgorithm 54 } 55 digestAlgorithms, _ := header.GetUint32s(rpmutils.FILEDIGESTALGO) 56 if len(digestAlgorithms) > 0 { 57 digestAlgo := int(digestAlgorithms[0]) 58 return rpmutils.GetFileAlgoName(digestAlgo) 59 } 60 return "" 61 } 62 63 func mapFiles(files []rpmutils.FileInfo, digestAlgorithm string) []pkg.RpmFileRecord { 64 var out []pkg.RpmFileRecord 65 for _, f := range files { 66 digest := file.Digest{} 67 if f.Digest() != "" { 68 digest = file.Digest{ 69 Algorithm: digestAlgorithm, 70 Value: f.Digest(), 71 } 72 } 73 out = append(out, pkg.RpmFileRecord{ 74 Path: f.Name(), 75 Mode: pkg.RpmFileMode(f.Mode()), 76 Size: int(f.Size()), 77 Digest: digest, 78 UserName: f.UserName(), 79 GroupName: f.GroupName(), 80 Flags: rpmdb.FileFlags(f.Flags()).String(), 81 }) 82 } 83 return out 84 } 85 86 func parseEpoch(epoch string) *int { 87 i, err := strconv.Atoi(epoch) 88 if err != nil { 89 return nil 90 } 91 return &i 92 }