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 }