Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Trivy GCR for Trivy vuln database #128

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.19.3
0.19.4
53 changes: 49 additions & 4 deletions pkg/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -57,6 +59,7 @@ func scanImageCommand(
imageName string,
severity string,
disableError bool,
versionOlderThan0_57_1 bool,
runOptions *command.RunOptions,
) command.Output {
exitCode := func() string {
Expand All @@ -78,17 +81,22 @@ 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,
"--scanners",
"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)
Expand Down Expand Up @@ -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,
)

Expand Down Expand Up @@ -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
}
119 changes: 101 additions & 18 deletions pkg/scan/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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",
Expand All @@ -42,6 +39,7 @@ func TestScanImageCommandNormal(t *testing.T) {
imageName,
severity,
disableError,
versionOlderThan0_57_1,
&command.RunOptions{DryRun: true},
)

Expand All @@ -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{
Expand All @@ -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",
Expand All @@ -86,6 +81,7 @@ func TestScanImageDisableErrorAndMoreSeverities(t *testing.T) {
imageName,
severity,
disableError,
versionOlderThan0_57_1,
&command.RunOptions{DryRun: true},
)

Expand All @@ -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{
Expand All @@ -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",
Expand All @@ -130,6 +123,7 @@ func TestScanImageCommandDisableErrorAndLessSeverities(t *testing.T) {
imageName,
severity,
disableError,
versionOlderThan0_57_1,
&command.RunOptions{DryRun: true},
)

Expand All @@ -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{
Expand All @@ -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",
Expand All @@ -174,6 +165,7 @@ func TestScanImageCommandEventMoreSeverities(t *testing.T) {
imageName,
severity,
disableError,
versionOlderThan0_57_1,
&command.RunOptions{DryRun: true},
)

Expand All @@ -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{
Expand All @@ -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,
},
" ",
Expand All @@ -218,6 +300,7 @@ func TestScanImageCommandAllSeveritiesAndVersionTag(t *testing.T) {
imageName,
severity,
disableError,
versionOlderThan0_57_1,
&command.RunOptions{DryRun: true},
)

Expand Down
Loading