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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions pkg/detector/ospkg/ubuntu/ubuntu.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ var (
"18.10": time.Date(2019, 7, 18, 23, 59, 59, 0, time.UTC),
"19.04": time.Date(2020, 1, 18, 23, 59, 59, 0, time.UTC),
"19.10": time.Date(2020, 7, 17, 23, 59, 59, 0, time.UTC),
"20.04": time.Date(2025, 4, 23, 23, 59, 59, 0, time.UTC),
"20.04": time.Date(2025, 5, 31, 23, 59, 59, 0, time.UTC),
"20.04-ESM": time.Date(2030, 4, 30, 23, 59, 59, 0, time.UTC),
"20.10": time.Date(2021, 7, 22, 23, 59, 59, 0, time.UTC),
"21.04": time.Date(2022, 1, 20, 23, 59, 59, 0, time.UTC),
"21.10": time.Date(2022, 7, 14, 23, 59, 59, 0, time.UTC),
Expand All @@ -67,15 +68,37 @@ var (
}
)

type options struct {
eolDates map[string]time.Time
}

type Option func(*options)

// WithEOLDates takes eol dates for testability
func WithEOLDates(dates map[string]time.Time) Option {
return func(opts *options) {
opts.eolDates = dates
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type Option func(*options)
// WithEOLDates takes eol dates for testability
func WithEOLDates(dates map[string]time.Time) Option {
return func(opts *options) {
opts.eolDates = dates
}
}
type Option func(*Scanner)
// WithEOLDates takes eol dates for testability
func WithEOLDates(dates map[string]time.Time) Option {
return func(s *Scanner) {
s.eolDates = dates
}
}


// Scanner implements the Ubuntu scanner
type Scanner struct {
*options
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Since there is only one field, defining a new struct may be too much. We may want to add the field directly rather than embedding.

Suggested change
*options
eolDates map[string]time.Time

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks simpler, thanks!
updated in dd44435

vs ubuntu.VulnSrc
}

// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
func NewScanner(opts ...Option) *Scanner {
o := &options{
eolDates: eolDates,
}

for _, opt := range opts {
opt(o)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
o := &options{
eolDates: eolDates,
}
for _, opt := range opts {
opt(o)
}
s := &Scanner{
eolDates: eolDates,
vs: ubuntu.NewVulnSrc(),
}
for _, opt := range opts {
opt(s)
}
return s

return &Scanner{
vs: ubuntu.NewVulnSrc(),
options: o,
vs: ubuntu.NewVulnSrc(),
}
}

Expand Down Expand Up @@ -133,12 +156,13 @@ func (s *Scanner) Detect(ctx context.Context, osVer string, _ *ftypes.Repository

// IsSupportedVersion checks is OSFamily can be scanned using Ubuntu scanner
func (s *Scanner) IsSupportedVersion(ctx context.Context, osFamily ftypes.OSType, osVer string) bool {
return osver.Supported(ctx, eolDates, osFamily, osVer)
osVer = s.versionFromEolDates(ctx, osVer)
return osver.Supported(ctx, s.eolDates, osFamily, osVer)
}

// versionFromEolDates checks if actual (not ESM) version is not outdated
func (s *Scanner) versionFromEolDates(ctx context.Context, osVer string) string {
if _, ok := eolDates[osVer]; ok {
if _, ok := s.eolDates[osVer]; ok {
return osVer
}

Expand All @@ -148,7 +172,7 @@ func (s *Scanner) versionFromEolDates(ctx context.Context, osVer string) string
// then we need to get vulnerabilities for `18.04`
// if `18.04` is outdated - we need to use `18.04-ESM` (we will return error until we add `18.04-ESM` to eolDates)
ver := strings.TrimRight(osVer, "-ESM")
if eol, ok := eolDates[ver]; ok && clock.Now(ctx).Before(eol) {
if eol, ok := s.eolDates[ver]; ok && clock.Now(ctx).Before(eol) {
return ver
}
return osVer
Expand Down
69 changes: 56 additions & 13 deletions pkg/detector/ospkg/ubuntu/ubuntu_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ubuntu_test

import (
"bytes"
"sort"
"testing"
"time"
Expand All @@ -15,9 +16,20 @@ import (
"github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/ubuntu"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
)

var testEOLDates = map[string]time.Time{
"12.04": time.Date(2019, 4, 26, 23, 59, 59, 0, time.UTC),
"12.04-ESM": time.Date(2019, 4, 28, 23, 59, 59, 0, time.UTC),
"18.04": time.Date(2023, 5, 31, 23, 59, 59, 0, time.UTC),
"18.04-ESM": time.Date(2028, 3, 31, 23, 59, 59, 0, time.UTC),
"19.04": time.Date(2020, 1, 18, 23, 59, 59, 0, time.UTC),
"20.04": time.Date(2025, 5, 31, 23, 59, 59, 0, time.UTC),
"21.04": time.Date(2022, 1, 20, 23, 59, 59, 0, time.UTC),
}

func TestScanner_Detect(t *testing.T) {
type args struct {
osVer string
Expand Down Expand Up @@ -180,7 +192,7 @@ func TestScanner_Detect(t *testing.T) {
_ = dbtest.InitDB(t, tt.fixtures)
defer db.Close()

s := ubuntu.NewScanner()
s := ubuntu.NewScanner(ubuntu.WithEOLDates(testEOLDates))
got, err := s.Detect(ctx, tt.args.osVer, nil, tt.args.pkgs)
if tt.wantErr != "" {
require.ErrorContains(t, err, tt.wantErr)
Expand All @@ -201,10 +213,11 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
osVer string
}
tests := []struct {
name string
now time.Time
args args
want bool
name string
now time.Time
args args
want bool
wantLog string
}{
{
name: "ubuntu 12.04 eol ends",
Expand All @@ -216,7 +229,7 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
want: true,
},
{
name: "ubuntu12.04",
name: "ubuntu 12.04",
now: time.Date(2019, 4, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "ubuntu",
Expand All @@ -225,22 +238,41 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
want: false,
},
{
name: "ubuntu 18.04 ESM. 18.04 is not outdated",
now: time.Date(2022, 4, 31, 23, 59, 59, 0, time.UTC),
name: "ubuntu 18.04 ESM and 18.04 are outdated",
now: time.Date(2030, 4, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "ubuntu",
osVer: "18.04-ESM",
},
want: false,
},
{
name: "ubuntu 18.04 ESM. Only 18.04 is outdated",
now: time.Date(2027, 4, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "ubuntu",
osVer: "18.04-ESM",
},
want: true,
},
{
name: "ubuntu 18.04 ESM. 18.04 is outdated",
name: "ubuntu 20.04 ESM. 20.04 is not outdated, 20.04 ESM not added in EOL dates",
now: time.Date(2022, 4, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "ubuntu",
osVer: "20.04-ESM",
},
want: true,
},
{
name: "ubuntu 20.04 ESM. 20.04 is outdated, 20.04 ESM not added in EOL dates",
now: time.Date(2030, 4, 31, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "ubuntu",
osVer: "18.04-ESM",
osVer: "20.04-ESM",
},
want: false,
want: true,
wantLog: "This OS version is not on the EOL list\tfamily=\"ubuntu\" version=\"20.04-ESM\"",
},
{
name: "latest",
Expand All @@ -249,15 +281,26 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
osFamily: "ubuntu",
osVer: "99.04",
},
want: true,
want: true,
wantLog: "This OS version is not on the EOL list\tfamily=\"ubuntu\" version=\"99.04\"",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := bytes.NewBuffer(nil)
logger := log.New(log.NewHandler(out, &log.Options{Level: log.LevelInfo}))
log.SetDefault(logger)

ctx := clock.With(t.Context(), tt.now)
s := ubuntu.NewScanner()
s := ubuntu.NewScanner(ubuntu.WithEOLDates(testEOLDates))
got := s.IsSupportedVersion(ctx, tt.args.osFamily, tt.args.osVer)
assert.Equal(t, tt.want, got)

if out.Len() > 0 && tt.wantLog == "" {
t.Errorf("IsSupportedVersion() logs not expected. Found logs: %s", out.String())
return
}
assert.Contains(t, out.String(), tt.wantLog)
})
}
}