Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for openEuler OS. #6475

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions docs/docs/scanner/vulnerability.md
wjunLu marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ See [here](../coverage/os/index.md#supported-os) for the supported OSes.
| CBL-Mariner | [OVAL][mariner] |
| OpenSUSE/SLES | [CVRF][suse] |
| Photon OS | [Photon Security Advisory][photon] |
| openEuler | [openEuler Security Data][openeuler] |

#### Data Source Selection
Trivy **only** consumes security advisories from the sources listed in the above table.
Expand Down Expand Up @@ -289,6 +290,7 @@ Total: 7 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 3, CRITICAL: 2)
[suse]: http://ftp.suse.com/pub/projects/security/cvrf/
[photon]: https://packages.vmware.com/photon/photon_cve_metadata/
[mariner]: https://github.com/microsoft/CBL-MarinerVulnerabilityData/
[openeuler]: https://repo.openeuler.org/security/data/cvrf

[php-ghsa]: https://github.com/advisories?query=ecosystem%3Acomposer
[python-ghsa]: https://github.com/advisories?query=ecosystem%3Apip
Expand Down
2 changes: 2 additions & 0 deletions pkg/detector/ospkg/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/aquasecurity/trivy/pkg/detector/ospkg/chainguard"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/mariner"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/openeuler"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/oracle"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/photon"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/redhat"
Expand Down Expand Up @@ -46,6 +47,7 @@ var (
ftypes.Photon: photon.NewScanner(),
ftypes.Wolfi: wolfi.NewScanner(),
ftypes.Chainguard: chainguard.NewScanner(),
ftypes.OpenEuler: openeuler.NewScanner(),
}
)

Expand Down
91 changes: 91 additions & 0 deletions pkg/detector/ospkg/openeuler/openeuler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package openeuler

import (
"context"
"time"

version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"

openeuler "github.com/aquasecurity/trivy-db/pkg/vulnsrc/openeuler"
osver "github.com/aquasecurity/trivy/pkg/detector/ospkg/version"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
)

var (
openeulerEOLDates = map[string]time.Time{
// Source: https://www.openeuler.org/zh/other/lifecycle/
"20.09": time.Date(2021, 3, 31, 23, 59, 59, 0, time.UTC),
"21.03": time.Date(2021, 9, 30, 23, 59, 59, 0, time.UTC),
"21.09": time.Date(2022, 3, 31, 23, 59, 59, 0, time.UTC),
"22.09": time.Date(2023, 3, 31, 23, 59, 59, 0, time.UTC),
"23.03": time.Date(2023, 9, 30, 23, 59, 59, 0, time.UTC),
"23.09": time.Date(2024, 3, 31, 23, 59, 59, 0, time.UTC),
"20.03-LTS": time.Date(2022, 3, 31, 23, 59, 59, 0, time.UTC),
"22.03-LTS": time.Date(2024, 3, 31, 23, 59, 59, 0, time.UTC),
"20.03-LTS-SP1": time.Date(2022, 12, 31, 23, 59, 59, 0, time.UTC),
"20.03-LTS-SP2": time.Date(2022, 3, 31, 23, 59, 59, 0, time.UTC),
"20.03-LTS-SP3": time.Date(2026, 3, 31, 23, 59, 59, 0, time.UTC),
"20.03-LTS-SP4": time.Date(2026, 3, 31, 23, 59, 59, 0, time.UTC),
"22.03-LTS-SP1": time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC),
"22.03-LTS-SP2": time.Date(2024, 3, 31, 23, 59, 59, 0, time.UTC),
"22.03-LTS-SP3": time.Date(2028, 3, 31, 23, 59, 59, 0, time.UTC),
"22.03-LTS-SP4": time.Date(2028, 3, 31, 23, 59, 59, 0, time.UTC),
"24.03-LTS": time.Date(2028, 3, 31, 23, 59, 59, 0, time.UTC),
}
)

// Scanner implements the openEuler scanner
type Scanner struct {
vs openeuler.VulnSrc
}

// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
return &Scanner{
vs: openeuler.NewVulnSrc(),
}
}

// Detect scans and returns the vulnerabilities
func (s *Scanner) Detect(ctx context.Context, osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.InfoContext(ctx, "Detecting openEuler vulnerabilities...", log.String("os_version", osVer),
log.Int("pkg_num", len(pkgs)))

var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
advisories, err := s.vs.Get(osVer, pkg.Name, pkg.Arch)
if err != nil {
return nil, xerrors.Errorf("failed to get openEuler advisory: %w", err)
}

installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)
for _, adv := range advisories {
fixedVersion := version.NewVersion(adv.FixedVersion)
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgID: pkg.ID,
PkgName: pkg.Name,
InstalledVersion: installed,
PkgIdentifier: pkg.Identifier,
Layer: pkg.Layer,
Custom: adv.Custom,
DataSource: adv.DataSource,
}
if installedVersion.LessThan(fixedVersion) {
vuln.FixedVersion = adv.FixedVersion
vulns = append(vulns, vuln)
}
}
}
return vulns, nil
}

// IsSupportedVersion checks if OSFamily can be scanned using openEuler scanner
func (s *Scanner) IsSupportedVersion(ctx context.Context, osFamily ftypes.OSType, osVer string) bool {
return osver.Supported(ctx, openeulerEOLDates, osFamily, osVer)
}
158 changes: 158 additions & 0 deletions pkg/detector/ospkg/openeuler/openeuler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package openeuler_test

import (
"context"
"testing"
"time"

"github.com/aquasecurity/trivy/pkg/clock"

"github.com/aquasecurity/trivy-db/pkg/db"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/dbtest"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/openeuler"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestScanner_Detect(t *testing.T) {
type args struct {
osVer string
pkgs []ftypes.Package
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "happy path",
fixtures: []string{
"testdata/fixtures/openeuler.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
osVer: "22.03-LTS-SP2",
pkgs: []ftypes.Package{
{
Name: "perf",
Version: "5.10.0",
Arch: "x86_64",
Release: "153.48.0.125",
SrcName: "postgresql",
SrcVersion: "5.10.0",
SrcRelease: "153.48.0.125",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
},
},
want: []types.DetectedVulnerability{
{
PkgName: "perf",
VulnerabilityID: "openEuler-SA-2024-1349",
InstalledVersion: "5.10.0-153.48.0.125",
FixedVersion: "5.10.0-153.48.0.126",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OpenEuler,
Name: "openEuler CVRF",
URL: "https://repo.openeuler.org/security/data/cvrf",
},
},
},
},
{
name: "broken bucket",
fixtures: []string{
"testdata/fixtures/invalid.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
osVer: "22.03-LTS-SP2",
pkgs: []ftypes.Package{
{
Name: "perf",
Version: "1.6-r0",
SrcName: "perf",
SrcVersion: "1.6-r0",
},
},
},
wantErr: "failed to get openEuler advisories",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_ = dbtest.InitDB(t, tt.fixtures)
defer db.Close()

s := openeuler.NewScanner()
got, err := s.Detect(nil, tt.args.osVer, nil, tt.args.pkgs)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

func TestScanner_IsSupportedVersion(t *testing.T) {
type args struct {
osFamily ftypes.OSType
osVer string
}
tests := []struct {
name string
now time.Time
args args
want bool
}{
{
name: "openEuler-20.03-LTS",
now: time.Date(2021, 5, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "openEuler",
osVer: "20.03-LTS",
},
want: true,
},
{
name: "21.09",
now: time.Date(2022, 5, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "openEuler",
osVer: "21.09",
},
want: false,
},
{
name: "22.03-LTS-SP3",
now: time.Date(2023, 5, 2, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "openEuler",
osVer: "22.03-LTS-SP3",
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := clock.With(context.Background(), tt.now)
s := openeuler.NewScanner()
got := s.IsSupportedVersion(ctx, tt.args.osFamily, tt.args.osVer)
assert.Equal(t, tt.want, got)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- bucket: data-source
pairs:
- key: openEuler-22.03-LTS-SP2
value:
ID: "openeuler"
Name: "openEuler CVRF"
URL: "https://repo.openeuler.org/security/data/cvrf"
9 changes: 9 additions & 0 deletions pkg/detector/ospkg/openeuler/testdata/fixtures/invalid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- bucket: openEuler-22.03-LTS-SP2
pairs:
- bucket: perf
pairs:
- key: CVE-2021-47014
value:
FixedVersion:
- foo
- bar
13 changes: 13 additions & 0 deletions pkg/detector/ospkg/openeuler/testdata/fixtures/openeuler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
- bucket: openEuler-22.03-LTS-SP2
pairs:
- bucket: perf
pairs:
- key: openEuler-SA-2024-1349
value:
FixedVersion: "5.10.0-153.48.0.126"
Arches:
- x86_64
- aarch64
- key: CVE-2021-47014
value:
FixedVersion: ""
wjunLu marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 10 additions & 0 deletions pkg/fanal/analyzer/os/release/release.go
wjunLu marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"slices"
"strings"
"regexp"

"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
Expand Down Expand Up @@ -40,7 +41,14 @@ func (a osReleaseAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInp
case "ID":
id = strings.Trim(value, `"'`)
case "VERSION_ID":
if id == "openEuler" {
continue
}
versionID = strings.Trim(value, `"'`)
case "PRETTY_NAME":
// Get openEuler Version
re := regexp.MustCompile(`openEuler |\(|\)`)
versionID = strings.Replace(re.ReplaceAllString(strings.Trim(value, `"'`), ""), " ", "-", -1)
default:
continue
}
Expand All @@ -61,6 +69,8 @@ func (a osReleaseAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInp
family = types.Wolfi
case "chainguard":
family = types.Chainguard
case "openEuler":
family = types.OpenEuler
}

if family != "" && versionID != "" {
Expand Down
1 change: 1 addition & 0 deletions pkg/fanal/types/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
SLES OSType = "suse linux enterprise server"
Ubuntu OSType = "ubuntu"
Wolfi OSType = "wolfi"
OpenEuler OSType = "openEuler"
)

// Programming language dependencies
Expand Down
2 changes: 1 addition & 1 deletion pkg/purl/purl.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ func purlType(t ftypes.TargetType) string {
case ftypes.RedHat, ftypes.CentOS, ftypes.Rocky, ftypes.Alma,
ftypes.Amazon, ftypes.Fedora, ftypes.Oracle, ftypes.OpenSUSE,
ftypes.OpenSUSELeap, ftypes.OpenSUSETumbleweed, ftypes.SLES, ftypes.Photon,
ftypes.CBLMariner:
ftypes.CBLMariner, ftypes.OpenEuler:
return packageurl.TypeRPM
case TypeOCI:
return packageurl.TypeOCI
Expand Down