github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/misconf/scanner_test.go (about)

     1  package misconf
     2  
     3  import (
     4  	"context"
     5  	"io/fs"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/devseccon/trivy/pkg/fanal/types"
    14  	"github.com/devseccon/trivy/pkg/mapfs"
    15  )
    16  
    17  func TestScannerOption_Sort(t *testing.T) {
    18  	type fields struct {
    19  		Namespaces  []string
    20  		PolicyPaths []string
    21  		DataPaths   []string
    22  	}
    23  	tests := []struct {
    24  		name   string
    25  		fields fields
    26  		want   ScannerOption
    27  	}{
    28  		{
    29  			name: "happy path",
    30  			fields: fields{
    31  				Namespaces: []string{
    32  					"main",
    33  					"custom",
    34  					"default",
    35  				},
    36  				PolicyPaths: []string{"policy"},
    37  				DataPaths: []string{
    38  					"data/b",
    39  					"data/c",
    40  					"data/a",
    41  				},
    42  			},
    43  			want: ScannerOption{
    44  				Namespaces: []string{
    45  					"custom",
    46  					"default",
    47  					"main",
    48  				},
    49  				PolicyPaths: []string{"policy"},
    50  				DataPaths: []string{
    51  					"data/a",
    52  					"data/b",
    53  					"data/c",
    54  				},
    55  			},
    56  		},
    57  		{
    58  			name: "missing some fields",
    59  			fields: fields{
    60  				Namespaces:  []string{"main"},
    61  				PolicyPaths: nil,
    62  				DataPaths:   nil,
    63  			},
    64  			want: ScannerOption{
    65  				Namespaces: []string{"main"},
    66  			},
    67  		},
    68  	}
    69  	for _, tt := range tests {
    70  		t.Run(tt.name, func(t *testing.T) {
    71  			o := ScannerOption{
    72  				Namespaces:  tt.fields.Namespaces,
    73  				PolicyPaths: tt.fields.PolicyPaths,
    74  				DataPaths:   tt.fields.DataPaths,
    75  			}
    76  			o.Sort()
    77  
    78  			assert.Equal(t, tt.want, o)
    79  		})
    80  	}
    81  }
    82  
    83  func TestScanner_Scan(t *testing.T) {
    84  	type fields struct {
    85  		filePatterns []string
    86  		opt          ScannerOption
    87  	}
    88  	type file struct {
    89  		path    string
    90  		content []byte
    91  	}
    92  	tests := []struct {
    93  		name             string
    94  		scannerFunc      func(filePatterns []string, opt ScannerOption) (*Scanner, error)
    95  		fields           fields
    96  		files            []file
    97  		wantFilePath     string
    98  		wantFileType     types.ConfigType
    99  		misconfsExpected int
   100  	}{
   101  		{
   102  			name:        "happy path. Dockerfile",
   103  			scannerFunc: NewDockerfileScanner,
   104  			fields: fields{
   105  				opt: ScannerOption{},
   106  			},
   107  			files: []file{
   108  				{
   109  					path:    "Dockerfile",
   110  					content: []byte(`FROM alpine`),
   111  				},
   112  			},
   113  			wantFilePath:     "Dockerfile",
   114  			wantFileType:     types.Dockerfile,
   115  			misconfsExpected: 1,
   116  		},
   117  		{
   118  			name:        "happy path. Dockerfile with custom file name",
   119  			scannerFunc: NewDockerfileScanner,
   120  			fields: fields{
   121  				filePatterns: []string{"dockerfile:dockerf"},
   122  				opt:          ScannerOption{},
   123  			},
   124  			files: []file{
   125  				{
   126  					path:    "dockerf",
   127  					content: []byte(`FROM alpine`),
   128  				},
   129  			},
   130  			wantFilePath:     "dockerf",
   131  			wantFileType:     types.Dockerfile,
   132  			misconfsExpected: 1,
   133  		},
   134  		{
   135  			name:        "happy path. terraform plan file",
   136  			scannerFunc: NewTerraformPlanScanner,
   137  			files: []file{
   138  				{
   139  					path:    "main.tfplan.json",
   140  					content: []byte(`{"format_version":"1.1","terraform_version":"1.4.6","planned_values":{"root_module":{"resources":[{"address":"aws_s3_bucket.my-bucket","mode":"managed","type":"aws_s3_bucket","name":"my-bucket","provider_name":"registry.terraform.io/hashicorp/aws","schema_version":0,"values":{"bucket":"evil","force_destroy":false,"tags":null,"timeouts":null},"sensitive_values":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags_all":{},"versioning":[],"website":[]}}]}},"resource_changes":[{"address":"aws_s3_bucket.my-bucket","mode":"managed","type":"aws_s3_bucket","name":"my-bucket","provider_name":"registry.terraform.io/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"evil","force_destroy":false,"tags":null,"timeouts":null},"after_unknown":{"acceleration_status":true,"acl":true,"arn":true,"bucket_domain_name":true,"bucket_prefix":true,"bucket_regional_domain_name":true,"cors_rule":true,"grant":true,"hosted_zone_id":true,"id":true,"lifecycle_rule":true,"logging":true,"object_lock_configuration":true,"object_lock_enabled":true,"policy":true,"region":true,"replication_configuration":true,"request_payer":true,"server_side_encryption_configuration":true,"tags_all":true,"versioning":true,"website":true,"website_domain":true,"website_endpoint":true},"before_sensitive":false,"after_sensitive":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags_all":{},"versioning":[],"website":[]}}}],"configuration":{"provider_config":{"aws":{"name":"aws","full_name":"registry.terraform.io/hashicorp/aws","expressions":{"profile":{"constant_value":"foo-bar-123123123"},"region":{"constant_value":"us-west-1"}}}},"root_module":{"resources":[{"address":"aws_s3_bucket.my-bucket","mode":"managed","type":"aws_s3_bucket","name":"my-bucket","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"evil"}},"schema_version":0}]}}}`),
   141  				},
   142  			},
   143  			wantFilePath:     "main.tf",
   144  			wantFileType:     types.TerraformPlan,
   145  			misconfsExpected: 2,
   146  		},
   147  	}
   148  	for _, tt := range tests {
   149  		t.Run(tt.name, func(t *testing.T) {
   150  			// Create a virtual filesystem for testing
   151  			fsys := mapfs.New()
   152  			for _, f := range tt.files {
   153  				err := fsys.WriteVirtualFile(f.path, f.content, 0666)
   154  				require.NoError(t, err)
   155  			}
   156  
   157  			s, err := tt.scannerFunc(tt.fields.filePatterns, tt.fields.opt)
   158  			require.NoError(t, err)
   159  
   160  			misconfs, err := s.Scan(context.Background(), fsys)
   161  			require.NoError(t, err)
   162  			require.Equal(t, tt.misconfsExpected, len(misconfs), "wrong number of misconfigurations found")
   163  			if tt.misconfsExpected == 1 {
   164  				assert.Equal(t, tt.wantFilePath, misconfs[0].FilePath, "filePaths don't equal")
   165  				assert.Equal(t, tt.wantFileType, misconfs[0].FileType, "fileTypes don't equal")
   166  			}
   167  		})
   168  	}
   169  }
   170  
   171  func Test_createPolicyFS(t *testing.T) {
   172  	t.Run("outside pwd", func(t *testing.T) {
   173  		tmpDir := t.TempDir()
   174  		require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "subdir/testdir"), 0750))
   175  		f, got, err := CreatePolicyFS([]string{filepath.Join(tmpDir, "subdir/testdir")})
   176  		assertFS(t, tmpDir, f, got, err)
   177  	})
   178  }
   179  
   180  func Test_CreateDataFS(t *testing.T) {
   181  	t.Run("outside pwd", func(t *testing.T) {
   182  		tmpDir := t.TempDir()
   183  		require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, "subdir/testdir"), 0750))
   184  		f, got, err := CreateDataFS([]string{filepath.Join(tmpDir, "subdir/testdir")})
   185  		assertFS(t, tmpDir, f, got, err)
   186  	})
   187  }
   188  
   189  func assertFS(t *testing.T, tmpDir string, f fs.FS, got []string, err error) {
   190  	t.Helper()
   191  
   192  	require.NoError(t, err)
   193  	assert.Equal(t, []string{"."}, got)
   194  
   195  	d, err := f.Open(tmpDir)
   196  	require.NoError(t, err)
   197  	stat, err := d.Stat()
   198  	require.NoError(t, err)
   199  	assert.True(t, stat.IsDir())
   200  }