Skip to content

Commit

Permalink
feat(tflint-ruleset): add terraform_minimum_required_version
Browse files Browse the repository at this point in the history
  • Loading branch information
apeabody committed Aug 2, 2024
1 parent ccd164f commit 70cbb5d
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 10 deletions.
12 changes: 6 additions & 6 deletions go.work
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
go 1.22
go 1.22.2

use (
./cli
./infra/blueprint-test
./infra/module-swapper
./infra/utils/fbf
./tflint-ruleset-blueprint
./cli
./infra/blueprint-test
./infra/module-swapper
./infra/utils/fbf
./tflint-ruleset-blueprint
)
10 changes: 6 additions & 4 deletions tflint-ruleset-blueprint/go.mod
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
module github.com/cloud-foundation-toolkit/tflint-ruleset-blueprint

go 1.22
go 1.22.2

toolchain go1.22.5

require github.com/terraform-linters/tflint-plugin-sdk v0.21.0
require (
github.com/hashicorp/hcl/v2 v2.21.0
github.com/terraform-linters/tflint-plugin-sdk v0.21.0
golang.org/x/mod v0.19.0
)

require (
github.com/agext/levenshtein v1.2.1 // indirect
Expand All @@ -15,7 +19,6 @@ require (
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.6.1 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl/v2 v2.21.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
Expand All @@ -25,7 +28,6 @@ require (
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/zclconf/go-cty v1.15.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package rules

import (
"fmt"
"regexp"

"github.com/hashicorp/hcl/v2/gohcl"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"golang.org/x/mod/semver"
)

// TerraformMinimumRequiredVersion checks if a module has a valid minimum terraform required_version.
type TerraformMinimumRequiredVersion struct {
tflint.DefaultRule
}

// NewTerraformMinimumRequiredVersion returns a new rule.
func NewTerraformMinimumRequiredVersion() *TerraformMinimumRequiredVersion {
return &TerraformMinimumRequiredVersion{}
}

// Name returns the rule name.
func (r *TerraformMinimumRequiredVersion) Name() string {
return "terraform_minimum_required_version"
}

// Enabled returns whether the rule is enabled by default.
func (r *TerraformMinimumRequiredVersion) Enabled() bool {
return false
}

// Severity returns the rule severity.
func (r *TerraformMinimumRequiredVersion) Severity() tflint.Severity {
return tflint.ERROR
}

// Link returns the rule reference link
func (r *TerraformMinimumRequiredVersion) Link() string {
return "https://googlecloudplatform.github.io/samples-style-guide/#language-specific"
}

const (
terraform_minimum_required_version = "v1.3.0"
)

// Check checks whether config contains restricted resource types.
func (r *TerraformMinimumRequiredVersion) Check(runner tflint.Runner) error {
path, err := runner.GetModulePath()
if err != nil {
return err
}

if !path.IsRoot() {
return nil
}

content, err := runner.GetModuleContent(&hclext.BodySchema{
Blocks: []hclext.BlockSchema{
{
Type: "terraform",
Body: &hclext.BodySchema{
Attributes: []hclext.AttributeSchema{{Name: "required_version"}},
},
},
},
}, &tflint.GetModuleContentOption{ExpandMode: tflint.ExpandModeNone})
if err != nil {
return err
}

for _, block := range content.Blocks {
var raw_terraform_required_version string
diags := gohcl.DecodeExpression(block.Body.Attributes["required_version"].Expr, nil, &raw_terraform_required_version)
if diags.HasErrors() {
return fmt.Errorf("failed to decode terraform_required_version %q: %v", block.Labels[0], diags.Error())
}

re := regexp.MustCompile(`^(?:>=|=)*[ v]*([0-9.]*)`)
matches := re.FindStringSubmatch(raw_terraform_required_version)
if len (matches) != 2 || matches[1] == "" {
return runner.EmitIssue(r, fmt.Sprintf("unable to parse required_version to semver, raw: %q", raw_terraform_required_version), block.DefRange)
}
terraform_required_version := fmt.Sprintf("v%s", matches[1])

if !semver.IsValid(terraform_required_version) {
fmt.Println(terraform_required_version)
return runner.EmitIssue(r, fmt.Sprintf("unable to parse required_version %q to semver, raw: %q", terraform_required_version, raw_terraform_required_version), block.DefRange)
} else if semver.Compare(terraform_required_version, terraform_minimum_required_version) == -1 {
//TODO: use EmitIssueWithFix()
runner.EmitIssue(r, fmt.Sprintf("required_version %q is less than terraform_minimum_required_version %q, raw: %q", terraform_required_version, terraform_minimum_required_version, raw_terraform_required_version), block.DefRange)

Check failure on line 91 in tflint-ruleset-blueprint/rules/terraform_minimum_required_version.go

View workflow job for this annotation

GitHub Actions / lint (tflint-ruleset-blueprint)

Error return value of `runner.EmitIssue` is not checked (errcheck)
}

}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package rules

import (
"path"
"testing"

"golang.org/x/mod/semver"
)

const (
terraformMinimumRequiredVersionTestDir = "terraform_minimum_required_version"
)

func TestTerraformMinimumRequiredVersion(t *testing.T) {
if !semver.IsValid(terraform_minimum_required_version) {
t.Fatal("unable to parse terraform_minimum_required_version: ", terraform_minimum_required_version)
}

tests := []ruleTC{
{
dir: path.Join(terraformMinimumRequiredVersionTestDir, "multiple-valid"),
},
{
dir: path.Join(terraformMinimumRequiredVersionTestDir, "multiple-invalid"),
},
}

rule := NewTerraformMinimumRequiredVersion()

for _, tc := range tests {
t.Run(tc.dir, func(t *testing.T) {
ruleTest(t, rule, tc)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
[
{
"Message": "required_version \"v1\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \">= 1\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 1,
"Column": 1
},
"End": {
"Line": 1,
"Column": 10
}
}
},
{
"Message": "required_version \"v1.1\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \">= 1.1\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 5,
"Column": 1
},
"End": {
"Line": 5,
"Column": 10
}
}
},
{
"Message": "required_version \"v1.1.0\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \">= 1.1.0\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 9,
"Column": 1
},
"End": {
"Line": 9,
"Column": 10
}
}
},
{
"Message": "required_version \"v1.1.0\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \">=1.1.0\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 13,
"Column": 1
},
"End": {
"Line": 13,
"Column": 10
}
}
},
{
"Message": "required_version \"v1.1.0\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \">= 1.1.0, < 2.0\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 17,
"Column": 1
},
"End": {
"Line": 17,
"Column": 10
}
}
},
{
"Message": "required_version \"v0.13.0\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \">=0.13.0\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 21,
"Column": 1
},
"End": {
"Line": 21,
"Column": 10
}
}
},
{
"Message": "required_version \"v0.13.0\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \"=0.13.0\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 25,
"Column": 1
},
"End": {
"Line": 25,
"Column": 10
}
}
},
{
"Message": "required_version \"v0.13.0\" is less than terraform_minimum_required_version \"v1.3.0\", raw: \"0.13.0\"",
"Range": {
"Filename": "main.tf",
"Start": {
"Line": 29,
"Column": 1
},
"End": {
"Line": 29,
"Column": 10
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
terraform {
required_version = ">= 1"
}

terraform {
required_version = ">= 1.1"
}

terraform {
required_version = ">= 1.1.0"
}

terraform {
required_version = ">=1.1.0"
}

terraform {
required_version = ">= 1.1.0, < 2.0"
}

terraform {
required_version = ">=0.13.0"
}

terraform {
required_version = "=0.13.0"
}

terraform {
required_version = "0.13.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
terraform {
required_version = ">=1.3"
}

terraform {
required_version = ">=1.3.0"
}

terraform {
required_version = ">=v1.3"
}

terraform {
required_version = ">=1.4"
}

terraform {
required_version = ">= 1.3"
}

terraform {
required_version = ">= v1.3"
}

terraform {
required_version = ">=1.3, <2.0"
}

terraform {
required_version = ">= 1.3, < 2.0"
}

terraform {
required_version = "=1.3"
}

terraform {
required_version = "1.3"
}

0 comments on commit 70cbb5d

Please sign in to comment.