From bc616d87ed1a72f1da929bbb6e84409bfa3fbfdb Mon Sep 17 00:00:00 2001 From: Andreas Salhus Bakseter <141913422+baksetercx@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:05:48 +0100 Subject: [PATCH] Use Trivy GCR for Trivy vuln database https://github.com/aquasecurity/trivy/issues/7938 --- pkg/scan/scan.go | 53 +++++++++++++++++-- pkg/scan/scan_test.go | 119 +++++++++++++++++++++++++++++++++++------- 2 files changed, 150 insertions(+), 22 deletions(-) diff --git a/pkg/scan/scan.go b/pkg/scan/scan.go index aaad869..55b5f88 100644 --- a/pkg/scan/scan.go +++ b/pkg/scan/scan.go @@ -7,11 +7,13 @@ import ( "os" "os/exec" "slices" + "strings" "github.com/3lvia/cli/pkg/command" "github.com/3lvia/cli/pkg/shared" "github.com/3lvia/cli/pkg/utils" "github.com/urfave/cli/v2" + "golang.org/x/mod/semver" ) const commandName = "scan" @@ -57,6 +59,7 @@ func scanImageCommand( imageName string, severity string, disableError bool, + versionOlderThan0_57_1 bool, runOptions *command.RunOptions, ) command.Output { exitCode := func() string { @@ -78,10 +81,6 @@ func scanImageCommand( "json", "--output", "trivy.json", - "--db-repository", - "ghcr.io/3lvia/trivy-db", - "--java-db-repository", - "ghcr.io/3lvia/trivy-java-db", "--ignore-unfixed", "--exit-code", exitCode, @@ -89,6 +88,15 @@ func scanImageCommand( "vuln", ) + // Before v0.57.1, the default database repository was using Aqua's GHCR which was heavily rate-limited. + // To circumvent this, we used a mirror of the database repository hosted on 3lvia's GHCR. + // This is no longer necessary as the default database repository is now hosted on Google Container Registry. + // So, we will only explicitly set the database repository if the version is older than 0.57.1. + if versionOlderThan0_57_1 { + cmd.Args = append(cmd.Args, "--db-repository", "mirror.gcr.io/aquasec/trivy-db:2") + cmd.Args = append(cmd.Args, "--java-db-repository", "mirror.gcr.io/aquasec/trivy-java-db:1") + } + cmd.Args = append(cmd.Args, imageName) return command.Run(*cmd, runOptions) @@ -135,10 +143,19 @@ func ScanImage( formats []string, disableError bool, ) error { + version, err := getTrivyVersion() + if err != nil { + log.Printf("Could not get Trivy version: %v", err) + log.Println("Will assume version is older than 0.57.1 and continue.") + } else { + log.Printf("Trivy version: %s", version) + } + scanImageOutput := scanImageCommand( imageName, severity, disableError, + checkIfVersionOlderThan0_57_1(version), nil, ) @@ -212,3 +229,31 @@ func ScanImage( return nil } + +func checkIfVersionOlderThan0_57_1(version string) bool { + if version == "" { + return true + } + + return semver.Compare(version, "v0.57.1") == -1 +} + +func getTrivyVersion() (string, error) { + cmd := exec.Command("trivy", "--version") + output := command.Run(*cmd, nil) + if command.IsError(output) { + return "", output.Error + } + + versionLine := strings.Split(output.Output, "\n") + if len(versionLine) < 1 { + return "", fmt.Errorf("Trivy version not found") + } + + version, wasFound := strings.CutPrefix(versionLine[0], "Version: ") + if !wasFound { + return "", fmt.Errorf("Trivy version not found") + } + + return "v" + version, nil +} diff --git a/pkg/scan/scan_test.go b/pkg/scan/scan_test.go index 4c37bb0..ea6bd6a 100644 --- a/pkg/scan/scan_test.go +++ b/pkg/scan/scan_test.go @@ -11,6 +11,7 @@ func TestScanImageCommandNormal(t *testing.T) { const imageName = "test-image:latest" const severity = "CRITICAL,HIGH" const disableError = false + const versionOlderThan0_57_1 = false expectedCommandString := strings.Join( []string{ @@ -24,10 +25,6 @@ func TestScanImageCommandNormal(t *testing.T) { "json", "--output", "trivy.json", - "--db-repository", - "ghcr.io/3lvia/trivy-db", - "--java-db-repository", - "ghcr.io/3lvia/trivy-java-db", "--ignore-unfixed", "--exit-code", "1", @@ -42,6 +39,7 @@ func TestScanImageCommandNormal(t *testing.T) { imageName, severity, disableError, + versionOlderThan0_57_1, &command.RunOptions{DryRun: true}, ) @@ -56,6 +54,7 @@ func TestScanImageDisableErrorAndMoreSeverities(t *testing.T) { const imageName = "test-image:latest" const severity = "CRITICAL,HIGH,MEDIUM" const disableError = true + const versionOlderThan0_57_1 = false expectedCommandString := strings.Join( []string{ @@ -68,10 +67,6 @@ func TestScanImageDisableErrorAndMoreSeverities(t *testing.T) { "json", "--output", "trivy.json", - "--db-repository", - "ghcr.io/3lvia/trivy-db", - "--java-db-repository", - "ghcr.io/3lvia/trivy-java-db", "--ignore-unfixed", "--exit-code", "0", @@ -86,6 +81,7 @@ func TestScanImageDisableErrorAndMoreSeverities(t *testing.T) { imageName, severity, disableError, + versionOlderThan0_57_1, &command.RunOptions{DryRun: true}, ) @@ -100,6 +96,7 @@ func TestScanImageCommandDisableErrorAndLessSeverities(t *testing.T) { const imageName = "test-image:latest" const severity = "CRITICAL" const disableError = true + const versionOlderThan0_57_1 = false expectedCommandString := strings.Join( []string{ @@ -112,10 +109,6 @@ func TestScanImageCommandDisableErrorAndLessSeverities(t *testing.T) { "json", "--output", "trivy.json", - "--db-repository", - "ghcr.io/3lvia/trivy-db", - "--java-db-repository", - "ghcr.io/3lvia/trivy-java-db", "--ignore-unfixed", "--exit-code", "0", @@ -130,6 +123,7 @@ func TestScanImageCommandDisableErrorAndLessSeverities(t *testing.T) { imageName, severity, disableError, + versionOlderThan0_57_1, &command.RunOptions{DryRun: true}, ) @@ -144,6 +138,7 @@ func TestScanImageCommandEventMoreSeverities(t *testing.T) { const imageName = "test-image:latest" const severity = "CRITICAL,HIGH,MEDIUM,LOW" const disableError = true + const versionOlderThan0_57_1 = false expectedCommandString := strings.Join( []string{ @@ -156,10 +151,6 @@ func TestScanImageCommandEventMoreSeverities(t *testing.T) { "json", "--output", "trivy.json", - "--db-repository", - "ghcr.io/3lvia/trivy-db", - "--java-db-repository", - "ghcr.io/3lvia/trivy-java-db", "--ignore-unfixed", "--exit-code", "0", @@ -174,6 +165,7 @@ func TestScanImageCommandEventMoreSeverities(t *testing.T) { imageName, severity, disableError, + versionOlderThan0_57_1, &command.RunOptions{DryRun: true}, ) @@ -188,6 +180,7 @@ func TestScanImageCommandAllSeveritiesAndVersionTag(t *testing.T) { const imageName = "test-image:v42" const severity = "CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN" const disableError = false + const versionOlderThan0_57_1 = false expectedCommandString := strings.Join( []string{ @@ -200,15 +193,104 @@ func TestScanImageCommandAllSeveritiesAndVersionTag(t *testing.T) { "json", "--output", "trivy.json", + "--ignore-unfixed", + "--exit-code", + "1", + "--scanners", + "vuln", + imageName, + }, + " ", + ) + + actualCommand := scanImageCommand( + imageName, + severity, + disableError, + versionOlderThan0_57_1, + &command.RunOptions{DryRun: true}, + ) + + command.ExpectedCommandStringEqualsActualCommand( + t, + expectedCommandString, + actualCommand, + ) +} + +func TestScanImageCommandVersionOlderThan0_57_1(t *testing.T) { + const imageName = "test-image:latest" + const severity = "CRITICAL,HIGH" + const disableError = false + const versionOlderThan0_57_1 = true + + expectedCommandString := strings.Join( + []string{ + "trivy", + "image", + "--severity", + severity, + "--timeout", + "15m0s", + "--format", + "json", + "--output", + "trivy.json", + "--ignore-unfixed", + "--exit-code", + "1", + "--scanners", + "vuln", "--db-repository", - "ghcr.io/3lvia/trivy-db", + "mirror.gcr.io/aquasec/trivy-db:2", "--java-db-repository", - "ghcr.io/3lvia/trivy-java-db", + "mirror.gcr.io/aquasec/trivy-java-db:1", + imageName, + }, + " ", + ) + + actualCommand := scanImageCommand( + imageName, + severity, + disableError, + versionOlderThan0_57_1, + &command.RunOptions{DryRun: true}, + ) + + command.ExpectedCommandStringEqualsActualCommand( + t, + expectedCommandString, + actualCommand, + ) +} + +func TestScanImageCommandAllSeveritiesAndVersionTagAndVersionOlderThan0_57_1(t *testing.T) { + const imageName = "test-image:v42" + const severity = "CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN" + const disableError = false + const versionOlderThan0_57_1 = true + + expectedCommandString := strings.Join( + []string{ + "image", + "--severity", + severity, + "--timeout", + "15m0s", + "--format", + "json", + "--output", + "trivy.json", "--ignore-unfixed", "--exit-code", "1", "--scanners", "vuln", + "--db-repository", + "mirror.gcr.io/aquasec/trivy-db:2", + "--java-db-repository", + "mirror.gcr.io/aquasec/trivy-java-db:1", imageName, }, " ", @@ -218,6 +300,7 @@ func TestScanImageCommandAllSeveritiesAndVersionTag(t *testing.T) { imageName, severity, disableError, + versionOlderThan0_57_1, &command.RunOptions{DryRun: true}, )