mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -08:00
refactor: use testing DB instead of mock (#1234)
This commit is contained in:
5
go.mod
5
go.mod
@@ -13,13 +13,12 @@ require (
|
||||
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210809142931-da8e09204404
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210907100132-2ec74c43526d
|
||||
github.com/caarlos0/env/v6 v6.0.0
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/cheggaaa/pb/v3 v3.0.3
|
||||
github.com/docker/docker v20.10.8+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d // indirect
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/go-redis/redis/v8 v8.11.3
|
||||
github.com/goccy/go-yaml v1.8.2 // indirect
|
||||
@@ -27,7 +26,6 @@ require (
|
||||
github.com/google/go-containerregistry v0.6.0
|
||||
github.com/google/go-github/v33 v33.0.0
|
||||
github.com/google/wire v0.4.0
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
|
||||
github.com/hashicorp/go-getter v1.5.2
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
|
||||
@@ -38,7 +36,6 @@ require (
|
||||
github.com/mitchellh/copystructure v1.1.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/open-policy-agent/opa v0.32.0
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/spf13/afero v1.6.0
|
||||
github.com/stretchr/objx v0.3.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
|
||||
17
go.sum
17
go.sum
@@ -218,9 +218,8 @@ github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 h1:moQmzbp
|
||||
github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516/go.mod h1:gTd97VdQ0rg8Mkiic3rPgNOQdprZ7feTAhiD5mGQjgM=
|
||||
github.com/aquasecurity/tfsec v0.46.0 h1:R9djHTpk+YrFuFv2GRdfU4rRz6uk5wLrgfx1fp9K1es=
|
||||
github.com/aquasecurity/tfsec v0.46.0/go.mod h1:Dafx5dX/1QV1d5en62shpzEXfq5F31IG6oNNxhleV5Y=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210809142931-da8e09204404 h1:6nJle4kjovrm3gK+xl1iuYkv1vbbMRRviHkR7fj3Tjc=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210809142931-da8e09204404/go.mod h1:N7CWA/vjVw78GWAdCJGhFQVqNGEA4e47a6eIWm+C/Bc=
|
||||
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2 h1:xbdUfr2KE4THsFx9CFWtWpU91lF+YhgP46moV94nYTA=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210907100132-2ec74c43526d h1:AMuCVa54YX5wVmvqeUZY/PSfMbHtiX1PukVZHocCLr0=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20210907100132-2ec74c43526d/go.mod h1:lcUx+KZjKYLu7gCe8Gwe3ZUBUsxeRUg3mwkvzikP6kQ=
|
||||
github.com/aquasecurity/vuln-list-update v0.0.0-20191016075347-3d158c2bf9a2/go.mod h1:6NhOP0CjZJL27bZZcaHECtzWdwDDm2g6yCY0QgXEGQQ=
|
||||
github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
@@ -496,10 +495,7 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d h1:rtM8HsT3NG37YPjz8sYSbUSdElP9lUsQENYzJDZDUBE=
|
||||
github.com/elazarl/goproxy v0.0.0-20200809112317-0581fc3aee2d/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
@@ -724,6 +720,7 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u
|
||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||
github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM=
|
||||
github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
|
||||
github.com/google/go-github/v38 v38.1.0/go.mod h1:cStvrz/7nFr0FoENgG6GLbp53WaelXucT+BBz/3VKx4=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
||||
@@ -776,8 +773,6 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
|
||||
github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/goreleaser/goreleaser v0.136.0/go.mod h1:wiKrPUeSNh6Wu8nUHxZydSOVQ/OZvOaO7DTtFqie904=
|
||||
github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w=
|
||||
github.com/goreleaser/nfpm v1.3.0/go.mod h1:w0p7Kc9TAUgWMyrub63ex3M2Mgw88M4GZXoTq5UCb40=
|
||||
@@ -912,7 +907,6 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
@@ -1156,7 +1150,6 @@ github.com/owenrumney/go-sarif v1.0.11/go.mod h1:hTBFbxU7GuVRUvwMx+eStp9M/Oun4xH
|
||||
github.com/owenrumney/squealer v0.2.26/go.mod h1:wwVPzhjiUBILIdDtnzGSEcapXczIj/tONP+ZJ49IhPY=
|
||||
github.com/owenrumney/squealer v0.2.28 h1:LYsqUHal+5QlANjbZ+h44SN5kIZSfHCWKUzBAS1KwB0=
|
||||
github.com/owenrumney/squealer v0.2.28/go.mod h1:wwVPzhjiUBILIdDtnzGSEcapXczIj/tONP+ZJ49IhPY=
|
||||
github.com/parnurzeal/gorequest v0.2.16 h1:T/5x+/4BT+nj+3eSknXmCTnEVGSzFzPGdpqmUVVZXHQ=
|
||||
github.com/parnurzeal/gorequest v0.2.16/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
@@ -1277,11 +1270,8 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
@@ -2137,7 +2127,6 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
version "github.com/knqyf263/go-apk-version"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/alpine"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -43,15 +43,36 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
type options struct {
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
type option func(*options)
|
||||
|
||||
func WithClock(clock clock.Clock) option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Scanner implements the Alpine scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
vs alpine.VulnSrc
|
||||
*options
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
func NewScanner(opts ...option) *Scanner {
|
||||
o := &options{
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
return &Scanner{
|
||||
vs: alpine.NewVulnSrc(),
|
||||
vs: alpine.NewVulnSrc(),
|
||||
options: o,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +122,6 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
|
||||
// IsSupportedVersion checks the OSFamily can be scanned using Alpine scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
}
|
||||
|
||||
func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool {
|
||||
if strings.Count(osVer, ".") > 1 {
|
||||
osVer = osVer[:strings.LastIndex(osVer, ".")]
|
||||
}
|
||||
@@ -115,5 +131,6 @@ func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool
|
||||
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
|
||||
return false
|
||||
}
|
||||
return now.Before(eol)
|
||||
|
||||
return s.clock.Now().Before(eol)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package alpine
|
||||
package alpine_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/alpine"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
@@ -18,31 +20,16 @@ func TestScanner_Detect(t *testing.T) {
|
||||
osVer string
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
type getInput struct {
|
||||
osVer string
|
||||
pkgName string
|
||||
}
|
||||
type getOutput struct {
|
||||
advisories []dbTypes.Advisory
|
||||
err error
|
||||
}
|
||||
type get struct {
|
||||
input getInput
|
||||
output getOutput
|
||||
}
|
||||
type mocks struct {
|
||||
get []get
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
mocks mocks
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
name string
|
||||
args args
|
||||
fixtures []string
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
name: "happy path",
|
||||
fixtures: []string{"testdata/fixtures/alpine310.yaml"},
|
||||
args: args{
|
||||
osVer: "3.10.2",
|
||||
pkgs: []ftypes.Package{
|
||||
@@ -63,39 +50,6 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
mocks: mocks{
|
||||
get: []get{
|
||||
{
|
||||
input: getInput{
|
||||
osVer: "3.10",
|
||||
pkgName: "ansible",
|
||||
},
|
||||
output: getOutput{
|
||||
advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2018-10875",
|
||||
FixedVersion: "2.6.3-r0",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-10217",
|
||||
FixedVersion: "2.8.4-r0",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-INVALID",
|
||||
FixedVersion: "invalid", // skipped
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: getInput{
|
||||
osVer: "3.10",
|
||||
pkgName: "invalid",
|
||||
},
|
||||
output: getOutput{advisories: []dbTypes.Advisory{{}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "ansible",
|
||||
@@ -109,9 +63,10 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "contain rc",
|
||||
name: "contain rc",
|
||||
fixtures: []string{"testdata/fixtures/alpine310.yaml"},
|
||||
args: args{
|
||||
osVer: "3.9",
|
||||
osVer: "3.10",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
@@ -121,40 +76,20 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
mocks: mocks{
|
||||
get: []get{
|
||||
{
|
||||
input: getInput{
|
||||
osVer: "3.9",
|
||||
pkgName: "jq",
|
||||
},
|
||||
output: getOutput{
|
||||
advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2016-4074",
|
||||
FixedVersion: "1.6_rc1-r0",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-9999",
|
||||
FixedVersion: "1.6_rc2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: getInput{
|
||||
osVer: "3.10",
|
||||
pkgName: "invalid",
|
||||
},
|
||||
output: getOutput{advisories: []dbTypes.Advisory{{}}},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "jq",
|
||||
VulnerabilityID: "CVE-2020-1234",
|
||||
InstalledVersion: "1.6-r0",
|
||||
FixedVersion: "1.6-r1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "contain pre",
|
||||
name: "contain pre",
|
||||
fixtures: []string{"testdata/fixtures/alpine310.yaml"},
|
||||
args: args{
|
||||
osVer: "3.12",
|
||||
osVer: "3.10",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "test",
|
||||
@@ -167,28 +102,6 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
mocks: mocks{
|
||||
get: []get{
|
||||
{
|
||||
input: getInput{
|
||||
osVer: "3.12",
|
||||
pkgName: "test-src",
|
||||
},
|
||||
output: getOutput{
|
||||
advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2030-0001",
|
||||
FixedVersion: "0.1.0_alpha_pre2",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2030-0002",
|
||||
FixedVersion: "0.1.0_alpha2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2030-0002",
|
||||
@@ -202,9 +115,10 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Get returns an error",
|
||||
name: "Get returns an error",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
args: args{
|
||||
osVer: "3.8.1",
|
||||
osVer: "3.10.2",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
@@ -214,91 +128,89 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
mocks: mocks{
|
||||
get: []get{
|
||||
{
|
||||
input: getInput{
|
||||
osVer: "3.8",
|
||||
pkgName: "jq",
|
||||
},
|
||||
output: getOutput{err: errors.New("error")},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to get alpine advisories",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockVulnSrc := new(dbTypes.MockVulnSrc)
|
||||
for _, g := range tt.mocks.get {
|
||||
mockVulnSrc.On("Get", g.input.osVer, g.input.pkgName).Return(
|
||||
g.output.advisories, g.output.err)
|
||||
}
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
s := &Scanner{
|
||||
vs: mockVulnSrc,
|
||||
}
|
||||
s := alpine.NewScanner()
|
||||
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
|
||||
|
||||
switch {
|
||||
case tt.wantErr != "":
|
||||
assert.Contains(t, err.Error(), tt.wantErr, tt.name)
|
||||
default:
|
||||
assert.NoError(t, err, tt.name)
|
||||
if tt.wantErr != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
assert.ElementsMatch(t, got, tt.want, tt.name)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanner_IsSupportedVersion(t *testing.T) {
|
||||
vectors := map[string]struct {
|
||||
now time.Time
|
||||
osFamily string
|
||||
osVersion string
|
||||
expected bool
|
||||
type args struct {
|
||||
osFamily string
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
"alpine3.6": {
|
||||
now: time.Date(2019, 3, 2, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "alpine",
|
||||
osVersion: "3.6",
|
||||
expected: true,
|
||||
{
|
||||
name: "alpine 3.6",
|
||||
now: time.Date(2019, 3, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "alpine",
|
||||
osVer: "3.6",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"alpine3.6 with EOL": {
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "alpine",
|
||||
osVersion: "3.6.5",
|
||||
expected: false,
|
||||
{
|
||||
name: "alpine 3.6 with EOL",
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "alpine",
|
||||
osVer: "3.6.5",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
"alpine3.9": {
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "alpine",
|
||||
osVersion: "3.9.0",
|
||||
expected: true,
|
||||
{
|
||||
name: "alpine 3.9",
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "alpine",
|
||||
osVer: "3.9.0",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"alpine3.10": {
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "alpine",
|
||||
osVersion: "3.10",
|
||||
expected: true,
|
||||
{
|
||||
name: "alpine 3.10",
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "alpine",
|
||||
osVer: "3.10",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"unknown": {
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "alpine",
|
||||
osVersion: "unknown",
|
||||
expected: false,
|
||||
{
|
||||
name: "unknown",
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "alpine",
|
||||
osVer: "unknown",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, v := range vectors {
|
||||
s := NewScanner()
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
actual := s.isSupportedVersion(v.now, v.osFamily, v.osVersion)
|
||||
if actual != v.expected {
|
||||
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := alpine.NewScanner(alpine.WithClock(fake.NewFakeClock(tt.now)))
|
||||
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
32
pkg/detector/ospkg/alpine/testdata/fixtures/alpine310.yaml
vendored
Normal file
32
pkg/detector/ospkg/alpine/testdata/fixtures/alpine310.yaml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
- bucket: alpine 3.10
|
||||
pairs:
|
||||
- bucket: ansible
|
||||
pairs:
|
||||
- key: CVE-2018-10875
|
||||
value:
|
||||
FixedVersion: "2.6.3-r0"
|
||||
- key: CVE-2019-10217
|
||||
value:
|
||||
FixedVersion: "2.8.4-r0"
|
||||
- key: CVE-2019-INVALID
|
||||
value:
|
||||
FixedVersion: "invalid"
|
||||
- bucket: jq
|
||||
pairs:
|
||||
- key: CVE-2016-4074
|
||||
value:
|
||||
FixedVersion: "1.6_rc1-r0"
|
||||
- key: CVE-2019-9999
|
||||
value:
|
||||
FixedVersion: "1.6_rc2"
|
||||
- key: CVE-2020-1234
|
||||
value:
|
||||
FixedVersion: "1.6-r1"
|
||||
- bucket: test-src
|
||||
pairs:
|
||||
- key: CVE-2030-0001
|
||||
value:
|
||||
FixedVersion: "0.1.0_alpha_pre2"
|
||||
- key: CVE-2030-0002
|
||||
value:
|
||||
FixedVersion: "0.1.0_alpha2"
|
||||
9
pkg/detector/ospkg/alpine/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/alpine/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: alpine 3.10
|
||||
pairs:
|
||||
- bucket: jq
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
@@ -4,12 +4,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/amazon"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -24,17 +25,38 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
type options struct {
|
||||
clock clock.Clock
|
||||
l *zap.SugaredLogger
|
||||
}
|
||||
|
||||
type option func(*options)
|
||||
|
||||
func WithClock(clock clock.Clock) option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Scanner to scan amazon vulnerabilities
|
||||
type Scanner struct {
|
||||
l *zap.SugaredLogger
|
||||
ac dbTypes.VulnSrc
|
||||
ac amazon.VulnSrc
|
||||
options
|
||||
}
|
||||
|
||||
// NewScanner is the factory method to return Amazon scanner
|
||||
func NewScanner() *Scanner {
|
||||
func NewScanner(opts ...option) *Scanner {
|
||||
o := &options{
|
||||
l: log.Logger,
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
return &Scanner{
|
||||
l: log.Logger,
|
||||
ac: amazon.NewVulnSrc(),
|
||||
ac: amazon.NewVulnSrc(),
|
||||
options: *o,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,11 +113,6 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
|
||||
// IsSupportedVersion checks if os can be scanned using amazon scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
}
|
||||
|
||||
func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool {
|
||||
osVer = strings.Fields(osVer)[0]
|
||||
if osVer != "2" {
|
||||
osVer = "1"
|
||||
@@ -105,5 +122,6 @@ func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool
|
||||
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
|
||||
return false
|
||||
}
|
||||
return now.Before(eol)
|
||||
|
||||
return s.clock.Now().Before(eol)
|
||||
}
|
||||
|
||||
@@ -1,213 +1,179 @@
|
||||
package amazon
|
||||
package amazon_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"go.uber.org/zap/zaptest/observer"
|
||||
"github.com/stretchr/testify/require"
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/amazon"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
type MockAmazonConfig struct {
|
||||
update func(string) error
|
||||
get func(string, string) ([]dbTypes.Advisory, error)
|
||||
}
|
||||
|
||||
func (mac MockAmazonConfig) Update(a string) error {
|
||||
if mac.update != nil {
|
||||
return mac.update(a)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mac MockAmazonConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
|
||||
if mac.get != nil {
|
||||
return mac.get(a, b)
|
||||
}
|
||||
return []dbTypes.Advisory{}, nil
|
||||
}
|
||||
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
zc, recorder := observer.New(zapcore.DebugLevel)
|
||||
log.Logger = zap.New(zc).Sugar()
|
||||
s := &Scanner{
|
||||
l: log.Logger,
|
||||
ac: MockAmazonConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, e error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "123",
|
||||
FixedVersion: "3.0.0",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "2.1.0",
|
||||
Release: "hotfix",
|
||||
SrcRelease: "test-hotfix",
|
||||
SrcVersion: "2.1.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foopkg",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "123",
|
||||
PkgName: "testpkg",
|
||||
InstalledVersion: "2.1.0-hotfix",
|
||||
FixedVersion: "3.0.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
}, vuls)
|
||||
|
||||
loggedMessages := getAllLoggedLogs(recorder)
|
||||
assert.Contains(t, loggedMessages, "amazon: os version: 1")
|
||||
assert.Contains(t, loggedMessages, "amazon: the number of packages: 2")
|
||||
})
|
||||
|
||||
t.Run("get vulnerabilities fails to fetch", func(t *testing.T) {
|
||||
s := &Scanner{
|
||||
l: log.Logger,
|
||||
ac: MockAmazonConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, e error) {
|
||||
return nil, errors.New("failed to fetch advisories")
|
||||
},
|
||||
},
|
||||
}
|
||||
vuls, err := s.Detect("foo", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
},
|
||||
})
|
||||
assert.Equal(t, "failed to get amazon advisories: failed to fetch advisories", err.Error())
|
||||
assert.Empty(t, vuls)
|
||||
})
|
||||
|
||||
t.Run("invalid installed package version", func(t *testing.T) {
|
||||
zc, recorder := observer.New(zapcore.DebugLevel)
|
||||
log.Logger = zap.New(zc).Sugar()
|
||||
s := &Scanner{
|
||||
l: log.Logger,
|
||||
ac: MockAmazonConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, e error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "123",
|
||||
FixedVersion: "3.0.0",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "badsourceversion",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability(nil), vuls)
|
||||
loggedMessages := getAllLoggedLogs(recorder)
|
||||
assert.Contains(t, loggedMessages, "failed to parse Amazon Linux installed package version: upstream_version must start with digit")
|
||||
})
|
||||
|
||||
t.Run("invalid fixed package version", func(t *testing.T) {
|
||||
zc, recorder := observer.New(zapcore.DebugLevel)
|
||||
log.Logger = zap.New(zc).Sugar()
|
||||
s := &Scanner{
|
||||
l: log.Logger,
|
||||
ac: MockAmazonConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, e error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "123",
|
||||
FixedVersion: "thisisbadversioning",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "3.1.0",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability(nil), vuls)
|
||||
loggedMessages := getAllLoggedLogs(recorder)
|
||||
assert.Contains(t, loggedMessages, "failed to parse Amazon Linux package version: upstream_version must start with digit")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func getAllLoggedLogs(recorder *observer.ObservedLogs) []string {
|
||||
allLogs := recorder.AllUntimed()
|
||||
var loggedMessages []string
|
||||
for _, l := range allLogs {
|
||||
loggedMessages = append(loggedMessages, l.Message)
|
||||
type args struct {
|
||||
osVer string
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
fixtures []string
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "amazon linux 1",
|
||||
fixtures: []string{"testdata/fixtures/amazon.yaml"},
|
||||
args: args{
|
||||
osVer: "1.2",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "bind",
|
||||
Epoch: 32,
|
||||
Version: "9.8.2",
|
||||
Release: "0.68.rc1.85.amzn1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "bind",
|
||||
VulnerabilityID: "CVE-2020-8625",
|
||||
InstalledVersion: "32:9.8.2-0.68.rc1.85.amzn1",
|
||||
FixedVersion: "32:9.8.2-0.68.rc1.86.amzn1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "amazon linux 2",
|
||||
fixtures: []string{"testdata/fixtures/amazon.yaml"},
|
||||
args: args{
|
||||
osVer: "2",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "bash",
|
||||
Version: "4.2.45",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "bash",
|
||||
VulnerabilityID: "CVE-2019-9924",
|
||||
InstalledVersion: "4.2.45",
|
||||
FixedVersion: "4.2.46-34.amzn2",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty version",
|
||||
fixtures: []string{"testdata/fixtures/amazon.yaml"},
|
||||
args: args{
|
||||
osVer: "2",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "bash",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Get returns an error",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
args: args{
|
||||
osVer: "1",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
Version: "1.6-r0",
|
||||
SrcName: "jq",
|
||||
SrcVersion: "1.6-r0",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to get amazon advisories",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
s := amazon.NewScanner()
|
||||
got, err := s.Detect(tt.args.osVer, 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)
|
||||
})
|
||||
}
|
||||
return loggedMessages
|
||||
}
|
||||
|
||||
func TestScanner_IsSupportedVersion(t *testing.T) {
|
||||
vectors := map[string]struct {
|
||||
now time.Time
|
||||
osFamily string
|
||||
osVersion string
|
||||
expected bool
|
||||
type args struct {
|
||||
osFamily string
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
"1": {
|
||||
now: time.Date(2022, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "amazon",
|
||||
osVersion: "1",
|
||||
expected: true,
|
||||
{
|
||||
name: "amazon linux 1",
|
||||
now: time.Date(2022, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "amazon",
|
||||
osVer: "1",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"1 (eol ends)": {
|
||||
now: time.Date(2024, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "amazon",
|
||||
osVersion: "1",
|
||||
expected: false,
|
||||
{
|
||||
name: "amazon linux 1 EOL",
|
||||
now: time.Date(2024, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "amazon",
|
||||
osVer: "1",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
"2": {
|
||||
now: time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC),
|
||||
osFamily: "amazon",
|
||||
osVersion: "2",
|
||||
expected: true,
|
||||
{
|
||||
name: "amazon linux 2",
|
||||
now: time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "amazon",
|
||||
osVer: "2",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, v := range vectors {
|
||||
s := NewScanner()
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
actual := s.isSupportedVersion(v.now, v.osFamily, v.osVersion)
|
||||
if actual != v.expected {
|
||||
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := amazon.NewScanner(amazon.WithClock(fake.NewFakeClock(tt.now)))
|
||||
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
14
pkg/detector/ospkg/amazon/testdata/fixtures/amazon.yaml
vendored
Normal file
14
pkg/detector/ospkg/amazon/testdata/fixtures/amazon.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
- bucket: amazon linux 1
|
||||
pairs:
|
||||
- bucket: bind
|
||||
pairs:
|
||||
- key: CVE-2020-8625
|
||||
value:
|
||||
FixedVersion: "32:9.8.2-0.68.rc1.86.amzn1"
|
||||
- bucket: amazon linux 2
|
||||
pairs:
|
||||
- bucket: bash
|
||||
pairs:
|
||||
- key: CVE-2019-9924
|
||||
value:
|
||||
FixedVersion: "4.2.46-34.amzn2"
|
||||
9
pkg/detector/ospkg/amazon/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/amazon/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: amazon linux 1
|
||||
pairs:
|
||||
- bucket: jq
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
@@ -4,14 +4,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/debian"
|
||||
debianoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/debian-oval"
|
||||
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/debian"
|
||||
debianoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/debian-oval"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
@@ -40,17 +39,38 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
type options struct {
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
type option func(*options)
|
||||
|
||||
func WithClock(clock clock.Clock) option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Scanner implements the Debian scanner
|
||||
type Scanner struct {
|
||||
ovalVs dbTypes.VulnSrc
|
||||
vs dbTypes.VulnSrc
|
||||
ovalVs debianoval.VulnSrc
|
||||
vs debian.VulnSrc
|
||||
*options
|
||||
}
|
||||
|
||||
// NewScanner is the factory method to return Scanner
|
||||
func NewScanner() *Scanner {
|
||||
func NewScanner(opts ...option) *Scanner {
|
||||
o := &options{
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
return &Scanner{
|
||||
ovalVs: debianoval.NewVulnSrc(),
|
||||
vs: debian.NewVulnSrc(),
|
||||
ovalVs: debianoval.NewVulnSrc(),
|
||||
vs: debian.NewVulnSrc(),
|
||||
options: o,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,11 +141,6 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned using Debian
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
}
|
||||
|
||||
func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool {
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
osVer = osVer[:strings.Index(osVer, ".")]
|
||||
}
|
||||
@@ -135,5 +150,5 @@ func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool
|
||||
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
|
||||
return false
|
||||
}
|
||||
return now.Before(eol)
|
||||
return s.clock.Now().Before(eol)
|
||||
}
|
||||
|
||||
@@ -1,182 +1,152 @@
|
||||
package debian
|
||||
package debian_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type MockOvalConfig struct {
|
||||
update func(string) error
|
||||
get func(string, string) ([]dbTypes.Advisory, error)
|
||||
}
|
||||
|
||||
func (mdc MockOvalConfig) Update(a string) error {
|
||||
if mdc.update != nil {
|
||||
return mdc.update(a)
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
type args struct {
|
||||
osVer string
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mdc MockOvalConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
|
||||
if mdc.get != nil {
|
||||
return mdc.get(a, b)
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
fixtures []string
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fixtures: []string{"testdata/fixtures/debian.yaml"},
|
||||
args: args{
|
||||
osVer: "9.1",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "htpasswd",
|
||||
Version: "2.4.24",
|
||||
SrcName: "apache2",
|
||||
SrcVersion: "2.4.24",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "htpasswd",
|
||||
VulnerabilityID: "CVE-2020-11985",
|
||||
InstalledVersion: "2.4.24",
|
||||
FixedVersion: "2.4.25-1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
{
|
||||
PkgName: "htpasswd",
|
||||
VulnerabilityID: "CVE-2021-31618",
|
||||
InstalledVersion: "2.4.24",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid bucket",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
args: args{
|
||||
osVer: "9.1",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "htpasswd",
|
||||
Version: "2.4.24",
|
||||
SrcName: "apache2",
|
||||
SrcVersion: "2.4.24",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to get Debian OVAL advisories",
|
||||
},
|
||||
}
|
||||
return []dbTypes.Advisory{}, nil
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
type MockDebianConfig struct {
|
||||
update func(string) error
|
||||
get func(string, string) ([]dbTypes.Advisory, error)
|
||||
}
|
||||
|
||||
func (mdc MockDebianConfig) Update(a string) error {
|
||||
if mdc.update != nil {
|
||||
return mdc.update(a)
|
||||
s := debian.NewScanner()
|
||||
got, err := s.Detect(tt.args.osVer, 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)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mdc MockDebianConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
|
||||
if mdc.get != nil {
|
||||
return mdc.get(a, b)
|
||||
}
|
||||
return []dbTypes.Advisory{}, nil
|
||||
}
|
||||
|
||||
func TestScanner_IsSupportedVersion(t *testing.T) {
|
||||
vectors := map[string]struct {
|
||||
now time.Time
|
||||
osFamily string
|
||||
osVersion string
|
||||
expected bool
|
||||
type args struct {
|
||||
osFamily string
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
"debian7": {
|
||||
now: time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "7",
|
||||
expected: false,
|
||||
{
|
||||
name: "debian 7",
|
||||
now: time.Date(2018, 3, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "debian",
|
||||
osVer: "7",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"debian8": {
|
||||
now: time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "8.11",
|
||||
expected: true,
|
||||
{
|
||||
name: "debian 8 EOL",
|
||||
now: time.Date(2020, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "debian",
|
||||
osVer: "8.2",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
"debian8 eol ends": {
|
||||
now: time.Date(2020, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "8.0",
|
||||
expected: false,
|
||||
},
|
||||
"debian9": {
|
||||
now: time.Date(2020, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "9",
|
||||
expected: true,
|
||||
},
|
||||
"debian9 eol ends": {
|
||||
now: time.Date(2022, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "9",
|
||||
expected: false,
|
||||
},
|
||||
"debian10": {
|
||||
now: time.Date(2020, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "10",
|
||||
expected: true,
|
||||
},
|
||||
"debian10 eol ends": {
|
||||
now: time.Date(2024, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "10",
|
||||
expected: false,
|
||||
},
|
||||
"unknown": {
|
||||
now: time.Date(2020, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "unknown",
|
||||
expected: false,
|
||||
{
|
||||
name: "unknown",
|
||||
now: time.Date(2020, 7, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "debian",
|
||||
osVer: "unknown",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, v := range vectors {
|
||||
s := NewScanner()
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
actual := s.isSupportedVersion(v.now, v.osFamily, v.osVersion)
|
||||
if actual != v.expected {
|
||||
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := debian.NewScanner(debian.WithClock(fake.NewFakeClock(tt.now)))
|
||||
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
s := &Scanner{
|
||||
vs: MockDebianConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, err error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "debian-123",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
ovalVs: MockOvalConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, e error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "oval-123",
|
||||
FixedVersion: "3.0.0",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "2.1.0",
|
||||
Release: "hotfix",
|
||||
SrcRelease: "test-hotfix",
|
||||
SrcVersion: "2.1.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foopkg",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "oval-123",
|
||||
PkgName: "testpkg",
|
||||
InstalledVersion: "2.1.0-test-hotfix",
|
||||
FixedVersion: "3.0.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "debian-123",
|
||||
PkgName: "testpkg",
|
||||
InstalledVersion: "2.1.0-test-hotfix",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
}, vuls)
|
||||
})
|
||||
|
||||
// TODO: Add unhappy paths
|
||||
}
|
||||
|
||||
17
pkg/detector/ospkg/debian/testdata/fixtures/debian.yaml
vendored
Normal file
17
pkg/detector/ospkg/debian/testdata/fixtures/debian.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
- bucket: debian 9
|
||||
pairs:
|
||||
- bucket: apache2
|
||||
pairs:
|
||||
- key: CVE-2021-31618
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- bucket: debian oval 9
|
||||
pairs:
|
||||
- bucket: apache2
|
||||
pairs:
|
||||
- key: CVE-2012-3499
|
||||
value:
|
||||
FixedVersion: "2.2.22-13"
|
||||
- key: CVE-2020-11985
|
||||
value:
|
||||
FixedVersion: "2.4.25-1"
|
||||
9
pkg/detector/ospkg/debian/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/debian/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: debian oval 9
|
||||
pairs:
|
||||
- bucket: apache2
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
oracleoval "github.com/aquasecurity/trivy-db/pkg/vulnsrc/oracle-oval"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -32,7 +31,7 @@ var (
|
||||
|
||||
// Scanner implements oracle vulnerability scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
vs oracleoval.VulnSrc
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@ package photon
|
||||
import (
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/photon"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -18,17 +16,15 @@ import (
|
||||
// eolDates = map[string]time.Time{}
|
||||
//)
|
||||
|
||||
// Scanner implements Photon scanner
|
||||
// Scanner implements the Photon scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
clock clock.Clock
|
||||
vs photon.VulnSrc
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
return &Scanner{
|
||||
vs: photon.NewVulnSrc(),
|
||||
clock: clock.RealClock{},
|
||||
vs: photon.NewVulnSrc(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +61,6 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
}
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
func (s *Scanner) IsSupportedVersion(_, _ string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,73 +1,92 @@
|
||||
package photon
|
||||
package photon_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/photon"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
type MockPhotonConfig struct {
|
||||
update func(string) error
|
||||
get func(string, string) ([]dbTypes.Advisory, error)
|
||||
}
|
||||
|
||||
func (mpc MockPhotonConfig) Update(a string) error {
|
||||
if mpc.update != nil {
|
||||
return mpc.update(a)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mpc MockPhotonConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
|
||||
if mpc.get != nil {
|
||||
return mpc.get(a, b)
|
||||
}
|
||||
return []dbTypes.Advisory{}, nil
|
||||
}
|
||||
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
s := &Scanner{
|
||||
vs: MockPhotonConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, err error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "photon-123",
|
||||
FixedVersion: "3.0.0",
|
||||
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/photon.yaml"},
|
||||
args: args{
|
||||
osVer: "1.0",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "PyYAML",
|
||||
Version: "3.12",
|
||||
Release: "4.ph1",
|
||||
SrcName: "PyYAML",
|
||||
SrcVersion: "3.12",
|
||||
SrcRelease: "4.ph1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "PyYAML",
|
||||
VulnerabilityID: "CVE-2020-1747",
|
||||
InstalledVersion: "3.12-4.ph1",
|
||||
FixedVersion: "3.12-5.ph1",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid bucket",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
args: args{
|
||||
osVer: "1.0",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "PyYAML",
|
||||
Version: "3.12",
|
||||
SrcName: "PyYAML",
|
||||
SrcVersion: "3.12",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to get Photon advisories",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "2.1.0",
|
||||
Release: "hotfix",
|
||||
SrcRelease: "test-hotfix",
|
||||
SrcVersion: "2.1.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
s := photon.NewScanner()
|
||||
got, err := s.Detect(tt.args.osVer, 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)
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "photon-123",
|
||||
PkgName: "testpkg",
|
||||
InstalledVersion: "2.1.0-hotfix",
|
||||
FixedVersion: "3.0.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
}, vuls)
|
||||
})
|
||||
|
||||
// TODO: Add unhappy paths
|
||||
}
|
||||
}
|
||||
|
||||
9
pkg/detector/ospkg/photon/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/photon/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: Photon OS 1.0
|
||||
pairs:
|
||||
- bucket: PyYAML
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
10
pkg/detector/ospkg/photon/testdata/fixtures/photon.yaml
vendored
Normal file
10
pkg/detector/ospkg/photon/testdata/fixtures/photon.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
- bucket: Photon OS 1.0
|
||||
pairs:
|
||||
- bucket: PyYAML
|
||||
pairs:
|
||||
- key: CVE-2017-18342
|
||||
value:
|
||||
FixedVersion: "3.12-3.ph1"
|
||||
- key: CVE-2020-1747
|
||||
value:
|
||||
FixedVersion: "3.12-5.ph1"
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
|
||||
version "github.com/knqyf263/go-rpm-version"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
"github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -38,15 +38,36 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements the Redhat scanner
|
||||
type options struct {
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
type option func(*options)
|
||||
|
||||
func WithClock(clock clock.Clock) option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Scanner implements the Alpine scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
vs redhat.VulnSrc
|
||||
*options
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
func NewScanner(opts ...option) *Scanner {
|
||||
o := &options{
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
return &Scanner{
|
||||
vs: redhat.NewVulnSrc(),
|
||||
vs: redhat.NewVulnSrc(),
|
||||
options: o,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +136,6 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned with Redhat scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
}
|
||||
|
||||
func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool {
|
||||
if strings.Count(osVer, ".") > 0 {
|
||||
osVer = osVer[:strings.Index(osVer, ".")]
|
||||
}
|
||||
@@ -135,7 +151,8 @@ func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool
|
||||
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
|
||||
return false
|
||||
}
|
||||
return now.Before(eolDate)
|
||||
|
||||
return s.clock.Now().Before(eolDate)
|
||||
}
|
||||
|
||||
func (s *Scanner) isFromSupportedVendor(pkg ftypes.Package) bool {
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
package redhat
|
||||
package redhat_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/redhat"
|
||||
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
@@ -20,14 +23,15 @@ func TestScanner_Detect(t *testing.T) {
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
get []dbTypes.GetExpectation
|
||||
want []types.DetectedVulnerability
|
||||
wantErr bool
|
||||
name string
|
||||
fixtures []string
|
||||
args args
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path: src pkg name is different from bin pkg name",
|
||||
name: "happy path: src pkg name is different from bin pkg name",
|
||||
fixtures: []string{"testdata/fixtures/redhat.yaml"},
|
||||
args: args{
|
||||
osVer: "7.6",
|
||||
pkgs: []ftypes.Package{
|
||||
@@ -47,40 +51,6 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
get: []dbTypes.GetExpectation{
|
||||
{
|
||||
Args: dbTypes.GetArgs{
|
||||
Release: "7",
|
||||
PkgName: "vim",
|
||||
},
|
||||
Returns: dbTypes.GetReturns{
|
||||
Advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2017-5953",
|
||||
FixedVersion: "",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2017-6350",
|
||||
FixedVersion: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: dbTypes.GetArgs{
|
||||
Release: "7",
|
||||
PkgName: "vim-minimal",
|
||||
},
|
||||
Returns: dbTypes.GetReturns{
|
||||
Advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-12735",
|
||||
FixedVersion: "2:7.4.160-6.el7_6",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2017-5953",
|
||||
@@ -110,9 +80,10 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path: src pkg name is the same as bin pkg name",
|
||||
name: "happy path: src pkg name is the same as bin pkg name",
|
||||
fixtures: []string{"testdata/fixtures/redhat.yaml"},
|
||||
args: args{
|
||||
osVer: "6.5",
|
||||
osVer: "7.3",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "nss",
|
||||
@@ -127,30 +98,6 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
get: []dbTypes.GetExpectation{
|
||||
{
|
||||
Args: dbTypes.GetArgs{
|
||||
Release: "6",
|
||||
PkgName: "nss",
|
||||
},
|
||||
Returns: dbTypes.GetReturns{
|
||||
Advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2015-2808",
|
||||
FixedVersion: "",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2016-2183",
|
||||
FixedVersion: "",
|
||||
},
|
||||
{
|
||||
VulnerabilityID: "CVE-2018-12404",
|
||||
FixedVersion: "3.44.0-4.el7",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2015-2808",
|
||||
@@ -171,7 +118,8 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path: modular packages",
|
||||
name: "happy path: modular packages",
|
||||
fixtures: []string{"testdata/fixtures/redhat.yaml"},
|
||||
args: args{
|
||||
osVer: "8.3",
|
||||
pkgs: []ftypes.Package{
|
||||
@@ -192,22 +140,6 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
get: []dbTypes.GetExpectation{
|
||||
{
|
||||
Args: dbTypes.GetArgs{
|
||||
Release: "8",
|
||||
PkgName: "php:7.2::php",
|
||||
},
|
||||
Returns: dbTypes.GetReturns{
|
||||
Advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-11043",
|
||||
FixedVersion: "7.3.5-5.module+el8.1.0+4560+e0eee7d6",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "CVE-2019-11043",
|
||||
@@ -221,7 +153,8 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path: packages from remi repository are skipped",
|
||||
name: "happy path: packages from remi repository are skipped",
|
||||
fixtures: []string{"testdata/fixtures/redhat.yaml"},
|
||||
args: args{
|
||||
osVer: "7.6",
|
||||
pkgs: []ftypes.Package{
|
||||
@@ -241,171 +174,105 @@ func TestScanner_Detect(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
get: []dbTypes.GetExpectation{
|
||||
{
|
||||
Args: dbTypes.GetArgs{
|
||||
Release: "7",
|
||||
PkgName: "php",
|
||||
},
|
||||
Returns: dbTypes.GetReturns{
|
||||
Advisories: []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "CVE-2011-4718",
|
||||
FixedVersion: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability(nil),
|
||||
},
|
||||
{
|
||||
name: "sad path: Get returns an error",
|
||||
name: "invalid bucket",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
args: args{
|
||||
osVer: "5",
|
||||
osVer: "6",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "nss",
|
||||
Name: "jq",
|
||||
Version: "3.36.0",
|
||||
Release: "7.1.el7_6",
|
||||
Epoch: 0,
|
||||
Arch: "x86_64",
|
||||
SrcName: "nss",
|
||||
SrcName: "jq",
|
||||
SrcVersion: "3.36.0",
|
||||
SrcRelease: "7.4.160",
|
||||
SrcEpoch: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
get: []dbTypes.GetExpectation{
|
||||
{
|
||||
Args: dbTypes.GetArgs{
|
||||
Release: "5",
|
||||
PkgName: "nss",
|
||||
},
|
||||
Returns: dbTypes.GetReturns{
|
||||
Err: xerrors.New("error"),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
wantErr: "failed to get Red Hat advisories",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockVs := new(dbTypes.MockVulnSrc)
|
||||
mockVs.ApplyGetExpectations(tt.get)
|
||||
s := &Scanner{
|
||||
vs: mockVs,
|
||||
}
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
s := redhat.NewScanner()
|
||||
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
|
||||
require.Equal(t, tt.wantErr, err != nil)
|
||||
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) {
|
||||
vectors := map[string]struct {
|
||||
now time.Time
|
||||
osFamily string
|
||||
osVersion string
|
||||
expected bool
|
||||
type args struct {
|
||||
osFamily string
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
"centos5": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "5.0",
|
||||
expected: false,
|
||||
{
|
||||
name: "centos 6",
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "centos",
|
||||
osVer: "6.8",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"centos6": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "6.7",
|
||||
expected: true,
|
||||
{
|
||||
name: "centos 6 EOL",
|
||||
now: time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "centos",
|
||||
osVer: "6.7",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
"centos6 (eol ends)": {
|
||||
now: time.Date(2020, 12, 1, 0, 0, 0, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "6.7",
|
||||
expected: false,
|
||||
{
|
||||
name: "two dots",
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "centos",
|
||||
osVer: "8.0.1",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"centos7": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "7.5",
|
||||
expected: true,
|
||||
{
|
||||
name: "rhel 8",
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "redhat",
|
||||
osVer: "8.0",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"centos8": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "8.0",
|
||||
expected: true,
|
||||
},
|
||||
"centos8 (eol ends)": {
|
||||
now: time.Date(2022, 12, 1, 0, 0, 0, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "8.0",
|
||||
expected: false,
|
||||
},
|
||||
"two dots": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "centos",
|
||||
osVersion: "8.0.1",
|
||||
expected: true,
|
||||
},
|
||||
"redhat5": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "redhat",
|
||||
osVersion: "5.0",
|
||||
expected: true,
|
||||
},
|
||||
"redhat6": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "redhat",
|
||||
osVersion: "6.7",
|
||||
expected: true,
|
||||
},
|
||||
"redhat6 (eol ends)": {
|
||||
now: time.Date(2024, 7, 1, 0, 0, 0, 0, time.UTC),
|
||||
osFamily: "redhat",
|
||||
osVersion: "6.7",
|
||||
expected: false,
|
||||
},
|
||||
"redhat7": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "redhat",
|
||||
osVersion: "7.5",
|
||||
expected: true,
|
||||
},
|
||||
"redhat8": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "redhat",
|
||||
osVersion: "8.0",
|
||||
expected: true,
|
||||
},
|
||||
"no dot": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "redhat",
|
||||
osVersion: "8",
|
||||
expected: true,
|
||||
},
|
||||
"debian": {
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "debian",
|
||||
osVersion: "8",
|
||||
expected: false,
|
||||
{
|
||||
name: "unknown",
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "unknown",
|
||||
osVer: "8.0",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, v := range vectors {
|
||||
s := NewScanner()
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
actual := s.isSupportedVersion(v.now, v.osFamily, v.osVersion)
|
||||
if actual != v.expected {
|
||||
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := redhat.NewScanner(redhat.WithClock(fake.NewFakeClock(tt.now)))
|
||||
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
9
pkg/detector/ospkg/redhat/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/redhat/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: Red Hat Enterprise Linux 6
|
||||
pairs:
|
||||
- bucket: jq
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
38
pkg/detector/ospkg/redhat/testdata/fixtures/redhat.yaml
vendored
Normal file
38
pkg/detector/ospkg/redhat/testdata/fixtures/redhat.yaml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
- bucket: Red Hat Enterprise Linux 7
|
||||
pairs:
|
||||
- bucket: php
|
||||
pairs:
|
||||
- key: CVE-2011-4718
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- bucket: vim
|
||||
pairs:
|
||||
- key: CVE-2017-5953
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- key: CVE-2017-6350
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- bucket: vim-minimal
|
||||
pairs:
|
||||
- key: CVE-2019-12735
|
||||
value:
|
||||
FixedVersion: "2:7.4.160-6.el7_6"
|
||||
- bucket: nss
|
||||
pairs:
|
||||
- key: CVE-2015-2808
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- key: CVE-2016-2183
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- key: CVE-2018-12404
|
||||
value:
|
||||
FixedVersion: "3.44.0-4.el7"
|
||||
- bucket: Red Hat Enterprise Linux 8
|
||||
pairs:
|
||||
- bucket: "php:7.2::php"
|
||||
pairs:
|
||||
- key: CVE-2019-11043
|
||||
value:
|
||||
FixedVersion: "7.3.5-5.module+el8.1.0+4560+e0eee7d6"
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
fos "github.com/aquasecurity/fanal/analyzer/os"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
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"
|
||||
@@ -57,13 +56,19 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements suse scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
type options struct {
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
// Type to define SUSE type
|
||||
type option func(*options)
|
||||
|
||||
func WithClock(clock clock.Clock) option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Type defines SUSE type
|
||||
type Type int
|
||||
|
||||
const (
|
||||
@@ -73,18 +78,32 @@ const (
|
||||
OpenSUSE
|
||||
)
|
||||
|
||||
// Scanner implements the Alpine scanner
|
||||
type Scanner struct {
|
||||
vs susecvrf.VulnSrc
|
||||
*options
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner(t Type) *Scanner {
|
||||
func NewScanner(t Type, opts ...option) *Scanner {
|
||||
o := &options{
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
|
||||
switch t {
|
||||
case SUSEEnterpriseLinux:
|
||||
return &Scanner{
|
||||
vs: susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinux),
|
||||
clock: clock.RealClock{},
|
||||
vs: susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinux),
|
||||
options: o,
|
||||
}
|
||||
case OpenSUSE:
|
||||
return &Scanner{
|
||||
vs: susecvrf.NewVulnSrc(susecvrf.OpenSUSE),
|
||||
clock: clock.RealClock{},
|
||||
vs: susecvrf.NewVulnSrc(susecvrf.OpenSUSE),
|
||||
options: o,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -1,153 +1,148 @@
|
||||
package suse
|
||||
package suse_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
susecvrf "github.com/aquasecurity/trivy-db/pkg/vulnsrc/suse-cvrf"
|
||||
|
||||
"k8s.io/utils/clock"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/suse"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
type MockSuseConfig struct {
|
||||
update func(string) error
|
||||
get func(string, string) ([]dbTypes.Advisory, error)
|
||||
}
|
||||
|
||||
func (msc MockSuseConfig) Update(a string) error {
|
||||
if msc.update != nil {
|
||||
return msc.update(a)
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
type args struct {
|
||||
osVer string
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msc MockSuseConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
|
||||
if msc.get != nil {
|
||||
return msc.get(a, b)
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
fixtures []string
|
||||
distribution suse.Type
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fixtures: []string{"testdata/fixtures/suse.yaml"},
|
||||
distribution: suse.OpenSUSE,
|
||||
args: args{
|
||||
osVer: "15.3",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "postgresql",
|
||||
Version: "13",
|
||||
Release: "4.6.6",
|
||||
SrcName: "postgresql",
|
||||
SrcVersion: "13",
|
||||
SrcRelease: "4.6.6",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "postgresql",
|
||||
VulnerabilityID: "SUSE-SU-2021:0175-1",
|
||||
InstalledVersion: "13-4.6.6",
|
||||
FixedVersion: "13-4.6.7",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broken bucket",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
distribution: suse.SUSEEnterpriseLinux,
|
||||
args: args{
|
||||
osVer: "15.3",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
Version: "1.6-r0",
|
||||
SrcName: "jq",
|
||||
SrcVersion: "1.6-r0",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to get SUSE advisories",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
s := suse.NewScanner(tt.distribution)
|
||||
got, err := s.Detect(tt.args.osVer, 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)
|
||||
})
|
||||
}
|
||||
return []dbTypes.Advisory{}, nil
|
||||
}
|
||||
|
||||
func TestScanner_IsSupportedVersion(t *testing.T) {
|
||||
vectors := map[string]struct {
|
||||
clock clock.Clock
|
||||
osFamily string
|
||||
osVersion string
|
||||
distribution susecvrf.Distribution
|
||||
expected bool
|
||||
type args struct {
|
||||
osFamily string
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
distribution suse.Type
|
||||
args args
|
||||
want 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,
|
||||
{
|
||||
name: "opensuse.leap42.3",
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "opensuse.leap",
|
||||
osVer: "42.3",
|
||||
},
|
||||
distribution: suse.OpenSUSE,
|
||||
want: 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,
|
||||
{
|
||||
name: "sles12.3",
|
||||
now: time.Date(2019, 5, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "suse linux enterprise server",
|
||||
osVer: "12.3",
|
||||
},
|
||||
distribution: suse.SUSEEnterpriseLinux,
|
||||
want: false,
|
||||
},
|
||||
"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,
|
||||
{
|
||||
name: "unknown",
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "unknown",
|
||||
osVer: "unknown",
|
||||
},
|
||||
want: 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)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := suse.NewScanner(tt.distribution, suse.WithClock(fake.NewFakeClock(tt.now)))
|
||||
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
s := &Scanner{
|
||||
vs: MockSuseConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, err error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "suse-123",
|
||||
FixedVersion: "3.0.0",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "2.1.0",
|
||||
Release: "hotfix",
|
||||
SrcRelease: "test-hotfix",
|
||||
SrcVersion: "2.1.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "suse-123",
|
||||
PkgName: "testpkg",
|
||||
InstalledVersion: "2.1.0-hotfix",
|
||||
FixedVersion: "3.0.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
}, vuls)
|
||||
})
|
||||
|
||||
// TODO: Add unhappy paths
|
||||
}
|
||||
|
||||
9
pkg/detector/ospkg/suse/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/suse/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: SUSE Linux Enterprise 15.3
|
||||
pairs:
|
||||
- bucket: jq
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
10
pkg/detector/ospkg/suse/testdata/fixtures/suse.yaml
vendored
Normal file
10
pkg/detector/ospkg/suse/testdata/fixtures/suse.yaml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
- bucket: openSUSE Leap 15.3
|
||||
pairs:
|
||||
- bucket: postgresql
|
||||
pairs:
|
||||
- key: SUSE-SU-2021:0175-1
|
||||
value:
|
||||
FixedVersion: "13-4.6.7"
|
||||
- key: CVE-2021-0001
|
||||
value:
|
||||
FixedVersion: ""
|
||||
9
pkg/detector/ospkg/ubuntu/testdata/fixtures/invalid.yaml
vendored
Normal file
9
pkg/detector/ospkg/ubuntu/testdata/fixtures/invalid.yaml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
- bucket: ubuntu 21.04
|
||||
pairs:
|
||||
- bucket: jq
|
||||
pairs:
|
||||
- key: CVE-2020-8177
|
||||
value:
|
||||
FixedVersion:
|
||||
- foo
|
||||
- bar
|
||||
13
pkg/detector/ospkg/ubuntu/testdata/fixtures/ubuntu.yaml
vendored
Normal file
13
pkg/detector/ospkg/ubuntu/testdata/fixtures/ubuntu.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
- bucket: ubuntu 20.04
|
||||
pairs:
|
||||
- bucket: wpa
|
||||
pairs:
|
||||
- key: CVE-2021-27803
|
||||
value:
|
||||
FixedVersion: "2:2.9-1ubuntu4.3"
|
||||
- key: CVE-2019-9243
|
||||
value:
|
||||
FixedVersion: ""
|
||||
- key: CVE-2016-4476
|
||||
value:
|
||||
FixedVersion: "2.4-0ubuntu10"
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/ubuntu"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||
@@ -54,15 +54,36 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Scanner implements the Ubuntu scanner
|
||||
type options struct {
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
type option func(*options)
|
||||
|
||||
func WithClock(clock clock.Clock) option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Scanner implements the Alpine scanner
|
||||
type Scanner struct {
|
||||
vs dbTypes.VulnSrc
|
||||
vs ubuntu.VulnSrc
|
||||
*options
|
||||
}
|
||||
|
||||
// NewScanner is the factory method for Scanner
|
||||
func NewScanner() *Scanner {
|
||||
func NewScanner(opts ...option) *Scanner {
|
||||
o := &options{
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
return &Scanner{
|
||||
vs: ubuntu.NewVulnSrc(),
|
||||
vs: ubuntu.NewVulnSrc(),
|
||||
options: o,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,15 +137,10 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
|
||||
|
||||
// IsSupportedVersion checks is OSFamily can be scanned using Ubuntu scanner
|
||||
func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
|
||||
now := time.Now()
|
||||
return s.isSupportedVersion(now, osFamily, osVer)
|
||||
}
|
||||
|
||||
func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool {
|
||||
eol, ok := eolDates[osVer]
|
||||
if !ok {
|
||||
log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer)
|
||||
return false
|
||||
}
|
||||
return now.Before(eol)
|
||||
return s.clock.Now().Before(eol)
|
||||
}
|
||||
|
||||
@@ -1,131 +1,149 @@
|
||||
package ubuntu
|
||||
package ubuntu_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
ftypes "github.com/aquasecurity/fanal/types"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/dbtest"
|
||||
"github.com/aquasecurity/trivy/pkg/detector/ospkg/ubuntu"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
type MockUbuntuConfig struct {
|
||||
update func(string) error
|
||||
get func(string, string) ([]dbTypes.Advisory, error)
|
||||
}
|
||||
|
||||
func (muc MockUbuntuConfig) Update(a string) error {
|
||||
if muc.update != nil {
|
||||
return muc.update(a)
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
type args struct {
|
||||
osVer string
|
||||
pkgs []ftypes.Package
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (muc MockUbuntuConfig) Get(a string, b string) ([]dbTypes.Advisory, error) {
|
||||
if muc.get != nil {
|
||||
return muc.get(a, b)
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
fixtures []string
|
||||
want []types.DetectedVulnerability
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
fixtures: []string{"testdata/fixtures/ubuntu.yaml"},
|
||||
args: args{
|
||||
osVer: "20.04",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "wpa",
|
||||
Version: "2.9",
|
||||
SrcName: "wpa",
|
||||
SrcVersion: "2.9",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []types.DetectedVulnerability{
|
||||
{
|
||||
PkgName: "wpa",
|
||||
VulnerabilityID: "CVE-2019-9243",
|
||||
InstalledVersion: "2.9",
|
||||
FixedVersion: "",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
{
|
||||
PkgName: "wpa",
|
||||
VulnerabilityID: "CVE-2021-27803",
|
||||
InstalledVersion: "2.9",
|
||||
FixedVersion: "2:2.9-1ubuntu4.3",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broken bucket",
|
||||
fixtures: []string{"testdata/fixtures/invalid.yaml"},
|
||||
args: args{
|
||||
osVer: "21.04",
|
||||
pkgs: []ftypes.Package{
|
||||
{
|
||||
Name: "jq",
|
||||
Version: "1.6-r0",
|
||||
SrcName: "jq",
|
||||
SrcVersion: "1.6-r0",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to get Ubuntu advisories",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_ = dbtest.InitDB(t, tt.fixtures)
|
||||
defer db.Close()
|
||||
|
||||
s := ubuntu.NewScanner()
|
||||
got, err := s.Detect(tt.args.osVer, 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)
|
||||
})
|
||||
}
|
||||
return []dbTypes.Advisory{}, nil
|
||||
}
|
||||
|
||||
func TestScanner_IsSupportedVersion(t *testing.T) {
|
||||
vectors := map[string]struct {
|
||||
now time.Time
|
||||
osFamily string
|
||||
osVersion string
|
||||
expected bool
|
||||
type args struct {
|
||||
osFamily string
|
||||
osVer string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
"ubuntu12.04 eol ends": {
|
||||
now: time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "ubuntu",
|
||||
osVersion: "12.04",
|
||||
expected: true,
|
||||
{
|
||||
name: "ubuntu 12.04 eol ends",
|
||||
now: time.Date(2019, 3, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "ubuntu",
|
||||
osVer: "12.04",
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
"ubuntu12.04": {
|
||||
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "ubuntu",
|
||||
osVersion: "12.04",
|
||||
expected: false,
|
||||
{
|
||||
name: "ubuntu12.04",
|
||||
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "ubuntu",
|
||||
osVer: "12.04",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
"ubuntu12.10": {
|
||||
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "ubuntu",
|
||||
osVersion: "12.10",
|
||||
expected: false,
|
||||
},
|
||||
"ubuntu18.04": {
|
||||
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "ubuntu",
|
||||
osVersion: "18.04",
|
||||
expected: true,
|
||||
},
|
||||
"ubuntu19.04": {
|
||||
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "ubuntu",
|
||||
osVersion: "19.04",
|
||||
expected: true,
|
||||
},
|
||||
"unknown": {
|
||||
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
|
||||
osFamily: "ubuntu",
|
||||
osVersion: "unknown",
|
||||
expected: false,
|
||||
{
|
||||
name: "unknown",
|
||||
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
|
||||
args: args{
|
||||
osFamily: "ubuntu",
|
||||
osVer: "unknown",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for testName, v := range vectors {
|
||||
s := NewScanner()
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
actual := s.isSupportedVersion(v.now, v.osFamily, v.osVersion)
|
||||
if actual != v.expected {
|
||||
t.Errorf("[%s] got %v, want %v", testName, actual, v.expected)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := ubuntu.NewScanner(ubuntu.WithClock(fake.NewFakeClock(tt.now)))
|
||||
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanner_Detect(t *testing.T) {
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
s := &Scanner{
|
||||
vs: MockUbuntuConfig{
|
||||
get: func(s string, s2 string) (advisories []dbTypes.Advisory, err error) {
|
||||
return []dbTypes.Advisory{
|
||||
{
|
||||
VulnerabilityID: "ubuntu-123",
|
||||
FixedVersion: "3.0.0",
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vuls, err := s.Detect("3.1.0", []ftypes.Package{
|
||||
{
|
||||
Name: "testpkg",
|
||||
Version: "2.1.0",
|
||||
Release: "hotfix",
|
||||
SrcRelease: "test-hotfix",
|
||||
SrcVersion: "2.1.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []types.DetectedVulnerability{
|
||||
{
|
||||
VulnerabilityID: "ubuntu-123",
|
||||
PkgName: "testpkg",
|
||||
InstalledVersion: "2.1.0-test-hotfix",
|
||||
FixedVersion: "3.0.0",
|
||||
Layer: ftypes.Layer{
|
||||
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
|
||||
},
|
||||
},
|
||||
}, vuls)
|
||||
})
|
||||
|
||||
// TODO: Add unhappy paths
|
||||
}
|
||||
|
||||
@@ -104,8 +104,8 @@ func (c Client) getVendorSeverity(vuln *types.DetectedVulnerability, source stri
|
||||
}
|
||||
|
||||
// Try NVD as a fallback if it exists
|
||||
if vs, ok := vuln.VendorSeverity[vulnerability.Nvd]; ok {
|
||||
return vs.String(), vulnerability.Nvd
|
||||
if vs, ok := vuln.VendorSeverity[vulnerability.NVD]; ok {
|
||||
return vs.String(), vulnerability.NVD
|
||||
}
|
||||
|
||||
if vuln.Severity == "" {
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) {
|
||||
LastModifiedDate: utils.MustTimeParse("2020-01-01T01:01:00Z"),
|
||||
PublishedDate: utils.MustTimeParse("2001-01-01T01:01:00Z"),
|
||||
},
|
||||
SeveritySource: vulnerability.Nvd,
|
||||
SeveritySource: vulnerability.NVD,
|
||||
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2019-0002",
|
||||
},
|
||||
},
|
||||
@@ -118,7 +118,7 @@ func TestClient_FillVulnerabilityInfo(t *testing.T) {
|
||||
CweIDs: []string{"CWE-311"},
|
||||
References: []string{"http://example.com"},
|
||||
CVSS: map[string]dbTypes.CVSS{
|
||||
vulnerability.Nvd: {
|
||||
vulnerability.NVD: {
|
||||
V2Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||
V2Score: 4.5,
|
||||
V3Vector: "CVSS:3.0/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
SrcVersion: "1.2.3",
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
License: "MIT",
|
||||
License: "MIT",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -55,7 +55,7 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
SrcVersion: "1.2.3",
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
License: "MIT",
|
||||
License: "MIT",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -90,7 +90,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
SrcVersion: "1.2.3",
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
License: "MIT",
|
||||
License: "MIT",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -105,7 +105,7 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
SrcVersion: "1.2.3",
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
License: "MIT",
|
||||
License: "MIT",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -329,7 +329,7 @@ func TestConvertFromRPCResults(t *testing.T) {
|
||||
Title: "DoS",
|
||||
Description: "Denial of Service",
|
||||
Severity: common.Severity_MEDIUM,
|
||||
SeveritySource: vulnerability.Nvd,
|
||||
SeveritySource: vulnerability.NVD,
|
||||
CweIds: []string{"CWE-123", "CWE-456"},
|
||||
Cvss: map[string]*common.CVSS{
|
||||
"redhat": {
|
||||
@@ -365,7 +365,7 @@ func TestConvertFromRPCResults(t *testing.T) {
|
||||
Digest: "sha256:154ad0735c360b212b167f424d33a62305770a1fcfb6363882f5c436cfbd9812",
|
||||
DiffID: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
|
||||
},
|
||||
SeveritySource: vulnerability.Nvd,
|
||||
SeveritySource: vulnerability.NVD,
|
||||
PrimaryURL: "https://avd.aquasec.com/nvd/CVE-2019-0001",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: "DoS",
|
||||
@@ -405,7 +405,7 @@ func TestConvertFromRPCResults(t *testing.T) {
|
||||
Title: "DoS",
|
||||
Description: "Denial of Service",
|
||||
Severity: common.Severity_MEDIUM,
|
||||
SeveritySource: vulnerability.Nvd,
|
||||
SeveritySource: vulnerability.NVD,
|
||||
CweIds: []string{"CWE-123", "CWE-456"},
|
||||
Cvss: map[string]*common.CVSS{
|
||||
"redhat": {
|
||||
@@ -441,7 +441,7 @@ func TestConvertFromRPCResults(t *testing.T) {
|
||||
Digest: "sha256:154ad0735c360b212b167f424d33a62305770a1fcfb6363882f5c436cfbd9812",
|
||||
DiffID: "sha256:b2a1a2d80bf0c747a4f6b0ca6af5eef23f043fcdb1ed4f3a3e750aef2dc68079",
|
||||
},
|
||||
SeveritySource: vulnerability.Nvd,
|
||||
SeveritySource: vulnerability.NVD,
|
||||
PrimaryURL: "https://avd.aquasec.com/nvd/CVE-2019-0001",
|
||||
Vulnerability: dbTypes.Vulnerability{
|
||||
Title: "DoS",
|
||||
|
||||
Reference in New Issue
Block a user