github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/os/rpm/metadata/metadata.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package metadata defines a metadata struct for rpm packages. 16 package metadata 17 18 import ( 19 "fmt" 20 "regexp" 21 "strings" 22 23 "github.com/google/osv-scalibr/log" 24 25 pb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto" 26 ) 27 28 var ( 29 // pattern to match: openEuler version (qualifier) 30 // where (qualifier) is optional. Those without qualifier are considered innovation versions. 31 // version: YY.MM format. e.g. 24.03 32 // qualifier: currently supported are LTS, LTS SPd. e.g. LTS, LTS-SP1, LTS-SP2 33 openEulerPrettyNameRegexp = regexp.MustCompile(`^openEuler\s+([0-9]{2}\.[0-9]{2})(?:\s*\((LTS(?:[- ]SP\d+)?)\))?$`) 34 ) 35 36 // Metadata holds parsing information for an rpm package. 37 type Metadata struct { 38 PackageName string 39 SourceRPM string 40 Epoch int 41 OSName string 42 OSCPEName string 43 OSPrettyName string 44 OSID string 45 OSVersionID string 46 OSBuildID string 47 Vendor string 48 Architecture string 49 } 50 51 // ToNamespace extracts the PURL namespace from the metadata. 52 func (m *Metadata) ToNamespace() string { 53 if m.OSID != "" { 54 return m.OSID 55 } 56 log.Errorf("os-release[ID] not set, fallback to ''") 57 return "" 58 } 59 60 // ToDistro extracts the OS distro from the metadata. 61 func (m *Metadata) ToDistro() string { 62 v := m.OSVersionID 63 if v == "" { 64 v = m.OSBuildID 65 if v == "" { 66 log.Errorf("VERSION_ID and BUILD_ID not set in os-release") 67 return "" 68 } 69 log.Errorf("os-release[VERSION_ID] not set, fallback to BUILD_ID") 70 } 71 72 id := m.OSID 73 if id == "" { 74 log.Errorf("os-release[ID] not set, fallback to ''") 75 return v 76 } 77 return fmt.Sprintf("%s-%s", id, v) 78 } 79 80 // SetProto sets the RPMPackageMetadata field in the Package proto. 81 func (m *Metadata) SetProto(p *pb.Package) { 82 if m == nil { 83 return 84 } 85 if p == nil { 86 return 87 } 88 89 p.Metadata = &pb.Package_RpmMetadata{ 90 RpmMetadata: &pb.RPMPackageMetadata{ 91 PackageName: m.PackageName, 92 SourceRpm: m.SourceRPM, 93 Epoch: int32(m.Epoch), 94 OsName: m.OSName, 95 OsCpeName: m.OSCPEName, 96 OsPrettyName: m.OSPrettyName, 97 OsId: m.OSID, 98 OsVersionId: m.OSVersionID, 99 OsBuildId: m.OSBuildID, 100 Vendor: m.Vendor, 101 Architecture: m.Architecture, 102 }, 103 } 104 } 105 106 // ToStruct converts the RPMPackageMetadata proto to a Metadata struct. 107 func ToStruct(m *pb.RPMPackageMetadata) *Metadata { 108 if m == nil { 109 return nil 110 } 111 112 return &Metadata{ 113 PackageName: m.GetPackageName(), 114 SourceRPM: m.GetSourceRpm(), 115 Epoch: int(m.GetEpoch()), 116 OSName: m.GetOsName(), 117 OSCPEName: m.GetOsCpeName(), 118 OSPrettyName: m.GetOsPrettyName(), 119 OSID: m.GetOsId(), 120 OSVersionID: m.GetOsVersionId(), 121 OSBuildID: m.GetOsBuildId(), 122 Vendor: m.GetVendor(), 123 Architecture: m.GetArchitecture(), 124 } 125 } 126 127 // OpenEulerEcosystemSuffix returns the normalized ecosystem suffix for openEuler RPMs with uses of pretty name. 128 // e.g. openEuler 24.03 (LTS) -> 24.03-LTS 129 func (m *Metadata) OpenEulerEcosystemSuffix() string { 130 if m == nil { 131 return "" 132 } 133 134 prettyName := strings.TrimSpace(m.OSPrettyName) 135 if prettyName != "" { 136 if matches := openEulerPrettyNameRegexp.FindStringSubmatch(prettyName); len(matches) > 0 { 137 version := matches[1] 138 qualifier := strings.TrimSpace(matches[2]) 139 if qualifier == "" { 140 return version 141 } 142 143 qualifier = strings.ReplaceAll(qualifier, " ", "-") 144 qualifier = strings.Trim(qualifier, "-") 145 if qualifier == "" { 146 return version 147 } 148 149 return version + "-" + qualifier 150 } 151 } 152 153 versionID := strings.TrimSpace(m.OSVersionID) 154 return versionID 155 }