github.com/jpreese/tflint@v0.19.2-0.20200908152133-b01686250fb6/rules/terraformrules/terraform_module_pinned_source_test.go (about)

     1  package terraformrules
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"testing"
     7  
     8  	hcl "github.com/hashicorp/hcl/v2"
     9  	"github.com/terraform-linters/tflint/tflint"
    10  )
    11  
    12  func Test_TerraformModulePinnedSource(t *testing.T) {
    13  	cases := []struct {
    14  		Name     string
    15  		Content  string
    16  		Config   string
    17  		Expected tflint.Issues
    18  	}{
    19  		{
    20  			Name: "git module is not pinned",
    21  			Content: `
    22  module "unpinned" {
    23    source = "git://hashicorp.com/consul.git"
    24  }`,
    25  			Expected: tflint.Issues{
    26  				{
    27  					Rule:    NewTerraformModulePinnedSourceRule(),
    28  					Message: "Module source \"git://hashicorp.com/consul.git\" is not pinned",
    29  					Range: hcl.Range{
    30  						Filename: "module.tf",
    31  						Start:    hcl.Pos{Line: 3, Column: 12},
    32  						End:      hcl.Pos{Line: 3, Column: 44},
    33  					},
    34  				},
    35  			},
    36  		},
    37  		{
    38  			Name: "git module reference is default",
    39  			Content: `
    40  module "default_git" {
    41    source = "git://hashicorp.com/consul.git?ref=master"
    42  }`,
    43  			Expected: tflint.Issues{
    44  				{
    45  					Rule:    NewTerraformModulePinnedSourceRule(),
    46  					Message: "Module source \"git://hashicorp.com/consul.git?ref=master\" uses default ref \"master\"",
    47  					Range: hcl.Range{
    48  						Filename: "module.tf",
    49  						Start:    hcl.Pos{Line: 3, Column: 12},
    50  						End:      hcl.Pos{Line: 3, Column: 55},
    51  					},
    52  				},
    53  			},
    54  		},
    55  		{
    56  			Name: "git module reference is pinned",
    57  			Content: `
    58  module "pinned_git" {
    59    source = "git://hashicorp.com/consul.git?ref=pinned"
    60  }`,
    61  			Expected: tflint.Issues{},
    62  		},
    63  		{
    64  			Name: "git module reference is pinned, but style is semver",
    65  			Content: `
    66  module "pinned_git" {
    67    source = "git://hashicorp.com/consul.git?ref=pinned"
    68  }`,
    69  			Config: `
    70  rule "terraform_module_pinned_source" {
    71    enabled = true
    72    style = "semver"
    73  }`,
    74  			Expected: tflint.Issues{
    75  				{
    76  					Rule:    NewTerraformModulePinnedSourceRule(),
    77  					Message: "Module source \"git://hashicorp.com/consul.git?ref=pinned\" uses a ref which is not a version string",
    78  					Range: hcl.Range{
    79  						Filename: "module.tf",
    80  						Start:    hcl.Pos{Line: 3, Column: 12},
    81  						End:      hcl.Pos{Line: 3, Column: 55},
    82  					},
    83  				},
    84  			},
    85  		},
    86  		{
    87  			Name: "git module reference is pinned to semver",
    88  			Content: `
    89  module "pinned_git" {
    90    source = "git://hashicorp.com/consul.git?ref=v1.2.3"
    91  }`,
    92  			Config: `
    93  rule "terraform_module_pinned_source" {
    94    enabled = true
    95    style = "semver"
    96  }`,
    97  			Expected: tflint.Issues{},
    98  		},
    99  		{
   100  			Name: "git module reference is pinned to semver (no leading v)",
   101  			Content: `
   102  module "pinned_git" {
   103    source = "git://hashicorp.com/consul.git?ref=1.2.3"
   104  }`,
   105  			Config: `
   106  rule "terraform_module_pinned_source" {
   107    enabled = true
   108    style = "semver"
   109  }`,
   110  			Expected: tflint.Issues{},
   111  		},
   112  		{
   113  			Name: "github module is not pinned",
   114  			Content: `
   115  module "unpinned" {
   116    source = "github.com/hashicorp/consul"
   117  }`,
   118  			Expected: tflint.Issues{
   119  				{
   120  					Rule:    NewTerraformModulePinnedSourceRule(),
   121  					Message: "Module source \"github.com/hashicorp/consul\" is not pinned",
   122  					Range: hcl.Range{
   123  						Filename: "module.tf",
   124  						Start:    hcl.Pos{Line: 3, Column: 12},
   125  						End:      hcl.Pos{Line: 3, Column: 41},
   126  					},
   127  				},
   128  			},
   129  		},
   130  		{
   131  			Name: "github module reference is default",
   132  			Content: `
   133  module "default_git" {
   134    source = "github.com/hashicorp/consul.git?ref=master"
   135  }`,
   136  			Expected: tflint.Issues{
   137  				{
   138  					Rule:    NewTerraformModulePinnedSourceRule(),
   139  					Message: "Module source \"github.com/hashicorp/consul.git?ref=master\" uses default ref \"master\"",
   140  					Range: hcl.Range{
   141  						Filename: "module.tf",
   142  						Start:    hcl.Pos{Line: 3, Column: 12},
   143  						End:      hcl.Pos{Line: 3, Column: 56},
   144  					},
   145  				},
   146  			},
   147  		},
   148  		{
   149  			Name: "github module reference is pinned",
   150  			Content: `
   151  module "pinned_git" {
   152    source = "github.com/hashicorp/consul.git?ref=pinned"
   153  }`,
   154  			Expected: tflint.Issues{},
   155  		},
   156  		{
   157  			Name: "github module reference is pinned, but style is semver",
   158  			Content: `
   159  module "pinned_git" {
   160    source = "github.com/hashicorp/consul.git?ref=pinned"
   161  }`,
   162  			Config: `
   163  rule "terraform_module_pinned_source" {
   164    enabled = true
   165    style = "semver"
   166  }`,
   167  			Expected: tflint.Issues{
   168  				{
   169  					Rule:    NewTerraformModulePinnedSourceRule(),
   170  					Message: "Module source \"github.com/hashicorp/consul.git?ref=pinned\" uses a ref which is not a version string",
   171  					Range: hcl.Range{
   172  						Filename: "module.tf",
   173  						Start:    hcl.Pos{Line: 3, Column: 12},
   174  						End:      hcl.Pos{Line: 3, Column: 56},
   175  					},
   176  				},
   177  			},
   178  		},
   179  		{
   180  			Name: "github module reference is pinned to semver",
   181  			Content: `
   182  module "pinned_git" {
   183    source = "github.com/hashicorp/consul.git?ref=v1.2.3"
   184  }`,
   185  			Config: `
   186  rule "terraform_module_pinned_source" {
   187    enabled = true
   188    style = "semver"
   189  }`,
   190  			Expected: tflint.Issues{},
   191  		},
   192  		{
   193  			Name: "bitbucket module is not pinned",
   194  			Content: `
   195  module "unpinned" {
   196    source = "bitbucket.org/hashicorp/consul"
   197  }`,
   198  			Expected: tflint.Issues{
   199  				{
   200  					Rule:    NewTerraformModulePinnedSourceRule(),
   201  					Message: "Module source \"bitbucket.org/hashicorp/consul\" is not pinned",
   202  					Range: hcl.Range{
   203  						Filename: "module.tf",
   204  						Start:    hcl.Pos{Line: 3, Column: 12},
   205  						End:      hcl.Pos{Line: 3, Column: 44},
   206  					},
   207  				},
   208  			},
   209  		},
   210  		{
   211  			Name: "bitbucket git module reference is default",
   212  			Content: `
   213  module "default_git" {
   214    source = "bitbucket.org/hashicorp/consul.git?ref=master"
   215  }`,
   216  			Expected: tflint.Issues{
   217  				{
   218  					Rule:    NewTerraformModulePinnedSourceRule(),
   219  					Message: "Module source \"bitbucket.org/hashicorp/consul.git?ref=master\" uses default ref \"master\"",
   220  					Range: hcl.Range{
   221  						Filename: "module.tf",
   222  						Start:    hcl.Pos{Line: 3, Column: 12},
   223  						End:      hcl.Pos{Line: 3, Column: 59},
   224  					},
   225  				},
   226  			},
   227  		},
   228  		{
   229  			Name: "bitbucket mercurial module reference is default",
   230  			Content: `
   231  module "default_git" {
   232    source = "bitbucket.org/hg/mercurial?rev=default"
   233  }`,
   234  			Expected: tflint.Issues{
   235  				{
   236  					Rule:    NewTerraformModulePinnedSourceRule(),
   237  					Message: "Module source \"bitbucket.org/hg/mercurial?rev=default\" uses default rev \"default\"",
   238  					Range: hcl.Range{
   239  						Filename: "module.tf",
   240  						Start:    hcl.Pos{Line: 3, Column: 12},
   241  						End:      hcl.Pos{Line: 3, Column: 52},
   242  					},
   243  				},
   244  			},
   245  		},
   246  		{
   247  			Name: "bitbucket git module reference is pinned",
   248  			Content: `
   249  module "pinned_git" {
   250    source = "bitbucket.org/hashicorp/consul.git?ref=pinned"
   251  }`,
   252  			Expected: tflint.Issues{},
   253  		},
   254  		{
   255  			Name: "bitbucket git module reference is pinned, but style is semver",
   256  			Content: `
   257  module "pinned_git" {
   258    source = "bitbucket.org/hashicorp/consul.git?ref=pinned"
   259  }`,
   260  			Config: `
   261  rule "terraform_module_pinned_source" {
   262    enabled = true
   263    style = "semver"
   264  }`,
   265  			Expected: tflint.Issues{
   266  				{
   267  					Rule:    NewTerraformModulePinnedSourceRule(),
   268  					Message: "Module source \"bitbucket.org/hashicorp/consul.git?ref=pinned\" uses a ref which is not a version string",
   269  					Range: hcl.Range{
   270  						Filename: "module.tf",
   271  						Start:    hcl.Pos{Line: 3, Column: 12},
   272  						End:      hcl.Pos{Line: 3, Column: 59},
   273  					},
   274  				},
   275  			},
   276  		},
   277  		{
   278  			Name: "bitbucket git module reference is pinned to semver",
   279  			Content: `
   280  module "pinned_git" {
   281    source = "bitbucket.org/hashicorp/consul.git?ref=v1.2.3"
   282  }`,
   283  			Config: `
   284  rule "terraform_module_pinned_source" {
   285    enabled = true
   286    style = "semver"
   287  }`,
   288  			Expected: tflint.Issues{},
   289  		},
   290  		{
   291  			Name: "bitbucket mercurial module reference is pinned",
   292  			Content: `
   293  module "pinned_git" {
   294    source = "bitbucket.org/hg/mercurial?rev=pinned"
   295  }`,
   296  			Expected: tflint.Issues{},
   297  		},
   298  		{
   299  			Name: "bitbucket mercurial module reference is pinned, but style is semver",
   300  			Content: `
   301  module "pinned_git" {
   302    source = "bitbucket.org/hg/mercurial?rev=pinned"
   303  }`,
   304  			Config: `
   305  rule "terraform_module_pinned_source" {
   306    enabled = true
   307    style = "semver"
   308  }`,
   309  			Expected: tflint.Issues{
   310  				{
   311  					Rule:    NewTerraformModulePinnedSourceRule(),
   312  					Message: "Module source \"bitbucket.org/hg/mercurial?rev=pinned\" uses a rev which is not a version string",
   313  					Range: hcl.Range{
   314  						Filename: "module.tf",
   315  						Start:    hcl.Pos{Line: 3, Column: 12},
   316  						End:      hcl.Pos{Line: 3, Column: 51},
   317  					},
   318  				},
   319  			},
   320  		},
   321  		{
   322  			Name: "bitbucket mercurial module reference is pinned to semver",
   323  			Content: `
   324  module "pinned_git" {
   325    source = "bitbucket.org/hg/mercurial?rev=v1.2.3"
   326  }`,
   327  			Config: `
   328  rule "terraform_module_pinned_source" {
   329    enabled = true
   330    style = "semver"
   331  }`,
   332  			Expected: tflint.Issues{},
   333  		},
   334  		{
   335  			Name: "bitbucket mercurial module reference is pinned to semver (no leading v)",
   336  			Content: `
   337  module "pinned_git" {
   338    source = "bitbucket.org/hg/mercurial?rev=1.2.3"
   339  }`,
   340  			Expected: tflint.Issues{},
   341  		},
   342  		{
   343  			Name: "generic git (git::https) module reference is not pinned",
   344  			Content: `
   345  module "unpinned_generic_git_https" {
   346    source = "git::https://hashicorp.com/consul.git"
   347  }
   348  `,
   349  			Expected: tflint.Issues{
   350  				{
   351  					Rule:    NewTerraformModulePinnedSourceRule(),
   352  					Message: "Module source \"git::https://hashicorp.com/consul.git\" is not pinned",
   353  					Range: hcl.Range{
   354  						Filename: "module.tf",
   355  						Start:    hcl.Pos{Line: 3, Column: 12},
   356  						End:      hcl.Pos{Line: 3, Column: 51},
   357  					},
   358  				},
   359  			},
   360  		},
   361  		{
   362  			Name: "generic git (git::ssh) module reference is not pinned",
   363  			Content: `
   364  module "unpinned_generic_git_ssh" {
   365    source = "git::ssh://git@github.com/owner/repo.git"
   366  }
   367  `,
   368  			Expected: tflint.Issues{
   369  				{
   370  					Rule:    NewTerraformModulePinnedSourceRule(),
   371  					Message: "Module source \"git::ssh://git@github.com/owner/repo.git\" is not pinned",
   372  					Range: hcl.Range{
   373  						Filename: "module.tf",
   374  						Start:    hcl.Pos{Line: 3, Column: 12},
   375  						End:      hcl.Pos{Line: 3, Column: 54},
   376  					},
   377  				},
   378  			},
   379  		},
   380  		{
   381  			Name: "generic git (git::https) module reference is default",
   382  			Content: `
   383  module "default_generic_git_https" {
   384    source = "git::https://hashicorp.com/consul.git?ref=master"
   385  }
   386  `,
   387  			Expected: tflint.Issues{
   388  				{
   389  					Rule:    NewTerraformModulePinnedSourceRule(),
   390  					Message: "Module source \"git::https://hashicorp.com/consul.git?ref=master\" uses default ref \"master\"",
   391  					Range: hcl.Range{
   392  						Filename: "module.tf",
   393  						Start:    hcl.Pos{Line: 3, Column: 12},
   394  						End:      hcl.Pos{Line: 3, Column: 62},
   395  					},
   396  				},
   397  			},
   398  		},
   399  		{
   400  			Name: "generic git (git::ssh) module reference is default",
   401  			Content: `
   402  module "default_generic_git_ssh" {
   403    source = "git::ssh://git@github.com/owner/repo.git?ref=master"
   404  }
   405  `,
   406  			Expected: tflint.Issues{
   407  				{
   408  					Rule:    NewTerraformModulePinnedSourceRule(),
   409  					Message: "Module source \"git::ssh://git@github.com/owner/repo.git?ref=master\" uses default ref \"master\"",
   410  					Range: hcl.Range{
   411  						Filename: "module.tf",
   412  						Start:    hcl.Pos{Line: 3, Column: 12},
   413  						End:      hcl.Pos{Line: 3, Column: 65},
   414  					},
   415  				},
   416  			},
   417  		},
   418  		{
   419  			Name: "generic git (git::https) module reference is pinned",
   420  			Content: `
   421  module "pinned_generic_git_https" {
   422    source = "git::https://hashicorp.com/consul.git?ref=pinned"
   423  }
   424  `,
   425  			Expected: tflint.Issues{},
   426  		},
   427  		{
   428  			Name: "generic git (git::ssh) module reference is pinned",
   429  			Content: `
   430  module "pinned_generic_git_ssh" {
   431    source = "git::ssh://git@github.com/owner/repo.git?ref=pinned"
   432  }
   433  `,
   434  			Expected: tflint.Issues{},
   435  		},
   436  		{
   437  			Name: "mercurial module is not pinned",
   438  			Content: `
   439  module "default_mercurial" {
   440    source = "hg::http://hashicorp.com/consul.hg"
   441  }`,
   442  			Expected: tflint.Issues{
   443  				{
   444  					Rule:    NewTerraformModulePinnedSourceRule(),
   445  					Message: "Module source \"hg::http://hashicorp.com/consul.hg\" is not pinned",
   446  					Range: hcl.Range{
   447  						Filename: "module.tf",
   448  						Start:    hcl.Pos{Line: 3, Column: 12},
   449  						End:      hcl.Pos{Line: 3, Column: 48},
   450  					},
   451  				},
   452  			},
   453  		},
   454  		{
   455  			Name: "mercurial module reference is default",
   456  			Content: `
   457  module "default_mercurial" {
   458    source = "hg::http://hashicorp.com/consul.hg?rev=default"
   459  }`,
   460  			Expected: tflint.Issues{
   461  				{
   462  					Rule:    NewTerraformModulePinnedSourceRule(),
   463  					Message: "Module source \"hg::http://hashicorp.com/consul.hg?rev=default\" uses default rev \"default\"",
   464  					Range: hcl.Range{
   465  						Filename: "module.tf",
   466  						Start:    hcl.Pos{Line: 3, Column: 12},
   467  						End:      hcl.Pos{Line: 3, Column: 60},
   468  					},
   469  				},
   470  			},
   471  		},
   472  		{
   473  			Name: "mercurial module reference is pinned",
   474  			Content: `
   475  module "pinned_mercurial" {
   476    source = "hg::http://hashicorp.com/consul.hg?rev=pinned"
   477  }`,
   478  			Expected: tflint.Issues{},
   479  		},
   480  		{
   481  			Name: "git module is not pinned with default config",
   482  			Content: `
   483  module "unpinned" {
   484    source = "git://hashicorp.com/consul.git"
   485  }`,
   486  			Config: `
   487  rule "terraform_module_pinned_source" {
   488    enabled = true
   489    style = "flexible"
   490  }`,
   491  			Expected: tflint.Issues{
   492  				{
   493  					Rule:    NewTerraformModulePinnedSourceRule(),
   494  					Message: "Module source \"git://hashicorp.com/consul.git\" is not pinned",
   495  					Range: hcl.Range{
   496  						Filename: "module.tf",
   497  						Start:    hcl.Pos{Line: 3, Column: 12},
   498  						End:      hcl.Pos{Line: 3, Column: 44},
   499  					},
   500  				},
   501  			},
   502  		},
   503  	}
   504  
   505  	rule := NewTerraformModulePinnedSourceRule()
   506  
   507  	for _, tc := range cases {
   508  		runner := tflint.TestRunnerWithConfig(t, map[string]string{"module.tf": tc.Content}, loadConfigfromTempFile(t, tc.Config))
   509  
   510  		if err := rule.Check(runner); err != nil {
   511  			t.Fatalf("Unexpected error occurred: %s", err)
   512  		}
   513  
   514  		tflint.AssertIssues(t, tc.Expected, runner.Issues)
   515  	}
   516  }
   517  
   518  // TODO: Replace with TestRunner
   519  func loadConfigfromTempFile(t *testing.T, content string) *tflint.Config {
   520  	if content == "" {
   521  		return tflint.EmptyConfig()
   522  	}
   523  
   524  	tmpfile, err := ioutil.TempFile("", "terraform_module_pinned_source")
   525  	if err != nil {
   526  		t.Fatal(err)
   527  	}
   528  	defer os.Remove(tmpfile.Name())
   529  
   530  	if _, err := tmpfile.Write([]byte(content)); err != nil {
   531  		t.Fatal(err)
   532  	}
   533  	config, err := tflint.LoadConfig(tmpfile.Name())
   534  	if err != nil {
   535  		t.Fatal(err)
   536  	}
   537  	return config
   538  }