github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/scanner/local/scan_test.go (about) 1 package local 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/samber/lo" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/aquasecurity/trivy-db/pkg/db" 14 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 15 "github.com/devseccon/trivy/pkg/dbtest" 16 "github.com/devseccon/trivy/pkg/fanal/analyzer" 17 ftypes "github.com/devseccon/trivy/pkg/fanal/types" 18 "github.com/devseccon/trivy/pkg/scanner/langpkg" 19 "github.com/devseccon/trivy/pkg/scanner/ospkg" 20 "github.com/devseccon/trivy/pkg/types" 21 "github.com/devseccon/trivy/pkg/vulnerability" 22 ) 23 24 func TestScanner_Scan(t *testing.T) { 25 type args struct { 26 target string 27 layerIDs []string 28 options types.ScanOptions 29 } 30 tests := []struct { 31 name string 32 args args 33 fixtures []string 34 applyLayersExpectation ApplierApplyLayersExpectation 35 wantResults types.Results 36 wantOS ftypes.OS 37 wantErr string 38 }{ 39 { 40 name: "happy path", 41 args: args{ 42 target: "alpine:latest", 43 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 44 options: types.ScanOptions{ 45 VulnType: []string{ 46 types.VulnTypeOS, 47 types.VulnTypeLibrary, 48 }, 49 Scanners: types.Scanners{types.VulnerabilityScanner}, 50 }, 51 }, 52 fixtures: []string{"testdata/fixtures/happy.yaml"}, 53 applyLayersExpectation: ApplierApplyLayersExpectation{ 54 Args: ApplierApplyLayersArgs{ 55 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 56 }, 57 Returns: ApplierApplyLayersReturns{ 58 Detail: ftypes.ArtifactDetail{ 59 OS: ftypes.OS{ 60 Family: ftypes.Alpine, 61 Name: "3.11", 62 }, 63 Packages: []ftypes.Package{ 64 { 65 Name: "musl", 66 Version: "1.2.3", 67 SrcName: "musl", 68 SrcVersion: "1.2.3", 69 Layer: ftypes.Layer{ 70 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 71 }, 72 }, 73 }, 74 Applications: []ftypes.Application{ 75 { 76 Type: ftypes.Bundler, 77 FilePath: "/app/Gemfile.lock", 78 Libraries: []ftypes.Package{ 79 { 80 Name: "rails", 81 Version: "4.0.2", 82 Layer: ftypes.Layer{ 83 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 84 }, 85 }, 86 }, 87 }, 88 }, 89 }, 90 }, 91 }, 92 wantResults: types.Results{ 93 { 94 Target: "alpine:latest (alpine 3.11)", 95 Class: types.ClassOSPkg, 96 Type: ftypes.Alpine, 97 Vulnerabilities: []types.DetectedVulnerability{ 98 { 99 VulnerabilityID: "CVE-2020-9999", 100 PkgName: "musl", 101 InstalledVersion: "1.2.3", 102 FixedVersion: "1.2.4", 103 Status: dbTypes.StatusFixed, 104 Layer: ftypes.Layer{ 105 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 106 }, 107 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-9999", 108 Vulnerability: dbTypes.Vulnerability{ 109 Title: "dos", 110 Description: "dos vulnerability", 111 Severity: "HIGH", 112 }, 113 }, 114 }, 115 }, 116 { 117 Target: "/app/Gemfile.lock", 118 Class: types.ClassLangPkg, 119 Type: ftypes.Bundler, 120 Vulnerabilities: []types.DetectedVulnerability{ 121 { 122 VulnerabilityID: "CVE-2014-0081", 123 PkgName: "rails", 124 InstalledVersion: "4.0.2", 125 FixedVersion: "4.0.3, 3.2.17", 126 Status: dbTypes.StatusFixed, 127 Layer: ftypes.Layer{ 128 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 129 }, 130 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 131 Vulnerability: dbTypes.Vulnerability{ 132 Title: "xss", 133 Description: "xss vulnerability", 134 Severity: "MEDIUM", 135 References: []string{ 136 "http://example.com", 137 }, 138 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 139 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 140 }, 141 }, 142 }, 143 }, 144 }, 145 wantOS: ftypes.OS{ 146 Family: "alpine", 147 Name: "3.11", 148 Eosl: true, 149 }, 150 }, 151 { 152 name: "happy path with list all packages", 153 args: args{ 154 target: "alpine:latest", 155 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 156 options: types.ScanOptions{ 157 VulnType: []string{ 158 types.VulnTypeOS, 159 types.VulnTypeLibrary, 160 }, 161 Scanners: types.Scanners{types.VulnerabilityScanner}, 162 ListAllPackages: true, 163 }, 164 }, 165 fixtures: []string{"testdata/fixtures/happy.yaml"}, 166 applyLayersExpectation: ApplierApplyLayersExpectation{ 167 Args: ApplierApplyLayersArgs{ 168 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 169 }, 170 Returns: ApplierApplyLayersReturns{ 171 Detail: ftypes.ArtifactDetail{ 172 OS: ftypes.OS{ 173 Family: "alpine", 174 Name: "3.11", 175 }, 176 Packages: []ftypes.Package{ 177 { 178 Name: "musl", 179 Version: "1.2.3", 180 SrcName: "musl", 181 SrcVersion: "1.2.3", 182 Layer: ftypes.Layer{ 183 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 184 }, 185 }, 186 { 187 Name: "ausl", 188 Version: "1.2.3", 189 SrcName: "ausl", 190 SrcVersion: "1.2.3", 191 Layer: ftypes.Layer{ 192 DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 193 }, 194 }, 195 }, 196 Applications: []ftypes.Application{ 197 { 198 Type: "bundler", 199 FilePath: "/app/Gemfile.lock", 200 Libraries: []ftypes.Package{ 201 { 202 Name: "rails", 203 Version: "4.0.2", 204 Layer: ftypes.Layer{ 205 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 206 }, 207 }, 208 }, 209 }, 210 }, 211 }, 212 }, 213 }, 214 wantResults: types.Results{ 215 { 216 Target: "alpine:latest (alpine 3.11)", 217 Class: types.ClassOSPkg, 218 Type: ftypes.Alpine, 219 Packages: []ftypes.Package{ 220 { 221 Name: "ausl", 222 Version: "1.2.3", 223 SrcName: "ausl", 224 SrcVersion: "1.2.3", 225 Layer: ftypes.Layer{ 226 DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 227 }, 228 }, 229 { 230 Name: "musl", 231 Version: "1.2.3", 232 SrcName: "musl", 233 SrcVersion: "1.2.3", 234 Layer: ftypes.Layer{ 235 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 236 }, 237 }, 238 }, 239 // For backward compatibility, will be removed 240 Vulnerabilities: []types.DetectedVulnerability{ 241 { 242 VulnerabilityID: "CVE-2020-9999", 243 PkgName: "musl", 244 InstalledVersion: "1.2.3", 245 FixedVersion: "1.2.4", 246 Status: dbTypes.StatusFixed, 247 Layer: ftypes.Layer{ 248 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 249 }, 250 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-9999", 251 Vulnerability: dbTypes.Vulnerability{ 252 Title: "dos", 253 Description: "dos vulnerability", 254 Severity: "HIGH", 255 }, 256 }, 257 }, 258 }, 259 { 260 Target: "/app/Gemfile.lock", 261 Class: types.ClassLangPkg, 262 Type: ftypes.Bundler, 263 Packages: []ftypes.Package{ 264 { 265 Name: "rails", 266 Version: "4.0.2", 267 Layer: ftypes.Layer{ 268 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 269 }, 270 }, 271 }, 272 // For backward compatibility, will be removed 273 Vulnerabilities: []types.DetectedVulnerability{ 274 { 275 VulnerabilityID: "CVE-2014-0081", 276 PkgName: "rails", 277 InstalledVersion: "4.0.2", 278 FixedVersion: "4.0.3, 3.2.17", 279 Status: dbTypes.StatusFixed, 280 Layer: ftypes.Layer{ 281 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 282 }, 283 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 284 Vulnerability: dbTypes.Vulnerability{ 285 Title: "xss", 286 Description: "xss vulnerability", 287 Severity: "MEDIUM", 288 References: []string{ 289 "http://example.com", 290 }, 291 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 292 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 293 }, 294 }, 295 }, 296 }, 297 }, 298 wantOS: ftypes.OS{ 299 Family: "alpine", 300 Name: "3.11", 301 Eosl: true, 302 }, 303 }, 304 { 305 name: "happy path with list all packages and without vulnerabilities", 306 args: args{ 307 target: "alpine:latest", 308 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 309 options: types.ScanOptions{ 310 VulnType: []string{ 311 types.VulnTypeOS, 312 types.VulnTypeLibrary, 313 }, 314 Scanners: types.Scanners{types.VulnerabilityScanner}, 315 ListAllPackages: true, 316 }, 317 }, 318 applyLayersExpectation: ApplierApplyLayersExpectation{ 319 Args: ApplierApplyLayersArgs{ 320 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 321 }, 322 Returns: ApplierApplyLayersReturns{ 323 Detail: ftypes.ArtifactDetail{ 324 OS: ftypes.OS{ 325 Family: "alpine", 326 Name: "3.11", 327 }, 328 Packages: []ftypes.Package{ 329 { 330 Name: "musl", 331 Version: "1.2.3", 332 SrcName: "musl", 333 SrcVersion: "1.2.3", 334 Layer: ftypes.Layer{ 335 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 336 }, 337 }, 338 { 339 Name: "ausl", 340 Version: "1.2.3", 341 SrcName: "ausl", 342 SrcVersion: "1.2.3", 343 Layer: ftypes.Layer{ 344 DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 345 }, 346 }, 347 }, 348 Applications: []ftypes.Application{ 349 { 350 Type: "bundler", 351 FilePath: "/app/Gemfile.lock", 352 Libraries: []ftypes.Package{ 353 { 354 Name: "rails", 355 Version: "4.0.2", 356 Layer: ftypes.Layer{ 357 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 358 }, 359 }, 360 }, 361 }, 362 }, 363 }, 364 }, 365 }, 366 wantResults: types.Results{ 367 { 368 Target: "alpine:latest (alpine 3.11)", 369 Class: types.ClassOSPkg, 370 Type: ftypes.Alpine, 371 Packages: []ftypes.Package{ 372 { 373 Name: "ausl", 374 Version: "1.2.3", 375 SrcName: "ausl", 376 SrcVersion: "1.2.3", 377 Layer: ftypes.Layer{ 378 DiffID: "sha256:bbf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 379 }, 380 }, 381 { 382 Name: "musl", 383 Version: "1.2.3", 384 SrcName: "musl", 385 SrcVersion: "1.2.3", 386 Layer: ftypes.Layer{ 387 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 388 }, 389 }, 390 }, 391 }, 392 { 393 Target: "/app/Gemfile.lock", 394 Class: types.ClassLangPkg, 395 Type: ftypes.Bundler, 396 Packages: []ftypes.Package{ 397 { 398 Name: "rails", 399 Version: "4.0.2", 400 Layer: ftypes.Layer{ 401 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 402 }, 403 }, 404 }, 405 }, 406 }, 407 wantOS: ftypes.OS{ 408 Family: "alpine", 409 Name: "3.11", 410 Eosl: true, 411 }, 412 }, 413 { 414 name: "happy path with empty os", 415 args: args{ 416 target: "alpine:latest", 417 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 418 options: types.ScanOptions{ 419 VulnType: []string{ 420 types.VulnTypeOS, 421 types.VulnTypeLibrary, 422 }, 423 Scanners: types.Scanners{types.VulnerabilityScanner}, 424 }, 425 }, 426 fixtures: []string{"testdata/fixtures/happy.yaml"}, 427 applyLayersExpectation: ApplierApplyLayersExpectation{ 428 Args: ApplierApplyLayersArgs{ 429 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 430 }, 431 Returns: ApplierApplyLayersReturns{ 432 Detail: ftypes.ArtifactDetail{ 433 OS: ftypes.OS{}, 434 Applications: []ftypes.Application{ 435 { 436 Type: ftypes.Bundler, 437 FilePath: "/app/Gemfile.lock", 438 Libraries: []ftypes.Package{ 439 { 440 Name: "innocent", // no vulnerability 441 Version: "1.2.3", 442 Layer: ftypes.Layer{ 443 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 444 }, 445 }, 446 }, 447 }, 448 { 449 Type: ftypes.Bundler, 450 FilePath: "/app/Gemfile.lock", 451 Libraries: []ftypes.Package{ 452 { 453 Name: "rails", // one vulnerability 454 Version: "4.0.2", 455 Layer: ftypes.Layer{ 456 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 457 }, 458 }, 459 }, 460 }, 461 }, 462 }, 463 }, 464 }, 465 wantResults: types.Results{ 466 { 467 Target: "/app/Gemfile.lock", 468 Class: types.ClassLangPkg, 469 Type: "bundler", 470 Vulnerabilities: []types.DetectedVulnerability{ 471 { 472 VulnerabilityID: "CVE-2014-0081", 473 PkgName: "rails", 474 InstalledVersion: "4.0.2", 475 FixedVersion: "4.0.3, 3.2.17", 476 Status: dbTypes.StatusFixed, 477 Layer: ftypes.Layer{ 478 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 479 }, 480 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 481 Vulnerability: dbTypes.Vulnerability{ 482 Title: "xss", 483 Description: "xss vulnerability", 484 Severity: "MEDIUM", 485 References: []string{ 486 "http://example.com", 487 }, 488 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 489 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 490 }, 491 }, 492 }, 493 }, 494 }, 495 wantOS: ftypes.OS{}, 496 }, 497 { 498 name: "happy path. Empty filePaths (e.g. Scanned SBOM)", 499 args: args{ 500 target: "./result.cdx", 501 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 502 options: types.ScanOptions{ 503 VulnType: []string{types.VulnTypeLibrary}, 504 Scanners: types.Scanners{types.VulnerabilityScanner}, 505 ListAllPackages: true, 506 }, 507 }, 508 fixtures: []string{"testdata/fixtures/happy.yaml"}, 509 applyLayersExpectation: ApplierApplyLayersExpectation{ 510 Args: ApplierApplyLayersArgs{ 511 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 512 }, 513 Returns: ApplierApplyLayersReturns{ 514 Detail: ftypes.ArtifactDetail{ 515 Applications: []ftypes.Application{ 516 { 517 Type: "bundler", 518 FilePath: "", 519 Libraries: []ftypes.Package{ 520 { 521 Name: "rails", 522 Version: "4.0.2", 523 }, 524 }, 525 }, 526 { 527 Type: "composer", 528 FilePath: "", 529 Libraries: []ftypes.Package{ 530 { 531 Name: "laravel/framework", 532 Version: "6.0.0", 533 }, 534 }, 535 }, 536 }, 537 }, 538 }, 539 }, 540 wantResults: types.Results{ 541 { 542 Target: "", 543 Class: types.ClassLangPkg, 544 Type: ftypes.Bundler, 545 Packages: []ftypes.Package{ 546 { 547 Name: "rails", 548 Version: "4.0.2", 549 }, 550 }, 551 Vulnerabilities: []types.DetectedVulnerability{ 552 { 553 VulnerabilityID: "CVE-2014-0081", 554 PkgName: "rails", 555 InstalledVersion: "4.0.2", 556 FixedVersion: "4.0.3, 3.2.17", 557 Status: dbTypes.StatusFixed, 558 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 559 Vulnerability: dbTypes.Vulnerability{ 560 Title: "xss", 561 Description: "xss vulnerability", 562 Severity: "MEDIUM", 563 References: []string{ 564 "http://example.com", 565 }, 566 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 567 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 568 }, 569 }, 570 }, 571 }, 572 { 573 Target: "", 574 Class: types.ClassLangPkg, 575 Type: ftypes.Composer, 576 Packages: []ftypes.Package{ 577 { 578 Name: "laravel/framework", 579 Version: "6.0.0", 580 }, 581 }, 582 Vulnerabilities: []types.DetectedVulnerability{ 583 { 584 VulnerabilityID: "CVE-2021-21263", 585 PkgName: "laravel/framework", 586 InstalledVersion: "6.0.0", 587 FixedVersion: "8.22.1, 7.30.3, 6.20.12", 588 Status: dbTypes.StatusFixed, 589 }, 590 }, 591 }, 592 }, 593 }, 594 { 595 name: "happy path with no package", 596 args: args{ 597 target: "alpine:latest", 598 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 599 options: types.ScanOptions{ 600 VulnType: []string{ 601 types.VulnTypeOS, 602 types.VulnTypeLibrary, 603 }, 604 Scanners: types.Scanners{types.VulnerabilityScanner}, 605 }, 606 }, 607 fixtures: []string{"testdata/fixtures/happy.yaml"}, 608 applyLayersExpectation: ApplierApplyLayersExpectation{ 609 Args: ApplierApplyLayersArgs{ 610 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 611 }, 612 Returns: ApplierApplyLayersReturns{ 613 Detail: ftypes.ArtifactDetail{ 614 OS: ftypes.OS{ 615 Family: "alpine", 616 Name: "3.11", 617 }, 618 Applications: []ftypes.Application{ 619 { 620 Type: "bundler", 621 FilePath: "/app/Gemfile.lock", 622 Libraries: []ftypes.Package{ 623 { 624 Name: "rails", 625 Version: "4.0.2", 626 Layer: ftypes.Layer{ 627 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 628 }, 629 }, 630 }, 631 }, 632 }, 633 }, 634 Err: analyzer.ErrNoPkgsDetected, 635 }, 636 }, 637 wantResults: types.Results{ 638 { 639 Target: "alpine:latest (alpine 3.11)", 640 Class: types.ClassOSPkg, 641 Type: ftypes.Alpine, 642 }, 643 { 644 Target: "/app/Gemfile.lock", 645 Class: types.ClassLangPkg, 646 Type: ftypes.Bundler, 647 Vulnerabilities: []types.DetectedVulnerability{ 648 { 649 VulnerabilityID: "CVE-2014-0081", 650 PkgName: "rails", 651 InstalledVersion: "4.0.2", 652 FixedVersion: "4.0.3, 3.2.17", 653 Status: dbTypes.StatusFixed, 654 Layer: ftypes.Layer{ 655 DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", 656 }, 657 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 658 Vulnerability: dbTypes.Vulnerability{ 659 Title: "xss", 660 Description: "xss vulnerability", 661 Severity: "MEDIUM", 662 References: []string{ 663 "http://example.com", 664 }, 665 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 666 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 667 }, 668 }, 669 }, 670 }, 671 }, 672 wantOS: ftypes.OS{ 673 Family: "alpine", 674 Name: "3.11", 675 Eosl: true, 676 }, 677 }, 678 { 679 name: "happy path with unsupported os", 680 args: args{ 681 target: "fedora:27", 682 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 683 options: types.ScanOptions{ 684 VulnType: []string{ 685 types.VulnTypeOS, 686 types.VulnTypeLibrary, 687 }, 688 Scanners: types.Scanners{types.VulnerabilityScanner}, 689 }, 690 }, 691 fixtures: []string{"testdata/fixtures/happy.yaml"}, 692 applyLayersExpectation: ApplierApplyLayersExpectation{ 693 Args: ApplierApplyLayersArgs{ 694 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 695 }, 696 Returns: ApplierApplyLayersReturns{ 697 Detail: ftypes.ArtifactDetail{ 698 OS: ftypes.OS{ 699 Family: "fedora", 700 Name: "27", 701 }, 702 Applications: []ftypes.Application{ 703 { 704 Type: "bundler", 705 FilePath: "/app/Gemfile.lock", 706 Libraries: []ftypes.Package{ 707 { 708 Name: "rails", 709 Version: "4.0.2", 710 Layer: ftypes.Layer{ 711 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 712 }, 713 }, 714 }, 715 }, 716 }, 717 }, 718 }, 719 }, 720 wantResults: types.Results{ 721 { 722 Target: "/app/Gemfile.lock", 723 Class: types.ClassLangPkg, 724 Type: ftypes.Bundler, 725 Vulnerabilities: []types.DetectedVulnerability{ 726 { 727 VulnerabilityID: "CVE-2014-0081", 728 PkgName: "rails", 729 InstalledVersion: "4.0.2", 730 FixedVersion: "4.0.3, 3.2.17", 731 Status: dbTypes.StatusFixed, 732 Layer: ftypes.Layer{ 733 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 734 }, 735 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 736 Vulnerability: dbTypes.Vulnerability{ 737 Title: "xss", 738 Description: "xss vulnerability", 739 Severity: "MEDIUM", 740 References: []string{ 741 "http://example.com", 742 }, 743 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 744 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 745 }, 746 }, 747 }, 748 }, 749 }, 750 wantOS: ftypes.OS{ 751 Family: "fedora", 752 Name: "27", 753 }, 754 }, 755 { 756 name: "happy path with a scratch image", 757 args: args{ 758 target: "busybox:latest", 759 layerIDs: []string{"sha256:a6d503001157aedc826853f9b67f26d35966221b158bff03849868ae4a821116"}, 760 options: types.ScanOptions{ 761 VulnType: []string{ 762 types.VulnTypeOS, 763 types.VulnTypeLibrary, 764 }, 765 Scanners: types.Scanners{types.VulnerabilityScanner}, 766 }, 767 }, 768 fixtures: []string{"testdata/fixtures/happy.yaml"}, 769 applyLayersExpectation: ApplierApplyLayersExpectation{ 770 Args: ApplierApplyLayersArgs{ 771 BlobIDs: []string{"sha256:a6d503001157aedc826853f9b67f26d35966221b158bff03849868ae4a821116"}, 772 }, 773 Returns: ApplierApplyLayersReturns{ 774 Err: analyzer.ErrUnknownOS, 775 }, 776 }, 777 wantResults: nil, 778 }, 779 { 780 name: "happy path with only language-specific package detection", 781 args: args{ 782 target: "alpine:latest", 783 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 784 options: types.ScanOptions{ 785 VulnType: []string{types.VulnTypeLibrary}, 786 Scanners: types.Scanners{types.VulnerabilityScanner}, 787 }, 788 }, 789 fixtures: []string{"testdata/fixtures/happy.yaml"}, 790 applyLayersExpectation: ApplierApplyLayersExpectation{ 791 Args: ApplierApplyLayersArgs{ 792 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 793 }, 794 Returns: ApplierApplyLayersReturns{ 795 Detail: ftypes.ArtifactDetail{ 796 OS: ftypes.OS{ 797 Family: "alpine", 798 Name: "3.11", 799 }, 800 Packages: []ftypes.Package{ 801 { 802 Name: "musl", 803 Version: "1.2.3", 804 SrcName: "musl", 805 SrcVersion: "1.2.3", 806 }, 807 }, 808 Applications: []ftypes.Application{ 809 { 810 Type: "bundler", 811 FilePath: "/app/Gemfile.lock", 812 Libraries: []ftypes.Package{ 813 { 814 Name: "rails", 815 Version: "4.0.2", 816 Layer: ftypes.Layer{ 817 DiffID: "sha256:5cb2a5009179b1e78ecfef81a19756328bb266456cf9a9dbbcf9af8b83b735f0", 818 }, 819 }, 820 }, 821 }, 822 { 823 Type: "composer", 824 FilePath: "/app/composer-lock.json", 825 Libraries: []ftypes.Package{ 826 { 827 Name: "laravel/framework", 828 Version: "6.0.0", 829 Layer: ftypes.Layer{ 830 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 831 }, 832 }, 833 }, 834 }, 835 }, 836 }, 837 }, 838 }, 839 wantResults: types.Results{ 840 { 841 Target: "/app/Gemfile.lock", 842 Class: types.ClassLangPkg, 843 Type: ftypes.Bundler, 844 Vulnerabilities: []types.DetectedVulnerability{ 845 { 846 VulnerabilityID: "CVE-2014-0081", 847 PkgName: "rails", 848 InstalledVersion: "4.0.2", 849 FixedVersion: "4.0.3, 3.2.17", 850 Status: dbTypes.StatusFixed, 851 Layer: ftypes.Layer{ 852 DiffID: "sha256:5cb2a5009179b1e78ecfef81a19756328bb266456cf9a9dbbcf9af8b83b735f0", 853 }, 854 PrimaryURL: "https://avd.aquasec.com/nvd/cve-2014-0081", 855 Vulnerability: dbTypes.Vulnerability{ 856 Title: "xss", 857 Description: "xss vulnerability", 858 Severity: "MEDIUM", 859 References: []string{ 860 "http://example.com", 861 }, 862 LastModifiedDate: lo.ToPtr(time.Date(2020, 2, 1, 1, 1, 0, 0, time.UTC)), 863 PublishedDate: lo.ToPtr(time.Date(2020, 1, 1, 1, 1, 0, 0, time.UTC)), 864 }, 865 }, 866 }, 867 }, 868 { 869 Target: "/app/composer-lock.json", 870 Class: types.ClassLangPkg, 871 Type: ftypes.Composer, 872 Vulnerabilities: []types.DetectedVulnerability{ 873 { 874 VulnerabilityID: "CVE-2021-21263", 875 PkgName: "laravel/framework", 876 InstalledVersion: "6.0.0", 877 FixedVersion: "8.22.1, 7.30.3, 6.20.12", 878 Status: dbTypes.StatusFixed, 879 Layer: ftypes.Layer{ 880 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 881 }, 882 }, 883 }, 884 }, 885 }, 886 wantOS: ftypes.OS{ 887 Family: "alpine", 888 Name: "3.11", 889 }, 890 }, 891 { 892 name: "happy path with misconfigurations", 893 args: args{ 894 target: "/app/configs", 895 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 896 options: types.ScanOptions{ 897 Scanners: types.Scanners{types.MisconfigScanner}, 898 }, 899 }, 900 fixtures: []string{"testdata/fixtures/happy.yaml"}, 901 applyLayersExpectation: ApplierApplyLayersExpectation{ 902 Args: ApplierApplyLayersArgs{ 903 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 904 }, 905 Returns: ApplierApplyLayersReturns{ 906 Detail: ftypes.ArtifactDetail{ 907 Misconfigurations: []ftypes.Misconfiguration{ 908 { 909 FileType: ftypes.Kubernetes, 910 FilePath: "/app/configs/pod.yaml", 911 Warnings: []ftypes.MisconfResult{ 912 { 913 Namespace: "main.kubernetes.id300", 914 PolicyMetadata: ftypes.PolicyMetadata{ 915 ID: "ID300", 916 Type: "Kubernetes Security Check", 917 Title: "Bad Deployment", 918 Severity: "DUMMY", 919 }, 920 }, 921 }, 922 Exceptions: ftypes.MisconfResults{ 923 { 924 Namespace: "main.kubernetes.id100", 925 PolicyMetadata: ftypes.PolicyMetadata{ 926 ID: "ID100", 927 Type: "Kubernetes Security Check", 928 Title: "Bad Deployment", 929 Severity: "HIGH", 930 }, 931 }, 932 }, 933 Layer: ftypes.Layer{ 934 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 935 }, 936 }, 937 { 938 FileType: ftypes.Kubernetes, 939 FilePath: "/app/configs/deployment.yaml", 940 Successes: []ftypes.MisconfResult{ 941 { 942 Namespace: "builtin.kubernetes.id200", 943 PolicyMetadata: ftypes.PolicyMetadata{ 944 ID: "ID200", 945 Type: "Kubernetes Security Check", 946 Title: "Bad Deployment", 947 Severity: "MEDIUM", 948 }, 949 }, 950 }, 951 Failures: ftypes.MisconfResults{ 952 { 953 Namespace: "main.kubernetes.id100", 954 Message: "something bad", 955 PolicyMetadata: ftypes.PolicyMetadata{ 956 ID: "ID100", 957 Type: "Kubernetes Security Check", 958 Title: "Bad Deployment", 959 Severity: "HIGH", 960 }, 961 }, 962 }, 963 Layer: ftypes.Layer{ 964 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 965 }, 966 }, 967 }, 968 }, 969 }, 970 }, 971 wantResults: types.Results{ 972 { 973 Target: "/app/configs/deployment.yaml", 974 Class: types.ClassConfig, 975 Type: ftypes.Kubernetes, 976 Misconfigurations: []types.DetectedMisconfiguration{ 977 { 978 Type: "Kubernetes Security Check", 979 ID: "ID100", 980 Title: "Bad Deployment", 981 Message: "something bad", 982 Namespace: "main.kubernetes.id100", 983 Severity: "HIGH", 984 Status: types.StatusFailure, 985 Layer: ftypes.Layer{ 986 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 987 }, 988 }, 989 { 990 Type: "Kubernetes Security Check", 991 ID: "ID200", 992 Title: "Bad Deployment", 993 Message: "No issues found", 994 Namespace: "builtin.kubernetes.id200", 995 Severity: "MEDIUM", 996 PrimaryURL: "https://avd.aquasec.com/misconfig/id200", 997 References: []string{ 998 "https://avd.aquasec.com/misconfig/id200", 999 }, 1000 Status: types.StatusPassed, 1001 Layer: ftypes.Layer{ 1002 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 1003 }, 1004 }, 1005 }, 1006 }, 1007 { 1008 Target: "/app/configs/pod.yaml", 1009 Class: types.ClassConfig, 1010 Type: ftypes.Kubernetes, 1011 Misconfigurations: []types.DetectedMisconfiguration{ 1012 { 1013 Type: "Kubernetes Security Check", 1014 ID: "ID300", 1015 Title: "Bad Deployment", 1016 Message: "No issues found", 1017 Namespace: "main.kubernetes.id300", 1018 Severity: "MEDIUM", 1019 Status: types.StatusFailure, 1020 Layer: ftypes.Layer{ 1021 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 1022 }, 1023 }, 1024 { 1025 Type: "Kubernetes Security Check", 1026 ID: "ID100", 1027 Title: "Bad Deployment", 1028 Message: "No issues found", 1029 Namespace: "main.kubernetes.id100", 1030 Severity: "HIGH", 1031 Status: types.StatusException, 1032 Layer: ftypes.Layer{ 1033 DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", 1034 }, 1035 }, 1036 }, 1037 }, 1038 }, 1039 }, 1040 { 1041 name: "sad path: ApplyLayers returns an error", 1042 args: args{ 1043 target: "alpine:latest", 1044 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 1045 options: types.ScanOptions{ 1046 VulnType: []string{ 1047 types.VulnTypeOS, 1048 types.VulnTypeLibrary, 1049 }, 1050 Scanners: types.Scanners{types.VulnerabilityScanner}, 1051 }, 1052 }, 1053 fixtures: []string{"testdata/fixtures/happy.yaml"}, 1054 applyLayersExpectation: ApplierApplyLayersExpectation{ 1055 Args: ApplierApplyLayersArgs{ 1056 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 1057 }, 1058 Returns: ApplierApplyLayersReturns{ 1059 Err: errors.New("error"), 1060 }, 1061 }, 1062 wantErr: "failed to apply layers", 1063 }, 1064 { 1065 name: "sad path: library.Detect returns an error", 1066 args: args{ 1067 target: "alpine:latest", 1068 layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 1069 options: types.ScanOptions{ 1070 VulnType: []string{types.VulnTypeLibrary}, 1071 Scanners: types.Scanners{types.VulnerabilityScanner}, 1072 }, 1073 }, 1074 fixtures: []string{"testdata/fixtures/sad.yaml"}, 1075 applyLayersExpectation: ApplierApplyLayersExpectation{ 1076 Args: ApplierApplyLayersArgs{ 1077 BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, 1078 }, 1079 Returns: ApplierApplyLayersReturns{ 1080 Detail: ftypes.ArtifactDetail{ 1081 OS: ftypes.OS{ 1082 Family: "alpine", 1083 Name: "3.11", 1084 }, 1085 Packages: []ftypes.Package{ 1086 { 1087 Name: "musl", 1088 Version: "1.2.3", 1089 Layer: ftypes.Layer{ 1090 DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", 1091 }, 1092 }, 1093 }, 1094 Applications: []ftypes.Application{ 1095 { 1096 Type: "bundler", 1097 FilePath: "/app/Gemfile.lock", 1098 Libraries: []ftypes.Package{ 1099 { 1100 Name: "rails", 1101 Version: "6.0", 1102 Layer: ftypes.Layer{ 1103 DiffID: "sha256:9bdb2c849099a99c8ab35f6fd7469c623635e8f4479a0a5a3df61e22bae509f6", 1104 }, 1105 }, 1106 }, 1107 }, 1108 }, 1109 }, 1110 }, 1111 }, 1112 wantErr: "failed to scan application libraries", 1113 }, 1114 } 1115 1116 for _, tt := range tests { 1117 t.Run(tt.name, func(t *testing.T) { 1118 _ = dbtest.InitDB(t, tt.fixtures) 1119 defer db.Close() 1120 1121 applier := new(MockApplier) 1122 applier.ApplyApplyLayersExpectation(tt.applyLayersExpectation) 1123 1124 s := NewScanner(applier, ospkg.NewScanner(), langpkg.NewScanner(), vulnerability.NewClient(db.Config{})) 1125 gotResults, gotOS, err := s.Scan(context.Background(), tt.args.target, "", tt.args.layerIDs, tt.args.options) 1126 if tt.wantErr != "" { 1127 require.NotNil(t, err, tt.name) 1128 require.Contains(t, err.Error(), tt.wantErr, tt.name) 1129 return 1130 } 1131 1132 require.NoError(t, err, tt.name) 1133 assert.Equal(t, tt.wantResults, gotResults) 1134 assert.Equal(t, tt.wantOS, gotOS) 1135 1136 applier.AssertExpectations(t) 1137 }) 1138 } 1139 }