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 }