Support SUSE (#337)

* Add suse support

* Add suse support

* Add OpenSUSETumbleweed

* mv suse to detector

* Add trivy-db

* Fix suse test

* Add integration test

* Change README.md

* change go.mod

* Fix bug

* Fix integration

* Fix golden file

* update go.mod

Co-authored-by: Teppei Fukuda <knqyf263@gmail.com>
This commit is contained in:
Masahiro Fujimura
2019-12-24 04:27:25 +09:00
committed by Teppei Fukuda
parent b1ea09d901
commit b127c1c8a7
12 changed files with 381 additions and 9 deletions

View File

@@ -76,7 +76,7 @@ See [here](#continuous-integration-ci) for details.
# Features
- Detect comprehensive vulnerabilities
- OS packages (Alpine, **Red Hat Universal Base Image**, Red Hat Enterprise Linux, CentOS, Oracle Linux, Debian, Ubuntu, Amazon Linux and Distroless)
- OS packages (Alpine, **Red Hat Universal Base Image**, Red Hat Enterprise Linux, CentOS, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux and Distroless)
- **Application dependencies** (Bundler, Composer, Pipenv, Poetry, npm, yarn and Cargo)
- Simple
- Specify only an image name
@@ -1298,11 +1298,13 @@ The unfixed/unfixable vulnerabilities mean that the patch has not yet been provi
| CentOS | 6, 7 | Installed by yum/rpm | YES |
| Oracle Linux | 5, 6, 7, 8 | Installed by yum/rpm | NO |
| Amazon Linux | 1, 2 | Installed by yum/rpm | NO |
| openSUSE Leap | 42, 15 | Installed by zypper/rpm | NO |
| SUSE Enterprise Linux | 11, 12, 15 | Installed by zypper/rpm | NO |
| Debian GNU/Linux | wheezy, jessie, stretch, buster | Installed by apt/apt-get/dpkg | YES |
| Ubuntu | 12.04, 14.04, 16.04, 18.04, 18.10, 19.04 | Installed by apt/apt-get/dpkg | YES |
| Distroless | Any | Installed by apt/apt-get/dpkg | YES |
RHEL, CentOS, Oracle Linux and Amazon Linux package information is stored in a binary format, and Trivy uses the `rpm` executable to parse this information when scanning an image based on RHEL or CentOS. The Trivy container image includes `rpm`, and the installers include it as a dependency. If you installed the `trivy` binary using `wget` or `curl`, or if you build it from source, you will also need to ensure that `rpm` is available.
RHEL, CentOS, Oracle Linux, SUSE and Amazon Linux package information is stored in a binary format, and Trivy uses the `rpm` executable to parse this information when scanning an image based on RHEL or CentOS. The Trivy container image includes `rpm`, and the installers include it as a dependency. If you installed the `trivy` binary using `wget` or `curl`, or if you build it from source, you will also need to ensure that `rpm` is available.
Distroless: https://github.com/GoogleContainerTools/distroless

4
go.mod
View File

@@ -3,9 +3,9 @@ module github.com/aquasecurity/trivy
go 1.13
require (
github.com/aquasecurity/fanal v0.0.0-20191205044128-99e4876e56b0
github.com/aquasecurity/fanal v0.0.0-20191215125351-0473ad881a79
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b
github.com/aquasecurity/trivy-db v0.0.0-20191120190201-a6645984b409
github.com/aquasecurity/trivy-db v0.0.0-20191223151440-3e45ca45a297
github.com/caarlos0/env/v6 v6.0.0
github.com/cheggaaa/pb/v3 v3.0.3
github.com/genuinetools/reg v0.16.0

8
go.sum
View File

@@ -27,13 +27,13 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/aquasecurity/fanal v0.0.0-20190819081512-f04452b627c6/go.mod h1:enEz4FFetw4XAbkffaYgyCVq1556R9Ry+noqT4rq9BE=
github.com/aquasecurity/fanal v0.0.0-20191205044128-99e4876e56b0 h1:wjQXLf/TGvwd/YVNciqTwOQV3aywS9oC/oCo6N92E8Y=
github.com/aquasecurity/fanal v0.0.0-20191205044128-99e4876e56b0/go.mod h1:fV5n9NH3ICFxMrVEoCOg+yKmwjww6SnkdlZb9cT/sVo=
github.com/aquasecurity/fanal v0.0.0-20191215125351-0473ad881a79 h1:apz8Fc2jOnS7S50x9UwfQ2OqMbx3JJ+ti3oFOz9v0ZU=
github.com/aquasecurity/fanal v0.0.0-20191215125351-0473ad881a79/go.mod h1:fV5n9NH3ICFxMrVEoCOg+yKmwjww6SnkdlZb9cT/sVo=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b h1:55Ulc/gvfWm4ylhVaR7MxOwujRjA6et7KhmUbSgUFf4=
github.com/aquasecurity/go-dep-parser v0.0.0-20190819075924-ea223f0ef24b/go.mod h1:BpNTD9vHfrejKsED9rx04ldM1WIbeyXGYxUrqTVwxVQ=
github.com/aquasecurity/trivy v0.1.6/go.mod h1:5hobyhxLzDtxruHzPxpND2PUKOssvGUdE9BocpJUwo4=
github.com/aquasecurity/trivy-db v0.0.0-20191120190201-a6645984b409 h1:RrFBrw3qZXH/AIEtEYF1WgYhXae3VPPaaPIJic5p1gw=
github.com/aquasecurity/trivy-db v0.0.0-20191120190201-a6645984b409/go.mod h1:vYzX1UhX0o29E+/nuFJTgUJBM5UA7I/NftnbBcYyYRE=
github.com/aquasecurity/trivy-db v0.0.0-20191223151440-3e45ca45a297 h1:XyGsaTMGASjxlXW2w+Dn6vwRje8MHASymxj1QEE+xwI=
github.com/aquasecurity/trivy-db v0.0.0-20191223151440-3e45ca45a297/go.mod h1:Uf9bXd50zTHtWTP7+7u5+OFCPtUVrmsS4v0RXd7E5lw=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8=

View File

@@ -257,6 +257,22 @@ func TestClientServer(t *testing.T) {
},
golden: "testdata/oraclelinux-8-slim.json.golden",
},
{
name: "opensuse leap 15.1 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/opensuse-leap-151.tar.gz",
},
golden: "testdata/opensuse-leap-151.json.golden",
},
{
name: "opensuse leap 42.3 integration",
testArgs: args{
Version: "dev",
Input: "testdata/fixtures/opensuse-leap-423.tar.gz",
},
golden: "testdata/opensuse-leap-423.json.golden",
},
{
name: "invalid token",
testArgs: args{

View File

@@ -291,6 +291,26 @@ func TestRun_WithTar(t *testing.T) {
},
golden: "testdata/oraclelinux-8-slim.json.golden",
},
{
name: "opensuse leap 15.1 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/opensuse-leap-151.tar.gz",
},
golden: "testdata/opensuse-leap-151.json.golden",
},
{
name: "opensuse leap 42.3 integration",
testArgs: args{
Version: "dev",
SkipUpdate: true,
Format: "json",
Input: "testdata/fixtures/opensuse-leap-423.tar.gz",
},
golden: "testdata/opensuse-leap-423.json.golden",
},
}
for _, c := range cases {

View File

@@ -0,0 +1,103 @@
[
{
"Target": "testdata/fixtures/opensuse-leap-151.tar.gz (opensuse.leap 15.1)",
"Vulnerabilities": [
{
"VulnerabilityID": "openSUSE-SU-2019:2596-1",
"PkgName": "cpio",
"InstalledVersion": "2.12-lp151.2.68",
"FixedVersion": "2.12-lp151.3.3.1",
"Title": "Security update for cpio",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00076.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2611-1",
"PkgName": "libidn2-0",
"InstalledVersion": "2.0.4-lp151.2.3",
"FixedVersion": "2.2.0-lp151.3.3.1",
"Title": "Security update for libidn2",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2551-1",
"PkgName": "libncurses6",
"InstalledVersion": "6.1-lp151.5.41",
"FixedVersion": "6.1-lp151.6.3.1",
"Title": "Security update for ncurses",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00059.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2689-1",
"PkgName": "libssh4",
"InstalledVersion": "0.8.7-lp151.2.3.1",
"FixedVersion": "0.8.7-lp151.2.6.1",
"Title": "Security update for libssh",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00033.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2612-1",
"PkgName": "libxml2-2",
"InstalledVersion": "2.9.7-lp151.5.3.1",
"FixedVersion": "2.9.7-lp151.5.6.1",
"Title": "Security update for libxml2",
"Severity": "UNKNOWN",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00010.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2551-1",
"PkgName": "ncurses-utils",
"InstalledVersion": "6.1-lp151.5.41",
"FixedVersion": "6.1-lp151.6.3.1",
"Title": "Security update for ncurses",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00059.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2672-1",
"PkgName": "permissions",
"InstalledVersion": "20181116-lp151.4.6.1",
"FixedVersion": "20181116-lp151.4.9.1",
"Title": "Security update for permissions",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00024.html",
"https://www.suse.com/support/security/rating/"
]
},
{
"VulnerabilityID": "openSUSE-SU-2019:2551-1",
"PkgName": "terminfo-base",
"InstalledVersion": "6.1-lp151.5.41",
"FixedVersion": "6.1-lp151.6.3.1",
"Title": "Security update for ncurses",
"Severity": "MEDIUM",
"References": [
"http://lists.opensuse.org/opensuse-security-announce/2019-11/msg00059.html",
"https://www.suse.com/support/security/rating/"
]
}
]
}
]

View File

@@ -0,0 +1,6 @@
[
{
"Target": "testdata/fixtures/opensuse-leap-423.tar.gz (opensuse.leap 42.3)",
"Vulnerabilities": null
}
]

Binary file not shown.

View File

@@ -6,6 +6,7 @@ import (
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/oracle"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/redhat"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/suse"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/ubuntu"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/google/wire"
@@ -68,6 +69,10 @@ func newDriver(osFamily, osName string) Driver {
d = amazon.NewScanner()
case fos.Oracle:
d = oracle.NewScanner()
case fos.OpenSUSELeap:
d = suse.NewScanner(suse.OpenSUSE)
case fos.SLES:
d = suse.NewScanner(suse.SUSEEnterpriseLinux)
default:
log.Logger.Warnf("unsupported os : %s", osFamily)
return nil

View File

@@ -0,0 +1,128 @@
package suse
import (
"time"
"github.com/aquasecurity/fanal/analyzer"
fos "github.com/aquasecurity/fanal/analyzer/os"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scanner/utils"
"github.com/aquasecurity/trivy/pkg/types"
version "github.com/knqyf263/go-rpm-version"
"golang.org/x/xerrors"
"k8s.io/utils/clock"
)
var (
slesEolDates = map[string]time.Time{
// Source: https://www.suse.com/lifecycle/
"10": time.Date(2007, 12, 31, 23, 59, 59, 0, time.UTC),
"10.1": time.Date(2008, 11, 30, 23, 59, 59, 0, time.UTC),
"10.2": time.Date(2010, 4, 11, 23, 59, 59, 0, time.UTC),
"10.3": time.Date(2011, 10, 11, 23, 59, 59, 0, time.UTC),
"10.4": time.Date(2013, 7, 31, 23, 59, 59, 0, time.UTC),
"11": time.Date(2010, 12, 31, 23, 59, 59, 0, time.UTC),
"11.1": time.Date(2012, 8, 31, 23, 59, 59, 0, time.UTC),
"11.2": time.Date(2014, 1, 31, 23, 59, 59, 0, time.UTC),
"11.3": time.Date(2016, 1, 31, 23, 59, 59, 0, time.UTC),
"11.4": time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
"12": time.Date(2016, 6, 30, 23, 59, 59, 0, time.UTC),
"12.1": time.Date(2017, 5, 31, 23, 59, 59, 0, time.UTC),
"12.2": time.Date(2018, 3, 31, 23, 59, 59, 0, time.UTC),
"12.3": time.Date(2019, 1, 30, 23, 59, 59, 0, time.UTC),
// 6 months after SLES12 SP5 release
// "12.4": time.Date(2024, 10, 31, 23, 59, 59, 0, time.UTC),
"15": time.Date(2019, 12, 31, 23, 59, 59, 0, time.UTC),
// 6 months after SLES 15 SP2 release
// "15.1": time.Date(2028, 7, 31, 23, 59, 59, 0, time.UTC),
}
opensuseEolDates = map[string]time.Time{
// Source: https://en.opensuse.org/Lifetime
"42.1": time.Date(2017, 5, 17, 23, 59, 59, 0, time.UTC),
"42.2": time.Date(2018, 1, 26, 23, 59, 59, 0, time.UTC),
"42.3": time.Date(2019, 6, 30, 23, 59, 59, 0, time.UTC),
"15.0": time.Date(2019, 12, 3, 23, 59, 59, 0, time.UTC),
"15.1": time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC),
"15.2": time.Date(2021, 11, 30, 23, 59, 59, 0, time.UTC),
}
)
type Scanner struct {
vs dbTypes.VulnSrc
clock clock.Clock
family string
}
type SUSEType int
const (
SUSEEnterpriseLinux SUSEType = iota
OpenSUSE
)
func NewScanner(t SUSEType) *Scanner {
switch t {
case SUSEEnterpriseLinux:
return &Scanner{
vs: susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinux),
clock: clock.RealClock{},
}
case OpenSUSE:
return &Scanner{
vs: susecvrf.NewVulnSrc(susecvrf.OpenSUSE),
clock: clock.RealClock{},
}
}
return nil
}
func (s *Scanner) Detect(osVer string, pkgs []analyzer.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting SUSE vulnerabilities...")
log.Logger.Debugf("SUSE: os version: %s", osVer)
log.Logger.Debugf("SUSE: the number of packages: %d", len(pkgs))
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
advisories, err := s.vs.Get(osVer, pkg.SrcName)
if err != nil {
return nil, xerrors.Errorf("failed to get SUSE 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,
PkgName: pkg.Name,
InstalledVersion: installed,
}
if installedVersion.LessThan(fixedVersion) {
vuln.FixedVersion = adv.FixedVersion
vulns = append(vulns, vuln)
}
}
}
return vulns, nil
}
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
var eolDate time.Time
var ok bool
if osFamily == fos.SLES {
eolDate, ok = slesEolDates[osVer]
} else if osFamily == fos.OpenSUSELeap {
eolDate, ok = opensuseEolDates[osVer]
}
if !ok {
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
return false
}
return s.clock.Now().Before(eolDate)
}

View File

@@ -0,0 +1,92 @@
package suse
import (
"os"
"testing"
"time"
susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
"github.com/aquasecurity/trivy/pkg/log"
"k8s.io/utils/clock"
clocktesting "k8s.io/utils/clock/testing"
)
func TestMain(m *testing.M) {
log.InitLogger(false, false)
os.Exit(m.Run())
}
func TestScanner_IsSupportedVersion(t *testing.T) {
vectors := map[string]struct {
clock clock.Clock
osFamily string
osVersion string
distribution susecvrf.Distribution
expected bool
}{
"opensuse.leap42.3": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "42.3",
distribution: susecvrf.OpenSUSE,
expected: true,
},
"opensuse.leap15": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "15.0",
distribution: susecvrf.OpenSUSE,
expected: true,
},
"opensuse.leap15.1": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "15.1",
distribution: susecvrf.OpenSUSE,
expected: true,
},
"opensuse.leap15.1-sametime": {
clock: clocktesting.NewFakeClock(time.Date(2020, 11, 30, 23, 59, 59, 0, time.UTC)),
osFamily: "opensuse.leap",
osVersion: "15.1",
distribution: susecvrf.OpenSUSE,
expected: false,
},
"sles12.3": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "suse linux enterprise server",
osVersion: "12.3",
distribution: susecvrf.SUSEEnterpriseLinux,
expected: false,
},
"sles15": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "suse linux enterprise server",
osVersion: "15",
distribution: susecvrf.SUSEEnterpriseLinux,
expected: true,
},
"unknown": {
clock: clocktesting.NewFakeClock(time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC)),
osFamily: "oracle",
osVersion: "unknown",
distribution: susecvrf.SUSEEnterpriseLinux,
expected: false,
},
}
for testName, v := range vectors {
s := &Scanner{
vs: susecvrf.NewVulnSrc(v.distribution),
clock: v.clock,
}
t.Run(testName, func(t *testing.T) {
actual := s.IsSupportedVersion(v.osFamily, v.osVersion)
if actual != v.expected {
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
}
})
}
}

View File

@@ -8,8 +8,8 @@ import (
_ "github.com/aquasecurity/fanal/analyzer/os/alpine"
_ "github.com/aquasecurity/fanal/analyzer/os/amazonlinux"
_ "github.com/aquasecurity/fanal/analyzer/os/debianbase"
_ "github.com/aquasecurity/fanal/analyzer/os/opensuse"
_ "github.com/aquasecurity/fanal/analyzer/os/redhatbase"
_ "github.com/aquasecurity/fanal/analyzer/os/suse"
_ "github.com/aquasecurity/fanal/analyzer/pkg/apk"
_ "github.com/aquasecurity/fanal/analyzer/pkg/dpkg"
"github.com/aquasecurity/fanal/extractor"