Skip to content

Commit

Permalink
Add hardcoded AMI ID check
Browse files Browse the repository at this point in the history
  • Loading branch information
YakDriver committed Jul 2, 2020
1 parent 7a7693d commit efa2f87
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 0 deletions.
1 change: 1 addition & 0 deletions awsproviderlint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The `awsproviderlint` tool extends the `tfproviderlint` tool and its checks. See
| Check | Description |
|---|---|
| [AWSAT001](passes/AWSAT001/README.md) | check for `resource.TestMatchResourceAttr()` calls against ARN attributes |
| [AWSAT002](passes/AWSAT002/README.md) | check for hardcoded AMI IDs |

### AWS Resource Checks

Expand Down
59 changes: 59 additions & 0 deletions awsproviderlint/passes/AWSAT002/AWSAT002.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Package AWSAT002 defines an Analyzer that checks for
// hardcoded AMI IDs
package AWSAT002

import (
"go/ast"
"go/token"
"regexp"

"github.com/bflad/tfproviderlint/passes/commentignore"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)

const Doc = `check for hardcoded AMI IDs
The AWSAT002 analyzer reports hardcoded AMI IDs. AMI IDs are region dependent and tests will fail in any region or partition other than where the AMI was created.
`

const analyzerName = "AWSAT002"

var Analyzer = &analysis.Analyzer{
Name: analyzerName,
Doc: Doc,
Requires: []*analysis.Analyzer{
commentignore.Analyzer,
inspect.Analyzer,
},
Run: run,
}

func run(pass *analysis.Pass) (interface{}, error) {
ignorer := pass.ResultOf[commentignore.Analyzer].(*commentignore.Ignorer)
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)

nodeFilter := []ast.Node{
(*ast.BasicLit)(nil),
}
re := regexp.MustCompile("ami-[0-9a-z]{8,17}")
inspect.Preorder(nodeFilter, func(n ast.Node) {
x := n.(*ast.BasicLit)

if ignorer.ShouldIgnore(analyzerName, x) {
return
}

if x.Kind != token.STRING {
return
}

if !re.MatchString(x.Value) {
return
}

pass.Reportf(x.ValuePos, "%s: AMI IDs should not be hardcoded", analyzerName)
})
return nil, nil
}
13 changes: 13 additions & 0 deletions awsproviderlint/passes/AWSAT002/AWSAT002_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package AWSAT002_test

import (
"testing"

"github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSAT002"
"golang.org/x/tools/go/analysis/analysistest"
)

func TestAWSAT002(t *testing.T) {
testdata := analysistest.TestData()
analysistest.Run(t, testdata, AWSAT002.Analyzer, "a")
}
56 changes: 56 additions & 0 deletions awsproviderlint/passes/AWSAT002/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# AWSAT002

The AWSAT002 analyzer reports hardcoded AMI IDs. AMI IDs are region dependent and tests will fail in any region or partition other than where the AMI was created.

## Flagged Code

```go
func testAccAWSSpotFleetRequestConfig(rName string, rInt int, validUntil string) string {
return testAccAWSSpotFleetRequestConfigBase(rName, rInt) + fmt.Sprintf(`
resource "aws_spot_fleet_request" "test" {
launch_specification {
instance_type = "m1.small"
ami = "ami-516b9131"
}
}
`, validUntil)
}
```

## Passing Code

```go
func testAccAWSSpotFleetRequestConfig(rName string, rInt int, validUntil string) string {
return testAccAWSSpotFleetRequestConfigBase(rName, rInt) + fmt.Sprintf(`
data "aws_ami" "amzn-ami-minimal-hvm-ebs" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn-ami-minimal-hvm-*"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
}
resource "aws_spot_fleet_request" "test" {
launch_specification {
instance_type = "m1.small"
ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id
}
}
`, validUntil)
}
```

## Ignoring Reports

Singular reports can be ignored by adding the a `//lintignore:AWSAT002` Go code comment at the end of the offending line or on the line immediately proceding, e.g.

```go
ami = "ami-516b9131" //lintignore:AWSAT002
```
43 changes: 43 additions & 0 deletions awsproviderlint/passes/AWSAT002/testdata/src/a/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package a

import (
"fmt"
)

func f() {
/* Passing cases */
fmt.Sprintf(`
data "aws_ami" "amzn-ami-minimal-hvm-ebs" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn-ami-minimal-hvm-*"]
}
filter {
name = "root-device-type"
values = [%q]
}
}
resource "aws_spot_fleet_request" "test" {
launch_specification {
ami = data.aws_ami.amzn-ami-minimal-hvm-ebs.id
}
}
`, "ebs")

/* Comment ignored cases */

//lintignore:AWSAT002
fmt.Sprintf(`ami = "%s"`, "ami-516b9131")

fmt.Sprintf(`ami = "%s"`, "ami-516b9131") //lintignore:AWSAT002
fmt.Sprintf(`ami = "%s"`, "amzn-ami-minimalist-ebs") //lintignore:AWSAT002

/* Failing cases */

fmt.Sprintf(`ami = "%s"`, "ami-516b9131") // want "AMI IDs should not be hardcoded"
}
1 change: 1 addition & 0 deletions awsproviderlint/passes/AWSAT002/testdata/src/a/vendor
2 changes: 2 additions & 0 deletions awsproviderlint/passes/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package passes

import (
"github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSAT001"
"github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSAT002"
"github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSR001"
"github.com/terraform-providers/terraform-provider-aws/awsproviderlint/passes/AWSR002"
"golang.org/x/tools/go/analysis"
)

var AllChecks = []*analysis.Analyzer{
AWSAT001.Analyzer,
AWSAT002.Analyzer,
AWSR001.Analyzer,
AWSR002.Analyzer,
}

0 comments on commit efa2f87

Please sign in to comment.