diff --git a/go.mod b/go.mod index ea65d56a2f41..ca061ec875dc 100644 --- a/go.mod +++ b/go.mod @@ -116,6 +116,8 @@ require ( modernc.org/sqlite v1.23.1 ) +require github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c + require ( cloud.google.com/go v0.110.7 // indirect cloud.google.com/go/compute v1.23.0 // indirect diff --git a/go.sum b/go.sum index ebf176383970..0a2ceabc86fe 100644 --- a/go.sum +++ b/go.sum @@ -516,6 +516,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c h1:C4UZIaS+HAw+X6jGUsoP2ZbM99PuqhCttjomg1yhNAI= +github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= diff --git a/pkg/detector/library/compare/bitnami/compare.go b/pkg/detector/library/compare/bitnami/compare.go new file mode 100644 index 000000000000..f3f62a7194d1 --- /dev/null +++ b/pkg/detector/library/compare/bitnami/compare.go @@ -0,0 +1,32 @@ +package bitnami + +import ( + version "github.com/bitnami/go-version/pkg/version" + "golang.org/x/xerrors" + + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy/pkg/detector/library/compare" +) + +// Comparer represents a comparer for Bitnami +type Comparer struct{} + +// IsVulnerable checks if the package version is vulnerable to the advisory. +func (n Comparer) IsVulnerable(ver string, advisory dbTypes.Advisory) bool { + return compare.IsVulnerable(ver, advisory, n.matchVersion) +} + +// matchVersion checks if the package version satisfies the given constraint. +func (n Comparer) matchVersion(currentVersion, constraint string) (bool, error) { + v, err := version.Parse(currentVersion) + if err != nil { + return false, xerrors.Errorf("bitnami version error (%s): %s", currentVersion, err) + } + + c, err := version.NewConstraints(constraint) + if err != nil { + return false, xerrors.Errorf("bitnami constraint error (%s): %s", constraint, err) + } + + return c.Check(v), nil +} diff --git a/pkg/detector/library/compare/bitnami/compare_test.go b/pkg/detector/library/compare/bitnami/compare_test.go new file mode 100644 index 000000000000..fda9c5e5f0e0 --- /dev/null +++ b/pkg/detector/library/compare/bitnami/compare_test.go @@ -0,0 +1,141 @@ +package bitnami_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy/pkg/detector/library/compare/bitnami" +) + +func TestBitnamiComparer_IsVulnerable(t *testing.T) { + type args struct { + currentVersion string + advisory types.Advisory + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "not vulnerable", + args: args{ + currentVersion: "1.2.3", + advisory: types.Advisory{ + VulnerableVersions: []string{"<1.2.3"}, + }, + }, + want: false, + }, + { + name: "vulnerable", + args: args{ + currentVersion: "1.2.3", + advisory: types.Advisory{ + VulnerableVersions: []string{"<=1.2.3"}, + }, + }, + want: true, + }, + { + name: "patched", + args: args{ + currentVersion: "1.2.3", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.3"}, + }, + }, + want: false, + }, + { + name: "unaffected", + args: args{ + currentVersion: "1.2.3", + advisory: types.Advisory{ + UnaffectedVersions: []string{"=1.2.3"}, + }, + }, + want: false, + }, + { + name: "vulnerable based on patched & unaffected versions", + args: args{ + currentVersion: "1.2.3", + advisory: types.Advisory{ + UnaffectedVersions: []string{"=1.2.0"}, + PatchedVersions: []string{">=1.2.4"}, + }, + }, + want: true, + }, + { + name: "patched with revision on current version", + args: args{ + currentVersion: "1.2.3-1", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.3"}, + }, + }, + want: false, + }, + { + name: "vulnerable with revision on current version", + args: args{ + currentVersion: "1.2.3-1", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.4"}, + }, + }, + want: true, + }, + { + name: "patched with revision on patch", + args: args{ + currentVersion: "1.2.4", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.3-1"}, + }, + }, + want: false, + }, + { + name: "vulnerable with revision on patch", + args: args{ + currentVersion: "1.2.3", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.3-1"}, + }, + }, + want: true, + }, + { + name: "patched with revisions on both current and patch", + args: args{ + currentVersion: "1.2.4-2", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.3-1"}, + }, + }, + want: false, + }, + { + name: "vulnerable with revision on both current and patch", + args: args{ + currentVersion: "1.2.3-0", + advisory: types.Advisory{ + PatchedVersions: []string{">=1.2.3-1"}, + }, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := bitnami.Comparer{} + got := b.IsVulnerable(tt.args.currentVersion, tt.args.advisory) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/detector/library/driver.go b/pkg/detector/library/driver.go index e18f926a3964..b2f5b6babc38 100644 --- a/pkg/detector/library/driver.go +++ b/pkg/detector/library/driver.go @@ -11,6 +11,7 @@ import ( dbTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" "github.com/aquasecurity/trivy/pkg/detector/library/compare" + "github.com/aquasecurity/trivy/pkg/detector/library/compare/bitnami" "github.com/aquasecurity/trivy/pkg/detector/library/compare/maven" "github.com/aquasecurity/trivy/pkg/detector/library/compare/npm" "github.com/aquasecurity/trivy/pkg/detector/library/compare/pep440" @@ -76,7 +77,7 @@ func NewDriver(libType ftypes.LangType) (Driver, bool) { return Driver{}, false case ftypes.Bitnami: ecosystem = vulnerability.Bitnami - comparer = compare.GenericComparer{} + comparer = bitnami.Comparer{} case ftypes.K8sUpstream: ecosystem = vulnerability.Kubernetes comparer = compare.GenericComparer{}