github.com/wata727/tflint@v0.12.2-0.20191013070026-96dd0d36f385/rules/terraformrules/terraform_module_pinned_source.go (about) 1 package terraformrules 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "strings" 8 9 "github.com/hashicorp/terraform/configs" 10 "github.com/wata727/tflint/tflint" 11 ) 12 13 // TerraformModulePinnedSourceRule checks unpinned or default version module source 14 type TerraformModulePinnedSourceRule struct { 15 attributeName string 16 } 17 18 // NewTerraformModulePinnedSourceRule returns new rule with default attributes 19 func NewTerraformModulePinnedSourceRule() *TerraformModulePinnedSourceRule { 20 return &TerraformModulePinnedSourceRule{ 21 attributeName: "source", 22 } 23 } 24 25 // Name returns the rule name 26 func (r *TerraformModulePinnedSourceRule) Name() string { 27 return "terraform_module_pinned_source" 28 } 29 30 // Enabled returns whether the rule is enabled by default 31 func (r *TerraformModulePinnedSourceRule) Enabled() bool { 32 return true 33 } 34 35 // Severity returns the rule severity 36 func (r *TerraformModulePinnedSourceRule) Severity() string { 37 return tflint.WARNING 38 } 39 40 // Link returns the rule reference link 41 func (r *TerraformModulePinnedSourceRule) Link() string { 42 return tflint.ReferenceLink(r.Name()) 43 } 44 45 var reGithub = regexp.MustCompile("(^github.com/(.+)/(.+)$)|(^git@github.com:(.+)/(.+)$)") 46 var reBitbucket = regexp.MustCompile("^bitbucket.org/(.+)/(.+)$") 47 var reGenericGit = regexp.MustCompile("(git://(.+)/(.+))|(git::https://(.+)/(.+))|(git::ssh://((.+)@)??(.+)/(.+)/(.+))") 48 49 // Check checks if module source version is default or unpinned 50 // Note that this rule is valid only for Git or Mercurial source 51 func (r *TerraformModulePinnedSourceRule) Check(runner *tflint.Runner) error { 52 log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath()) 53 54 for _, module := range runner.TFConfig.Module.ModuleCalls { 55 log.Printf("[DEBUG] Walk `%s` attribute", module.Name+".source") 56 57 lower := strings.ToLower(module.SourceAddr) 58 59 if reGithub.MatchString(lower) || reBitbucket.MatchString(lower) || reGenericGit.MatchString(lower) { 60 r.checkGitSource(runner, module) 61 } else if strings.HasPrefix(lower, "hg::") { 62 r.checkMercurialSource(runner, module) 63 } 64 } 65 66 return nil 67 } 68 69 // If the source has `ref=master` or doesn't have reference, it reports an issue for the module 70 func (r *TerraformModulePinnedSourceRule) checkGitSource(runner *tflint.Runner, module *configs.ModuleCall) { 71 lower := strings.ToLower(module.SourceAddr) 72 73 if strings.Contains(lower, "ref=") { 74 if strings.Contains(lower, "ref=master") { 75 runner.EmitIssue( 76 r, 77 fmt.Sprintf("Module source \"%s\" uses default ref \"master\"", module.SourceAddr), 78 module.SourceAddrRange, 79 ) 80 } 81 } else { 82 runner.EmitIssue( 83 r, 84 fmt.Sprintf("Module source \"%s\" is not pinned", module.SourceAddr), 85 module.SourceAddrRange, 86 ) 87 } 88 } 89 90 // If the source has `rev=default` or doesn't have reference, it reports an issue for the module 91 func (r *TerraformModulePinnedSourceRule) checkMercurialSource(runner *tflint.Runner, module *configs.ModuleCall) { 92 lower := strings.ToLower(module.SourceAddr) 93 94 if strings.Contains(lower, "rev=") { 95 if strings.Contains(lower, "rev=default") { 96 runner.EmitIssue( 97 r, 98 fmt.Sprintf("Module source \"%s\" uses default rev \"default\"", module.SourceAddr), 99 module.SourceAddrRange, 100 ) 101 } 102 } else { 103 runner.EmitIssue( 104 r, 105 fmt.Sprintf("Module source \"%s\" is not pinned", module.SourceAddr), 106 module.SourceAddrRange, 107 ) 108 } 109 }