Skip to content

Commit

Permalink
INSIGHTS-588 - support for multiple test files (#230)
Browse files Browse the repository at this point in the history
* support for multiple test files

* add tests and some fixes

---------

Co-authored-by: jdesouza <[email protected]>
  • Loading branch information
vitorvezani and jdesouza authored Jan 8, 2025
1 parent 9813fcf commit 2ee3dfd
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 16 deletions.
5 changes: 4 additions & 1 deletion pkg/opavalidation/opavalidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ func RunBatch(batchDir string, expectAIOptions ExpectActionItemOptions, insights
return successfulPolicies, failedPolicies, fmt.Errorf("unable to list .rego files: %v", err)
}
for _, regoFileName := range regoFiles {
objectFileNames, ok := expectAIOptions.getObjectFileNamesForPolicy(regoFileName)
objectFileNames, ok, err := expectAIOptions.getObjectFileNamesForPolicy(regoFileName)
if err != nil {
return nil, nil, fmt.Errorf("error finding object files for policy %s: %w", regoFileName, err)
}
if !ok {
logrus.Errorf("No Kubernetes manifest files found to use as input for validation of OPA policy %s", regoFileName)
failedPolicies = append(failedPolicies, regoFileName)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
22 changes: 22 additions & 0 deletions pkg/opavalidation/testdata/multiple-validations/rego.failure.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
14 changes: 14 additions & 0 deletions pkg/opavalidation/testdata/multiple-validations/rego.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fairwinds

labelrequired[actionItem] {
requiredLabelValue := "development"
provided := [input.metadata.labels[_]]
description := sprintf("Label value %v is missing", [requiredLabelValue])
actionItem := {
"title": "Label is missing",
"description": description,
"severity": .2,
"remediation": "Add the label",
"category": "Reliability"
}
}
22 changes: 22 additions & 0 deletions pkg/opavalidation/testdata/multiple-validations/rego.success.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:1.0
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
47 changes: 32 additions & 15 deletions pkg/opavalidation/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package opavalidation
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/fatih/color"
Expand Down Expand Up @@ -174,7 +174,7 @@ type ExpectActionItemOptions struct {
}

// ForFileName returns true if the given Kubernetes manifest file name should
// expectan OPA policy to output an action item.
// expect an OPA policy to output an action item.
func (o ExpectActionItemOptions) ForFileName(fileName string) bool {
LCFileName := strings.ToLower(fileName)
LCSuccessExtension := strings.ToLower(o.SuccessFileExtension)
Expand All @@ -192,24 +192,41 @@ func (o ExpectActionItemOptions) ForFileName(fileName string) bool {
}

// getObjectFileNamesForPolicy returns a list of existing file names matching
// the pattern {base rego file name}.yaml|.success.yaml|.failure.yaml (the
// the pattern {base rego file name}.yaml|{base rego file name}.<anything>.success.yaml|{base rego file name}.<anything>.failure.yaml (the
// latter two being configurable via the expectActionItemOptions struct).
func (o ExpectActionItemOptions) getObjectFileNamesForPolicy(regoFileName string) (objectFileNames []string, foundAny bool) {
func (o ExpectActionItemOptions) getObjectFileNamesForPolicy(regoFileName string) (objectFileNames []string, foundAny bool, err error) {
baseFileName := strings.TrimSuffix(regoFileName, filepath.Ext(regoFileName))
var lookForFileNames []string = []string{
baseFileName + ".yaml",
baseFileName + o.SuccessFileExtension,
baseFileName + o.FailureFileExtension}
logrus.Debugf("Looking for these object files for policy %s: %v", regoFileName, lookForFileNames)
for _, potentialFileName := range lookForFileNames {
_, err := os.Stat(potentialFileName)
if err == nil {
objectFileNames = append(objectFileNames, potentialFileName)
foundAny = true
dir := filepath.Dir(regoFileName)

filenameYaml := fmt.Sprintf(`^%s\.yaml$`, regexp.QuoteMeta(baseFileName))
anythingFailureYaml := fmt.Sprintf(`^%s(\.[a-zA-Z0-9_-]+)?%s$`, regexp.QuoteMeta(baseFileName), regexp.QuoteMeta(o.FailureFileExtension))
anythingSuccessYaml := fmt.Sprintf(`^%s(\.[a-zA-Z0-9_-]+)?%s$`, regexp.QuoteMeta(baseFileName), regexp.QuoteMeta(o.SuccessFileExtension))

filenameYamlRegex := regexp.MustCompile(filenameYaml)
anythingFailureYamlRegex := regexp.MustCompile(anythingFailureYaml)
anythingSuccessYamlRegex := regexp.MustCompile(anythingSuccessYaml)

files, err := ListAllFilesInDir(dir, true)
if err != nil {
return nil, false, err
}

for _, file := range files {
if filenameYamlRegex.MatchString(file) {
objectFileNames = append(objectFileNames, file)
}
if anythingFailureYamlRegex.MatchString(file) {
objectFileNames = append(objectFileNames, file)
}
if anythingSuccessYamlRegex.MatchString(file) {
objectFileNames = append(objectFileNames, file)
}
}
if foundAny {

if len(objectFileNames) > 0 {
logrus.Debugf("Matched these object files for policy %s: %v", regoFileName, objectFileNames)
foundAny = true
}

return
}
20 changes: 20 additions & 0 deletions pkg/opavalidation/types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package opavalidation

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetObjectFileNamesForPolicy(t *testing.T) {
opts := ExpectActionItemOptions{
Default: true,
SuccessFileExtension: ".success.yaml",
FailureFileExtension: ".failure.yaml",
}

f, ok, err := opts.getObjectFileNamesForPolicy("testdata/multiple-validations/rego.rego")
assert.NoError(t, err)
assert.True(t, ok)
assert.Len(t, f, 6)
}
20 changes: 20 additions & 0 deletions pkg/opavalidation/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strings"

Expand Down Expand Up @@ -230,3 +231,22 @@ func FindFilesWithExtension(dir, ext string) ([]string, error) {
})
return files, err
}

func ListAllFilesInDir(dirPath string, includeDirPath bool) ([]string, error) {
files, err := os.ReadDir(dirPath)
if err != nil {
return nil, err
}
var fileNames []string
for _, file := range files {
if !file.IsDir() {
if includeDirPath {
fullPath := filepath.Join(dirPath, file.Name())
fileNames = append(fileNames, fullPath)
} else {
fileNames = append(fileNames, file.Name())
}
}
}
return fileNames, nil
}

0 comments on commit 2ee3dfd

Please sign in to comment.