github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/test/ignore_test.go (about) 1 package test 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/aquasecurity/defsec/pkg/providers" 9 "github.com/aquasecurity/defsec/pkg/rules" 10 "github.com/aquasecurity/defsec/pkg/scan" 11 "github.com/aquasecurity/defsec/pkg/severity" 12 "github.com/aquasecurity/defsec/pkg/terraform" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 var exampleRule = scan.Rule{ 17 Provider: providers.AWSProvider, 18 Service: "service", 19 ShortCode: "abc123", 20 AVDID: "AWS-ABC-123", 21 Aliases: []string{"aws-other-abc123"}, 22 Severity: severity.High, 23 CustomChecks: scan.CustomChecks{ 24 Terraform: &scan.TerraformCustomCheck{ 25 RequiredLabels: []string{"bad"}, 26 Check: func(resourceBlock *terraform.Block, _ *terraform.Module) (results scan.Results) { 27 attr := resourceBlock.GetAttribute("secure") 28 if attr.IsNil() { 29 results.Add("example problem", resourceBlock) 30 } 31 if attr.IsFalse() { 32 results.Add("example problem", attr) 33 } 34 return 35 }, 36 }, 37 }, 38 } 39 40 func Test_IgnoreAll(t *testing.T) { 41 42 var testCases = []struct { 43 name string 44 inputOptions string 45 assertLength int 46 }{ 47 {name: "IgnoreAll", inputOptions: ` 48 resource "bad" "my-rule" { 49 secure = false // tfsec:ignore:* 50 } 51 `, assertLength: 0}, 52 {name: "IgnoreLineAboveTheBlock", inputOptions: ` 53 // tfsec:ignore:* 54 resource "bad" "my-rule" { 55 secure = false 56 } 57 `, assertLength: 0}, 58 {name: "IgnoreLineAboveTheBlockMatchingParamBool", inputOptions: ` 59 // tfsec:ignore:*[secure=false] 60 resource "bad" "my-rule" { 61 secure = false 62 } 63 `, assertLength: 0}, 64 {name: "IgnoreLineAboveTheBlockNotMatchingParamBool", inputOptions: ` 65 // tfsec:ignore:*[secure=true] 66 resource "bad" "my-rule" { 67 secure = false 68 } 69 `, assertLength: 1}, 70 {name: "IgnoreLineAboveTheBlockMatchingParamString", inputOptions: ` 71 // tfsec:ignore:*[name=myrule] 72 resource "bad" "my-rule" { 73 name = "myrule" 74 secure = false 75 } 76 `, assertLength: 0}, 77 {name: "IgnoreLineAboveTheBlockNotMatchingParamString", inputOptions: ` 78 // tfsec:ignore:*[name=myrule2] 79 resource "bad" "my-rule" { 80 name = "myrule" 81 secure = false 82 } 83 `, assertLength: 1}, 84 {name: "IgnoreLineAboveTheBlockMatchingParamInt", inputOptions: ` 85 // tfsec:ignore:*[port=123] 86 resource "bad" "my-rule" { 87 secure = false 88 port = 123 89 } 90 `, assertLength: 0}, 91 {name: "IgnoreLineAboveTheBlockNotMatchingParamInt", inputOptions: ` 92 // tfsec:ignore:*[port=456] 93 resource "bad" "my-rule" { 94 secure = false 95 port = 123 96 } 97 `, assertLength: 1}, 98 {name: "IgnoreLineStackedAboveTheBlock", inputOptions: ` 99 // tfsec:ignore:* 100 // tfsec:ignore:a 101 // tfsec:ignore:b 102 // tfsec:ignore:c 103 // tfsec:ignore:d 104 resource "bad" "my-rule" { 105 secure = false 106 } 107 `, assertLength: 0}, 108 {name: "IgnoreLineStackedAboveTheBlockWithoutMatch", inputOptions: ` 109 #tfsec:ignore:* 110 111 #tfsec:ignore:x 112 #tfsec:ignore:a 113 #tfsec:ignore:b 114 #tfsec:ignore:c 115 #tfsec:ignore:d 116 resource "bad" "my-rule" { 117 secure = false 118 } 119 `, assertLength: 1}, 120 {name: "IgnoreLineStackedAboveTheBlockWithHashesWithoutSpaces", inputOptions: ` 121 #tfsec:ignore:* 122 #tfsec:ignore:a 123 #tfsec:ignore:b 124 #tfsec:ignore:c 125 #tfsec:ignore:d 126 resource "bad" "my-rule" { 127 secure = false 128 } 129 `, assertLength: 0}, 130 {name: "IgnoreLineStackedAboveTheBlockWithoutSpaces", inputOptions: ` 131 //tfsec:ignore:* 132 //tfsec:ignore:a 133 //tfsec:ignore:b 134 //tfsec:ignore:c 135 //tfsec:ignore:d 136 resource "bad" "my-rule" { 137 secure = false 138 } 139 `, assertLength: 0}, 140 {name: "IgnoreLineAboveTheLine", inputOptions: ` 141 resource "bad" "my-rule" { 142 # tfsec:ignore:aws-service-abc123 143 secure = false 144 } 145 `, assertLength: 0}, 146 {name: "IgnoreWithExpDateIfDateBreachedThenDontIgnore", inputOptions: ` 147 resource "bad" "my-rule" { 148 secure = false # tfsec:ignore:aws-service-abc123:exp:2000-01-02 149 } 150 `, assertLength: 1}, 151 {name: "IgnoreWithExpDateIfDateNotBreachedThenIgnoreIgnore", inputOptions: ` 152 resource "bad" "my-rule" { 153 secure = false # tfsec:ignore:aws-service-abc123:exp:2221-01-02 154 } 155 `, assertLength: 0}, 156 {name: "IgnoreWithExpDateIfDateInvalidThenDropTheIgnore", inputOptions: ` 157 resource "bad" "my-rule" { 158 secure = false # tfsec:ignore:aws-service-abc123:exp:2221-13-02 159 } 160 `, assertLength: 1}, 161 {name: "IgnoreAboveResourceBlockWithExpDateIfDateNotBreachedThenIgnoreIgnore", inputOptions: ` 162 #tfsec:ignore:aws-service-abc123:exp:2221-01-02 163 resource "bad" "my-rule" { 164 } 165 `, assertLength: 0}, 166 {name: "IgnoreAboveResourceBlockWithExpDateAndMultipleIgnoresIfDateNotBreachedThenIgnoreIgnore", inputOptions: ` 167 # tfsec:ignore:aws-service-abc123:exp:2221-01-02 168 resource "bad" "my-rule" { 169 170 } 171 `, assertLength: 0}, 172 {name: "IgnoreForImpliedIAMResource", inputOptions: ` 173 terraform { 174 required_version = "~> 1.1.6" 175 176 required_providers { 177 aws = { 178 source = "hashicorp/aws" 179 version = "~> 3.48" 180 } 181 } 182 } 183 184 # Retrieve an IAM group defined outside of this Terraform config. 185 186 # tfsec:ignore:aws-iam-enforce-mfa 187 data "aws_iam_group" "externally_defined_group" { 188 group_name = "group-name" # tfsec:ignore:aws-iam-enforce-mfa 189 } 190 191 # Create an IAM policy and attach it to the group. 192 193 # tfsec:ignore:aws-iam-enforce-mfa 194 resource "aws_iam_policy" "test_policy" { 195 name = "test-policy" # tfsec:ignore:aws-iam-enforce-mfa 196 policy = data.aws_iam_policy_document.test_policy.json # tfsec:ignore:aws-iam-enforce-mfa 197 } 198 199 # tfsec:ignore:aws-iam-enforce-mfa 200 resource "aws_iam_group_policy_attachment" "test_policy_attachment" { 201 group = data.aws_iam_group.externally_defined_group.group_name # tfsec:ignore:aws-iam-enforce-mfa 202 policy_arn = aws_iam_policy.test_policy.arn # tfsec:ignore:aws-iam-enforce-mfa 203 } 204 205 # tfsec:ignore:aws-iam-enforce-mfa 206 data "aws_iam_policy_document" "test_policy" { 207 statement { 208 sid = "PublishToCloudWatch" # tfsec:ignore:aws-iam-enforce-mfa 209 actions = [ 210 "cloudwatch:PutMetricData", # tfsec:ignore:aws-iam-enforce-mfa 211 ] 212 resources = ["*"] # tfsec:ignore:aws-iam-enforce-mfa 213 } 214 } 215 `, assertLength: 0}, 216 {name: "TrivyIgnoreAll", inputOptions: ` 217 resource "bad" "my-rule" { 218 secure = false // trivy:ignore:* 219 } 220 `, assertLength: 0}, 221 {name: "TrivyIgnoreLineAboveTheBlock", inputOptions: ` 222 // trivy:ignore:* 223 resource "bad" "my-rule" { 224 secure = false 225 } 226 `, assertLength: 0}, 227 {name: "TrivyIgnoreLineAboveTheBlockMatchingParamBool", inputOptions: ` 228 // trivy:ignore:*[secure=false] 229 resource "bad" "my-rule" { 230 secure = false 231 } 232 `, assertLength: 0}, 233 {name: "TrivyIgnoreLineAboveTheBlockNotMatchingParamBool", inputOptions: ` 234 // trivy:ignore:*[secure=true] 235 resource "bad" "my-rule" { 236 secure = false 237 } 238 `, assertLength: 1}, 239 {name: "TrivyIgnoreLineAboveTheBlockMatchingParamString", inputOptions: ` 240 // trivy:ignore:*[name=myrule] 241 resource "bad" "my-rule" { 242 name = "myrule" 243 secure = false 244 } 245 `, assertLength: 0}, 246 {name: "TrivyIgnoreLineAboveTheBlockNotMatchingParamString", inputOptions: ` 247 // trivy:ignore:*[name=myrule2] 248 resource "bad" "my-rule" { 249 name = "myrule" 250 secure = false 251 } 252 `, assertLength: 1}, 253 {name: "TrivyIgnoreLineAboveTheBlockMatchingParamInt", inputOptions: ` 254 // trivy:ignore:*[port=123] 255 resource "bad" "my-rule" { 256 secure = false 257 port = 123 258 } 259 `, assertLength: 0}, 260 {name: "TrivyIgnoreLineAboveTheBlockNotMatchingParamInt", inputOptions: ` 261 // trivy:ignore:*[port=456] 262 resource "bad" "my-rule" { 263 secure = false 264 port = 123 265 } 266 `, assertLength: 1}, 267 {name: "TrivyIgnoreLineStackedAboveTheBlock", inputOptions: ` 268 // trivy:ignore:* 269 // trivy:ignore:a 270 // trivy:ignore:b 271 // trivy:ignore:c 272 // trivy:ignore:d 273 resource "bad" "my-rule" { 274 secure = false 275 } 276 `, assertLength: 0}, 277 {name: "TrivyIgnoreLineStackedAboveTheBlockWithoutMatch", inputOptions: ` 278 #trivy:ignore:* 279 280 #trivy:ignore:x 281 #trivy:ignore:a 282 #trivy:ignore:b 283 #trivy:ignore:c 284 #trivy:ignore:d 285 resource "bad" "my-rule" { 286 secure = false 287 } 288 `, assertLength: 1}, 289 {name: "TrivyIgnoreLineStackedAboveTheBlockWithHashesWithoutSpaces", inputOptions: ` 290 #trivy:ignore:* 291 #trivy:ignore:a 292 #trivy:ignore:b 293 #trivy:ignore:c 294 #trivy:ignore:d 295 resource "bad" "my-rule" { 296 secure = false 297 } 298 `, assertLength: 0}, 299 {name: "TrivyIgnoreLineStackedAboveTheBlockWithoutSpaces", inputOptions: ` 300 //trivy:ignore:* 301 //trivy:ignore:a 302 //trivy:ignore:b 303 //trivy:ignore:c 304 //trivy:ignore:d 305 resource "bad" "my-rule" { 306 secure = false 307 } 308 `, assertLength: 0}, 309 {name: "TrivyIgnoreLineAboveTheLine", inputOptions: ` 310 resource "bad" "my-rule" { 311 # trivy:ignore:aws-service-abc123 312 secure = false 313 } 314 `, assertLength: 0}, 315 {name: "TrivyIgnoreWithExpDateIfDateBreachedThenDontIgnore", inputOptions: ` 316 resource "bad" "my-rule" { 317 secure = false # trivy:ignore:aws-service-abc123:exp:2000-01-02 318 } 319 `, assertLength: 1}, 320 {name: "TrivyIgnoreWithExpDateIfDateNotBreachedThenIgnoreIgnore", inputOptions: ` 321 resource "bad" "my-rule" { 322 secure = false # trivy:ignore:aws-service-abc123:exp:2221-01-02 323 } 324 `, assertLength: 0}, 325 {name: "TrivyIgnoreWithExpDateIfDateInvalidThenDropTheIgnore", inputOptions: ` 326 resource "bad" "my-rule" { 327 secure = false # trivy:ignore:aws-service-abc123:exp:2221-13-02 328 } 329 `, assertLength: 1}, 330 {name: "TrivyIgnoreAboveResourceBlockWithExpDateIfDateNotBreachedThenIgnoreIgnore", inputOptions: ` 331 #trivy:ignore:aws-service-abc123:exp:2221-01-02 332 resource "bad" "my-rule" { 333 } 334 `, assertLength: 0}, 335 {name: "TrivyIgnoreAboveResourceBlockWithExpDateAndMultipleIgnoresIfDateNotBreachedThenIgnoreIgnore", inputOptions: ` 336 # trivy:ignore:aws-service-abc123:exp:2221-01-02 337 resource "bad" "my-rule" { 338 339 } 340 `, assertLength: 0}, 341 {name: "TrivyIgnoreForImpliedIAMResource", inputOptions: ` 342 terraform { 343 required_version = "~> 1.1.6" 344 345 required_providers { 346 aws = { 347 source = "hashicorp/aws" 348 version = "~> 3.48" 349 } 350 } 351 } 352 353 # Retrieve an IAM group defined outside of this Terraform config. 354 355 # trivy:ignore:aws-iam-enforce-mfa 356 data "aws_iam_group" "externally_defined_group" { 357 group_name = "group-name" # trivy:ignore:aws-iam-enforce-mfa 358 } 359 360 # Create an IAM policy and attach it to the group. 361 362 # trivy:ignore:aws-iam-enforce-mfa 363 resource "aws_iam_policy" "test_policy" { 364 name = "test-policy" # trivy:ignore:aws-iam-enforce-mfa 365 policy = data.aws_iam_policy_document.test_policy.json # trivy:ignore:aws-iam-enforce-mfa 366 } 367 368 # trivy:ignore:aws-iam-enforce-mfa 369 resource "aws_iam_group_policy_attachment" "test_policy_attachment" { 370 group = data.aws_iam_group.externally_defined_group.group_name # trivy:ignore:aws-iam-enforce-mfa 371 policy_arn = aws_iam_policy.test_policy.arn # trivy:ignore:aws-iam-enforce-mfa 372 } 373 374 # trivy:ignore:aws-iam-enforce-mfa 375 data "aws_iam_policy_document" "test_policy" { 376 statement { 377 sid = "PublishToCloudWatch" # trivy:ignore:aws-iam-enforce-mfa 378 actions = [ 379 "cloudwatch:PutMetricData", # trivy:ignore:aws-iam-enforce-mfa 380 ] 381 resources = ["*"] # trivy:ignore:aws-iam-enforce-mfa 382 } 383 } 384 `, assertLength: 0}} 385 386 reg := rules.Register(exampleRule) 387 defer rules.Deregister(reg) 388 389 for _, tc := range testCases { 390 t.Run(tc.name, func(t *testing.T) { 391 results := scanHCL(t, tc.inputOptions) 392 assert.Len(t, results.GetFailed(), tc.assertLength) 393 }) 394 } 395 } 396 397 func Test_IgnoreIgnoreWithExpiryAndWorkspaceAndWorkspaceSupplied(t *testing.T) { 398 reg := rules.Register(exampleRule) 399 defer rules.Deregister(reg) 400 401 results := scanHCLWithWorkspace(t, ` 402 # tfsec:ignore:aws-service-abc123:exp:2221-01-02:ws:testworkspace 403 resource "bad" "my-rule" { 404 } 405 `, "testworkspace") 406 assert.Len(t, results.GetFailed(), 0) 407 } 408 409 func Test_IgnoreInline(t *testing.T) { 410 reg := rules.Register(exampleRule) 411 defer rules.Deregister(reg) 412 413 results := scanHCL(t, fmt.Sprintf(` 414 resource "bad" "sample" { 415 secure = false # tfsec:ignore:%s 416 } 417 `, exampleRule.LongID())) 418 assert.Len(t, results.GetFailed(), 0) 419 } 420 421 func Test_IgnoreIgnoreWithExpiryAndWorkspaceButWrongWorkspaceSupplied(t *testing.T) { 422 reg := rules.Register(exampleRule) 423 defer rules.Deregister(reg) 424 425 results := scanHCLWithWorkspace(t, ` 426 # tfsec:ignore:aws-service-abc123:exp:2221-01-02:ws:otherworkspace 427 resource "bad" "my-rule" { 428 429 } 430 `, "testworkspace") 431 assert.Len(t, results.GetFailed(), 1) 432 } 433 434 func Test_IgnoreWithAliasCodeStillIgnored(t *testing.T) { 435 reg := rules.Register(exampleRule) 436 defer rules.Deregister(reg) 437 438 results := scanHCLWithWorkspace(t, ` 439 # tfsec:ignore:aws-other-abc123 440 resource "bad" "my-rule" { 441 442 } 443 `, "testworkspace") 444 assert.Len(t, results.GetFailed(), 0) 445 } 446 447 func Test_TrivyIgnoreIgnoreWithExpiryAndWorkspaceAndWorkspaceSupplied(t *testing.T) { 448 reg := rules.Register(exampleRule) 449 defer rules.Deregister(reg) 450 451 results := scanHCLWithWorkspace(t, ` 452 # trivy:ignore:aws-service-abc123:exp:2221-01-02:ws:testworkspace 453 resource "bad" "my-rule" { 454 } 455 `, "testworkspace") 456 assert.Len(t, results.GetFailed(), 0) 457 } 458 459 func Test_TrivyIgnoreIgnoreWithExpiryAndWorkspaceButWrongWorkspaceSupplied(t *testing.T) { 460 reg := rules.Register(exampleRule) 461 defer rules.Deregister(reg) 462 463 results := scanHCLWithWorkspace(t, ` 464 # trivy:ignore:aws-service-abc123:exp:2221-01-02:ws:otherworkspace 465 resource "bad" "my-rule" { 466 467 } 468 `, "testworkspace") 469 assert.Len(t, results.GetFailed(), 1) 470 } 471 472 func Test_TrivyIgnoreWithAliasCodeStillIgnored(t *testing.T) { 473 reg := rules.Register(exampleRule) 474 defer rules.Deregister(reg) 475 476 results := scanHCLWithWorkspace(t, ` 477 # trivy:ignore:aws-other-abc123 478 resource "bad" "my-rule" { 479 480 } 481 `, "testworkspace") 482 assert.Len(t, results.GetFailed(), 0) 483 } 484 485 func Test_TrivyIgnoreInline(t *testing.T) { 486 reg := rules.Register(exampleRule) 487 defer rules.Deregister(reg) 488 489 results := scanHCL(t, fmt.Sprintf(` 490 resource "bad" "sample" { 491 secure = false # trivy:ignore:%s 492 } 493 `, exampleRule.LongID())) 494 assert.Len(t, results.GetFailed(), 0) 495 } 496 497 func Test_IgnoreInlineByAVDID(t *testing.T) { 498 testCases := []struct { 499 input string 500 }{ 501 { 502 input: ` 503 resource "bad" "sample" { 504 secure = false # tfsec:ignore:%s 505 } 506 `, 507 }, 508 { 509 input: ` 510 resource "bad" "sample" { 511 secure = false # trivy:ignore:%s 512 } 513 `, 514 }, 515 } 516 517 for _, tc := range testCases { 518 tc := tc 519 for _, id := range []string{exampleRule.AVDID, strings.ToLower(exampleRule.AVDID), exampleRule.ShortCode, exampleRule.LongID()} { 520 id := id 521 t.Run("", func(t *testing.T) { 522 reg := rules.Register(exampleRule) 523 defer rules.Deregister(reg) 524 results := scanHCL(t, fmt.Sprintf(tc.input, id)) 525 assert.Len(t, results.GetFailed(), 0) 526 }) 527 } 528 } 529 }