Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

terraformrules: Remove dependencies on Terraform internal packages from rules #1433

Merged
merged 1 commit into from
Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl/v2 v2.13.0
github.com/hashicorp/logutils v1.0.0
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734
github.com/jessevdk/go-flags v1.5.0
github.com/jstemmer/go-junit-report v1.0.0
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgC
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg=
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c/go.mod h1:Wn3Na71knbXc1G8Lh+yu/dQWWJeFQEpDeJMtWMtlmNI=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0=
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
Expand Down Expand Up @@ -391,6 +393,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
Expand Down
42 changes: 38 additions & 4 deletions rules/terraformrules/terraform_documented_outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"fmt"
"log"

"github.com/hashicorp/hcl/v2/gohcl"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
sdk "github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint/tflint"
)

Expand Down Expand Up @@ -44,12 +47,43 @@ func (r *TerraformDocumentedOutputsRule) Check(runner *tflint.Runner) error {

log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath())

for _, output := range runner.TFConfig.Module.Outputs {
if output.Description == "" {
body, diags := runner.GetModuleContent(&hclext.BodySchema{
Blocks: []hclext.BlockSchema{
{
Type: "output",
LabelNames: []string{"name"},
Body: &hclext.BodySchema{
Attributes: []hclext.AttributeSchema{{Name: "description"}},
},
},
},
}, sdk.GetModuleContentOption{})
if diags.HasErrors() {
return diags
}

for _, output := range body.Blocks {
attr, exists := output.Body.Attributes["description"]
if !exists {
runner.EmitIssue(
r,
fmt.Sprintf("`%s` output has no description", output.Labels[0]),
output.DefRange,
)
continue
}

var description string
diags = gohcl.DecodeExpression(attr.Expr, nil, &description)
if diags.HasErrors() {
return diags
}

if description == "" {
runner.EmitIssue(
r,
fmt.Sprintf("`%s` output has no description", output.Name),
output.DeclRange,
fmt.Sprintf("`%s` output has no description", output.Labels[0]),
output.DefRange,
)
}
}
Expand Down
42 changes: 38 additions & 4 deletions rules/terraformrules/terraform_documented_variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"fmt"
"log"

"github.com/hashicorp/hcl/v2/gohcl"
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
sdk "github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint/tflint"
)

Expand Down Expand Up @@ -44,12 +47,43 @@ func (r *TerraformDocumentedVariablesRule) Check(runner *tflint.Runner) error {

log.Printf("[TRACE] Check `%s` rule for `%s` runner", r.Name(), runner.TFConfigPath())

for _, variable := range runner.TFConfig.Module.Variables {
if variable.Description == "" {
body, diags := runner.GetModuleContent(&hclext.BodySchema{
Blocks: []hclext.BlockSchema{
{
Type: "variable",
LabelNames: []string{"name"},
Body: &hclext.BodySchema{
Attributes: []hclext.AttributeSchema{{Name: "description"}},
},
},
},
}, sdk.GetModuleContentOption{})
if diags.HasErrors() {
return diags
}

for _, variable := range body.Blocks {
attr, exists := variable.Body.Attributes["description"]
if !exists {
runner.EmitIssue(
r,
fmt.Sprintf("`%s` variable has no description", variable.Labels[0]),
variable.DefRange,
)
continue
}

var description string
diags = gohcl.DecodeExpression(attr.Expr, nil, &description)
if diags.HasErrors() {
return diags
}

if description == "" {
runner.EmitIssue(
r,
fmt.Sprintf("`%s` variable has no description", variable.Name),
variable.DeclRange,
fmt.Sprintf("`%s` variable has no description", variable.Labels[0]),
variable.DefRange,
)
}
}
Expand Down
38 changes: 24 additions & 14 deletions rules/terraformrules/terraform_module_pinned_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

"github.com/Masterminds/semver/v3"
"github.com/hashicorp/go-getter"
"github.com/terraform-linters/tflint/terraform/configs"
sdk "github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint/tflint"
)

Expand Down Expand Up @@ -66,7 +66,17 @@ func (r *TerraformModulePinnedSourceRule) Check(runner *tflint.Runner) error {
return err
}

for _, module := range runner.TFConfig.Module.ModuleCalls {
body, diags := runner.GetModuleContent(moduleCallSchema, sdk.GetModuleContentOption{})
if diags.HasErrors() {
return diags
}

for _, block := range body.Blocks {
module, diags := decodeModuleCall(block)
if diags.HasErrors() {
return diags
}

if err := r.checkModule(runner, module, config); err != nil {
return err
}
Expand All @@ -75,10 +85,10 @@ func (r *TerraformModulePinnedSourceRule) Check(runner *tflint.Runner) error {
return nil
}

func (r *TerraformModulePinnedSourceRule) checkModule(runner *tflint.Runner, module *configs.ModuleCall, config terraformModulePinnedSourceRuleConfig) error {
log.Printf("[DEBUG] Walk `%s` attribute", module.Name+".source")
func (r *TerraformModulePinnedSourceRule) checkModule(runner *tflint.Runner, module *moduleCall, config terraformModulePinnedSourceRuleConfig) error {
log.Printf("[DEBUG] Walk `%s` attribute", module.name+".source")

source, err := getter.Detect(module.SourceAddrRaw, filepath.Dir(module.DeclRange.Filename), []getter.Detector{
source, err := getter.Detect(module.source, filepath.Dir(module.defRange.Filename), []getter.Detector{
// https://github.com/hashicorp/terraform/blob/51b0aee36cc2145f45f5b04051a01eb6eb7be8bf/internal/getmodules/getter.go#L30-L52
new(getter.GitHubDetector),
new(getter.GitDetector),
Expand Down Expand Up @@ -116,8 +126,8 @@ func (r *TerraformModulePinnedSourceRule) checkModule(runner *tflint.Runner, mod
if u.Hostname() == "" {
runner.EmitIssue(
r,
fmt.Sprintf("Module source %q is not a valid URL", module.SourceAddr),
module.SourceAddrRange,
fmt.Sprintf("Module source %q is not a valid URL", module.source),
module.sourceAttr.Expr.Range(),
)

return nil
Expand All @@ -135,23 +145,23 @@ func (r *TerraformModulePinnedSourceRule) checkModule(runner *tflint.Runner, mod

runner.EmitIssue(
r,
fmt.Sprintf(`Module source "%s" is not pinned`, module.SourceAddr),
module.SourceAddrRange,
fmt.Sprintf(`Module source "%s" is not pinned`, module.source),
module.sourceAttr.Expr.Range(),
)

return nil
}

func (r *TerraformModulePinnedSourceRule) checkRevision(runner *tflint.Runner, module *configs.ModuleCall, config terraformModulePinnedSourceRuleConfig, key string, value string) error {
func (r *TerraformModulePinnedSourceRule) checkRevision(runner *tflint.Runner, module *moduleCall, config terraformModulePinnedSourceRuleConfig, key string, value string) error {
switch config.Style {
// The "flexible" style requires a revision that is not a default branch
case "flexible":
for _, branch := range config.DefaultBranches {
if value == branch {
runner.EmitIssue(
r,
fmt.Sprintf("Module source \"%s\" uses a default branch as %s (%s)", module.SourceAddr, key, branch),
module.SourceAddrRange,
fmt.Sprintf("Module source \"%s\" uses a default branch as %s (%s)", module.source, key, branch),
module.sourceAttr.Expr.Range(),
)

return nil
Expand All @@ -163,8 +173,8 @@ func (r *TerraformModulePinnedSourceRule) checkRevision(runner *tflint.Runner, m
if err != nil {
runner.EmitIssue(
r,
fmt.Sprintf("Module source \"%s\" uses a %s which is not a semantic version string", module.SourceAddr, key),
module.SourceAddrRange,
fmt.Sprintf("Module source \"%s\" uses a %s which is not a semantic version string", module.source, key),
module.sourceAttr.Expr.Range(),
)
}
default:
Expand Down
16 changes: 8 additions & 8 deletions rules/terraformrules/terraform_module_pinned_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ module "unpinned" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://github.com/hashicorp/consul.git\" is not pinned",
Message: "Module source \"github.com/hashicorp/consul\" is not pinned",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand All @@ -162,7 +162,7 @@ module "unpinned" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::ssh://git@github.com/hashicorp/consul.git\" is not pinned",
Message: "Module source \"[email protected]:hashicorp/consul.git\" is not pinned",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand All @@ -180,7 +180,7 @@ module "default_git" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://github.com/hashicorp/consul.git?ref=master\" uses a default branch as ref (master)",
Message: "Module source \"github.com/hashicorp/consul.git?ref=master\" uses a default branch as ref (master)",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand Down Expand Up @@ -219,7 +219,7 @@ rule "terraform_module_pinned_source" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://github.com/hashicorp/consul.git?ref=pinned\" uses a ref which is not a semantic version string",
Message: "Module source \"github.com/hashicorp/consul.git?ref=pinned\" uses a ref which is not a semantic version string",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand Down Expand Up @@ -250,7 +250,7 @@ module "unpinned" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://bitbucket.org/hashicorp/tf-test-git.git\" is not pinned",
Message: "Module source \"bitbucket.org/hashicorp/tf-test-git\" is not pinned",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand All @@ -268,7 +268,7 @@ module "default_git" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://bitbucket.org/hashicorp/tf-test-git.git?ref=master\" uses a default branch as ref (master)",
Message: "Module source \"bitbucket.org/hashicorp/tf-test-git.git?ref=master\" uses a default branch as ref (master)",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand Down Expand Up @@ -299,7 +299,7 @@ rule "terraform_module_pinned_source" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://bitbucket.org/hashicorp/tf-test-git.git?ref=pinned\" uses a ref which is not a semantic version string",
Message: "Module source \"bitbucket.org/hashicorp/tf-test-git.git?ref=pinned\" uses a ref which is not a semantic version string",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand Down Expand Up @@ -429,7 +429,7 @@ rule "terraform_module_pinned_source" {
Expected: tflint.Issues{
{
Rule: NewTerraformModulePinnedSourceRule(),
Message: "Module source \"git::https://github.com/hashicorp/consul.git?ref=foo\" uses a default branch as ref (foo)",
Message: "Module source \"github.com/hashicorp/consul.git?ref=foo\" uses a default branch as ref (foo)",
Range: hcl.Range{
Filename: "module.tf",
Start: hcl.Pos{Line: 3, Column: 12},
Expand Down
Loading