Skip to content

Commit 20b5d5e

Browse files
committed
don't enable the rule by default, handle more cases, use lang.ReferencesInExpr
1 parent 1b90b9f commit 20b5d5e

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

rules/aws_s3_no_global_endpoint.go

+39-19
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,33 @@
11
package rules
22

33
import (
4+
"strings"
5+
46
hcl "github.com/hashicorp/hcl/v2"
7+
hclsyntax "github.com/hashicorp/hcl/v2/hclsyntax"
8+
lang "github.com/terraform-linters/tflint-plugin-sdk/terraform/lang"
59
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
610
"github.com/terraform-linters/tflint-ruleset-aws/project"
711
)
812

9-
// AwsS3NoGlobalEndpointRule checks whether deprecated s3 global endpoint is used instead
10-
// of the regional endoint
13+
// AwsS3NoGlobalEndpointRule checks whether deprecated s3 global endpoint is used
1114
type AwsS3NoGlobalEndpointRule struct {
1215
tflint.DefaultRule
13-
14-
// TODO: do we need this, if so why
15-
resourceType string
16-
attributeName string
1716
}
1817

1918
// NewAwsS3NoGlobalEndpointRule returns new rule with default attributes
2019
func NewAwsS3NoGlobalEndpointRule() *AwsS3NoGlobalEndpointRule {
21-
return &AwsS3NoGlobalEndpointRule{
22-
resourceType: "aws_s3_bucket",
23-
attributeName: "",
24-
}
20+
return &AwsS3NoGlobalEndpointRule{}
2521
}
2622

2723
// Name returns the rule name
2824
func (r *AwsS3NoGlobalEndpointRule) Name() string {
29-
return "aws_acm_certificate_lifecycle"
25+
return "aws_s3_no_global_endpoint"
3026
}
3127

3228
// Enabled returns whether the rule is enabled by default
3329
func (r *AwsS3NoGlobalEndpointRule) Enabled() bool {
34-
return true
30+
return false
3531
}
3632

3733
// Severity returns the rule severity
@@ -44,23 +40,47 @@ func (r *AwsS3NoGlobalEndpointRule) Link() string {
4440
return project.ReferenceLink(r.Name())
4541
}
4642

47-
// Check checks whether the aws_acm_certificate resource contains create_before_destroy = true in lifecycle block
43+
func isS3BucketResourceOrData(str string) bool {
44+
return strings.HasPrefix(str, "aws_s3_bucket") || strings.HasPrefix(str, "data.aws_s3_bucket")
45+
}
46+
47+
func getRealRange(srcRange hcl.Range) hcl.Range {
48+
// ref.SourceRange doesn't include the bucket_domain_name attribute which is 19 characters long
49+
srcRange.End.Column += 19
50+
return srcRange
51+
}
52+
53+
// Check checks whether the deprecated s3 global endpoint is used
4854
func (r *AwsS3NoGlobalEndpointRule) Check(runner tflint.Runner) error {
4955
var err error
5056
runner.WalkExpressions(tflint.ExprWalkFunc(func(expr hcl.Expression) hcl.Diagnostics {
51-
vars := expr.Variables()
57+
_, isTemplateExpr := expr.(*hclsyntax.TemplateExpr)
58+
if isTemplateExpr {
59+
// TODO: check sth like .s3.amazonaws.com inside template expression ?
5260

53-
if len(vars) == 0 {
61+
// "${aws_s3_bucket.test.bucket_domain_name}" would report the same error twice if we didn't return here
5462
return nil
5563
}
5664

57-
// is this ever greater than 0
58-
v := vars[0]
65+
refs := lang.ReferencesInExpr(expr)
5966

60-
if v.RootName() == "aws_s3_bucket" && len(v) == 3 && v[2].(hcl.TraverseAttr).Name == "bucket_domain_name" {
61-
err = runner.EmitIssue(r, "`bucket_domain_name` returns the legacy s3 global endpoint, use `bucket_regional_domain_name` instead", v.SourceRange())
67+
if len(refs) != 1 {
68+
return nil
6269
}
6370

71+
ref := refs[0]
72+
73+
// lang.ReferencesInExpr(expr) is broken when the reference contains subexpression ?
74+
// e.g. aws_s3_bucket.test[length(var.bucket_names) - 1]
75+
// TODO: seems like a niche case, should we handle this ?
76+
if isS3BucketResourceOrData(ref.Subject.String()) && len(ref.Remaining) == 1 && ref.Remaining[0].(hcl.TraverseAttr).Name == "bucket_domain_name" {
77+
// ref.SourceRange doesn't include the bucket_domain_name attribute which is 19 characters long
78+
srcRange := getRealRange(ref.SourceRange)
79+
err = runner.EmitIssue(r, "`bucket_domain_name` returns the legacy s3 global endpoint, use `bucket_regional_domain_name` instead", srcRange)
80+
}
81+
82+
// TODO: handle foreach, count, dynamic blocks
83+
6484
return nil
6585
}))
6686

0 commit comments

Comments
 (0)