Repository: Azure/draft
Pull request #392 (2024-10-07 17:38:51)

Validate with Helm and Kustomize Support
# Description

Merging helm and kustomize support for draft validate.
Draft validate will validate manifests given a path to a helm chart, Kustomize dir, a directory of .yaml files, or a single yaml file.

Helm specifically requires --releaseName or -n and --releaseNamespace or -e flags. Otherwise, it uses the directory name as the default name.

Fixes # (issue)
Feature # (details)

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Refactor

## How Has This Been Tested?

Provide instructions so we can reproduce, and list any relevant details for your test configuration. Please mention if this is a breaking change which will impact consuming tool(s).

- [X] Unit Test: 
- [ ] E2E Test:
- [ ] Other Test:


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream modules



bacongobbler: Hey @profesor79! Can you give us more information on what version of draft you're running?
bacongobbler: Curious that in your first screenshot it looks like the path it's looking for is `...\.draft\packs\ack=csharp`. I haven't seen that before.
bacongobbler: Hmm. `draft create` works just fine for me using the example ASP.NET application.

```
PS C:\Users\mafishe\go\src\github.com\Azure\draft\examples\csharp> draft create
--> Draft detected the primary language as csharp with 84.861307% certainty.
--> Ready to sail
```

Do you have a public repository that we can use to test against?
bacongobbler: One PR that may assist with the language being detected as XML would be #344. If there is a large amount of code in your .csproj files then linguist is going to detect that a large majority of your codebase is written in XML. Once #344 is finalized and merged, you can fix this by writing out the following .gitattributes file in the root of your application:

```
*.csproj linguist-language=csharp
```
bacongobbler: ping, any news on this front?
profesor79: pong - will try to check that tomorrow and will revert here.
bacongobbler: I'm going to close this issue due to inactivity and due to lack of being able to reproduce the issue locally, but please feel free to re-open and report back once you get an idea how it occurred. Thanks!

Patch:
diff --git a/cmd/validate.go b/cmd/validate.go
index 0df3232..396db90 100644
--- a/cmd/validate.go
+++ b/cmd/validate.go
@@ -3,16 +3,20 @@ package cmd
 import (
 	"context"
 	"fmt"
-	"path"
 
 	"github.com/Azure/draft/pkg/safeguards"
+	"github.com/Azure/draft/pkg/safeguards/types"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
+
+	"helm.sh/helm/v3/pkg/chartutil"
 )
 
 type validateCmd struct {
-	manifestPath    string
-	imagePullSecret bool
+	manifestPath     string
+	imagePullSecret  bool
+	releaseName      string
+	releaseNamespace string
 }
 
 func init() {
@@ -38,6 +42,8 @@ func newValidateCmd() *cobra.Command {
 
 	f.StringVarP(&vc.manifestPath, "manifest", "m", "", "'manifest' asks for the path to the manifest")
 	f.BoolVarP(&vc.imagePullSecret, "imagePullSecret", "s", false, "'imagePullSecret' enables the Safeguard that checks for usage of an image pull secret within the manifest(s)")
+	f.StringVarP(&vc.releaseName, "releaseName", "n", "", "'releaseName' asks for a user-defined release name for the Helm package to use when rendering Helm projects in Draft")
+	f.StringVarP(&vc.releaseNamespace, "releaseNamespace", "e", "", "'releaseNamespace' asks for a user-defined release namespace for the Helm package to use when rendering Helm projects in Draft")
 
 	return cmd
 }
@@ -54,25 +60,19 @@ func (vc *validateCmd) run(c *cobra.Command) error {
 		safeguards.AddSafeguardCRIP()
 	}
 
-	ctx := context.Background()
-	isDir, err := safeguards.IsDirectory(vc.manifestPath)
-	if err != nil {
-		return fmt.Errorf("not a valid file or directory: %w", err)
+	var opt chartutil.ReleaseOptions
+	if vc.releaseName != "" {
+		opt.Name = vc.releaseName
+	}
+	if vc.releaseNamespace != "" {
+		opt.Namespace = vc.releaseNamespace
 	}
+	ctx := context.Background()
 
-	var manifestFiles []safeguards.ManifestFile
-	if isDir {
-		manifestFiles, err = safeguards.GetManifestFiles(vc.manifestPath)
-		if err != nil {
-			return err
-		}
-	} else if safeguards.IsYAML(vc.manifestPath) {
-		manifestFiles = append(manifestFiles, safeguards.ManifestFile{
-			Name: path.Base(vc.manifestPath),
-			Path: vc.manifestPath,
-		})
-	} else {
-		return fmt.Errorf("expected at least one .yaml or .yml file within given path")
+	var manifestFiles []types.ManifestFile
+	manifestFiles, err := safeguards.GetManifestFiles(vc.manifestPath, opt)
+	if err != nil {
+		return fmt.Errorf("error retrieving manifest files: %w", err)
 	}
 
 	log.Debugf("validating manifests")
diff --git a/pkg/safeguards/constants.go b/pkg/safeguards/constants.go
deleted file mode 100644
index 5ddff85..0000000
--- a/pkg/safeguards/constants.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package safeguards
-
-import (
-	"fmt"
-)
-
-const (
-	Constraint_CAI   = "container-allowed-images"
-	Constraint_CEP   = "container-enforce-probes"
-	Constraint_CRL   = "container-resource-limits"
-	Constraint_CRIP  = "container-restricted-image-pulls"
-	Constraint_DBPDB = "disallowed-bad-pod-disruption-budgets"
-	Constraint_PEA   = "pod-enforce-antiaffinity"
-	Constraint_RT    = "restricted-taints"
-	Constraint_USS   = "unique-service-selectors"
-	Constraint_all   = "all"
-)
-
-var selectedVersion = "v1.0.0"
-
-var supportedVersions = []string{selectedVersion}
-
-const (
-	templateFileName   = "template.yaml"
-	constraintFileName = "constraint.yaml"
-)
-
-var Safeguard_CRIP = Safeguard{
-	name:           Constraint_CRIP,
-	templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CRIP, templateFileName),
-	constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CRIP, constraintFileName),
-}
-
-var safeguards = []Safeguard{
-	{
-		name:           Constraint_CAI,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CAI, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CAI, constraintFileName),
-	},
-	{
-		name:           Constraint_CEP,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CEP, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CEP, constraintFileName),
-	},
-	{
-		name:           Constraint_CRL,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CRL, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_CRL, constraintFileName),
-	},
-	{
-		name:           Constraint_DBPDB,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_DBPDB, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_DBPDB, constraintFileName),
-	},
-	{
-		name:           Constraint_PEA,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_PEA, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_PEA, constraintFileName),
-	},
-	{
-		name:           Constraint_RT,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_RT, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_RT, constraintFileName),
-	},
-	{
-		name:           Constraint_USS,
-		templatePath:   fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_USS, templateFileName),
-		constraintPath: fmt.Sprintf("lib/%s/%s/%s", selectedVersion, Constraint_USS, constraintFileName),
-	},
-}
-
-var safeguardsTesting = append(safeguards, Safeguard_CRIP)
diff --git a/pkg/safeguards/helpers.go b/pkg/safeguards/helpers.go
index c64874f..a9009e6 100644
--- a/pkg/safeguards/helpers.go
+++ b/pkg/safeguards/helpers.go
@@ -1,148 +1,141 @@
 package safeguards
 
 import (
-	"bufio"
 	"context"
 	"fmt"
 	"io/fs"
 	"os"
+	"path"
 	"path/filepath"
+	"strings"
+
+	"helm.sh/helm/v3/pkg/chartutil"
 
 	constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
 	"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego"
 	"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
-	api "github.com/open-policy-agent/gatekeeper/v3/apis"
-	"github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader"
 	"github.com/open-policy-agent/gatekeeper/v3/pkg/target"
 	log "github.com/sirupsen/logrus"
 	"golang.org/x/mod/semver"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/apimachinery/pkg/runtime"
-	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
-)
-
-// retrieves the constraint client that does all rego code related operations
-func getConstraintClient() (*constraintclient.Client, error) {
-	driver, err := rego.New()
-	if err != nil {
-		return nil, fmt.Errorf("could not create rego driver: %w", err)
-	}
-
-	c, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
-	if err != nil {
-		return nil, fmt.Errorf("could not create constraint client: %w", err)
-	}
-
-	return c, nil
-}
 
-// sorts the list of supported safeguards versions and returns the last item in the list
-func getLatestSafeguardsVersion() string {
-	semver.Sort(supportedVersions)
-	return supportedVersions[len(supportedVersions)-1]
-}
-
-func updateSafeguardPaths(safeguardList *[]Safeguard) {
-	for _, sg := range *safeguardList {
-		sg.templatePath = fmt.Sprintf("%s/%s/%s", selectedVersion, sg.name, templateFileName)
-		sg.constraintPath = fmt.Sprintf("%s/%s/%s", selectedVersion, sg.name, constraintFileName)
-	}
-}
-
-// adds Safeguard_CRIP to full list of Safeguards
-func AddSafeguardCRIP() {
-	fc.Safeguards = append(fc.Safeguards, Safeguard_CRIP)
-}
+	"github.com/Azure/draft/pkg/safeguards/preprocessing"
+	"github.com/Azure/draft/pkg/safeguards/types"
+)
 
-// methods for retrieval of manifest, constraint templates, and constraints
-func (fc FileCrawler) ReadManifests(path string) ([]*unstructured.Unstructured, error) {
-	file, err := os.Open(path)
+// Given a path, will determine if it's Kustomize, Helm, a directory of manifests, or a single manifest
+func GetManifestFiles(manifestsPath string, opt chartutil.ReleaseOptions) ([]types.ManifestFile, error) {
+	isDir, err := IsDirectory(manifestsPath)
 	if err != nil {
-		return nil, fmt.Errorf("opening file %q: %w", path, err)
+		return nil, fmt.Errorf("not a valid file or directory: %w", err)
 	}
-	defer file.Close()
 
-	manifests, err := reader.ReadK8sResources(bufio.NewReader(file))
-	if err != nil {
-		return nil, fmt.Errorf("reading file %q: %w", path, err)
+	var manifestFiles []types.ManifestFile
+	if isDir {
+		// check if Helm or Kustomize dir
+		if isHelm(true, manifestsPath) {
+			return preprocessing.RenderHelmChart(false, manifestsPath, opt)
+		} else if isKustomize(true, manifestsPath) {
+			return preprocessing.RenderKustomizeManifest(manifestsPath)
+		} else {
+			manifestFiles, err = GetManifestFilesFromDir(manifestsPath)
+			return manifestFiles, err
+		}
+	} else if IsYAML(manifestsPath) { // path points to a file
+		if isHelm(false, manifestsPath) {
+			return preprocessing.RenderHelmChart(true, manifestsPath, opt)
+		} else if isKustomize(false, manifestsPath) {
+			return preprocessing.RenderKustomizeManifest(manifestsPath)
+		} else {
+			byteContent, err := os.ReadFile(manifestsPath)
+			if err != nil {
+				return nil, fmt.Errorf("could not read file %s: %s", manifestsPath, err)
+			}
+			manifestFiles = append(manifestFiles, types.ManifestFile{
+				Name:            path.Base(manifestsPath),
+				ManifestContent: byteContent,
+			})
+		}
+		return manifestFiles, nil
+	} else {
+		return nil, fmt.Errorf("expected at least one .yaml or .yml file within given path")
 	}
-
-	return manifests, nil
 }
 
-func GetScheme() *runtime.Scheme {
-	var s = runtime.NewScheme()
-	_ = clientgoscheme.AddToScheme(s)
-	_ = api.AddToScheme(s)
-	return s
-}
+// GetManifestFilesFromDir uses filepath.Walk to retrieve a list of the manifest files within a directory of .yaml files
+func GetManifestFilesFromDir(p string) ([]types.ManifestFile, error) {
+	var manifestFiles []types.ManifestFile
 
-func (fc FileCrawler) ReadConstraintTemplates() ([]*templates.ConstraintTemplate, error) {
-	var constraintTemplates []*templates.ConstraintTemplate
+	err := filepath.Walk(p, func(walkPath string, info fs.FileInfo, err error) error {
+		manifest := types.ManifestFile{}
+		// skip when walkPath is just given path and also a directory
+		if p == walkPath && info.IsDir() {
+			return nil
+		}
 
-	for _, sg := range fc.Safeguards {
-		ct, err := reader.ReadTemplate(GetScheme(), fc.constraintFS, sg.templatePath)
 		if err != nil {
-			return nil, fmt.Errorf("reading template: %w", err)
+			return fmt.Errorf("error walking path %s with error: %w", walkPath, err)
 		}
-		constraintTemplates = append(constraintTemplates, ct)
-	}
-
-	return constraintTemplates, nil
-}
 
-func (fc FileCrawler) ReadConstraintTemplate(name string) (*templates.ConstraintTemplate, error) {
-	var constraintTemplate *templates.ConstraintTemplate
+		if !info.IsDir() && info.Name() != "" && IsYAML(walkPath) {
+			log.Debugf("%s is not a directory, appending to manifestFiles", info.Name())
 
-	for _, sg := range fc.Safeguards {
-		if sg.name == name {
-			ct, err := reader.ReadTemplate(GetScheme(), fc.constraintFS, sg.templatePath)
+			byteContent, err := os.ReadFile(walkPath)
 			if err != nil {
-				return nil, fmt.Errorf("could not read template: %w", err)
+				return fmt.Errorf("could not read file %s: %s", walkPath, err)
 			}
-			constraintTemplate = ct
+			manifest.Name = info.Name()
+			manifest.ManifestContent = byteContent
+			manifestFiles = append(manifestFiles, manifest)
+		} else if !IsYAML(p) {
+			log.Debugf("%s is not a manifest file, skipping...", info.Name())
+		} else {
+			log.Debugf("%s is a directory, skipping...", info.Name())
 		}
+
+		return nil
+	})
+	if err != nil {
+		return nil, fmt.Errorf("could not walk directory: %w", err)
 	}
-	if constraintTemplate == nil {
-		return nil, fmt.Errorf("no constraint template exists with name: %s", name)
+	if len(manifestFiles) == 0 {
+		return nil, fmt.Errorf("no manifest files found within given path")
 	}
 
-	return constraintTemplate, nil
+	return manifestFiles, nil
 }
 
-func (fc FileCrawler) ReadConstraints() ([]*unstructured.Unstructured, error) {
-	var constraints []*unstructured.Unstructured
-
-	for _, sg := range fc.Safeguards {
-		u, err := reader.ReadConstraint(fc.constraintFS, sg.constraintPath)
-		if err != nil {
-			return nil, fmt.Errorf("could not add constraint: %w", err)
-		}
+// retrieves the constraint client that does all rego code related operations
+func getConstraintClient() (*constraintclient.Client, error) {
+	driver, err := rego.New()
+	if err != nil {
+		return nil, fmt.Errorf("could not create rego driver: %w", err)
+	}
 
-		constraints = append(constraints, u)
+	c, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver))
+	if err != nil {
+		return nil, fmt.Errorf("could not create constraint client: %w", err)
 	}
 
-	return constraints, nil
+	return c, nil
 }
 
-func (fc FileCrawler) ReadConstraint(name string) (*unstructured.Unstructured, error) {
-	var constraint *unstructured.Unstructured
-
-	for _, sg := range fc.Safeguards {
-		if sg.name == name {
-			c, err := reader.ReadConstraint(fc.constraintFS, sg.constraintPath)
-			if err != nil {
-				return nil, fmt.Errorf("could not add constraint: %w", err)
-			}
+// sorts the list of supported safeguards versions and returns the last item in the list
+func getLatestSafeguardsVersion() string {
+	semver.Sort(types.SupportedVersions)
+	return types.SupportedVersions[len(types.SupportedVersions)-1]
+}
 
-			constraint = c
-		}
-	}
-	if constraint == nil {
-		return nil, fmt.Errorf("no constraint exists with name: %s", name)
+func updateSafeguardPaths(safeguardList *[]types.Safeguard) {
+	for _, sg := range *safeguardList {
+		sg.TemplatePath = fmt.Sprintf("%s/%s/%s", types.SelectedVersion, sg.Name, types.TemplateFileName)
+		sg.ConstraintPath = fmt.Sprintf("%s/%s/%s", types.SelectedVersion, sg.Name, types.ConstraintFileName)
 	}
+}
 
-	return constraint, nil
+// adds Safeguard_CRIP to full list of Safeguards
+func AddSafeguardCRIP() {
+	fc.Safeguards = append(fc.Safeguards, types.Safeguard_CRIP)
 }
 
 // loads constraint templates, constraints into constraint client
@@ -203,45 +196,6 @@ func IsYAML(path string) bool {
 	return filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml"
 }
 
-// GetManifestFiles uses filepath.Walk to retrieve a list of the manifest files within the given manifest path
-func GetManifestFiles(p string) ([]ManifestFile, error) {
-	var manifestFiles []ManifestFile
-
-	err := filepath.Walk(p, func(walkPath string, info fs.FileInfo, err error) error {
-		manifest := ManifestFile{}
-		// skip when walkPath is just given path and also a directory
-		if p == walkPath && info.IsDir() {
-			return nil
-		}
-
-		if err != nil {
-			return fmt.Errorf("error walking path %s with error: %w", walkPath, err)
-		}
-
-		if !info.IsDir() && info.Name() != "" && IsYAML(walkPath) {
-			log.Debugf("%s is not a directory, appending to manifestFiles", info.Name())
-
-			manifest.Name = info.Name()
-			manifest.Path = walkPath
-			manifestFiles = append(manifestFiles, manifest)
-		} else if !IsYAML(p) {
-			log.Debugf("%s is not a manifest file, skipping...", info.Name())
-		} else {
-			log.Debugf("%s is a directory, skipping...", info.Name())
-		}
-
-		return nil
-	})
-	if err != nil {
-		return nil, fmt.Errorf("could not walk directory: %w", err)
-	}
-	if len(manifestFiles) == 0 {
-		return nil, fmt.Errorf("no manifest files found within given path")
-	}
-
-	return manifestFiles, nil
-}
-
 // getObjectViolations executes validation on manifests based on loaded constraint templates and returns a map of manifest name to list of objectViolations
 func getObjectViolations(ctx context.Context, c *constraintclient.Client, objects []*unstructured.Unstructured) (map[string][]string, error) {
 	// Review makes sure the provided object satisfies all stored constraints.
@@ -273,3 +227,43 @@ func getObjectViolations(ctx context.Context, c *constraintclient.Client, object
 
 	return results, nil
 }
+
+// Checks whether a given path is a helm directory or a path to a Helm Chart (contains/is Chart.yaml)
+func isHelm(isDir bool, path string) bool {
+	var chartPaths []string // Used to define what a valid helm chart looks like. Currently, presence of Chart.yaml/.yml.
+
+	if isDir {
+		chartPaths = []string{filepath.Join(path, "Chart.yaml")}
+		chartPaths = append(chartPaths, filepath.Join(path, "Chart.yml"))
+	} else {
+		if filepath.Base(path) != "Chart.yaml" && filepath.Base(path) != "Chart.yml" {
+			return false
+		}
+		chartPaths = []string{path}
+	}
+
+	for _, path := range chartPaths {
+		_, err := os.Stat(path)
+		if err == nil { //Found the file, it's a valid helm chart
+			return true
+		}
+	}
+
+	return false
+}
+
+// IsKustomize checks whether a given path should be treated as a kustomize project
+func isKustomize(isDir bool, p string) bool {
+	var err error
+	if isDir {
+		if _, err = os.Stat(filepath.Join(p, "kustomization.yaml")); err == nil {
+			return true
+		} else if _, err = os.Stat(filepath.Join(p, "kustomization.yml")); err == nil {
+			return true
+		} else {
+			return false
+		}
+	} else {
+		return strings.Contains(p, "kustomization.yaml")
+	}
+}
diff --git a/pkg/safeguards/manifestresults.go b/pkg/safeguards/manifestresults.go
index 23d6df6..091a063 100644
--- a/pkg/safeguards/manifestresults.go
+++ b/pkg/safeguards/manifestresults.go
@@ -7,33 +7,40 @@ import (
 
 	log "github.com/sirupsen/logrus"
 
+	"github.com/Azure/draft/pkg/safeguards/types"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 )
 
 //go:embed lib
 var embedFS embed.FS
 
-var fc FileCrawler
+var fc types.FileCrawler
 
 // primes the scheme to be able to interpret beta templates
 func init() {
 
-	selectedVersion = getLatestSafeguardsVersion()
-	updateSafeguardPaths(&safeguards)
+	types.SelectedVersion = getLatestSafeguardsVersion()
+	updateSafeguardPaths(&types.Safeguards)
 
-	fc = FileCrawler{
-		Safeguards:   safeguards,
-		constraintFS: embedFS,
+	fc = types.FileCrawler{
+		Safeguards:   types.Safeguards,
+		ConstraintFS: embedFS,
 	}
 }
 
+type ManifestResult struct {
+	Name             string              // the name of the manifest
+	ObjectViolations map[string][]string // a map of string object names to slice of string objectViolations
+	ViolationsCount  int                 // a count of how many violations are associated with this manifest
+}
+
 // GetManifestResults takes in a list of manifest files and returns a slice of ManifestViolation structs
-func GetManifestResults(ctx context.Context, manifestFiles []ManifestFile) ([]ManifestResult, error) {
+func GetManifestResults(ctx context.Context, manifestFiles []types.ManifestFile) ([]types.ManifestResult, error) {
 	if len(manifestFiles) == 0 {
 		return nil, fmt.Errorf("path cannot be empty")
 	}
 
-	manifestResults := make([]ManifestResult, 0)
+	manifestResults := make([]types.ManifestResult, 0)
 
 	// constraint client instantiation
 	c, err := getConstraintClient()
@@ -66,7 +73,7 @@ func GetManifestResults(ctx context.Context, manifestFiles []ManifestFile) ([]Ma
 	// aggregate of every manifest object into one list
 	allManifestObjects := []*unstructured.Unstructured{}
 	for _, m := range manifestFiles {
-		manifestObjects, err := fc.ReadManifests(m.Path) // read all the objects stored in a single file
+		manifestObjects, err := fc.ReadManifests(m.ManifestContent) // read all the objects stored in a single file
 		if err != nil {
 			log.Errorf("reading objects %s", err.Error())
 			return manifestResults, err
@@ -77,7 +84,10 @@ func GetManifestResults(ctx context.Context, manifestFiles []ManifestFile) ([]Ma
 	}
 
 	if len(allManifestObjects) > 0 {
-		err = loadManifestObjects(ctx, c, allManifestObjects)
+		err := loadManifestObjects(ctx, c, allManifestObjects)
+		if err != nil {
+			return manifestResults, err
+		}
 	}
 
 	for _, m := range manifestFiles {
@@ -89,7 +99,8 @@ func GetManifestResults(ctx context.Context, manifestFiles []ManifestFile) ([]Ma
 			log.Errorf("validating objects: %s", err.Error())
 			return manifestResults, err
 		}
-		manifestResults = append(manifestResults, ManifestResult{
+
+		manifestResults = append(manifestResults, types.ManifestResult{
 			Name:             m.Name,
 			ObjectViolations: objectViolations,
 			ViolationsCount:  len(objectViolations),
diff --git a/pkg/safeguards/preprocessing/preprocessing.go b/pkg/safeguards/preprocessing/preprocessing.go
index 2466167..53568d8 100644
--- a/pkg/safeguards/preprocessing/preprocessing.go
+++ b/pkg/safeguards/preprocessing/preprocessing.go
@@ -2,14 +2,14 @@ package preprocessing
 
 import (
 	"fmt"
-	"os"
 	"path/filepath"
-	"strings"
 
-	"github.com/Azure/draft/pkg/safeguards"
+	sgTypes "github.com/Azure/draft/pkg/safeguards/types"
 	log "github.com/sirupsen/logrus"
+
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chart/loader"
+	"helm.sh/helm/v3/pkg/chartutil"
 	"helm.sh/helm/v3/pkg/engine"
 	"sigs.k8s.io/kustomize/api/krusty"
 	"sigs.k8s.io/kustomize/api/types"
@@ -17,7 +17,7 @@ import (
 )
 
 // Given a Helm chart directory or file, renders all templates and writes them to the specified directory
-func RenderHelmChart(isFile bool, mainChartPath, tempDir string) ([]safeguards.ManifestFile, error) {
+func RenderHelmChart(isFile bool, mainChartPath string, opt chartutil.ReleaseOptions) ([]sgTypes.ManifestFile, error) {
 	if isFile { // Get the directory that the Chart.yaml lives in
 		mainChartPath = filepath.Dir(mainChartPath)
 	}
@@ -43,10 +43,10 @@ func RenderHelmChart(isFile bool, mainChartPath, tempDir string) ([]safeguards.M
 		loadedCharts[chartPath] = subChart
 	}
 
-	var manifestFiles []safeguards.ManifestFile
+	var manifestFiles []sgTypes.ManifestFile
 	for chartPath, chart := range loadedCharts {
 		valuesPath := filepath.Join(chartPath, "values.yaml") // Enforce that values.yaml must be at same level as Chart.yaml
-		mergedValues, err := getValues(chart, valuesPath)
+		mergedValues, err := getValues(chart, valuesPath, opt, filepath.Base(mainChartPath))
 		if err != nil {
 			return nil, fmt.Errorf("failed to load values: %s", err)
 		}
@@ -56,33 +56,20 @@ func RenderHelmChart(isFile bool, mainChartPath, tempDir string) ([]safeguards.M
 			return nil, fmt.Errorf("failed to render chart: %s", err)
 		}
 
-		// Write each rendered file to the output directory with the same name as in templates/
+		// Convert renderd files to []byte
 		for renderedPath, content := range renderedFiles {
-			outputFilePath := filepath.Join(tempDir, filepath.Base(renderedPath))
-			if err := os.WriteFile(outputFilePath, []byte(content), 0644); err != nil {
-				return nil, fmt.Errorf("failed to write manifest file: %s", err)
-			}
-			manifestFiles = append(manifestFiles, safeguards.ManifestFile{Name: filepath.Base(renderedPath), Path: outputFilePath})
+			byteContent := []byte(content)
+			manifestFiles = append(manifestFiles, sgTypes.ManifestFile{Name: filepath.Base(renderedPath), ManifestContent: byteContent})
 		}
 	}
 
 	return manifestFiles, nil
 }
 
-// CreateTempDir creates a temporary directory on the user's file system for rendering templates
-func CreateTempDir(p string) error {
-	err := os.MkdirAll(p, 0755)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	return err
-}
-
-// Given a kustomization manifest file within kustomizationPath, RenderKustomizeManifest will render templates out to tempDir
-func RenderKustomizeManifest(kustomizationPath, tempDir string) ([]safeguards.ManifestFile, error) {
+// Given a kustomization manifest file within kustomizationPath, RenderKustomizeManifest will return render templates
+func RenderKustomizeManifest(kustomizationPath string) ([]sgTypes.ManifestFile, error) {
 	log.Debugf("Rendering kustomization.yaml...")
-	if safeguards.IsYAML(kustomizationPath) {
+	if IsYAML(kustomizationPath) {
 		kustomizationPath = filepath.Dir(kustomizationPath)
 	}
 
@@ -97,31 +84,21 @@ func RenderKustomizeManifest(kustomizationPath, tempDir string) ([]safeguards.Ma
 	kustomizeFS := filesys.MakeFsOnDisk()
 	resMap, err := k.Run(kustomizeFS, kustomizationPath)
 	if err != nil {
-		return nil, fmt.Errorf("Error building manifests: %s\n", err.Error())
+		return nil, fmt.Errorf("error building manifests: %s", err.Error())
 	}
 
 	// Output the manifests
-	var manifestFiles []safeguards.ManifestFile
-	kindMap := make(map[string]int)
+	var manifestFiles []sgTypes.ManifestFile
 	for _, res := range resMap.Resources() {
 		yamlRes, err := res.AsYAML()
 		if err != nil {
-			return nil, fmt.Errorf("Error converting resource to YAML: %s\n", err.Error())
-		}
-
-		// index of every kind of manifest for outputRenderPath
-		kindMap[res.GetKind()] += 1
-		outputRenderPath := filepath.Join(tempDir, strings.ToLower(res.GetKind())) + fmt.Sprintf("-%d.yaml", kindMap[res.GetKind()])
-
-		err = kustomizeFS.WriteFile(outputRenderPath, yamlRes)
-		if err != nil {
-			return nil, fmt.Errorf("Error writing yaml resource: %s\n", err.Error())
+			return nil, fmt.Errorf("error converting resource to YAML: %s", err.Error())
 		}
 
 		// write yamlRes to dir
-		manifestFiles = append(manifestFiles, safeguards.ManifestFile{
-			Name: res.GetName(),
-			Path: outputRenderPath,
+		manifestFiles = append(manifestFiles, sgTypes.ManifestFile{
+			Name:            res.GetName(),
+			ManifestContent: yamlRes,
 		})
 	}
 
diff --git a/pkg/safeguards/preprocessing/preprocessing_helpers.go b/pkg/safeguards/preprocessing/preprocessing_helpers.go
index e6144b2..9f65799 100644
--- a/pkg/safeguards/preprocessing/preprocessing_helpers.go
+++ b/pkg/safeguards/preprocessing/preprocessing_helpers.go
@@ -4,16 +4,14 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
-	"strings"
 
-	"github.com/Azure/draft/pkg/safeguards"
 	"gopkg.in/yaml.v3"
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chartutil"
 )
 
 // Returns values from values.yaml and release options specified in values.yaml
-func getValues(chart *chart.Chart, valuesPath string) (chartutil.Values, error) {
+func getValues(chart *chart.Chart, valuesPath string, opt chartutil.ReleaseOptions, dirName string) (chartutil.Values, error) {
 	// Load values file
 	valuesFile, err := os.ReadFile(valuesPath)
 	if err != nil {
@@ -25,25 +23,44 @@ func getValues(chart *chart.Chart, valuesPath string) (chartutil.Values, error)
 		return nil, fmt.Errorf("failed to parse values.yaml: %s", err)
 	}
 
-	mergedValues, err := getReleaseOptions(chart, vals)
+	mergedValues, err := getReleaseOptions(chart, vals, opt, dirName)
 	return mergedValues, err
 }
 
-func getReleaseOptions(chart *chart.Chart, vals map[string]interface{}) (chartutil.Values, error) {
+// Extracts release options from either CLI flags, values.yaml, or name of containing directory
+func getReleaseOptions(chart *chart.Chart, vals map[string]interface{}, opt chartutil.ReleaseOptions, dirName string) (chartutil.Values, error) {
 	// Extract release options from values
-	releaseName, ok := vals["releaseName"].(string)
-	if !ok || releaseName == "" {
-		return nil, fmt.Errorf("releaseName not found or empty in values.yaml")
-	}
-
-	releaseNamespace, ok := vals["releaseNamespace"].(string)
-	if !ok || releaseNamespace == "" {
-		return nil, fmt.Errorf("releaseNamespace not found or empty in values.yaml")
-	}
+	var options chartutil.ReleaseOptions
+	if opt.Name != "" && opt.Namespace != "" {
+		options = opt
+	} else {
+		var releaseName string
+		var releaseNamespace string
+		if opt.Name != "" {
+			releaseName = opt.Name
+		} else {
+			rName, ok := vals["releaseName"].(string)
+			if !ok || rName == "" {
+				releaseName = dirName
+			} else {
+				releaseName = rName
+			}
+		}
+		if opt.Namespace != "" {
+			releaseNamespace = opt.Namespace
+		} else {
+			rNamespace, ok := vals["releaseNamespace"].(string)
+			if !ok || rNamespace == "" {
+				releaseNamespace = dirName
+			} else {
+				releaseNamespace = rNamespace
+			}
+		}
 
-	options := chartutil.ReleaseOptions{
-		Name:      releaseName,
-		Namespace: releaseNamespace,
+		options = chartutil.ReleaseOptions{
+			Name:      releaseName,
+			Namespace: releaseNamespace,
+		}
 	}
 
 	// Combine chart values with release options
@@ -56,37 +73,17 @@ func getReleaseOptions(chart *chart.Chart, vals map[string]interface{}) (chartut
 	return mergedValues, nil
 }
 
-// IsKustomize checks whether a given path should be treated as a kustomize project
-func IsKustomize(p string) bool {
-	var err error
-	if safeguards.IsYAML(p) {
-		return strings.Contains(p, "kustomization.yaml")
-	} else if _, err = os.Stat(filepath.Join(p, "kustomization.yaml")); err == nil {
-		return true
-	} else if _, err = os.Stat(filepath.Join(p, "kustomization.yml")); err == nil {
-		return true
-	}
-	return false
+// IsYAML determines if a file is of the YAML extension or not
+func IsYAML(path string) bool {
+	return filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml"
 }
 
-// Checks whether a given path is a helm directory or a path to a Helm Chart (contains/is Chart.yaml)
-func IsHelm(path string) bool {
+// IsDirectory determines if a file represented by path is a directory or not
+func IsDirectory(path string) (bool, error) {
 	fileInfo, err := os.Stat(path)
-	if os.IsNotExist(err) || err != nil {
-		return false
-	}
-
-	var chartPath string
-	if fileInfo.IsDir() {
-		chartPath = filepath.Join(path, "Chart.yaml")
-	} else {
-		chartPath = path
-	}
-
-	_, err = os.Stat(chartPath)
-	if err == nil && safeguards.IsYAML(chartPath) { // Couldn't find Chart.yaml in the directory
-		return true
+	if err != nil {
+		return false, err
 	}
 
-	return false
+	return fileInfo.IsDir(), nil
 }
diff --git a/pkg/safeguards/types.go b/pkg/safeguards/types.go
deleted file mode 100644
index bfa42c5..0000000
--- a/pkg/safeguards/types.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package safeguards
-
-import "io/fs"
-
-type FileCrawler struct {
-	Safeguards   []Safeguard
-	constraintFS fs.FS
-}
-
-type Safeguard struct {
-	name           string
-	templatePath   string
-	constraintPath string
-}
-
-type ManifestFile struct {
-	Name string
-	Path string
-}
-
-type ManifestResult struct {
-	Name             string              // the name of the manifest
-	ObjectViolations map[string][]string // a map of string object names to slice of string objectViolations
-	ViolationsCount  int                 // a count of how many violations are associated with this manifest
-}
diff --git a/pkg/safeguards/types/constants.go b/pkg/safeguards/types/constants.go
new file mode 100644
index 0000000..a2a7d0b
--- /dev/null
+++ b/pkg/safeguards/types/constants.go
@@ -0,0 +1,87 @@
+package types
+
+import (
+	"fmt"
+)
+
+const (
+	Constraint_CAI   = "container-allowed-images"
+	Constraint_CEP   = "container-enforce-probes"
+	Constraint_CRL   = "container-resource-limits"
+	Constraint_CRIP  = "container-restricted-image-pulls"
+	Constraint_DBPDB = "disallowed-bad-pod-disruption-budgets"
+	Constraint_PEA   = "pod-enforce-antiaffinity"
+	Constraint_RT    = "restricted-taints"
+	Constraint_USS   = "unique-service-selectors"
+	Constraint_all   = "all"
+
+	KustomizationPath       = "../tests/kustomize/overlays/production"
+	DirectPath_ToValidChart = "../tests/testmanifests/validchart/Chart.yaml"
+	ChartPath               = "../tests/testmanifests/validchart"
+	InvalidChartPath        = "../tests/testmanifests/invalidchart"
+	InvalidValuesChart      = "../tests/testmanifests/invalidvalues"
+	InvalidDeploymentSyntax = "../tests/testmanifests/invaliddeployment-syntax"
+	InvalidDeploymentValues = "../tests/testmanifests/invaliddeployment-values"
+	FolderwithHelpersTmpl   = "../tests/testmanifests/different-structure"
+	MultipleTemplateDirs    = "../tests/testmanifests/multiple-templates"
+	MultipleValuesFile      = "../tests/testmanifests/multiple-values-files"
+
+	Subcharts                  = "../tests/testmanifests/multiple-charts"
+	SubchartDir                = "../tests/testmanifests/multiple-charts/charts/subchart2"
+	DirectPath_ToSubchartYaml  = "../tests/testmanifests/multiple-charts/charts/subchart1/Chart.yaml"
+	DirectPath_ToMainChartYaml = "../tests/testmanifests/multiple-charts/Chart.yaml"
+	DirectPath_ToInvalidChart  = "../tests/testmanifests/invalidchart/Chart.yaml"
+
+	TemplateFileName   = "template.yaml"
+	ConstraintFileName = "constraint.yaml"
+)
+
+var SelectedVersion = "v1.0.0"
+
+var SupportedVersions = []string{SelectedVersion}
+
+var Safeguard_CRIP = Safeguard{
+	Name:           Constraint_CRIP,
+	TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CRIP, TemplateFileName),
+	ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CRIP, ConstraintFileName),
+}
+
+var Safeguards = []Safeguard{
+	{
+		Name:           Constraint_CAI,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CAI, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CAI, ConstraintFileName),
+	},
+	{
+		Name:           Constraint_CEP,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CEP, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CEP, ConstraintFileName),
+	},
+	{
+		Name:           Constraint_CRL,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CRL, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_CRL, ConstraintFileName),
+	},
+	{
+		Name:           Constraint_DBPDB,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_DBPDB, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_DBPDB, ConstraintFileName),
+	},
+	{
+		Name:           Constraint_PEA,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_PEA, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_PEA, ConstraintFileName),
+	},
+	{
+		Name:           Constraint_RT,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_RT, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_RT, ConstraintFileName),
+	},
+	{
+		Name:           Constraint_USS,
+		TemplatePath:   fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_USS, TemplateFileName),
+		ConstraintPath: fmt.Sprintf("lib/%s/%s/%s", SelectedVersion, Constraint_USS, ConstraintFileName),
+	},
+}
+
+var SafeguardsTesting = append(Safeguards, Safeguard_CRIP)
diff --git a/pkg/safeguards/types/types.go b/pkg/safeguards/types/types.go
new file mode 100644
index 0000000..ecdfe97
--- /dev/null
+++ b/pkg/safeguards/types/types.go
@@ -0,0 +1,126 @@
+package types
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io/fs"
+
+	"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
+	api "github.com/open-policy-agent/gatekeeper/v3/apis"
+	"github.com/open-policy-agent/gatekeeper/v3/pkg/gator/reader"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+)
+
+type FileCrawler struct {
+	Safeguards   []Safeguard
+	ConstraintFS fs.FS
+}
+
+type Safeguard struct {
+	Name           string
+	TemplatePath   string
+	ConstraintPath string
+}
+
+type ManifestFile struct {
+	Name            string
+	ManifestContent []byte
+}
+
+type ManifestResult struct {
+	Name             string              // the name of the manifest
+	ObjectViolations map[string][]string // a map of string object names to slice of string objectViolations
+	ViolationsCount  int                 // a count of how many violations are associated with this manifest
+}
+
+// methods for retrieval of manifest, constraint templates, and constraints
+func (fc FileCrawler) ReadManifests(manifestBytes []byte) ([]*unstructured.Unstructured, error) {
+	// Create a new bytes.Reader from the byte slice
+	bufReader := bufio.NewReader(bytes.NewReader(manifestBytes))
+
+	// Read the Kubernetes resources using the reader
+	manifests, err := reader.ReadK8sResources(bufReader)
+	if err != nil {
+		return nil, fmt.Errorf("reading manifests: %w", err)
+	}
+
+	return manifests, nil
+}
+
+func GetScheme() *runtime.Scheme {
+	var s = runtime.NewScheme()
+	_ = clientgoscheme.AddToScheme(s)
+	_ = api.AddToScheme(s)
+	return s
+}
+
+func (fc FileCrawler) ReadConstraintTemplates() ([]*templates.ConstraintTemplate, error) {
+	var constraintTemplates []*templates.ConstraintTemplate
+
+	for _, sg := range fc.Safeguards {
+		ct, err := reader.ReadTemplate(GetScheme(), fc.ConstraintFS, sg.TemplatePath)
+		if err != nil {
+			return nil, fmt.Errorf("reading template: %w", err)
+		}
+		constraintTemplates = append(constraintTemplates, ct)
+	}
+
+	return constraintTemplates, nil
+}
+
+func (fc FileCrawler) ReadConstraintTemplate(name string) (*templates.ConstraintTemplate, error) {
+	var constraintTemplate *templates.ConstraintTemplate
+
+	for _, sg := range fc.Safeguards {
+		if sg.Name == name {
+			ct, err := reader.ReadTemplate(GetScheme(), fc.ConstraintFS, sg.TemplatePath)
+			if err != nil {
+				return nil, fmt.Errorf("could not read template: %w", err)
+			}
+			constraintTemplate = ct
+		}
+	}
+	if constraintTemplate == nil {
+		return nil, fmt.Errorf("no constraint template exists with name: %s", name)
+	}
+
+	return constraintTemplate, nil
+}
+
+func (fc FileCrawler) ReadConstraints() ([]*unstructured.Unstructured, error) {
+	var constraints []*unstructured.Unstructured
+
+	for _, sg := range fc.Safeguards {
+		u, err := reader.ReadConstraint(fc.ConstraintFS, sg.ConstraintPath)
+		if err != nil {
+			return nil, fmt.Errorf("could not add constraint: %w", err)
+		}
+
+		constraints = append(constraints, u)
+	}
+
+	return constraints, nil
+}
+
+func (fc FileCrawler) ReadConstraint(name string) (*unstructured.Unstructured, error) {
+	var constraint *unstructured.Unstructured
+
+	for _, sg := range fc.Safeguards {
+		if sg.Name == name {
+			c, err := reader.ReadConstraint(fc.ConstraintFS, sg.ConstraintPath)
+			if err != nil {
+				return nil, fmt.Errorf("could not add constraint: %w", err)
+			}
+
+			constraint = c
+		}
+	}
+	if constraint == nil {
+		return nil, fmt.Errorf("no constraint exists with name: %s", name)
+	}
+
+	return constraint, nil
+}


Test patch:
diff --git a/cmd/validate_test.go b/cmd/validate_test.go
index c61c605..d323c7e 100644
--- a/cmd/validate_test.go
+++ b/cmd/validate_test.go
@@ -2,72 +2,40 @@ package cmd
 
 import (
 	"context"
-	"os"
-	"path"
-	"path/filepath"
-
 	"testing"
 
 	"github.com/Azure/draft/pkg/safeguards"
 	"github.com/Azure/draft/pkg/safeguards/preprocessing"
+	"github.com/Azure/draft/pkg/safeguards/types"
 	"github.com/stretchr/testify/assert"
-)
-
-// TestIsDirectory tests the isDirectory function for proper returns
-func TestIsDirectory(t *testing.T) {
-	testWd, _ := os.Getwd()
-	pathTrue := testWd
-	pathFalse := path.Join(testWd, "validate.go")
-	pathError := ""
-
-	isDir, err := safeguards.IsDirectory(pathTrue)
-	assert.True(t, isDir)
-	assert.Nil(t, err)
-
-	isDir, err = safeguards.IsDirectory(pathFalse)
-	assert.False(t, isDir)
-	assert.Nil(t, err)
-
-	isDir, err = safeguards.IsDirectory(pathError)
-	assert.False(t, isDir)
-	assert.NotNil(t, err)
-}
-
-// TestIsYAML tests the isYAML function for proper returns
-func TestIsYAML(t *testing.T) {
-	dirNotYaml, _ := filepath.Abs("../pkg/safeguards/tests/not-yaml")
-	dirYaml, _ := filepath.Abs("../pkg/safeguards/tests/all/success")
-	fileNotYaml, _ := filepath.Abs("../pkg/safeguards/tests/not-yaml/readme.md")
-	fileYaml, _ := filepath.Abs("../pkg/safeguards/tests/all/success/all-success-manifest-1.yaml")
-
-	assert.False(t, safeguards.IsYAML(fileNotYaml))
-	assert.True(t, safeguards.IsYAML(fileYaml))
 
-	manifestFiles, err := safeguards.GetManifestFiles(dirNotYaml)
-	assert.Nil(t, manifestFiles)
-	assert.NotNil(t, err)
+	"helm.sh/helm/v3/pkg/chartutil"
+)
 
-	manifestFiles, err = safeguards.GetManifestFiles(dirYaml)
-	assert.NotNil(t, manifestFiles)
-	assert.Nil(t, err)
-}
+const (
+	manifestPathDirectorySuccess = "../pkg/safeguards/tests/all/success"
+	manifestPathDirectoryError   = "../pkg/safeguards/tests/all/error"
+	manifestPathFileSuccess      = "../pkg/safeguards/tests/all/success/all-success-manifest-1.yaml"
+	manifestPathFileError        = "../pkg/safeguards/tests/all/error/all-error-manifest-1.yaml"
+	kustomizationPath            = "../pkg/safeguards/tests/kustomize/overlays/production"
+	chartPath                    = "../pkg/safeguards/tests/testmanifests/validchart"
+	kustomizationFilePath        = "../pkg/safeguards/tests/kustomize/overlays/production/kustomization.yaml"
+)
 
 // TestRunValidate tests the run command for `draft validate` for proper returns
 func TestRunValidate(t *testing.T) {
 	ctx := context.TODO()
-	manifestFilesEmpty := []safeguards.ManifestFile{}
-	manifestPathDirectorySuccess, _ := filepath.Abs("../pkg/safeguards/tests/all/success")
-	manifestPathDirectoryError, _ := filepath.Abs("../pkg/safeguards/tests/all/error")
-	manifestPathFileSuccess, _ := filepath.Abs("../pkg/safeguards/tests/all/success/all-success-manifest-1.yaml")
-	manifestPathFileError, _ := filepath.Abs("../pkg/safeguards/tests/all/error/all-error-manifest-1.yaml")
-	var manifestFiles []safeguards.ManifestFile
+	manifestFilesEmpty := []types.ManifestFile{}
+
+	var manifestFiles []types.ManifestFile
+	var opt chartutil.ReleaseOptions
 
 	// Scenario 1: empty manifest path should error
 	_, err := safeguards.GetManifestResults(ctx, manifestFilesEmpty)
 	assert.NotNil(t, err)
 
 	// Scenario 2a: manifest path leads to a directory of manifestFiles - expect success
-	manifestFiles, err = safeguards.GetManifestFiles(manifestPathDirectorySuccess)
+	manifestFiles, err = safeguards.GetManifestFiles(manifestPathDirectorySuccess, opt)
 	assert.Nil(t, err)
 	v, err := safeguards.GetManifestResults(ctx, manifestFiles)
 	assert.Nil(t, err)
@@ -75,7 +43,7 @@ func TestRunValidate(t *testing.T) {
 	assert.Equal(t, numViolations, 0)
 
 	// Scenario 2b: manifest path leads to a directory of manifestFiles - expect failure
-	manifestFiles, err = safeguards.GetManifestFiles(manifestPathDirectoryError)
+	manifestFiles, err = safeguards.GetManifestFiles(manifestPathDirectoryError, opt)
 	assert.Nil(t, err)
 	v, err = safeguards.GetManifestResults(ctx, manifestFiles)
 	assert.Nil(t, err)
@@ -83,14 +51,35 @@ func TestRunValidate(t *testing.T) {
 	assert.Greater(t, numViolations, 0)
 
 	// Scenario 3a: manifest path leads to one manifest file - expect success
-	manifestFiles, err = safeguards.GetManifestFiles(manifestPathFileSuccess)
+	manifestFiles, err = safeguards.GetManifestFiles(manifestPathFileSuccess, opt)
+	assert.Nil(t, err)
 	v, err = safeguards.GetManifestResults(ctx, manifestFiles)
 	assert.Nil(t, err)
 	numViolations = countTestViolations(v)
 	assert.Equal(t, numViolations, 0)
 
 	// Scenario 3b: manifest path leads to one manifest file - expect failure
-	manifestFiles, err = safeguards.GetManifestFiles(manifestPathFileError)
+	manifestFiles, err = safeguards.GetManifestFiles(manifestPathFileError, opt)
+	assert.Nil(t, err)
+	v, err = safeguards.GetManifestResults(ctx, manifestFiles)
+	assert.Nil(t, err)
+	numViolations = countTestViolations(v)
+	assert.Greater(t, numViolations, 0)
+
+	//Scenario 4: Test Kustomize
+	manifestFiles, err = safeguards.GetManifestFiles(kustomizationPath, opt)
+	assert.Nil(t, err)
+	v, err = safeguards.GetManifestResults(ctx, manifestFiles)
+	assert.Nil(t, err)
+	numViolations = countTestViolations(v)
+	assert.Greater(t, numViolations, 0)
+
+	// Scenario 5: Test Helm
+	opt.Name = "test-release-name"
+	opt.Namespace = "test-release-namespace"
+
+	manifestFiles, err = safeguards.GetManifestFiles(chartPath, opt)
+	assert.Nil(t, err)
 	v, err = safeguards.GetManifestResults(ctx, manifestFiles)
 	assert.Nil(t, err)
 	numViolations = countTestViolations(v)
@@ -100,17 +89,11 @@ func TestRunValidate(t *testing.T) {
 // TestRunValidate_Kustomize tests the run command for `draft validate` for proper returns when given a kustomize project
 func TestRunValidate_Kustomize(t *testing.T) {
 	ctx := context.TODO()
-	kustomizationPath, _ := filepath.Abs("../pkg/safeguards/tests/kustomize/overlays/production")
-	kustomizationFilePath, _ := filepath.Abs("../pkg/safeguards/tests/kustomize/overlays/production/kustomization.yaml")
-
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
-
-	var manifestFiles []safeguards.ManifestFile
+	var manifestFiles []types.ManifestFile
 	var err error
 
 	// Scenario 1a: kustomizationPath leads to a directory containing kustomization.yaml - expect success
-	manifestFiles, err = preprocessing.RenderKustomizeManifest(kustomizationPath, tempDir)
+	manifestFiles, err = preprocessing.RenderKustomizeManifest(kustomizationPath)
 	assert.Nil(t, err)
 	v, err := safeguards.GetManifestResults(ctx, manifestFiles)
 	assert.Nil(t, err)
@@ -118,7 +101,7 @@ func TestRunValidate_Kustomize(t *testing.T) {
 	assert.Equal(t, numViolations, 1)
 
 	// Scenario 1b: kustomizationFilePath path leads to a specific kustomization.yaml - expect success
-	manifestFiles, err = preprocessing.RenderKustomizeManifest(kustomizationFilePath, tempDir)
+	manifestFiles, err = preprocessing.RenderKustomizeManifest(kustomizationFilePath)
 	assert.Nil(t, err)
 	v, err = safeguards.GetManifestResults(ctx, manifestFiles)
 	assert.Nil(t, err)
diff --git a/cmd/validate_test_helpers.go b/cmd/validate_test_helpers.go
index 0109fe9..a47d37d 100644
--- a/cmd/validate_test_helpers.go
+++ b/cmd/validate_test_helpers.go
@@ -1,16 +1,10 @@
 package cmd
 
 import (
-	"os"
-	"path/filepath"
-	"testing"
-
-	"github.com/Azure/draft/pkg/safeguards"
+	types "github.com/Azure/draft/pkg/safeguards/types"
 )
 
-var tempDir, _ = filepath.Abs("./testdata")
-
-func countTestViolations(results []safeguards.ManifestResult) int {
+func countTestViolations(results []types.ManifestResult) int {
 	numViolations := 0
 	for _, r := range results {
 		numViolations += len(r.ObjectViolations)
@@ -18,16 +12,3 @@ func countTestViolations(results []safeguards.ManifestResult) int {
 
 	return numViolations
 }
-
-func makeTempDir(t *testing.T) {
-	if err := os.MkdirAll(tempDir, 0755); err != nil {
-		t.Fatalf("failed to create temporary output directory: %s", err)
-	}
-}
-
-func cleanupDir(t *testing.T, dir string) {
-	err := os.RemoveAll(dir)
-	if err != nil {
-		t.Fatalf("Failed to clean directory: %s", err)
-	}
-}
diff --git a/pkg/safeguards/helpers_test.go b/pkg/safeguards/helpers_test.go
index 255b7ca..9822fb2 100644
--- a/pkg/safeguards/helpers_test.go
+++ b/pkg/safeguards/helpers_test.go
@@ -2,15 +2,53 @@ package safeguards
 
 import (
 	"context"
+	"os"
+	"path/filepath"
 	"testing"
 
+	"github.com/Azure/draft/pkg/safeguards/types"
 	constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
 	"github.com/stretchr/testify/assert"
+
+	"helm.sh/helm/v3/pkg/chartutil"
+)
+
+const (
+	chartPath               = "tests/testmanifests/validchart"
+	kustomizationPath       = "tests/kustomize/overlays/production"
+	kustomizationFilePath   = "tests/kustomize/overlays/production/kustomization.yaml"
+	directPath_ToValidChart = "tests/testmanifests/validchart/Chart.yaml"
 )
 
-func validateOneTestManifestFail(ctx context.Context, t *testing.T, c *constraintclient.Client, testFc FileCrawler, testManifestPaths []string) {
+func TestGetManifestFiles(t *testing.T) {
+	var opt chartutil.ReleaseOptions
+	// Test Helm
+	_, err := GetManifestFiles(chartPath, opt)
+	assert.Nil(t, err)
+
+	// Test Kustomize
+	_, err = GetManifestFiles(kustomizationPath, opt)
+	assert.Nil(t, err)
+
+	// Test Normal Directory with manifest files
+	absPath, err := filepath.Abs("tests/all/success")
+	assert.Nil(t, err)
+	_, err = GetManifestFiles(absPath, opt)
+	assert.Nil(t, err)
+
+	// test single manifest file
+	manifestPathFileSuccess, err := filepath.Abs("tests/all/success/all-success-manifest-1.yaml")
+	assert.Nil(t, err)
+	_, err = GetManifestFiles(manifestPathFileSuccess, opt)
+	assert.Nil(t, err)
+}
+
+func validateOneTestManifestFail(ctx context.Context, t *testing.T, c *constraintclient.Client, testFc types.FileCrawler, testManifestPaths []string) {
 	for _, path := range testManifestPaths {
-		errManifests, err := testFc.ReadManifests(path)
+		byteContent, err := os.ReadFile(path)
+		assert.Nil(t, err)
+
+		errManifests, err := testFc.ReadManifests(byteContent)
 		assert.Nil(t, err)
 
 		err = loadManifestObjects(ctx, c, errManifests)
@@ -23,9 +61,12 @@ func validateOneTestManifestFail(ctx context.Context, t *testing.T, c *constrain
 	}
 }
 
-func validateOneTestManifestSuccess(ctx context.Context, t *testing.T, c *constraintclient.Client, testFc FileCrawler, testManifestPaths []string) {
+func validateOneTestManifestSuccess(ctx context.Context, t *testing.T, c *constraintclient.Client, testFc types.FileCrawler, testManifestPaths []string) {
 	for _, path := range testManifestPaths {
-		successManifests, err := testFc.ReadManifests(path)
+		byteContent, err := os.ReadFile(path)
+		assert.Nil(t, err)
+
+		successManifests, err := testFc.ReadManifests(byteContent)
 		assert.Nil(t, err)
 
 		err = loadManifestObjects(ctx, c, successManifests)
@@ -38,9 +79,10 @@ func validateOneTestManifestSuccess(ctx context.Context, t *testing.T, c *constr
 	}
 }
 
-func validateAllTestManifestsFail(ctx context.Context, t *testing.T, c *constraintclient.Client, testFc FileCrawler, testManifestPaths []string) {
+func validateAllTestManifestsFail(ctx context.Context, t *testing.T, testManifestPaths []string) {
+	var opt chartutil.ReleaseOptions
 	for _, path := range testManifestPaths {
-		manifestFiles, err := GetManifestFiles(path)
+		manifestFiles, err := GetManifestFiles(path, opt)
 		assert.Nil(t, err)
 
 		// error case - should throw error
@@ -52,9 +94,9 @@ func validateAllTestManifestsFail(ctx context.Context, t *testing.T, c *constrai
 	}
 }
 
-func validateAllTestManifestsSuccess(ctx context.Context, t *testing.T, c *constraintclient.Client, testFc FileCrawler, testManifestPaths []string) {
+func validateAllTestManifestsSuccess(ctx context.Context, t *testing.T, testManifestPaths []string) {
 	for _, path := range testManifestPaths {
-		manifestFiles, err := GetManifestFiles(path)
+		manifestFiles, err := GetManifestFilesFromDir(path)
 		assert.Nil(t, err)
 
 		// success case - should not throw error
@@ -65,3 +107,44 @@ func validateAllTestManifestsSuccess(ctx context.Context, t *testing.T, c *const
 		}
 	}
 }
+
+// TestIsKustomize checks whether the given path contains a kustomize project
+func TestIsKustomize(t *testing.T) {
+	kustomizationPath := "tests/kustomize/overlays/production"
+
+	// path contains a kustomization.yaml file
+	iskustomize := isKustomize(true, kustomizationPath)
+	assert.True(t, iskustomize)
+	// path is a kustomization.yaml file
+	iskustomize = isKustomize(false, kustomizationFilePath)
+	assert.True(t, iskustomize)
+	// not a kustomize project
+	iskustomize = isKustomize(true, chartPath)
+	assert.False(t, iskustomize)
+}
+
+func TestIsHelm(t *testing.T) {
+	// path is a directory
+	ishelm := isHelm(true, chartPath)
+	assert.True(t, ishelm)
+
+	// path is a Chart.yaml file
+	ishelm = isHelm(false, directPath_ToValidChart)
+	assert.True(t, ishelm)
+
+	// Is a directory but does not contain Chart.yaml
+	ishelm = isHelm(true, kustomizationPath)
+	assert.False(t, ishelm)
+
+	// Is a directory of manifest files, not a helm chart
+	ishelm = isHelm(false, "../pkg/safeguards/tests/all/success/all-success-manifest-1.yaml")
+	assert.False(t, ishelm)
+
+	// Is a directory of manifest files, not a helm chart
+	ishelm = isHelm(false, "../pkg/safeguards/tests/all/success/all-success-manifest-1.yaml")
+	assert.False(t, ishelm)
+
+	// invalid path
+	ishelm = isHelm(false, "invalid/path")
+	assert.False(t, ishelm)
+}
diff --git a/pkg/safeguards/manifestresults_test.go b/pkg/safeguards/manifestresults_test.go
index 729032f..0556731 100644
--- a/pkg/safeguards/manifestresults_test.go
+++ b/pkg/safeguards/manifestresults_test.go
@@ -6,20 +6,21 @@ import (
 
 	"github.com/open-policy-agent/frameworks/constraint/pkg/core/templates"
 	"github.com/stretchr/testify/assert"
-
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+
+	"github.com/Azure/draft/pkg/safeguards/types"
 )
 
 var ctx = context.Background()
-var testFc FileCrawler
+var testFc types.FileCrawler
 
 func init() {
-	selectedVersion = getLatestSafeguardsVersion()
-	updateSafeguardPaths(&safeguardsTesting)
+	types.SelectedVersion = getLatestSafeguardsVersion()
+	updateSafeguardPaths(&types.SafeguardsTesting)
 
-	testFc = FileCrawler{
-		Safeguards:   safeguardsTesting,
-		constraintFS: embedFS,
+	testFc = types.FileCrawler{
+		Safeguards:   types.SafeguardsTesting,
+		ConstraintFS: embedFS,
 	}
 }
 
@@ -30,9 +31,9 @@ func TestValidateDeployment_ContainerAllowedImages(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_CAI.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_CAI.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_CAI.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_CAI.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -43,8 +44,8 @@ func TestValidateDeployment_ContainerAllowedImages(t *testing.T) {
 
 	// validating deployment manifests
 	// tbarnes94: disabling failure case until we finalize logic on imageRegex for allowed images
-	//validateOneTestManifestFail(ctx, t, c, testFc, testManifest_CAI.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_CAI.SuccessPaths)
+	//validateOneTestManifestFail(ctx, t, c, testFc, h.TestManifest_CAI.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_CAI.SuccessPaths)
 }
 
 // TestValidateDeployment_ContainerEnforceProbes tests our Container Enforce Probes manifest
@@ -54,9 +55,9 @@ func TestValidateDeployment_ContainerEnforceProbes(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_CEP.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_CEP.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_CEP.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_CEP.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -66,8 +67,8 @@ func TestValidateDeployment_ContainerEnforceProbes(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_CEP.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_CEP.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_CEP.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_CEP.SuccessPaths)
 }
 
 // TestValidateDeployment_ContainerResourceLimits tests our Container Resource Limits manifest
@@ -77,9 +78,9 @@ func TestValidateDeployment_ContainerResourceLimits(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_CL.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_CL.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_CL.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_CL.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -89,8 +90,8 @@ func TestValidateDeployment_ContainerResourceLimits(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_CL.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_CL.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_CL.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_CL.SuccessPaths)
 }
 
 // TestValidateDeployment_ContainerRestrictedImagePulls tests our Container Restricted Image Pulls manifest
@@ -100,9 +101,9 @@ func TestValidateDeployment_ContainerRestrictedImagePulls(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_CRIP.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_CRIP.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_CRIP.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_CRIP.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -112,8 +113,8 @@ func TestValidateDeployment_ContainerRestrictedImagePulls(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_CRIP.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_CRIP.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_CRIP.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_CRIP.SuccessPaths)
 }
 
 // TestValidateDeployment_DisallowedBadPodDisruptionBudget tests our Disallowed Bad Pod Disruption Budget manifest
@@ -123,9 +124,9 @@ func TestValidateDeployment_DisallowedBadPodDisruptionBudget(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_DBPDB.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_DBPDB.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_DBPDB.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_DBPDB.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -135,8 +136,8 @@ func TestValidateDeployment_DisallowedBadPodDisruptionBudget(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_DBPDB.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_DBPDB.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_DBPDB.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_DBPDB.SuccessPaths)
 }
 
 // TestValidateDeployment_PodEnforceAntiaffinity tests our Pod Enforce Antiaffinity manifest
@@ -146,9 +147,9 @@ func TestValidateDeployment_PodEnforceAntiaffinity(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_PEA.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_PEA.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_PEA.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_PEA.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -158,8 +159,8 @@ func TestValidateDeployment_PodEnforceAntiaffinity(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_PEA.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_PEA.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_PEA.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_PEA.SuccessPaths)
 }
 
 // TestValidateDeployment_RestrictedTaints tests our Restricted Taints manifest
@@ -169,9 +170,9 @@ func TestValidateDeployment_RestrictedTaints(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_RT.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_RT.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_RT.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_RT.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -181,8 +182,8 @@ func TestValidateDeployment_RestrictedTaints(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_RT.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_RT.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_RT.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_RT.SuccessPaths)
 }
 
 // TestValidateDeployment_UniqueServiceSelectors tests our Unique Service Selectors manifest
@@ -192,9 +193,9 @@ func TestValidateDeployment_UniqueServiceSelectors(t *testing.T) {
 	assert.Nil(t, err)
 
 	// retrieving template, constraint, and deployments
-	constraintTemplate, err := testFc.ReadConstraintTemplate(testManifest_USS.Name)
+	constraintTemplate, err := testFc.ReadConstraintTemplate(types.TestManifest_USS.Name)
 	assert.Nil(t, err)
-	constraint, err := testFc.ReadConstraint(testManifest_USS.Name)
+	constraint, err := testFc.ReadConstraint(types.TestManifest_USS.Name)
 	assert.Nil(t, err)
 
 	// load template, constraint into constraint client
@@ -204,8 +205,8 @@ func TestValidateDeployment_UniqueServiceSelectors(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateOneTestManifestFail(ctx, t, c, testFc, testManifest_USS.ErrorPaths)
-	validateOneTestManifestSuccess(ctx, t, c, testFc, testManifest_USS.SuccessPaths)
+	validateOneTestManifestFail(ctx, t, c, testFc, types.TestManifest_USS.ErrorPaths)
+	validateOneTestManifestSuccess(ctx, t, c, testFc, types.TestManifest_USS.SuccessPaths)
 }
 
 // TestValidateDeployment_All tests all of our manifests in a few given manifest files
@@ -216,13 +217,13 @@ func TestValidateDeployment_All(t *testing.T) {
 
 	var testTemplates []*templates.ConstraintTemplate
 	var testConstraints []*unstructured.Unstructured
-	for _, sg := range safeguards {
+	for _, sg := range types.Safeguards {
 		// retrieving template, constraint, and deployments
-		constraintTemplate, err := testFc.ReadConstraintTemplate(sg.name)
+		constraintTemplate, err := testFc.ReadConstraintTemplate(sg.Name)
 		assert.Nil(t, err)
 		testTemplates = append(testTemplates, constraintTemplate)
 
-		constraint, err := testFc.ReadConstraint(sg.name)
+		constraint, err := testFc.ReadConstraint(sg.Name)
 		assert.Nil(t, err)
 		testConstraints = append(testConstraints, constraint)
 
@@ -235,6 +236,6 @@ func TestValidateDeployment_All(t *testing.T) {
 	assert.Nil(t, err)
 
 	// validating deployment manifests
-	validateAllTestManifestsFail(ctx, t, c, testFc, testManifest_all.ErrorPaths)
-	validateAllTestManifestsSuccess(ctx, t, c, testFc, testManifest_all.SuccessPaths)
+	validateAllTestManifestsFail(ctx, t, types.TestManifest_all.ErrorPaths)
+	validateAllTestManifestsSuccess(ctx, t, types.TestManifest_all.SuccessPaths)
 }
diff --git a/pkg/safeguards/preprocessing/preprocessing_test.go b/pkg/safeguards/preprocessing/preprocessing_test.go
index f110198..5da6cd6 100644
--- a/pkg/safeguards/preprocessing/preprocessing_test.go
+++ b/pkg/safeguards/preprocessing/preprocessing_test.go
@@ -1,104 +1,119 @@
 package preprocessing
 
 import (
-	"os"
-	"path/filepath"
+	"bytes"
 	"testing"
 
+	consts "github.com/Azure/draft/pkg/safeguards/types"
 	"github.com/stretchr/testify/assert"
+	"helm.sh/helm/v3/pkg/chartutil"
 )
 
 // Test rendering a valid Helm chart with no subcharts and three templates
 func TestRenderHelmChart_Valid(t *testing.T) {
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
+	var opt chartutil.ReleaseOptions
 
-	manifestFiles, err := RenderHelmChart(false, chartPath, tempDir)
+	manifestFiles, err := RenderHelmChart(false, consts.ChartPath, opt)
 	assert.Nil(t, err)
 
 	// Check that the output directory exists and contains expected files
-	expectedFiles := make(map[string]string)
-	expectedFiles["deployment.yaml"] = getManifestAsString(t, "../tests/testmanifests/expecteddeployment.yaml")
-	expectedFiles["service.yaml"] = getManifestAsString(t, "../tests/testmanifests/expectedservice.yaml")
-	expectedFiles["ingress.yaml"] = getManifestAsString(t, "../tests/testmanifests/expectedingress.yaml")
-
-	for _, writtenFile := range manifestFiles {
-		expectedYaml := expectedFiles[writtenFile.Name]
-		writtenYaml := parseYAML(t, getManifestAsString(t, writtenFile.Path))
-		assert.Equal(t, writtenYaml, parseYAML(t, expectedYaml))
+	expectedFiles := make(map[string][]byte)
+	expectedFiles["deployment.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expecteddeployment.yaml")
+	expectedFiles["service.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expectedservice.yaml")
+	expectedFiles["ingress.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expectedingress.yaml")
+
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		assert.Equal(t, bytes.TrimSpace(writtenManifestFile.ManifestContent), expectedYaml)
 	}
 
-	cleanupDir(t, tempDir)
-	makeTempDir(t)
+	// Test by giving file directly
+	manifestFiles, err = RenderHelmChart(true, consts.DirectPath_ToValidChart, opt)
+	assert.Nil(t, err)
+
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		assert.Equal(t, bytes.TrimSpace(writtenManifestFile.ManifestContent), expectedYaml)
+	}
+}
+
+// Test rendering a valid Helm chart with no subcharts and three templates, using command line flags
+func TestRenderHelmChartWithFlags_Valid(t *testing.T) {
+	// user defined release name and namespace from cli flags
+	opt := chartutil.ReleaseOptions{
+		Name:      "test-flags-name",
+		Namespace: "test-flags-namespace",
+	}
+
+	manifestFiles, err := RenderHelmChart(false, consts.ChartPath, opt)
+	assert.Nil(t, err)
+
+	// Check that the output directory exists and contains expected files
+	expectedFiles := make(map[string][]byte)
+	expectedFiles["deployment.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expecteddeployment_flags.yaml")
+	expectedFiles["service.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expectedservice_flags.yaml")
+	expectedFiles["ingress.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expectedingress_flags.yaml")
+
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		assert.Equal(t, bytes.TrimSpace(writtenManifestFile.ManifestContent), expectedYaml)
+	}
 
 	// Test by giving file directly
-	manifestFiles, err = RenderHelmChart(true, directPath_ToValidChart, tempDir)
+	manifestFiles, err = RenderHelmChart(true, consts.DirectPath_ToValidChart, opt)
 	assert.Nil(t, err)
 
-	for _, writtenFile := range manifestFiles {
-		expectedYaml := expectedFiles[writtenFile.Name]
-		writtenYaml := parseYAML(t, getManifestAsString(t, writtenFile.Path))
-		assert.Equal(t, writtenYaml, parseYAML(t, expectedYaml))
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		assert.Equal(t, bytes.TrimSpace(writtenManifestFile.ManifestContent), expectedYaml)
 	}
 }
 
 // Should successfully render a Helm chart with sub charts and be able to render subchart separately within a helm chart
 func TestSubCharts(t *testing.T) {
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
+	var opt chartutil.ReleaseOptions
 
-	manifestFiles, err := RenderHelmChart(false, subcharts, tempDir)
+	manifestFiles, err := RenderHelmChart(false, consts.Subcharts, opt)
 	assert.Nil(t, err)
 
-	// Assert that 3 files were created in temp dir: 1 from main chart, 2 from subcharts
-	files, _ := os.ReadDir(tempDir)
-	assert.Equal(t, len(files), 3)
+	expectedFiles := make(map[string][]byte)
+	expectedFiles["maindeployment.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expected-mainchart.yaml")
+	expectedFiles["deployment1.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expected-subchart1.yaml")
+	expectedFiles["deployment2.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expected-subchart2.yaml")
 
-	expectedFiles := make(map[string]string)
-	expectedFiles["maindeployment.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-mainchart.yaml")
-	expectedFiles["deployment1.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-subchart1.yaml")
-	expectedFiles["deployment2.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-subchart2.yaml")
-
-	for _, writtenFile := range manifestFiles {
-		expectedYaml := expectedFiles[writtenFile.Name]
-		writtenYaml := parseYAML(t, getManifestAsString(t, writtenFile.Path))
-		assert.Equal(t, writtenYaml, parseYAML(t, expectedYaml))
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		assert.Equal(t, bytes.TrimSpace(writtenManifestFile.ManifestContent), expectedYaml)
 	}
 
-	cleanupDir(t, tempDir)
-	makeTempDir(t)
-
 	// Given a sub-chart dir, that specific sub chart only should be evaluated and rendered
-	_, err = RenderHelmChart(false, subchartDir, tempDir)
+	_, err = RenderHelmChart(false, consts.SubchartDir, opt)
 	assert.Nil(t, err)
 
-	cleanupDir(t, tempDir)
-	makeTempDir(t)
-
 	// Given a Chart.yaml in the main directory, main chart and subcharts should be evaluated
-	_, err = RenderHelmChart(true, directPath_ToMainChartYaml, tempDir)
+	_, err = RenderHelmChart(true, consts.DirectPath_ToMainChartYaml, opt)
 	assert.Nil(t, err)
 
-	cleanupDir(t, tempDir)
-	makeTempDir(t)
-
 	// Given path to a sub-Chart.yaml with a dependency on another subchart, should render both subcharts, but not the main chart
-	manifestFiles, err = RenderHelmChart(true, directPath_ToSubchartYaml, tempDir)
+	manifestFiles, err = RenderHelmChart(true, consts.DirectPath_ToSubchartYaml, opt)
 	assert.Nil(t, err)
 
-	expectedFiles = make(map[string]string)
-	expectedFiles["deployment1.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-subchart1.yaml")
-	expectedFiles["deployment2.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-subchart2.yaml")
+	expectedFiles = make(map[string][]byte)
+	expectedFiles["deployment1.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expected-subchart1.yaml")
+	expectedFiles["deployment2.yaml"] = getManifestAsBytes(t, "../tests/testmanifests/expected-subchart2.yaml")
 
-	for _, writtenFile := range manifestFiles {
-		expectedYaml := expectedFiles[writtenFile.Name]
-		writtenYaml := parseYAML(t, getManifestAsString(t, writtenFile.Path))
-		assert.Equal(t, writtenYaml, parseYAML(t, expectedYaml))
+	assert.Equal(t, len(manifestFiles), 2)
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		assert.Equal(t, bytes.TrimSpace(writtenManifestFile.ManifestContent), expectedYaml)
+		assert.NoFileExists(t, "maindeployment.yaml", "Unexpected file was created: maindeployment.yaml")
 	}
-
-	//expect mainchart.yaml to not exist
-	outputFilePath := filepath.Join(tempDir, "maindeployment.yaml")
-	assert.NoFileExists(t, outputFilePath, "Unexpected file was created: %s", outputFilePath)
 }
 
 /**
@@ -107,107 +122,66 @@ func TestSubCharts(t *testing.T) {
 
 // Should fail if the Chart.yaml is invalid
 func TestInvalidChartAndValues(t *testing.T) {
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
+	var opt chartutil.ReleaseOptions
 
-	_, err := RenderHelmChart(false, invalidChartPath, tempDir)
+	_, err := RenderHelmChart(false, consts.InvalidChartPath, opt)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "failed to load main chart: validation: chart.metadata.name is required")
 
-	_, err = RenderHelmChart(true, directPath_ToValidChart, tempDir)
-	assert.Nil(t, err)
-
-	// Should fail if values.yaml doesn't contain all values necessary for templating
-	cleanupDir(t, tempDir)
-	makeTempDir(t)
+	_, err = RenderHelmChart(false, consts.InvalidValuesChart, opt)
+	assert.NotNil(t, err)
 
-	_, err = RenderHelmChart(false, invalidValuesChart, tempDir)
+	_, err = RenderHelmChart(false, consts.DirectPath_ToInvalidChart, opt)
 	assert.NotNil(t, err)
 }
 
+// Testing with malformed Deployment.yaml
 func TestInvalidDeployments(t *testing.T) {
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
+	var opt chartutil.ReleaseOptions
 
-	_, err := RenderHelmChart(false, invalidDeploymentSyntax, tempDir)
+	_, err := RenderHelmChart(false, consts.InvalidDeploymentSyntax, opt)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "parse error")
 	assert.Contains(t, err.Error(), "function \"selector\" not defined")
 
-	_, err = RenderHelmChart(false, invalidDeploymentValues, tempDir)
+	_, err = RenderHelmChart(false, consts.InvalidDeploymentValues, opt)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "map has no entry for key")
 }
 
 // Test different helm folder structures
 func TestDifferentFolderStructures(t *testing.T) {
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
-
-	manifestFiles, err := RenderHelmChart(false, folderwithHelpersTmpl, tempDir) // includes _helpers.tpl
+	var opt chartutil.ReleaseOptions
+	manifestFiles, err := RenderHelmChart(false, consts.FolderwithHelpersTmpl, opt) // includes _helpers.tpl
 	assert.Nil(t, err)
 
-	expectedFiles := make(map[string]string)
-	expectedFiles["deployment.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-helpers-deployment.yaml")
-	expectedFiles["service.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-helpers-service.yaml")
-	for _, writtenFile := range manifestFiles {
-		expectedYaml := expectedFiles[writtenFile.Name]
-		writtenYaml := parseYAML(t, getManifestAsString(t, writtenFile.Path))
-		assert.Equal(t, writtenYaml, parseYAML(t, expectedYaml))
+	expectedFiles := make(map[string][]byte)
+	expectedFiles["deployment.yaml"] = normalizeNewlines(getManifestAsBytes(t, "../tests/testmanifests/expected-helpers-deployment.yaml"))
+	expectedFiles["service.yaml"] = normalizeNewlines(getManifestAsBytes(t, "../tests/testmanifests/expected-helpers-service.yaml"))
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		resFile := bytes.TrimSpace(normalizeNewlines(writtenManifestFile.ManifestContent))
+		assert.Equal(t, resFile, expectedYaml)
 	}
-	cleanupDir(t, tempDir)
-	makeTempDir(t)
 
-	manifestFiles, err = RenderHelmChart(false, multipleTemplateDirs, tempDir) // all manifests defined in one file
+	manifestFiles, err = RenderHelmChart(false, consts.MultipleTemplateDirs, opt) // all manifests defined in one file
 	assert.Nil(t, err)
 
-	expectedFiles = make(map[string]string)
-	expectedFiles["resources.yaml"] = getManifestAsString(t, "../tests/testmanifests/expected-resources.yaml")
-	expectedFiles["service-1.yaml"] = getManifestAsString(t, "../tests/testmanifests/expectedservice.yaml")
-	expectedFiles["service-2.yaml"] = getManifestAsString(t, "../tests/testmanifests/expectedservice2.yaml")
-	for _, writtenFile := range manifestFiles {
-		expectedYaml := expectedFiles[writtenFile.Name]
-		writtenYaml := parseYAML(t, getManifestAsString(t, writtenFile.Path))
-		assert.Equal(t, writtenYaml, parseYAML(t, expectedYaml))
+	expectedFiles = make(map[string][]byte)
+	expectedFiles["resources.yaml"] = normalizeNewlines(getManifestAsBytes(t, "../tests/testmanifests/expected-resources.yaml"))
+	expectedFiles["service-1.yaml"] = normalizeNewlines(getManifestAsBytes(t, "../tests/testmanifests/expectedservice.yaml"))
+	expectedFiles["service-2.yaml"] = normalizeNewlines(getManifestAsBytes(t, "../tests/testmanifests/expectedservice2.yaml"))
+	for i, writtenManifestFile := range manifestFiles {
+		writtenFileName := manifestFiles[i].Name
+		expectedYaml := bytes.TrimSpace(expectedFiles[writtenFileName])
+		resFile := bytes.TrimSpace(normalizeNewlines(writtenManifestFile.ManifestContent))
+		assert.Equal(t, string(resFile), string(expectedYaml))
 	}
 }
 
 // Test rendering a valid kustomization.yaml
 func TestRenderKustomizeManifest_Valid(t *testing.T) {
-	makeTempDir(t)
-	t.Cleanup(func() { cleanupDir(t, tempDir) })
-
-	_, err := RenderKustomizeManifest(kustomizationPath, tempDir)
+	_, err := RenderKustomizeManifest(consts.KustomizationPath)
 	assert.Nil(t, err)
 }
-
-// TestIsKustomize checks whether the given path contains a kustomize project
-func TestIsKustomize(t *testing.T) {
-	// path contains a kustomization.yaml file
-	isKustomize := IsKustomize(kustomizationPath)
-	assert.True(t, isKustomize)
-	// path is a kustomization.yaml file
-	isKustomize = IsKustomize(kustomizationFilePath)
-	assert.True(t, isKustomize)
-	// not a kustomize project
-	isKustomize = IsKustomize(chartPath)
-	assert.False(t, isKustomize)
-}
-
-func TestIsHelm(t *testing.T) {
-	// path is a directory
-	isHelm := IsHelm(chartPath)
-	assert.True(t, isHelm)
-
-	// path is a Chart.yaml file
-	isHelm = IsHelm(directPath_ToValidChart)
-	assert.True(t, isHelm)
-
-	// Is a directory but does not contain Chart.yaml
-	isHelm = IsHelm(invalidNoChart)
-	assert.False(t, isHelm)
-
-	// invalid path
-	isHelm = IsHelm("invalid/path")
-	assert.False(t, isHelm)
-}
diff --git a/pkg/safeguards/preprocessing/preprocessing_test_helpers.go b/pkg/safeguards/preprocessing/preprocessing_test_helpers.go
index 47d1817..5078e7a 100644
--- a/pkg/safeguards/preprocessing/preprocessing_test_helpers.go
+++ b/pkg/safeguards/preprocessing/preprocessing_test_helpers.go
@@ -2,64 +2,36 @@ package preprocessing
 
 import (
 	"os"
+	"regexp"
+	"strings"
 	"testing"
-
-	"gopkg.in/yaml.v3"
-)
-
-const (
-	tempDir                 = "testdata" // Rendered files are stored here before they are read for comparison
-	chartPath               = "../tests/testmanifests/validchart"
-	invalidNoChart          = "../tests/testmanifests/nochart-invalid"
-	invalidChartPath        = "../tests/testmanifests/invalidchart"
-	invalidValuesChart      = "../tests/testmanifests/invalidvalues"
-	invalidDeploymentsChart = "../tests/testmanifests/invaliddeployment"
-	invalidDeploymentSyntax = "../tests/testmanifests/invaliddeployment-syntax"
-	invalidDeploymentValues = "../tests/testmanifests/invaliddeployment-values"
-	folderwithHelpersTmpl   = "../tests/testmanifests/different-structure"
-	multipleTemplateDirs    = "../tests/testmanifests/multiple-templates"
-	multipleValuesFile      = "../tests/testmanifests/multiple-values-files"
-
-	subcharts                  = "../tests/testmanifests/multiple-charts"
-	subchartDir                = "../tests/testmanifests/multiple-charts/charts/subchart2"
-	directPath_ToSubchartYaml  = "../tests/testmanifests/multiple-charts/charts/subchart1/Chart.yaml"
-	directPath_ToMainChartYaml = "../tests/testmanifests/multiple-charts/Chart.yaml"
-
-	directPath_ToValidChart   = "../tests/testmanifests/validchart/Chart.yaml"
-	directPath_ToInvalidChart = "../tests/testmanifests/invalidchart/Chart.yaml"
-
-	kustomizationPath     = "../tests/kustomize/overlays/production"
-	kustomizationFilePath = "../tests/kustomize/overlays/production/kustomization.yaml"
 )
 
-func makeTempDir(t *testing.T) {
-	if err := CreateTempDir(tempDir); err != nil {
-		t.Fatalf("failed to create temporary output directory: %s", err)
-	}
-}
-
-func cleanupDir(t *testing.T, dir string) {
-	err := os.RemoveAll(dir)
+// Returns the content of a manifest file as bytes
+func getManifestAsBytes(t *testing.T, filePath string) []byte {
+	yamlFileContent, err := os.ReadFile(filePath)
 	if err != nil {
-		t.Fatalf("Failed to clean directory: %s", err)
+		t.Fatalf("Failed to read YAML file: %s", err)
 	}
-}
 
-func parseYAML(t *testing.T, content string) map[string]interface{} {
-	var result map[string]interface{}
-	err := yaml.Unmarshal([]byte(content), &result)
-	if err != nil {
-		t.Fatalf("Failed to parse YAML: %s", err)
-	}
-	return result
+	return yamlFileContent
 }
 
-func getManifestAsString(t *testing.T, filePath string) string {
-	yamlFileContent, err := os.ReadFile(filePath)
-	if err != nil {
-		t.Fatalf("Failed to read YAML file: %s", err)
-	}
+// Normalize returns, newlines, extra characters with strings for easy .yaml byte comparison
+func normalizeNewlines(data []byte) []byte {
+	str := string(data)
+
+	// Replace various newline characters with a single newline
+	str = strings.ReplaceAll(str, "\r\n", "\n")
+	str = strings.ReplaceAll(str, "\r", "\n")
+
+	// Replace YAML block scalars' indicators and multiple spaces
+	str = regexp.MustCompile(`(\s*\|\s*)`).ReplaceAllString(str, " ")
+	str = strings.Join(strings.Fields(str), " ")
+
+	// Normalize empty mappings and fields
+	str = regexp.MustCompile(`\{\s*\}`).ReplaceAllString(str, "{}")
+	str = regexp.MustCompile(`\s*:\s*`).ReplaceAllString(str, ": ")
 
-	yamlContentString := string(yamlFileContent)
-	return yamlContentString
+	return []byte(str)
 }
diff --git a/pkg/safeguards/tests/testmanifests/expected-resources.yaml b/pkg/safeguards/tests/testmanifests/expected-resources.yaml
index 995a77d..396d626 100644
--- a/pkg/safeguards/tests/testmanifests/expected-resources.yaml
+++ b/pkg/safeguards/tests/testmanifests/expected-resources.yaml
@@ -35,11 +35,6 @@ data:
     ingress:
       enabled: true
       hostname: example.com
-      annotations: {}
+      annotations:
       tls: false
-      tlsSecret: ""
-
-
-
-
-
+      tlsSecret:
\ No newline at end of file
diff --git a/pkg/safeguards/tests/testmanifests/expecteddeployment_flags.yaml b/pkg/safeguards/tests/testmanifests/expecteddeployment_flags.yaml
new file mode 100644
index 0000000..2ccd550
--- /dev/null
+++ b/pkg/safeguards/tests/testmanifests/expecteddeployment_flags.yaml
@@ -0,0 +1,18 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: test-flags-name-deployment
+  namespace: test-flags-namespace
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: my-web-app
+  template:
+    metadata:
+      labels:
+        app: my-web-app
+    spec:
+      containers:
+        - name: nginx
+          image: nginx:stable
\ No newline at end of file
diff --git a/pkg/safeguards/tests/testmanifests/expectedingress_flags.yaml b/pkg/safeguards/tests/testmanifests/expectedingress_flags.yaml
new file mode 100644
index 0000000..fc83937
--- /dev/null
+++ b/pkg/safeguards/tests/testmanifests/expectedingress_flags.yaml
@@ -0,0 +1,17 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: test-flags-name-ingress
+  namespace: test-flags-namespace
+spec:
+  rules:
+    - host: example.com
+      http:
+        paths:
+          - path: /
+            pathType: Prefix
+            backend:
+              service:
+                name: test-flags-name-service
+                port:
+                  number: 80
\ No newline at end of file
diff --git a/pkg/safeguards/tests/testmanifests/expectedservice_flags.yaml b/pkg/safeguards/tests/testmanifests/expectedservice_flags.yaml
new file mode 100644
index 0000000..5836eef
--- /dev/null
+++ b/pkg/safeguards/tests/testmanifests/expectedservice_flags.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: test-flags-name-service
+  namespace: test-flags-namespace
+spec:
+  type: ClusterIP
+  ports:
+    - port: 80
+  selector:
+    app: my-web-app
\ No newline at end of file
diff --git a/pkg/safeguards/constants_test.go b/pkg/safeguards/types/test_constants.go
similarity index 83%
rename from pkg/safeguards/constants_test.go
rename to pkg/safeguards/types/test_constants.go
index dca381c..2358e30 100644
--- a/pkg/safeguards/constants_test.go
+++ b/pkg/safeguards/types/test_constants.go
@@ -1,4 +1,4 @@
-package safeguards
+package types
 
 import "fmt"
 
@@ -11,32 +11,32 @@ type TestManifest struct {
 const testManifestDirectory = "tests"
 
 var testDeployments = []TestManifest{
-	testManifest_CAI,
-	testManifest_CEP,
-	testManifest_CL,
-	testManifest_CRIP,
-	testManifest_DBPDB,
-	testManifest_PEA,
-	testManifest_RT,
-	testManifest_USS,
-	testManifest_all,
+	TestManifest_CAI,
+	TestManifest_CEP,
+	TestManifest_CL,
+	TestManifest_CRIP,
+	TestManifest_DBPDB,
+	TestManifest_PEA,
+	TestManifest_RT,
+	TestManifest_USS,
+	TestManifest_all,
 }
 
-var testError_CAI_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CAI, "CAI-error-manifest.yaml")
+var TestError_CAI_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CAI, "CAI-error-manifest.yaml")
 
-var testSuccess_CAI_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CAI, "CAI-success-manifest.yaml")
+var TestSuccess_CAI_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CAI, "CAI-success-manifest.yaml")
 
-var testManifest_CAI = TestManifest{
+var TestManifest_CAI = TestManifest{
 	Name:         Constraint_CAI,
-	SuccessPaths: []string{testSuccess_CAI_Standard},
-	ErrorPaths:   []string{testError_CAI_Standard},
+	SuccessPaths: []string{TestSuccess_CAI_Standard},
+	ErrorPaths:   []string{TestError_CAI_Standard},
 }
 
 var testError_CEP_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CEP, "CEP-error-manifest.yaml")
 
 var testSuccess_CEP_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CEP, "CEP-success-manifest.yaml")
 
-var testManifest_CEP = TestManifest{
+var TestManifest_CEP = TestManifest{
 	Name:         Constraint_CEP,
 	SuccessPaths: []string{testSuccess_CEP_Standard},
 	ErrorPaths:   []string{testError_CEP_Standard},
@@ -46,7 +46,7 @@ var testError_CRL_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Cons
 
 var testSuccess_CRL_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CRL, "CRL-success-manifest.yaml")
 
-var testManifest_CL = TestManifest{
+var TestManifest_CL = TestManifest{
 	Name:         Constraint_CRL,
 	SuccessPaths: []string{testSuccess_CRL_Standard},
 	ErrorPaths:   []string{testError_CRL_Standard},
@@ -56,7 +56,7 @@ var testError_CRIP_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Con
 
 var testSuccess_CRIP_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_CRIP, "CRIP-success-manifest.yaml")
 
-var testManifest_CRIP = TestManifest{
+var TestManifest_CRIP = TestManifest{
 	Name:         Constraint_CRIP,
 	SuccessPaths: []string{testSuccess_CRIP_Standard},
 	ErrorPaths:   []string{testError_CRIP_Standard},
@@ -66,7 +66,7 @@ var testError_DBPDB_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Co
 
 var testSuccess_DBPDB_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_DBPDB, "DBPDB-success-manifest.yaml")
 
-var testManifest_DBPDB = TestManifest{
+var TestManifest_DBPDB = TestManifest{
 	Name:         Constraint_DBPDB,
 	SuccessPaths: []string{testSuccess_DBPDB_Standard},
 	ErrorPaths:   []string{testError_DBPDB_Standard},
@@ -76,7 +76,7 @@ var testError_PEA_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Cons
 
 var testSuccess_PEA_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_PEA, "PEA-success-manifest.yaml")
 
-var testManifest_PEA = TestManifest{
+var TestManifest_PEA = TestManifest{
 	Name:         Constraint_PEA,
 	SuccessPaths: []string{testSuccess_PEA_Standard},
 	ErrorPaths:   []string{testError_PEA_Standard},
@@ -86,7 +86,7 @@ var testError_RT_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Const
 
 var testSuccess_RT_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_RT, "RT-success-manifest.yaml")
 
-var testManifest_RT = TestManifest{
+var TestManifest_RT = TestManifest{
 	Name:         Constraint_RT,
 	SuccessPaths: []string{testSuccess_RT_Standard},
 	ErrorPaths:   []string{testError_RT_Standard},
@@ -96,7 +96,7 @@ var testError_USS_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Cons
 
 var testSuccess_USS_Standard = fmt.Sprintf("%s/%s/%s", testManifestDirectory, Constraint_USS, "USS-success-manifest.yaml")
 
-var testManifest_USS = TestManifest{
+var TestManifest_USS = TestManifest{
 	Name:         Constraint_USS,
 	SuccessPaths: []string{testSuccess_USS_Standard},
 	ErrorPaths:   []string{testError_USS_Standard},
@@ -107,7 +107,7 @@ var testError_all_Standard_2 = fmt.Sprintf("%s/%s/%s/%s", testManifestDirectory,
 var testSuccess_all_Standard_1 = fmt.Sprintf("%s/%s/%s/%s", testManifestDirectory, Constraint_all, "success", "all-success-manifest-1.yaml")
 var testSuccess_all_Standard_2 = fmt.Sprintf("%s/%s/%s/%s", testManifestDirectory, Constraint_all, "success", "all-success-manifest-2.yaml")
 
-var testManifest_all = TestManifest{
+var TestManifest_all = TestManifest{
 	Name:         "all",
 	SuccessPaths: []string{testSuccess_all_Standard_1, testSuccess_all_Standard_2},
 	ErrorPaths:   []string{testError_all_Standard_1, testError_all_Standard_2},