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  }