github.com/ishita82/trivy-gitaction@v0.0.0-20240206054925-e937cc05f8e3/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  }