github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/terraform/parser/parser_test.go (about)

     1  package parser
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"sort"
     7  	"testing"
     8  
     9  	"github.com/khulnasoft-lab/defsec/pkg/scanners/options"
    10  
    11  	"github.com/khulnasoft-lab/defsec/test/testutil"
    12  
    13  	"github.com/zclconf/go-cty/cty"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func Test_BasicParsing(t *testing.T) {
    21  
    22  	fs := testutil.CreateFS(t, map[string]string{
    23  		"test.tf": `
    24  
    25  locals {
    26  	proxy = var.cats_mother
    27  }
    28  
    29  variable "cats_mother" {
    30  	default = "boots"
    31  }
    32  
    33  provider "cats" {
    34  
    35  }
    36  
    37  moved {
    38  
    39  }
    40  
    41  import {
    42    to = cats_cat.mittens
    43    id = "mittens"
    44  }
    45  
    46  resource "cats_cat" "mittens" {
    47  	name = "mittens"
    48  	special = true
    49  }
    50  
    51  resource "cats_kitten" "the-great-destroyer" {
    52  	name = "the great destroyer"
    53  	parent = cats_cat.mittens.name
    54  }
    55  
    56  data "cats_cat" "the-cats-mother" {
    57  	name = local.proxy
    58  }
    59  
    60  check "cats_mittens_is_special" {
    61    data "cats_cat" "mittens" {
    62      name = "mittens"
    63    }
    64  
    65    assert {
    66      condition = data.cats_cat.mittens.special == true
    67      error_message = "${data.cats_cat.mittens.name} must be special"
    68    }
    69  }
    70  
    71  `,
    72  	})
    73  
    74  	parser := New(fs, "", OptionStopOnHCLError(true))
    75  	if err := parser.ParseFS(context.TODO(), "."); err != nil {
    76  		t.Fatal(err)
    77  	}
    78  	modules, _, err := parser.EvaluateAll(context.TODO())
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  	blocks := modules[0].GetBlocks()
    83  
    84  	// variable
    85  	variables := blocks.OfType("variable")
    86  	require.Len(t, variables, 1)
    87  	assert.Equal(t, "variable", variables[0].Type())
    88  	require.Len(t, variables[0].Labels(), 1)
    89  	assert.Equal(t, "cats_mother", variables[0].TypeLabel())
    90  	defaultVal := variables[0].GetAttribute("default")
    91  	require.NotNil(t, defaultVal)
    92  	assert.Equal(t, cty.String, defaultVal.Value().Type())
    93  	assert.Equal(t, "boots", defaultVal.Value().AsString())
    94  
    95  	// provider
    96  	providerBlocks := blocks.OfType("provider")
    97  	require.Len(t, providerBlocks, 1)
    98  	assert.Equal(t, "provider", providerBlocks[0].Type())
    99  	require.Len(t, providerBlocks[0].Labels(), 1)
   100  	assert.Equal(t, "cats", providerBlocks[0].TypeLabel())
   101  
   102  	// resources
   103  	resourceBlocks := blocks.OfType("resource")
   104  
   105  	sort.Slice(resourceBlocks, func(i, j int) bool {
   106  		return resourceBlocks[i].TypeLabel() < resourceBlocks[j].TypeLabel()
   107  	})
   108  
   109  	require.Len(t, resourceBlocks, 2)
   110  	require.Len(t, resourceBlocks[0].Labels(), 2)
   111  
   112  	assert.Equal(t, "resource", resourceBlocks[0].Type())
   113  	assert.Equal(t, "cats_cat", resourceBlocks[0].TypeLabel())
   114  	assert.Equal(t, "mittens", resourceBlocks[0].NameLabel())
   115  
   116  	assert.Equal(t, "mittens", resourceBlocks[0].GetAttribute("name").Value().AsString())
   117  	assert.True(t, resourceBlocks[0].GetAttribute("special").Value().True())
   118  
   119  	assert.Equal(t, "resource", resourceBlocks[1].Type())
   120  	assert.Equal(t, "cats_kitten", resourceBlocks[1].TypeLabel())
   121  	assert.Equal(t, "the great destroyer", resourceBlocks[1].GetAttribute("name").Value().AsString())
   122  	assert.Equal(t, "mittens", resourceBlocks[1].GetAttribute("parent").Value().AsString())
   123  
   124  	// import
   125  	importBlocks := blocks.OfType("import")
   126  
   127  	assert.Equal(t, "import", importBlocks[0].Type())
   128  	require.NotNil(t, importBlocks[0].GetAttribute("to"))
   129  	assert.Equal(t, "mittens", importBlocks[0].GetAttribute("id").Value().AsString())
   130  
   131  	// data
   132  	dataBlocks := blocks.OfType("data")
   133  	require.Len(t, dataBlocks, 1)
   134  	require.Len(t, dataBlocks[0].Labels(), 2)
   135  
   136  	assert.Equal(t, "data", dataBlocks[0].Type())
   137  	assert.Equal(t, "cats_cat", dataBlocks[0].TypeLabel())
   138  	assert.Equal(t, "the-cats-mother", dataBlocks[0].NameLabel())
   139  
   140  	assert.Equal(t, "boots", dataBlocks[0].GetAttribute("name").Value().AsString())
   141  
   142  	// check
   143  	checkBlocks := blocks.OfType("check")
   144  	require.Len(t, checkBlocks, 1)
   145  	require.Len(t, checkBlocks[0].Labels(), 1)
   146  
   147  	assert.Equal(t, "check", checkBlocks[0].Type())
   148  	assert.Equal(t, "cats_mittens_is_special", checkBlocks[0].TypeLabel())
   149  
   150  	require.NotNil(t, checkBlocks[0].GetBlock("data"))
   151  	require.NotNil(t, checkBlocks[0].GetBlock("assert"))
   152  }
   153  
   154  func Test_Modules(t *testing.T) {
   155  
   156  	fs := testutil.CreateFS(t, map[string]string{
   157  		"code/test.tf": `
   158  module "my-mod" {
   159  	source = "../module"
   160  	input = "ok"
   161  }
   162  
   163  output "result" {
   164  	value = module.my-mod.mod_result
   165  }
   166  `,
   167  		"module/module.tf": `
   168  variable "input" {
   169  	default = "?"
   170  }
   171  
   172  output "mod_result" {
   173  	value = var.input
   174  }
   175  `,
   176  	})
   177  
   178  	parser := New(fs, "", OptionStopOnHCLError(true), options.ParserWithDebug(os.Stderr))
   179  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	modules, _, err := parser.EvaluateAll(context.TODO())
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  	require.Len(t, modules, 2)
   187  	rootModule := modules[0]
   188  	childModule := modules[1]
   189  
   190  	moduleBlocks := rootModule.GetBlocks().OfType("module")
   191  	require.Len(t, moduleBlocks, 1)
   192  
   193  	assert.Equal(t, "module", moduleBlocks[0].Type())
   194  	assert.Equal(t, "module.my-mod", moduleBlocks[0].FullName())
   195  	inputAttr := moduleBlocks[0].GetAttribute("input")
   196  	require.NotNil(t, inputAttr)
   197  	require.Equal(t, cty.String, inputAttr.Value().Type())
   198  	assert.Equal(t, "ok", inputAttr.Value().AsString())
   199  
   200  	rootOutputs := rootModule.GetBlocks().OfType("output")
   201  	require.Len(t, rootOutputs, 1)
   202  	assert.Equal(t, "output.result", rootOutputs[0].FullName())
   203  	valAttr := rootOutputs[0].GetAttribute("value")
   204  	require.NotNil(t, valAttr)
   205  	require.Equal(t, cty.String, valAttr.Type())
   206  	assert.Equal(t, "ok", valAttr.Value().AsString())
   207  
   208  	childOutputs := childModule.GetBlocks().OfType("output")
   209  	require.Len(t, childOutputs, 1)
   210  	assert.Equal(t, "module.my-mod.output.mod_result", childOutputs[0].FullName())
   211  	childValAttr := childOutputs[0].GetAttribute("value")
   212  	require.NotNil(t, childValAttr)
   213  	require.Equal(t, cty.String, childValAttr.Type())
   214  	assert.Equal(t, "ok", childValAttr.Value().AsString())
   215  
   216  }
   217  
   218  func Test_NestedParentModule(t *testing.T) {
   219  
   220  	fs := testutil.CreateFS(t, map[string]string{
   221  		"code/test.tf": `
   222  module "my-mod" {
   223  	source = "../."
   224  	input = "ok"
   225  }
   226  
   227  output "result" {
   228  	value = module.my-mod.mod_result
   229  }
   230  `,
   231  		"root.tf": `
   232  variable "input" {
   233  	default = "?"
   234  }
   235  
   236  output "mod_result" {
   237  	value = var.input
   238  }
   239  `,
   240  	})
   241  
   242  	parser := New(fs, "", OptionStopOnHCLError(true))
   243  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   244  		t.Fatal(err)
   245  	}
   246  	modules, _, err := parser.EvaluateAll(context.TODO())
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	require.Len(t, modules, 2)
   251  	rootModule := modules[0]
   252  	childModule := modules[1]
   253  
   254  	moduleBlocks := rootModule.GetBlocks().OfType("module")
   255  	require.Len(t, moduleBlocks, 1)
   256  
   257  	assert.Equal(t, "module", moduleBlocks[0].Type())
   258  	assert.Equal(t, "module.my-mod", moduleBlocks[0].FullName())
   259  	inputAttr := moduleBlocks[0].GetAttribute("input")
   260  	require.NotNil(t, inputAttr)
   261  	require.Equal(t, cty.String, inputAttr.Value().Type())
   262  	assert.Equal(t, "ok", inputAttr.Value().AsString())
   263  
   264  	rootOutputs := rootModule.GetBlocks().OfType("output")
   265  	require.Len(t, rootOutputs, 1)
   266  	assert.Equal(t, "output.result", rootOutputs[0].FullName())
   267  	valAttr := rootOutputs[0].GetAttribute("value")
   268  	require.NotNil(t, valAttr)
   269  	require.Equal(t, cty.String, valAttr.Type())
   270  	assert.Equal(t, "ok", valAttr.Value().AsString())
   271  
   272  	childOutputs := childModule.GetBlocks().OfType("output")
   273  	require.Len(t, childOutputs, 1)
   274  	assert.Equal(t, "module.my-mod.output.mod_result", childOutputs[0].FullName())
   275  	childValAttr := childOutputs[0].GetAttribute("value")
   276  	require.NotNil(t, childValAttr)
   277  	require.Equal(t, cty.String, childValAttr.Type())
   278  	assert.Equal(t, "ok", childValAttr.Value().AsString())
   279  }
   280  
   281  func Test_UndefinedModuleOutputReference(t *testing.T) {
   282  
   283  	fs := testutil.CreateFS(t, map[string]string{
   284  		"code/test.tf": `
   285  resource "something" "blah" {
   286  	value = module.x.y
   287  }
   288  `,
   289  	})
   290  
   291  	parser := New(fs, "", OptionStopOnHCLError(true))
   292  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   293  		t.Fatal(err)
   294  	}
   295  	modules, _, err := parser.EvaluateAll(context.TODO())
   296  	if err != nil {
   297  		t.Fatal(err)
   298  	}
   299  	require.Len(t, modules, 1)
   300  	rootModule := modules[0]
   301  
   302  	blocks := rootModule.GetResourcesByType("something")
   303  	require.Len(t, blocks, 1)
   304  	block := blocks[0]
   305  
   306  	attr := block.GetAttribute("value")
   307  	require.NotNil(t, attr)
   308  
   309  	assert.Equal(t, false, attr.IsResolvable())
   310  }
   311  
   312  func Test_UndefinedModuleOutputReferenceInSlice(t *testing.T) {
   313  
   314  	fs := testutil.CreateFS(t, map[string]string{
   315  		"code/test.tf": `
   316  resource "something" "blah" {
   317  	value = ["first", module.x.y, "last"]
   318  }
   319  `,
   320  	})
   321  
   322  	parser := New(fs, "", OptionStopOnHCLError(true))
   323  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   324  		t.Fatal(err)
   325  	}
   326  	modules, _, err := parser.EvaluateAll(context.TODO())
   327  	if err != nil {
   328  		t.Fatal(err)
   329  	}
   330  	require.Len(t, modules, 1)
   331  	rootModule := modules[0]
   332  
   333  	blocks := rootModule.GetResourcesByType("something")
   334  	require.Len(t, blocks, 1)
   335  	block := blocks[0]
   336  
   337  	attr := block.GetAttribute("value")
   338  	require.NotNil(t, attr)
   339  
   340  	assert.Equal(t, true, attr.IsResolvable())
   341  
   342  	values := attr.AsStringValueSliceOrEmpty(block)
   343  	require.Len(t, values, 3)
   344  
   345  	assert.Equal(t, "first", values[0].Value())
   346  	assert.Equal(t, true, values[0].GetMetadata().IsResolvable())
   347  
   348  	assert.Equal(t, false, values[1].GetMetadata().IsResolvable())
   349  
   350  	assert.Equal(t, "last", values[2].Value())
   351  	assert.Equal(t, true, values[2].GetMetadata().IsResolvable())
   352  }
   353  
   354  func Test_TemplatedSliceValue(t *testing.T) {
   355  
   356  	fs := testutil.CreateFS(t, map[string]string{
   357  		"code/test.tf": `
   358  
   359  variable "x" {
   360  	default = "hello"
   361  }
   362  
   363  resource "something" "blah" {
   364  	value = ["first", "${var.x}-${var.x}", "last"]
   365  }
   366  `,
   367  	})
   368  
   369  	parser := New(fs, "", OptionStopOnHCLError(true))
   370  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	modules, _, err := parser.EvaluateAll(context.TODO())
   374  	if err != nil {
   375  		t.Fatal(err)
   376  	}
   377  	require.Len(t, modules, 1)
   378  	rootModule := modules[0]
   379  
   380  	blocks := rootModule.GetResourcesByType("something")
   381  	require.Len(t, blocks, 1)
   382  	block := blocks[0]
   383  
   384  	attr := block.GetAttribute("value")
   385  	require.NotNil(t, attr)
   386  
   387  	assert.Equal(t, true, attr.IsResolvable())
   388  
   389  	values := attr.AsStringValueSliceOrEmpty(block)
   390  	require.Len(t, values, 3)
   391  
   392  	assert.Equal(t, "first", values[0].Value())
   393  	assert.Equal(t, true, values[0].GetMetadata().IsResolvable())
   394  
   395  	assert.Equal(t, "hello-hello", values[1].Value())
   396  	assert.Equal(t, true, values[1].GetMetadata().IsResolvable())
   397  
   398  	assert.Equal(t, "last", values[2].Value())
   399  	assert.Equal(t, true, values[2].GetMetadata().IsResolvable())
   400  }
   401  
   402  func Test_SliceOfVars(t *testing.T) {
   403  
   404  	fs := testutil.CreateFS(t, map[string]string{
   405  		"code/test.tf": `
   406  
   407  variable "x" {
   408  	default = "1"
   409  }
   410  
   411  variable "y" {
   412  	default = "2"
   413  }
   414  
   415  resource "something" "blah" {
   416  	value = [var.x, var.y]
   417  }
   418  `,
   419  	})
   420  
   421  	parser := New(fs, "", OptionStopOnHCLError(true))
   422  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   423  		t.Fatal(err)
   424  	}
   425  	modules, _, err := parser.EvaluateAll(context.TODO())
   426  	if err != nil {
   427  		t.Fatal(err)
   428  	}
   429  	require.Len(t, modules, 1)
   430  	rootModule := modules[0]
   431  
   432  	blocks := rootModule.GetResourcesByType("something")
   433  	require.Len(t, blocks, 1)
   434  	block := blocks[0]
   435  
   436  	attr := block.GetAttribute("value")
   437  	require.NotNil(t, attr)
   438  
   439  	assert.Equal(t, true, attr.IsResolvable())
   440  
   441  	values := attr.AsStringValueSliceOrEmpty(block)
   442  	require.Len(t, values, 2)
   443  
   444  	assert.Equal(t, "1", values[0].Value())
   445  	assert.Equal(t, true, values[0].GetMetadata().IsResolvable())
   446  
   447  	assert.Equal(t, "2", values[1].Value())
   448  	assert.Equal(t, true, values[1].GetMetadata().IsResolvable())
   449  }
   450  
   451  func Test_VarSlice(t *testing.T) {
   452  
   453  	fs := testutil.CreateFS(t, map[string]string{
   454  		"code/test.tf": `
   455  
   456  variable "x" {
   457  	default = ["a", "b", "c"]
   458  }
   459  
   460  resource "something" "blah" {
   461  	value = var.x
   462  }
   463  `,
   464  	})
   465  
   466  	parser := New(fs, "", OptionStopOnHCLError(true))
   467  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   468  		t.Fatal(err)
   469  	}
   470  	modules, _, err := parser.EvaluateAll(context.TODO())
   471  	if err != nil {
   472  		t.Fatal(err)
   473  	}
   474  	require.Len(t, modules, 1)
   475  	rootModule := modules[0]
   476  
   477  	blocks := rootModule.GetResourcesByType("something")
   478  	require.Len(t, blocks, 1)
   479  	block := blocks[0]
   480  
   481  	attr := block.GetAttribute("value")
   482  	require.NotNil(t, attr)
   483  
   484  	assert.Equal(t, true, attr.IsResolvable())
   485  
   486  	values := attr.AsStringValueSliceOrEmpty(block)
   487  	require.Len(t, values, 3)
   488  
   489  	assert.Equal(t, "a", values[0].Value())
   490  	assert.Equal(t, true, values[0].GetMetadata().IsResolvable())
   491  
   492  	assert.Equal(t, "b", values[1].Value())
   493  	assert.Equal(t, true, values[1].GetMetadata().IsResolvable())
   494  
   495  	assert.Equal(t, "c", values[2].Value())
   496  	assert.Equal(t, true, values[2].GetMetadata().IsResolvable())
   497  }
   498  
   499  func Test_LocalSliceNested(t *testing.T) {
   500  
   501  	fs := testutil.CreateFS(t, map[string]string{
   502  		"code/test.tf": `
   503  
   504  variable "x" {
   505  	default = "a"
   506  }
   507  
   508  locals {
   509  	y = [var.x, "b", "c"]
   510  }
   511  
   512  resource "something" "blah" {
   513  	value = local.y
   514  }
   515  `,
   516  	})
   517  
   518  	parser := New(fs, "", OptionStopOnHCLError(true))
   519  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   520  		t.Fatal(err)
   521  	}
   522  	modules, _, err := parser.EvaluateAll(context.TODO())
   523  	if err != nil {
   524  		t.Fatal(err)
   525  	}
   526  	require.Len(t, modules, 1)
   527  	rootModule := modules[0]
   528  
   529  	blocks := rootModule.GetResourcesByType("something")
   530  	require.Len(t, blocks, 1)
   531  	block := blocks[0]
   532  
   533  	attr := block.GetAttribute("value")
   534  	require.NotNil(t, attr)
   535  
   536  	assert.Equal(t, true, attr.IsResolvable())
   537  
   538  	values := attr.AsStringValueSliceOrEmpty(block)
   539  	require.Len(t, values, 3)
   540  
   541  	assert.Equal(t, "a", values[0].Value())
   542  	assert.Equal(t, true, values[0].GetMetadata().IsResolvable())
   543  
   544  	assert.Equal(t, "b", values[1].Value())
   545  	assert.Equal(t, true, values[1].GetMetadata().IsResolvable())
   546  
   547  	assert.Equal(t, "c", values[2].Value())
   548  	assert.Equal(t, true, values[2].GetMetadata().IsResolvable())
   549  }
   550  
   551  func Test_FunctionCall(t *testing.T) {
   552  
   553  	fs := testutil.CreateFS(t, map[string]string{
   554  		"code/test.tf": `
   555  
   556  variable "x" {
   557  	default = ["a", "b"]
   558  }
   559  
   560  resource "something" "blah" {
   561  	value = concat(var.x, ["c"])
   562  }
   563  `,
   564  	})
   565  
   566  	parser := New(fs, "", OptionStopOnHCLError(true))
   567  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   568  		t.Fatal(err)
   569  	}
   570  	modules, _, err := parser.EvaluateAll(context.TODO())
   571  	if err != nil {
   572  		t.Fatal(err)
   573  	}
   574  	require.Len(t, modules, 1)
   575  	rootModule := modules[0]
   576  
   577  	blocks := rootModule.GetResourcesByType("something")
   578  	require.Len(t, blocks, 1)
   579  	block := blocks[0]
   580  
   581  	attr := block.GetAttribute("value")
   582  	require.NotNil(t, attr)
   583  
   584  	assert.Equal(t, true, attr.IsResolvable())
   585  
   586  	values := attr.AsStringValueSliceOrEmpty(block)
   587  	require.Len(t, values, 3)
   588  
   589  	assert.Equal(t, "a", values[0].Value())
   590  	assert.Equal(t, true, values[0].GetMetadata().IsResolvable())
   591  
   592  	assert.Equal(t, "b", values[1].Value())
   593  	assert.Equal(t, true, values[1].GetMetadata().IsResolvable())
   594  
   595  	assert.Equal(t, "c", values[2].Value())
   596  	assert.Equal(t, true, values[2].GetMetadata().IsResolvable())
   597  }
   598  
   599  func Test_DefaultRegistry(t *testing.T) {
   600  
   601  	fs := testutil.CreateFS(t, map[string]string{
   602  		"code/test.tf": `
   603  module "registry" {
   604  	source = "terraform-aws-modules/vpc/aws"
   605  }
   606  `,
   607  	})
   608  
   609  	parser := New(fs, "", OptionStopOnHCLError(true))
   610  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   611  		t.Fatal(err)
   612  	}
   613  	modules, _, err := parser.EvaluateAll(context.TODO())
   614  	require.NoError(t, err)
   615  	require.Len(t, modules, 2)
   616  }
   617  
   618  func Test_SpecificRegistry(t *testing.T) {
   619  
   620  	fs := testutil.CreateFS(t, map[string]string{
   621  		"code/test.tf": `
   622  module "registry" {
   623  	source = "registry.terraform.io/terraform-aws-modules/vpc/aws"
   624  }
   625  `,
   626  	})
   627  
   628  	parser := New(fs, "", OptionStopOnHCLError(true))
   629  	if err := parser.ParseFS(context.TODO(), "code"); err != nil {
   630  		t.Fatal(err)
   631  	}
   632  	modules, _, err := parser.EvaluateAll(context.TODO())
   633  	require.NoError(t, err)
   634  	require.Len(t, modules, 2)
   635  }
   636  
   637  func Test_NullDefaultValueForVar(t *testing.T) {
   638  	fs := testutil.CreateFS(t, map[string]string{
   639  		"test.tf": `
   640  variable "bucket_name" {
   641    type    = string
   642    default = null
   643  }
   644  
   645  resource "aws_s3_bucket" "default" {
   646    bucket = var.bucket_name != null ? var.bucket_name : "default"
   647  }
   648  `,
   649  	})
   650  
   651  	parser := New(fs, "", OptionStopOnHCLError(true))
   652  	if err := parser.ParseFS(context.TODO(), "."); err != nil {
   653  		t.Fatal(err)
   654  	}
   655  	modules, _, err := parser.EvaluateAll(context.TODO())
   656  	require.NoError(t, err)
   657  	require.Len(t, modules, 1)
   658  
   659  	rootModule := modules[0]
   660  
   661  	blocks := rootModule.GetResourcesByType("aws_s3_bucket")
   662  	require.Len(t, blocks, 1)
   663  	block := blocks[0]
   664  
   665  	attr := block.GetAttribute("bucket")
   666  	require.NotNil(t, attr)
   667  	assert.Equal(t, "default", attr.Value().AsString())
   668  }
   669  
   670  func Test_MultipleInstancesOfSameResource(t *testing.T) {
   671  	fs := testutil.CreateFS(t, map[string]string{
   672  		"test.tf": `
   673  
   674  resource "aws_kms_key" "key1" {
   675  	description         = "Key #1"
   676  	enable_key_rotation = true
   677  }
   678  
   679  resource "aws_kms_key" "key2" {
   680  	description         = "Key #2"
   681  	enable_key_rotation = true
   682  }
   683  
   684  resource "aws_s3_bucket" "this" {
   685  	bucket        = "test"
   686    }
   687  
   688  
   689  resource "aws_s3_bucket_server_side_encryption_configuration" "this1" {
   690  	bucket = aws_s3_bucket.this.id
   691    
   692  	rule {
   693  	  apply_server_side_encryption_by_default {
   694  		kms_master_key_id = aws_kms_key.key1.arn
   695  		sse_algorithm     = "aws:kms"
   696  	  }
   697  	}
   698  }
   699  
   700  resource "aws_s3_bucket_server_side_encryption_configuration" "this2" {
   701  	bucket = aws_s3_bucket.this.id
   702    
   703  	rule {
   704  	  apply_server_side_encryption_by_default {
   705  		kms_master_key_id = aws_kms_key.key2.arn
   706  		sse_algorithm     = "aws:kms"
   707  	  }
   708  	}
   709  }
   710  `,
   711  	})
   712  
   713  	parser := New(fs, "", OptionStopOnHCLError(true))
   714  	if err := parser.ParseFS(context.TODO(), "."); err != nil {
   715  		t.Fatal(err)
   716  	}
   717  	modules, _, err := parser.EvaluateAll(context.TODO())
   718  	assert.NoError(t, err)
   719  	assert.Len(t, modules, 1)
   720  
   721  	rootModule := modules[0]
   722  
   723  	blocks := rootModule.GetResourcesByType("aws_s3_bucket_server_side_encryption_configuration")
   724  	assert.Len(t, blocks, 2)
   725  
   726  	for _, block := range blocks {
   727  		attr := block.GetNestedAttribute("rule.apply_server_side_encryption_by_default.kms_master_key_id")
   728  		assert.NotNil(t, attr)
   729  		assert.NotEmpty(t, attr.Value().AsString())
   730  	}
   731  }