github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/detection/detect_test.go (about) 1 package detection 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "os" 8 "strings" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func Test_Detection(t *testing.T) { 15 tests := []struct { 16 name string 17 path string 18 r io.ReadSeeker 19 expected []FileType 20 }{ 21 { 22 name: "text file, no reader", 23 path: "something.txt", 24 r: nil, 25 expected: nil, 26 }, 27 { 28 name: "text file, with reader", 29 path: "something.txt", 30 r: strings.NewReader("some file content"), 31 expected: nil, 32 }, 33 { 34 name: "terraform, no reader", 35 path: "main.tf", 36 r: nil, 37 expected: []FileType{ 38 FileTypeTerraform, 39 }, 40 }, 41 { 42 name: "terraform, with reader", 43 path: "main.tf", 44 r: strings.NewReader("some file content"), 45 expected: []FileType{ 46 FileTypeTerraform, 47 }, 48 }, 49 { 50 name: "cloudformation, no reader", 51 path: "main.yaml", 52 r: nil, 53 expected: []FileType{ 54 FileTypeYAML, 55 FileTypeHelm, 56 }, 57 }, 58 { 59 name: "terraform plan, with reader", 60 path: "plan.json", 61 r: strings.NewReader(`{ 62 "format_version": "0.2", 63 "terraform_version": "1.0.3", 64 "variables": { 65 "bucket_name": { 66 "value": "terrasec-plan-testing" 67 } 68 }, 69 "planned_values": {}, 70 "resource_changes": [], 71 "prior_state": {}, 72 "configuration": {} 73 }`), 74 expected: []FileType{ 75 FileTypeTerraformPlan, 76 FileTypeJSON, 77 }, 78 }, 79 { 80 name: "cloudformation, with reader", 81 path: "main.yaml", 82 r: strings.NewReader(`--- 83 AWSTemplateFormatVersion: 2010-09-09 84 85 Description: CodePipeline for continuous integration and continuous deployment 86 87 Parameters: 88 RepositoryName: 89 Type: String 90 Description: Name of the CodeCommit repository 91 BuildDockerImage: 92 Type: String 93 Default: aws/codebuild/ubuntu-base:14.04 94 Description: Docker image to use for the build phase 95 DeployDockerImage: 96 Type: String 97 Default: aws/codebuild/ubuntu-base:14.04 98 Description: Docker image to use for the deployment phase 99 100 Resources: 101 PipelineS3Bucket: 102 Type: AWS::S3::Bucket 103 `), 104 expected: []FileType{ 105 FileTypeCloudFormation, 106 FileTypeYAML, 107 FileTypeHelm, 108 }, 109 }, 110 { 111 name: "JSON with Resources, not cloudformation", 112 path: "whatever.json", 113 r: strings.NewReader(`{ 114 "Resources": ["something"] 115 }`), 116 expected: []FileType{ 117 FileTypeJSON, 118 }, 119 }, 120 { 121 name: "Dockerfile, no reader", 122 path: "Dockerfile", 123 r: nil, 124 expected: []FileType{ 125 FileTypeDockerfile, 126 }, 127 }, 128 { 129 name: "Containerfile, no reader", 130 path: "Containerfile", 131 r: nil, 132 expected: []FileType{ 133 FileTypeDockerfile, 134 }, 135 }, 136 { 137 name: "Dockerfile, reader", 138 path: "Dockerfile", 139 r: strings.NewReader("FROM ubuntu\n"), 140 expected: []FileType{ 141 FileTypeDockerfile, 142 }, 143 }, 144 { 145 name: "Dockerfile extension", 146 path: "lol.Dockerfile", 147 r: nil, 148 expected: []FileType{ 149 FileTypeDockerfile, 150 }, 151 }, 152 { 153 name: "kubernetes, no reader", 154 path: "k8s.yml", 155 r: nil, 156 expected: []FileType{ 157 FileTypeYAML, 158 }, 159 }, 160 { 161 name: "kubernetes, reader", 162 path: "k8s.yml", 163 r: strings.NewReader(`apiVersion: apps/v1 164 kind: Deployment 165 metadata: 166 name: nginx-deployment 167 labels: 168 app: nginx 169 spec: 170 replicas: 3 171 selector: 172 matchLabels: 173 app: nginx 174 template: 175 metadata: 176 labels: 177 app: nginx 178 spec: 179 containers: 180 - name: nginx 181 image: nginx:1.14.2 182 ports: 183 - containerPort: 80`), 184 expected: []FileType{ 185 FileTypeKubernetes, 186 FileTypeYAML, 187 }, 188 }, 189 { 190 name: "kubernetes, reader, JSON", 191 path: "k8s.json", 192 r: strings.NewReader(`{ 193 "apiVersion": "apps/v1", 194 "kind": "Deployment", 195 "metadata": { 196 "name": "nginx-deployment", 197 "labels": { 198 "app": "nginx" 199 } 200 }, 201 "spec": { 202 "replicas": 3, 203 "selector": { 204 "matchLabels": { 205 "app": "nginx" 206 } 207 }, 208 "template": { 209 "metadata": { 210 "labels": { 211 "app": "nginx" 212 } 213 }, 214 "spec": { 215 "containers": [ 216 { 217 "name": "nginx", 218 "image": "nginx:1.14.2", 219 "ports": [ 220 { 221 "containerPort": 80 222 } 223 ] 224 } 225 ] 226 } 227 } 228 } 229 }`), 230 expected: []FileType{ 231 FileTypeKubernetes, 232 FileTypeJSON, 233 }, 234 }, 235 { 236 name: "YAML, no reader", 237 path: "file.yaml", 238 r: nil, 239 expected: []FileType{ 240 FileTypeYAML, 241 FileTypeHelm, 242 }, 243 }, 244 { 245 name: "YML, no reader", 246 path: "file.yml", 247 r: nil, 248 expected: []FileType{ 249 FileTypeYAML, 250 }, 251 }, 252 { 253 name: "YML uppercase", 254 path: "file.YML", 255 r: nil, 256 expected: []FileType{ 257 FileTypeYAML, 258 }, 259 }, 260 { 261 name: "TOML, no reader", 262 path: "file.toml", 263 r: nil, 264 expected: []FileType{ 265 FileTypeTOML, 266 }, 267 }, 268 { 269 name: "JSON, no reader", 270 path: "file.json", 271 r: nil, 272 expected: []FileType{ 273 FileTypeJSON, 274 }, 275 }, 276 { 277 name: "kubernetes, configmap", 278 path: "k8s.yml", 279 r: strings.NewReader(`apiVersion: v1 280 kind: ConfigMap 281 metadata: 282 name: test 283 namespace: default 284 data: 285 AWS_ACCESS_KEY_ID: "XXX" 286 AWS_SECRET_ACCESS_KEY: "XXX"`), 287 expected: []FileType{ 288 FileTypeKubernetes, 289 FileTypeYAML, 290 }, 291 }, 292 { 293 name: "kubernetes, clusterRole", 294 path: "k8s.yml", 295 r: strings.NewReader(`apiVersion: rbac.authorization.k8s.io/v1 296 kind: ClusterRole 297 metadata: 298 annotations: 299 rbac.authorization.kubernetes.io/autoupdate: "true" 300 labels: 301 kubernetes.io/bootstrapping: rbac-defaults 302 rbac.authorization.k8s.io/aggregate-to-edit: "true" 303 name: view 304 rules: 305 - apiGroups: 306 - networking.k8s.io 307 resources: 308 - ingresses 309 - ingresses/status 310 - networkpolicies 311 verbs: 312 - get 313 - list 314 - watch`), 315 expected: []FileType{ 316 FileTypeKubernetes, 317 FileTypeYAML, 318 }, 319 }, 320 } 321 322 for _, test := range tests { 323 t.Run(test.name, func(t *testing.T) { 324 t.Run("GetTypes", func(t *testing.T) { 325 actualDetections := GetTypes(test.path, test.r) 326 assert.Equal(t, len(test.expected), len(actualDetections)) 327 for _, expected := range test.expected { 328 resetReader(test.r) 329 var found bool 330 for _, actual := range actualDetections { 331 if actual == expected { 332 found = true 333 break 334 } 335 } 336 assert.True(t, found, "%s should be detected", expected) 337 } 338 }) 339 for _, expected := range test.expected { 340 resetReader(test.r) 341 t.Run(fmt.Sprintf("IsType_%s", expected), func(t *testing.T) { 342 assert.True(t, IsType(test.path, test.r, expected)) 343 }) 344 } 345 t.Run("IsType_invalid", func(t *testing.T) { 346 resetReader(test.r) 347 assert.False(t, IsType(test.path, test.r, "invalid")) 348 }) 349 }) 350 } 351 } 352 353 func BenchmarkIsType_SmallFile(b *testing.B) { 354 data, err := os.ReadFile(fmt.Sprintf("./testdata/%s", "small.file")) 355 assert.Nil(b, err) 356 357 b.ReportAllocs() 358 b.ResetTimer() 359 for i := 0; i < b.N; i++ { 360 _ = IsType(fmt.Sprintf("./testdata/%s", "small.file"), bytes.NewReader(data), FileTypeAzureARM) 361 } 362 } 363 364 func BenchmarkIsType_BigFile(b *testing.B) { 365 data, err := os.ReadFile(fmt.Sprintf("./testdata/%s", "big.file")) 366 assert.Nil(b, err) 367 368 b.ReportAllocs() 369 b.ResetTimer() 370 for i := 0; i < b.N; i++ { 371 _ = IsType(fmt.Sprintf("./testdata/%s", "big.file"), bytes.NewReader(data), FileTypeAzureARM) 372 } 373 }