-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
David Gamero
committed
May 20, 2024
1 parent
755e4a5
commit a974ef7
Showing
50 changed files
with
2,784 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"path" | ||
|
||
"github.com/Azure/draft/pkg/safeguards" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type validateCmd struct { | ||
manifestPath string | ||
imagePullSecret bool | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(newValidateCmd()) | ||
} | ||
|
||
func newValidateCmd() *cobra.Command { | ||
vc := &validateCmd{} | ||
|
||
var cmd = &cobra.Command{ | ||
Use: "validate", | ||
Short: "Validates manifests against AKS best practices", | ||
Long: `This command validates manifests against several AKS best practices.`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if err := vc.run(cmd); err != nil { | ||
return err | ||
} | ||
return nil | ||
}, | ||
} | ||
|
||
f := cmd.Flags() | ||
|
||
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)") | ||
|
||
return cmd | ||
} | ||
|
||
// run is our entry point to GetManifestResults | ||
func (vc *validateCmd) run(c *cobra.Command) error { | ||
if vc.manifestPath == "" { | ||
return fmt.Errorf("path to the manifests cannot be empty") | ||
} | ||
|
||
// AddSafeguardCRIP just adds Container Restricted Image Pulls to the list of safeguards the client will review | ||
// against the given manifest | ||
if vc.imagePullSecret { | ||
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 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") | ||
} | ||
|
||
log.Debugf("validating manifests") | ||
manifestViolations, err := safeguards.GetManifestResults(ctx, manifestFiles) | ||
if err != nil { | ||
log.Errorf("validating safeguards: %s", err.Error()) | ||
return err | ||
} | ||
|
||
anyViolationsFound := false | ||
for _, v := range manifestViolations { | ||
log.Printf("Analyzing %s for violations", v.Name) | ||
manifestHasViolations := false | ||
// returning the full list of violations after each manifest is checked | ||
for file, violations := range v.ObjectViolations { | ||
log.Printf(" %s:", file) | ||
for _, violation := range violations { | ||
log.Printf(" ❌ %s", violation) | ||
anyViolationsFound = true | ||
manifestHasViolations = true | ||
} | ||
} | ||
if !manifestHasViolations { | ||
log.Printf(" ✅ no violations found.") | ||
} | ||
} | ||
|
||
if anyViolationsFound { | ||
c.SilenceUsage = true // suppress default Cobra behaviour of printing usage on all errors | ||
return fmt.Errorf("violations found") | ||
} else { | ||
log.Printf("✅ No violations found in \"%s\".", vc.manifestPath) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package cmd | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
|
||
"testing" | ||
|
||
"github.com/Azure/draft/pkg/safeguards" | ||
"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) | ||
|
||
manifestFiles, err = safeguards.GetManifestFiles(dirYaml) | ||
assert.NotNil(t, manifestFiles) | ||
assert.Nil(t, err) | ||
} | ||
|
||
// 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 | ||
|
||
// 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) | ||
assert.Nil(t, err) | ||
v, err := safeguards.GetManifestResults(ctx, manifestFiles) | ||
assert.Nil(t, err) | ||
numViolations := countTestViolations(v) | ||
assert.Equal(t, numViolations, 0) | ||
|
||
// Scenario 2b: manifest path leads to a directory of manifestFiles - expect failure | ||
manifestFiles, err = safeguards.GetManifestFiles(manifestPathDirectoryError) | ||
assert.Nil(t, err) | ||
v, err = safeguards.GetManifestResults(ctx, manifestFiles) | ||
assert.Nil(t, err) | ||
numViolations = countTestViolations(v) | ||
assert.Greater(t, numViolations, 0) | ||
|
||
// Scenario 3a: manifest path leads to one manifest file - expect success | ||
manifestFiles, err = safeguards.GetManifestFiles(manifestPathFileSuccess) | ||
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) | ||
v, err = safeguards.GetManifestResults(ctx, manifestFiles) | ||
assert.Nil(t, err) | ||
numViolations = countTestViolations(v) | ||
assert.Greater(t, numViolations, 0) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package cmd | ||
|
||
import "github.com/Azure/draft/pkg/safeguards" | ||
|
||
func countTestViolations(results []safeguards.ManifestResult) int { | ||
numViolations := 0 | ||
for _, r := range results { | ||
numViolations += len(r.ObjectViolations) | ||
} | ||
|
||
return numViolations | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.