Skip to content

Commit

Permalink
experiment: fix filter tfplan references for count
Browse files Browse the repository at this point in the history
  • Loading branch information
jaspervdj-snyk committed Mar 22, 2024
1 parent d867732 commit 1334ad2
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 7 deletions.
27 changes: 20 additions & 7 deletions pkg/input/tfplan.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ func (expr *tfplan_ConfigurationExpression) references(resolve func(string) *str
if expr.ConstantValue != nil {
return nil
} else if expr.References != nil {
refs := filterReferences(expr.References.References)
refs := TfPlanFilterReferences(expr.References.References)
resolved := make([]string, len(refs))
for i, ref := range refs {
if val := resolve(ref); val != nil {
Expand Down Expand Up @@ -647,13 +647,12 @@ func (w *replaceBoolTopDownWalker) WalkBool(b bool) (interface{}, bool) {

// Terraform plan format 0.2 introduced a change where the references array
// always includes both the property and its parent resource. We want to
// remove one of them (determined in should_filter) in order to maintain
// consistent behavior. The ordering is reliable - property followed by
// resource.
// remove one of them if possible so it can be matched as a resource.
//
// TODO: Maybe we should just do a version check and use that instead of
// this logic.
func filterReferences(refs []string) []string {
// TODO: this function is exposed we want to unit test it, and the tests use
// a different package for another reason. Consider moving `tfplan` to its
// own package like `arm`.
func TfPlanFilterReferences(refs []string) []string {
// Go in reverse to make use of the ordering.
prefixes := map[string]struct{}{}
for _, ref := range refs {
Expand All @@ -677,6 +676,20 @@ func filterReferences(refs []string) []string {
}
}

// If we had any counted resources, e.g. `aws_s3_bucket.bucket[0]`,
// we will have both `aws_s3_bucket.bucket[0]` as well as
// `aws_s3_bucket.bucket` in the list. We want to remove the latter since
// they don't point to an actual resource.
remove := map[string]struct{}{}
for prefix := range prefixes {
if idx := strings.IndexRune(prefix, '['); idx >= 0 {
remove[prefix[:idx]] = struct{}{}
}
}
for r := range remove {
delete(prefixes, r)
}

// Sort before returning
resources := []string{}
for k := range prefixes {
Expand Down
28 changes: 28 additions & 0 deletions pkg/input/tfplan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,31 @@ func TestTfPlanDetectorNotYAML(t *testing.T) {
assert.True(t, errors.Is(err, input.FailedToParseInput))
assert.Nil(t, tfplan)
}

func TestFilterReferences(t *testing.T) {
type test struct {
input []string
expected []string
}

tests := []test{
{
input: []string{
"aws_s3_bucket.bucket.id",
"aws_s3_bucket.bucket",
},
expected: []string{"aws_s3_bucket.bucket"},
},
{
input: []string{
"aws_s3_bucket.bucket[0].id",
"aws_s3_bucket.bucket[0]",
},
expected: []string{"aws_s3_bucket.bucket[0]"},
},
}

for _, test := range tests {
assert.Equal(t, input.TfPlanFilterReferences(test.input), test.expected)
}
}

0 comments on commit 1334ad2

Please sign in to comment.