rules/module_source.go (93 lines of code) (raw):

package rules import ( "strings" "github.com/hashicorp/go-multierror" "github.com/hashicorp/hcl/v2" "github.com/terraform-linters/tflint-plugin-sdk/hclext" "github.com/terraform-linters/tflint-plugin-sdk/tflint" ) var moduleSourceBodySchema = &hclext.BodySchema{ Blocks: []hclext.BlockSchema{ { Type: "module", LabelNames: []string{"name"}, Body: &hclext.BodySchema{ Attributes: []hclext.AttributeSchema{ { Name: "source", }, }, }, }, }, } var _ tflint.Rule = new(ModuleSourceRule) type ModuleSourceRule struct { tflint.DefaultRule } func NewModuleSourceRule() *ModuleSourceRule { return &ModuleSourceRule{} } func (t *ModuleSourceRule) Name() string { return "required_module_source_tffr1" } func (t *ModuleSourceRule) Link() string { return "https://azure.github.io/Azure-Verified-Modules/specs/terraform/#id-tffr1---category-composition---cross-referencing-modules" } func (t *ModuleSourceRule) Enabled() bool { return true } func (t *ModuleSourceRule) Severity() tflint.Severity { return tflint.ERROR } func (t *ModuleSourceRule) Check(r tflint.Runner) error { path, err := r.GetModulePath() if err != nil { return err } if !path.IsRoot() { return nil } body, err := r.GetModuleContent( moduleSourceBodySchema, &tflint.GetModuleContentOption{ExpandMode: tflint.ExpandModeNone}) if err != nil { return err } var errList error for _, block := range body.Blocks { if block.Type != "module" { continue } if subErr := t.checkBlock(r, block); subErr != nil { errList = multierror.Append(errList, subErr) } } return errList } func (t *ModuleSourceRule) checkBlock(r tflint.Runner, block *hclext.Block) error { source, exists := block.Body.Attributes["source"] if !exists { return r.EmitIssue( t, "The `source` field should be declared in the `module` block", block.DefRange, ) } if err := r.EvaluateExpr(source.Expr, t.isAVMModule(r, source.NameRange), &tflint.EvaluateExprOption{ModuleCtx: tflint.RootModuleCtxType}); err != nil { return err } return nil } func (t *ModuleSourceRule) isAVMModule(r tflint.Runner, issueRange hcl.Range) func(string) error { return func(source string) error { if (strings.HasPrefix(source, "Azure/") && strings.Contains(source, "avm-")) || strings.HasPrefix(source, "./modules/") { return nil } return r.EmitIssue( t, "The `source` property constraint should start with `Azure/` and contain `avm-` to only involve AVM Module", issueRange, ) } }