github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/integration/standalone_tar_test.go (about) 1 //go:build integration 2 3 package integration 4 5 import ( 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestTar(t *testing.T) { 16 type args struct { 17 IgnoreUnfixed bool 18 Severity []string 19 IgnoreIDs []string 20 Format string 21 Input string 22 SkipDirs []string 23 SkipFiles []string 24 } 25 tests := []struct { 26 name string 27 testArgs args 28 golden string 29 }{ 30 { 31 name: "alpine 3.9", 32 testArgs: args{ 33 Format: "json", 34 Input: "testdata/fixtures/images/alpine-39.tar.gz", 35 }, 36 golden: "testdata/alpine-39.json.golden", 37 }, 38 { 39 name: "alpine 3.9 with skip dirs", 40 testArgs: args{ 41 Format: "json", 42 Input: "testdata/fixtures/images/alpine-39.tar.gz", 43 SkipDirs: []string{ 44 "/etc", 45 }, 46 }, 47 golden: "testdata/alpine-39-skip.json.golden", 48 }, 49 { 50 name: "alpine 3.9 with skip files", 51 testArgs: args{ 52 Format: "json", 53 Input: "testdata/fixtures/images/alpine-39.tar.gz", 54 SkipFiles: []string{ 55 "/etc", 56 "/etc/TZ", 57 "/etc/alpine-release", 58 "/etc/apk", 59 "/etc/apk/arch", 60 "/etc/apk/keys", 61 "/etc/apk/keys/alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub", 62 "/etc/apk/keys/alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub", 63 "/etc/apk/keys/alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub", 64 "/etc/apk/protected_paths.d", 65 "/etc/apk/repositories", 66 "/etc/apk/world", 67 "/etc/conf.d", 68 "/etc/crontabs", 69 "/etc/crontabs/root", 70 "/etc/fstab", 71 "/etc/group", 72 "/etc/hostname", 73 "/etc/hosts", 74 "/etc/init.d", 75 "/etc/inittab", 76 "/etc/issue", 77 "/etc/logrotate.d", 78 "/etc/logrotate.d/acpid", 79 "/etc/modprobe.d", 80 "/etc/modprobe.d/aliases.conf", 81 "/etc/modprobe.d/blacklist.conf", 82 "/etc/modprobe.d/i386.conf", 83 "/etc/modprobe.d/kms.conf", 84 "/etc/modules", 85 "/etc/modules-load.d", 86 "/etc/motd", 87 "/etc/mtab", 88 "/etc/network", 89 "/etc/network/if-down.d", 90 "/etc/network/if-post-down.d", 91 "/etc/network/if-post-up.d", 92 "/etc/network/if-pre-down.d", 93 "/etc/network/if-pre-up.d", 94 "/etc/network/if-up.d", 95 "/etc/network/if-up.d/dad", 96 "/etc/opt", 97 "/etc/os-release", 98 "/etc/passwd", 99 "/etc/periodic", 100 "/etc/periodic/15min", 101 "/etc/periodic/daily", 102 "/etc/periodic/hourly", 103 "/etc/periodic/monthly", 104 "/etc/periodic/weekly", 105 "/etc/profile", 106 "/etc/profile.d", 107 "/etc/profile.d/color_prompt", 108 "/etc/protocols", 109 "/etc/securetty", 110 "/etc/services", 111 "/etc/shadow", 112 "/etc/shells", 113 "/etc/ssl", 114 "/etc/ssl/cert.pem", 115 "/etc/ssl/certs", 116 "/etc/ssl/ct_log_list.cnf", 117 "/etc/ssl/ct_log_list.cnf.dist", 118 "/etc/ssl/misc", 119 "/etc/ssl/misc/CA.pl", 120 "/etc/ssl/misc/tsget", 121 "/etc/ssl/misc/tsget.pl", 122 "/etc/ssl/openssl.cnf", 123 "/etc/ssl/openssl.cnf.dist", 124 "/etc/ssl/private", 125 "/etc/sysctl.conf", 126 "/etc/sysctl.d", 127 "/etc/sysctl.d/00-alpine.conf", 128 "/etc/udhcpd.conf", 129 }, 130 }, 131 golden: "testdata/alpine-39-skip.json.golden", 132 }, 133 { 134 name: "alpine 3.9 with high and critical severity", 135 testArgs: args{ 136 IgnoreUnfixed: true, 137 Severity: []string{ 138 "HIGH", 139 "CRITICAL", 140 }, 141 Format: "json", 142 Input: "testdata/fixtures/images/alpine-39.tar.gz", 143 }, 144 golden: "testdata/alpine-39-high-critical.json.golden", 145 }, 146 { 147 name: "alpine 3.9 with .trivyignore", 148 testArgs: args{ 149 IgnoreUnfixed: false, 150 IgnoreIDs: []string{ 151 "CVE-2019-1549", 152 "CVE-2019-14697", 153 }, 154 Format: "json", 155 Input: "testdata/fixtures/images/alpine-39.tar.gz", 156 }, 157 golden: "testdata/alpine-39-ignore-cveids.json.golden", 158 }, 159 { 160 name: "alpine 3.10", 161 testArgs: args{ 162 Format: "json", 163 Input: "testdata/fixtures/images/alpine-310.tar.gz", 164 }, 165 golden: "testdata/alpine-310.json.golden", 166 }, 167 { 168 name: "alpine distroless", 169 testArgs: args{ 170 Format: "json", 171 Input: "testdata/fixtures/images/alpine-distroless.tar.gz", 172 }, 173 golden: "testdata/alpine-distroless.json.golden", 174 }, 175 { 176 name: "amazon linux 1", 177 testArgs: args{ 178 Format: "json", 179 Input: "testdata/fixtures/images/amazon-1.tar.gz", 180 }, 181 golden: "testdata/amazon-1.json.golden", 182 }, 183 { 184 name: "amazon linux 2", 185 testArgs: args{ 186 Format: "json", 187 Input: "testdata/fixtures/images/amazon-2.tar.gz", 188 }, 189 golden: "testdata/amazon-2.json.golden", 190 }, 191 { 192 name: "debian buster/10", 193 testArgs: args{ 194 Format: "json", 195 Input: "testdata/fixtures/images/debian-buster.tar.gz", 196 }, 197 golden: "testdata/debian-buster.json.golden", 198 }, 199 { 200 name: "debian buster/10 with --ignore-unfixed option", 201 testArgs: args{ 202 IgnoreUnfixed: true, 203 Format: "json", 204 Input: "testdata/fixtures/images/debian-buster.tar.gz", 205 }, 206 golden: "testdata/debian-buster-ignore-unfixed.json.golden", 207 }, 208 { 209 name: "debian stretch/9", 210 testArgs: args{ 211 Format: "json", 212 Input: "testdata/fixtures/images/debian-stretch.tar.gz", 213 }, 214 golden: "testdata/debian-stretch.json.golden", 215 }, 216 { 217 name: "ubuntu 18.04", 218 testArgs: args{ 219 Format: "json", 220 Input: "testdata/fixtures/images/ubuntu-1804.tar.gz", 221 }, 222 golden: "testdata/ubuntu-1804.json.golden", 223 }, 224 { 225 name: "ubuntu 18.04 with --ignore-unfixed option", 226 testArgs: args{ 227 IgnoreUnfixed: true, 228 Format: "json", 229 Input: "testdata/fixtures/images/ubuntu-1804.tar.gz", 230 }, 231 golden: "testdata/ubuntu-1804-ignore-unfixed.json.golden", 232 }, 233 { 234 name: "centos 7", 235 testArgs: args{ 236 Format: "json", 237 Input: "testdata/fixtures/images/centos-7.tar.gz", 238 }, 239 golden: "testdata/centos-7.json.golden", 240 }, 241 { 242 name: "centos 7with --ignore-unfixed option", 243 testArgs: args{ 244 IgnoreUnfixed: true, 245 Format: "json", 246 Input: "testdata/fixtures/images/centos-7.tar.gz", 247 }, 248 golden: "testdata/centos-7-ignore-unfixed.json.golden", 249 }, 250 { 251 name: "centos 7 with medium severity", 252 testArgs: args{ 253 IgnoreUnfixed: true, 254 Severity: []string{"MEDIUM"}, 255 Format: "json", 256 Input: "testdata/fixtures/images/centos-7.tar.gz", 257 }, 258 golden: "testdata/centos-7-medium.json.golden", 259 }, 260 { 261 name: "centos 6", 262 testArgs: args{ 263 Format: "json", 264 Input: "testdata/fixtures/images/centos-6.tar.gz", 265 }, 266 golden: "testdata/centos-6.json.golden", 267 }, 268 { 269 name: "ubi 7", 270 testArgs: args{ 271 Format: "json", 272 Input: "testdata/fixtures/images/ubi-7.tar.gz", 273 }, 274 golden: "testdata/ubi-7.json.golden", 275 }, 276 { 277 name: "almalinux 8", 278 testArgs: args{ 279 Format: "json", 280 Input: "testdata/fixtures/images/almalinux-8.tar.gz", 281 }, 282 golden: "testdata/almalinux-8.json.golden", 283 }, 284 { 285 name: "rocky linux 8", 286 testArgs: args{ 287 Format: "json", 288 Input: "testdata/fixtures/images/rockylinux-8.tar.gz", 289 }, 290 golden: "testdata/rockylinux-8.json.golden", 291 }, 292 { 293 name: "distroless base", 294 testArgs: args{ 295 Format: "json", 296 Input: "testdata/fixtures/images/distroless-base.tar.gz", 297 }, 298 golden: "testdata/distroless-base.json.golden", 299 }, 300 { 301 name: "distroless python27", 302 testArgs: args{ 303 Format: "json", 304 Input: "testdata/fixtures/images/distroless-python27.tar.gz", 305 }, 306 golden: "testdata/distroless-python27.json.golden", 307 }, 308 { 309 name: "oracle linux 8", 310 testArgs: args{ 311 Format: "json", 312 Input: "testdata/fixtures/images/oraclelinux-8.tar.gz", 313 }, 314 golden: "testdata/oraclelinux-8.json.golden", 315 }, 316 { 317 name: "opensuse leap 15.1", 318 testArgs: args{ 319 Format: "json", 320 Input: "testdata/fixtures/images/opensuse-leap-151.tar.gz", 321 }, 322 golden: "testdata/opensuse-leap-151.json.golden", 323 }, 324 { 325 name: "photon 3.0", 326 testArgs: args{ 327 Format: "json", 328 Input: "testdata/fixtures/images/photon-30.tar.gz", 329 }, 330 golden: "testdata/photon-30.json.golden", 331 }, 332 { 333 name: "CBL-Mariner 1.0", 334 testArgs: args{ 335 Format: "json", 336 Input: "testdata/fixtures/images/mariner-1.0.tar.gz", 337 }, 338 golden: "testdata/mariner-1.0.json.golden", 339 }, 340 { 341 name: "busybox with Cargo.lock integration", 342 testArgs: args{ 343 Format: "json", 344 Input: "testdata/fixtures/images/busybox-with-lockfile.tar.gz", 345 }, 346 golden: "testdata/busybox-with-lockfile.json.golden", 347 }, 348 { 349 name: "fluentd with RubyGems", 350 testArgs: args{ 351 IgnoreUnfixed: true, 352 Format: "json", 353 Input: "testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz", 354 }, 355 golden: "testdata/fluentd-gems.json.golden", 356 }, 357 } 358 359 // Set up testing DB 360 cacheDir := initDB(t) 361 362 // Set a temp dir so that modules will not be loaded 363 t.Setenv("XDG_DATA_HOME", cacheDir) 364 365 for _, tt := range tests { 366 t.Run(tt.name, func(t *testing.T) { 367 osArgs := []string{ 368 "--cache-dir", 369 cacheDir, 370 "image", 371 "-q", 372 "--format", 373 tt.testArgs.Format, 374 "--skip-update", 375 } 376 377 if tt.testArgs.IgnoreUnfixed { 378 osArgs = append(osArgs, "--ignore-unfixed") 379 } 380 if len(tt.testArgs.Severity) != 0 { 381 osArgs = append(osArgs, "--severity", strings.Join(tt.testArgs.Severity, ",")) 382 } 383 if len(tt.testArgs.IgnoreIDs) != 0 { 384 trivyIgnore := ".trivyignore" 385 err := os.WriteFile(trivyIgnore, []byte(strings.Join(tt.testArgs.IgnoreIDs, "\n")), 0444) 386 assert.NoError(t, err, "failed to write .trivyignore") 387 defer os.Remove(trivyIgnore) 388 } 389 if tt.testArgs.Input != "" { 390 osArgs = append(osArgs, "--input", tt.testArgs.Input) 391 } 392 393 if len(tt.testArgs.SkipFiles) != 0 { 394 for _, skipFile := range tt.testArgs.SkipFiles { 395 osArgs = append(osArgs, "--skip-files", skipFile) 396 } 397 } 398 399 if len(tt.testArgs.SkipDirs) != 0 { 400 for _, skipDir := range tt.testArgs.SkipDirs { 401 osArgs = append(osArgs, "--skip-dirs", skipDir) 402 } 403 } 404 405 // Set up the output file 406 outputFile := filepath.Join(t.TempDir(), "output.json") 407 if *update { 408 outputFile = tt.golden 409 } 410 411 osArgs = append(osArgs, []string{ 412 "--output", 413 outputFile, 414 }...) 415 416 // Run Trivy 417 err := execute(osArgs) 418 require.NoError(t, err) 419 420 // Compare want and got 421 compareReports(t, tt.golden, outputFile, nil) 422 }) 423 } 424 } 425 426 func TestTarWithEnv(t *testing.T) { 427 type args struct { 428 IgnoreUnfixed bool 429 Severity []string 430 Format string 431 Input string 432 SkipDirs []string 433 } 434 tests := []struct { 435 name string 436 testArgs args 437 golden string 438 }{ 439 { 440 name: "alpine 3.9 with skip dirs", 441 testArgs: args{ 442 Format: "json", 443 Input: "testdata/fixtures/images/alpine-39.tar.gz", 444 SkipDirs: []string{ 445 "/etc", 446 }, 447 }, 448 golden: "testdata/alpine-39-skip.json.golden", 449 }, 450 { 451 name: "alpine 3.9 with high and critical severity", 452 testArgs: args{ 453 IgnoreUnfixed: true, 454 Severity: []string{ 455 "HIGH", 456 "CRITICAL", 457 }, 458 Format: "json", 459 Input: "testdata/fixtures/images/alpine-39.tar.gz", 460 }, 461 golden: "testdata/alpine-39-high-critical.json.golden", 462 }, 463 { 464 name: "debian buster/10 with --ignore-unfixed option", 465 testArgs: args{ 466 IgnoreUnfixed: true, 467 Format: "json", 468 Input: "testdata/fixtures/images/debian-buster.tar.gz", 469 }, 470 golden: "testdata/debian-buster-ignore-unfixed.json.golden", 471 }, 472 } 473 474 // Set up testing DB 475 cacheDir := initDB(t) 476 477 // Set a temp dir so that modules will not be loaded 478 t.Setenv("XDG_DATA_HOME", cacheDir) 479 480 for _, tt := range tests { 481 t.Run(tt.name, func(t *testing.T) { 482 osArgs := []string{"image"} 483 484 t.Setenv("TRIVY_FORMAT", tt.testArgs.Format) 485 t.Setenv("TRIVY_CACHE_DIR", cacheDir) 486 t.Setenv("TRIVY_QUIET", "true") 487 t.Setenv("TRIVY_SKIP_UPDATE", "true") 488 489 if tt.testArgs.IgnoreUnfixed { 490 t.Setenv("TRIVY_IGNORE_UNFIXED", "true") 491 } 492 if len(tt.testArgs.Severity) != 0 { 493 t.Setenv("TRIVY_SEVERITY", strings.Join(tt.testArgs.Severity, ",")) 494 } 495 if tt.testArgs.Input != "" { 496 osArgs = append(osArgs, "--input", tt.testArgs.Input) 497 } 498 499 if len(tt.testArgs.SkipDirs) != 0 { 500 t.Setenv("TRIVY_SKIP_DIRS", strings.Join(tt.testArgs.SkipDirs, ",")) 501 } 502 503 // Set up the output file 504 outputFile := filepath.Join(t.TempDir(), "output.json") 505 506 osArgs = append(osArgs, []string{ 507 "--output", 508 outputFile, 509 }...) 510 511 // Run Trivy 512 err := execute(osArgs) 513 require.NoError(t, err) 514 515 // Compare want and got 516 compareReports(t, tt.golden, outputFile, nil) 517 }) 518 } 519 } 520 521 func TestTarWithConfigFile(t *testing.T) { 522 tests := []struct { 523 name string 524 input string 525 configFile string 526 golden string 527 }{ 528 { 529 name: "alpine 3.9 with high and critical severity", 530 input: "testdata/fixtures/images/alpine-39.tar.gz", 531 configFile: `quiet: true 532 format: json 533 severity: 534 - HIGH 535 - CRITICAL 536 vulnerability: 537 type: 538 - os 539 cache: 540 dir: /should/be/overwritten 541 `, 542 golden: "testdata/alpine-39-high-critical.json.golden", 543 }, 544 { 545 name: "debian buster/10 with --ignore-unfixed option", 546 input: "testdata/fixtures/images/debian-buster.tar.gz", 547 configFile: `quiet: true 548 format: json 549 vulnerability: 550 ignore-unfixed: true 551 cache: 552 dir: /should/be/overwritten 553 `, 554 golden: "testdata/debian-buster-ignore-unfixed.json.golden", 555 }, 556 } 557 558 // Set up testing DB 559 cacheDir := initDB(t) 560 561 // Set a temp dir so that modules will not be loaded 562 t.Setenv("XDG_DATA_HOME", cacheDir) 563 564 for _, tt := range tests { 565 t.Run(tt.name, func(t *testing.T) { 566 tmpDir := t.TempDir() 567 outputFile := filepath.Join(tmpDir, "output.json") 568 configPath := filepath.Join(tmpDir, "trivy.yaml") 569 570 err := os.WriteFile(configPath, []byte(tt.configFile), 0600) 571 require.NoError(t, err) 572 573 osArgs := []string{ 574 "--cache-dir", 575 cacheDir, 576 "image", 577 "--skip-db-update", 578 "--config", 579 configPath, 580 "--input", 581 tt.input, 582 "--output", 583 outputFile, 584 } 585 586 // Run Trivy 587 err = execute(osArgs) 588 require.NoError(t, err) 589 590 // Compare want and got 591 compareReports(t, tt.golden, outputFile, nil) 592 }) 593 } 594 }