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  }