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

support lists of resources in rules #3

Merged
merged 3 commits into from
Jul 15, 2018
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 assertion/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type (
Message string
Severity string
Resource string
Resources []string
Category string // default is "resource", can be "data", "provider" for Terraform
Conditions []Expression
Assertions []Expression
Expand Down
33 changes: 33 additions & 0 deletions assertion/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ func FilterResourcesByType(resources []Resource, resourceType string, resourceCa
return filtered
}

// FilterResourcesByTypes filters a list of resources that match a slice of resource types
func FilterResourcesByTypes(resources []Resource, resourceTypes []string, resourceCategory string) []Resource {
filtered := make([]Resource, 0)
for _, resource := range resources {
if SliceContains(resourceTypes, resource.Type) && categoryMatches(resourceCategory, resource.Category) {
filtered = append(filtered, resource)
}
}
return filtered
}

func categoryMatches(c1, c2 string) bool {
if c1 == "" || c1 == "*" {
return true
Expand All @@ -118,3 +129,25 @@ func JSONStringify(data interface{}) (string, error) {
func currentTime() string {
return time.Now().UTC().Format(time.RFC3339)
}

func SliceContains(list []string, value string) bool {
for _, item := range list {
if item == value {
return true
}
}
return false
}

// FilterResourcesForRule returns resources applicable to the given rule
func FilterResourcesForRule(resources []Resource, rule Rule) []Resource {
var filteredResources []Resource
if rule.Resource != "" {
Debugf("filtering rule resources on Resource string")
filteredResources = FilterResourcesByType(resources, rule.Resource, rule.Category)
} else {
Debugf("filtering rule resources on Resources slice")
filteredResources = FilterResourcesByTypes(resources, rule.Resources, rule.Category)
}
return filteredResources
}
71 changes: 71 additions & 0 deletions assertion/util_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package assertion

import (
"strings"
"testing"
)

Expand Down Expand Up @@ -129,3 +130,73 @@ func TestFilterShouldMatchCategoryForResources(t *testing.T) {
t.Errorf("FilterResourcesByType expected to match one resource")
}
}

func TestSliceContainsTrue(t *testing.T) {
test := []string{"x", "y", "z"}
isPresent := SliceContains(test, "x")
if isPresent != true {
t.Errorf("SliceContains expected to return true when a value is present")
}
}

func TestSliceContainsFalse(t *testing.T) {
test := []string{"x", "y", "z"}
isPresent := SliceContains(test, "a")
if isPresent != false {
t.Errorf("SliceContains expected to return false when a value is not present")
}
}

func TestFilterPluralShouldMatchMultipleResources(t *testing.T) {
resources := []Resource{
Resource{Type: "instance", Category: "resource"},
Resource{Type: "bucket", Category: "resource"},
}
filtered := FilterResourcesByTypes(resources, []string{"instance", "bucket"}, "resource")
if len(filtered) != 2 {
t.Errorf("FilterResourcesByTypes expected to match multiple types")
}
}

func TestFilterPluralShouldNotHaveUnlistedResources(t *testing.T) {
resources := []Resource{
Resource{Type: "instance", Category: "resource"},
Resource{Type: "bucket", Category: "resource"},
}
resourceTypes := []string{"instance"}
filtered := FilterResourcesByTypes(resources, resourceTypes, "resource")
if len(filtered) != 1 {
t.Errorf("FilterResourcesByTypes expected to match only %s", strings.Join(resourceTypes, ", "))
}
}

func TestFilterResourcesForRuleSlice(t *testing.T) {
resources := []Resource{
Resource{Type: "instance", Category: "resource"},
Resource{Type: "bucket", Category: "resource"},
}
rule := Rule{
Resources: []string{
"instance",
"bucket",
},
}
filtered := FilterResourcesForRule(resources, rule)
if len(filtered) != 2 {
t.Errorf("FilterResourcesForRule expected to return both resource types")
}
}

func TestFilterResourcesForRuleString(t *testing.T) {
resources := []Resource{
Resource{Type: "instance", Category: "resource"},
Resource{Type: "bucket", Category: "resource"},
}
rule := Rule{
Resource: "instance",
}
filtered := FilterResourcesForRule(resources, rule)
if len(filtered) != 1 {
t.Errorf("FilterResourcesForRule only expected to return one type")
}
}
3 changes: 2 additions & 1 deletion linter/resource_linter.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ func (r ResourceLinter) ValidateResources(resources []assertion.Resource, rules

for _, rule := range resolvedRules {
assertion.Debugf("Rule: ID: %v Message: %s\n", rule.ID, rule.Message)
for _, resource := range assertion.FilterResourcesByType(resources, rule.Resource, rule.Category) {
filteredResources := assertion.FilterResourcesForRule(resources, rule)
for _, resource := range filteredResources {
if assertion.ExcludeResource(rule, resource) {
assertion.Debugf("Ignoring resource %s\n", resource.ID)
} else {
Expand Down