Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions binary/proto/scan_result.proto
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ message RPMPackageMetadata {
string os_name = 7;
string vendor = 8;
string architecture = 9;
string os_pretty_name = 11;

reserved "license";
}
Expand Down
17 changes: 13 additions & 4 deletions binary/proto/scan_result_go_proto/scan_result.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion extractor/filesystem/os/ecosystem/ecosystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func MakeEcosystem(metadata any) osvecosystem.Parsed {
return osvecosystem.FromEcosystem(osvschema.EcosystemRockyLinux)
}
if m.OSID == "openEuler" {
return osvecosystem.FromEcosystem(osvschema.EcosystemOpenEuler)
return osvecosystem.Parsed{Ecosystem: osvschema.EcosystemOpenEuler, Suffix: m.OpenEulerEcosystemSuffix()}
}

case *snapmeta.Metadata:
Expand Down
34 changes: 33 additions & 1 deletion extractor/filesystem/os/ecosystem/ecosystem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,39 @@ func TestEcosystemRPM(t *testing.T) {
want: "Rocky Linux",
},
{
desc: "openEuler",
desc: "openEuler base version from pretty name",
metadata: &rpmmeta.Metadata{
OSID: "openEuler",
OSPrettyName: "openEuler 24.03",
},
want: "openEuler:24.03",
},
{
desc: "openEuler LTS qualifier",
metadata: &rpmmeta.Metadata{
OSID: "openEuler",
OSPrettyName: "openEuler 24.03 (LTS)",
},
want: "openEuler:24.03-LTS",
},
{
desc: "openEuler LTS service pack qualifier",
metadata: &rpmmeta.Metadata{
OSID: "openEuler",
OSPrettyName: "openEuler 24.03 (LTS-SP1)",
},
want: "openEuler:24.03-LTS-SP1",
},
{
desc: "openEuler fallback to version ID",
metadata: &rpmmeta.Metadata{
OSID: "openEuler",
OSVersionID: "24.03",
},
want: "openEuler:24.03",
},
{
desc: "openEuler no version details",
metadata: &rpmmeta.Metadata{
OSID: "openEuler",
},
Expand Down
43 changes: 43 additions & 0 deletions extractor/filesystem/os/rpm/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,29 @@ package metadata

import (
"fmt"
"regexp"
"strings"

"github.com/google/osv-scalibr/log"

pb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto"
)

var (
// pattern to match: openEuler version (qualifier)
// where (qualifier) is optional. Those without qualifier are considered innovation versions.
// version: YY.MM format. e.g. 24.03
// qualifier: currently supported are LTS, LTS SPd. e.g. LTS, LTS-SP1, LTS-SP2
openEulerPrettyNameRegexp = regexp.MustCompile(`^openEuler\s+([0-9]{2}\.[0-9]{2})(?:\s*\((LTS(?:[- ]SP\d+)?)\))?$`)
)

// Metadata holds parsing information for an rpm package.
type Metadata struct {
PackageName string
SourceRPM string
Epoch int
OSName string
OSPrettyName string
OSID string
OSVersionID string
OSBuildID string
Expand Down Expand Up @@ -80,6 +91,7 @@ func (m *Metadata) SetProto(p *pb.Package) {
SourceRpm: m.SourceRPM,
Epoch: int32(m.Epoch),
OsName: m.OSName,
OsPrettyName: m.OSPrettyName,
OsId: m.OSID,
OsVersionId: m.OSVersionID,
OsBuildId: m.OSBuildID,
Expand All @@ -100,10 +112,41 @@ func ToStruct(m *pb.RPMPackageMetadata) *Metadata {
SourceRPM: m.GetSourceRpm(),
Epoch: int(m.GetEpoch()),
OSName: m.GetOsName(),
OSPrettyName: m.GetOsPrettyName(),
OSID: m.GetOsId(),
OSVersionID: m.GetOsVersionId(),
OSBuildID: m.GetOsBuildId(),
Vendor: m.GetVendor(),
Architecture: m.GetArchitecture(),
}
}

// OpenEulerEcosystemSuffix returns the normalized ecosystem suffix for openEuler RPMs with uses of pretty name.
// e.g. openEuler 24.03 (LTS) -> 24.03-LTS
func (m *Metadata) OpenEulerEcosystemSuffix() string {
if m == nil {
return ""
}

prettyName := strings.TrimSpace(m.OSPrettyName)
if prettyName != "" {
if matches := openEulerPrettyNameRegexp.FindStringSubmatch(prettyName); len(matches) > 0 {
version := matches[1]
qualifier := strings.TrimSpace(matches[2])
if qualifier == "" {
return version
}

qualifier = strings.ReplaceAll(qualifier, " ", "-")
qualifier = strings.Trim(qualifier, "-")
if qualifier == "" {
return version
}

return version + "-" + qualifier
}
}

versionID := strings.TrimSpace(m.OSVersionID)
return versionID
}
69 changes: 69 additions & 0 deletions extractor/filesystem/os/rpm/metadata/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func TestSetProto(t *testing.T) {
SourceRPM: "source-rpm",
Epoch: 1,
OSName: "os-name",
OSPrettyName: "os-pretty-name",
OSID: "os-id",
OSVersionID: "os-version-id",
OSBuildID: "os-build-id",
Expand All @@ -105,6 +106,7 @@ func TestSetProto(t *testing.T) {
SourceRpm: "source-rpm",
Epoch: 1,
OsName: "os-name",
OsPrettyName: "os-pretty-name",
OsId: "os-id",
OsVersionId: "os-version-id",
OsBuildId: "os-build-id",
Expand Down Expand Up @@ -168,6 +170,7 @@ func TestToStruct(t *testing.T) {
SourceRpm: "source-rpm",
Epoch: 1,
OsName: "os-name",
OsPrettyName: "os-pretty-name",
OsId: "os-id",
OsVersionId: "os-version-id",
OsBuildId: "os-build-id",
Expand All @@ -179,6 +182,7 @@ func TestToStruct(t *testing.T) {
SourceRPM: "source-rpm",
Epoch: 1,
OSName: "os-name",
OSPrettyName: "os-pretty-name",
OSID: "os-id",
OSVersionID: "os-version-id",
OSBuildID: "os-build-id",
Expand Down Expand Up @@ -217,3 +221,68 @@ func TestToStruct(t *testing.T) {
})
}
}

func TestOpenEulerEcosystemSuffix(t *testing.T) {
testCases := []struct {
desc string
meta *metadata.Metadata
want string
}{
{
desc: "base version from pretty name",
meta: &metadata.Metadata{
OSPrettyName: "openEuler 24.03",
},
want: "24.03",
},
{
desc: "lts qualifier",
meta: &metadata.Metadata{
OSPrettyName: "openEuler 24.03 (LTS)",
},
want: "24.03-LTS",
},
{
desc: "lts space qualifier",
meta: &metadata.Metadata{
OSPrettyName: "openEuler 24.03 (LTS SP1)",
},
want: "24.03-LTS-SP1",
},
{
desc: "lts hyphen qualifier",
meta: &metadata.Metadata{
OSPrettyName: "openEuler 24.03 (LTS-SP1)",
},
want: "24.03-LTS-SP1",
},
{
desc: "fallback to version id",
meta: &metadata.Metadata{
OSVersionID: "24.03",
},
want: "24.03",
},
{
desc: "non openEuler pretty name",
meta: &metadata.Metadata{
OSPrettyName: "Fedora Linux 38 (Container Image)",
OSVersionID: "38",
},
want: "38",
},
{
desc: "no details",
meta: &metadata.Metadata{},
want: "",
},
}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
if got := tc.meta.OpenEulerEcosystemSuffix(); got != tc.want {
t.Fatalf("OpenEulerEcosystemSuffix() = %q, want %q", got, tc.want)
}
})
}
}
1 change: 1 addition & 0 deletions extractor/filesystem/os/rpm/rpm_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ func (e Extractor) extractFromInput(ctx context.Context, input *filesystem.ScanI
SourceRPM: p.SourceRPM,
Epoch: p.Epoch,
OSName: m["NAME"],
OSPrettyName: m["PRETTY_NAME"],
OSID: m["ID"],
OSVersionID: m["VERSION_ID"],
OSBuildID: m["BUILD_ID"],
Expand Down
Loading