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

INSIGHTS-588 - support for multiple test files #230

Merged
merged 3 commits into from
Jan 8, 2025
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
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
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"
}
}
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
}