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 14 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions docs/docs/coverage/os/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Trivy supports operating systems for
| [Photon OS](photon.md) | 1.0, 2.0, 3.0, 4.0 | tndf/yum/rpm |
| [Debian GNU/Linux](debian.md) | 7, 8, 9, 10, 11, 12 | apt/dpkg |
| [Ubuntu](ubuntu.md) | All versions supported by Canonical | apt/dpkg |
| [openEuler](openeuler.md) | All versions supported by openEuler | dnf/yum/rpm |
| [OSs with installed Conda](../others/conda.md) | - | conda |

## Supported container images
Expand Down
47 changes: 47 additions & 0 deletions docs/docs/coverage/os/openeuler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# openEuler
Trivy supports these scanners for OS packages.

| Scanner | Supported |
| :-----------: | :-------: |
| SBOM | ✓ |
| Vulnerability | ✓ |
| License | ✓ |

Please see [here](index.md#supported-os) for supported versions.

The table below outlines the features offered by Trivy.

| Feature | Supported |
|:------------------------------------:|:---------:|
| Unfixed vulnerabilities | - |
| [Dependency graph][dependency-graph] | ✓ |

## SBOM
Trivy detects packages that have been installed through package managers such as `dnf` and `yum`.

## Vulnerability
openEuler offers its [own security advisories][cvrf], and these are utilized when scanning openEuler for vulnerabilities.

### Data Source
See [here](../../scanner/vulnerability.md#data-sources).

### Severity
Trivy calculates the severity of a vulnerability based on the severity provided in [openEuler Security Data][cvrf].

The table below is the mapping of openEuler's severity to Trivy's severity levels.

| openEuler | Trivy |
| :---------: | :------: |
| Low | Low |
| Medium | Medium |
| High | High |
| Critical | Critical |

## License
Trivy identifies licenses by examining the metadata of RPM packages.


[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies
[cvrf]: https://repo.openeuler.org/security/data/cvrf/

[vulnerability statuses]: ../../configuration/filtering.md#by-status
2 changes: 2 additions & 0 deletions docs/docs/scanner/vulnerability.md
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.
| Azure Linux (CBL-Mariner) | [OVAL][azure] |
| 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 @@ -372,6 +373,7 @@ Regardless of the chosen mode, user review of detected vulnerabilities is crucia
[oracle]: https://linux.oracle.com/security/oval/
[suse]: http://ftp.suse.com/pub/projects/security/cvrf/
[photon]: https://packages.vmware.com/photon/photon_cve_metadata/
[openeuler]: https://repo.openeuler.org/security/data/cvrf
[azure]: https://github.com/microsoft/AzureLinuxVulnerabilityData/

[php-ghsa]: https://github.com/advisories?query=ecosystem%3Acomposer
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,5 @@ require (
sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)

replace github.com/aquasecurity/trivy-db => github.com/wjunLu/trivy-db v0.0.0-20241011083049-6286f5bea7ba
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,6 @@ github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gw
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
github.com/aquasecurity/trivy-checks v1.1.0 h1:I0tVOK8dG/KHrWsqfGNYp2uD/i0f+yS7Je31F+LIUqQ=
github.com/aquasecurity/trivy-checks v1.1.0/go.mod h1:tVzhU0gajD3GmxKPLn/BHR8ZeUquc5ajQTmAsi0kCCU=
github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 h1:G0gnacAORRUqz2Tm5MqivSpldY2GZ74ijhJcMsae+sA=
github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b h1:h7gsIzHyrxpQnayOuQI0kX7+8rVcqhV6G5bM3KVFyJU=
Expand Down Expand Up @@ -1359,6 +1357,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/wjunLu/trivy-db v0.0.0-20241011083049-6286f5bea7ba h1:xbH4SxlNcKYve5u2SmxIoS9QyQyxfepjeGIS+T6G8iU=
github.com/wjunLu/trivy-db v0.0.0-20241011083049-6286f5bea7ba/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xanzy/go-gitlab v0.102.0 h1:ExHuJ1OTQ2yt25zBMMj0G96ChBirGYv8U7HyUiYkZ+4=
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/azure"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/chainguard"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
"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 @@ -48,6 +49,7 @@ var (
ftypes.Photon: photon.NewScanner(),
ftypes.Wolfi: wolfi.NewScanner(),
ftypes.Chainguard: chainguard.NewScanner(),
ftypes.OpenEuler: openeuler.NewScanner(),
}
)

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

import (
"context"
"strings"
"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(2023, 12, 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(2025, 12, 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(2026, 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 {
srcName := pkg.SrcName
if srcName == "" {
srcName = pkg.Name
}
advisories, err := s.vs.Get(osVer, srcName, pkg.Arch)
if err != nil {
return nil, xerrors.Errorf("failed to get openEuler advisory: %w", err)
}

installed, _, _ := strings.Cut(utils.FormatVersion(pkg), ".oe")
srcVersion, _, _ := strings.Cut(utils.FormatSrcVersion(pkg), ".oe")
sourceVersion := version.NewVersion(srcVersion)
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 sourceVersion.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/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"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/internal/dbtest"
"github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/openeuler"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
)

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
}
require.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
10 changes: 10 additions & 0 deletions pkg/detector/ospkg/openeuler/testdata/fixtures/openeuler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- bucket: openEuler-22.03-LTS-SP2
pairs:
- bucket: postgresql
pairs:
- key: openEuler-SA-2024-1349
value:
FixedVersion: "5.10.0-153.48.0.126"
Arches:
- x86_64
- aarch64
Loading