github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/test/ignore_test.go (about)

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