Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Draft Validate functionality into main #281

Merged
merged 1 commit into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ For more information, please visit the Draft Github page: https://github.com/Azu
logrus.SetOutput(&logger.OutputSplitter{})
logrus.SetFormatter(new(logger.CustomFormatter))
},
SilenceErrors: true,
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand Down
111 changes: 111 additions & 0 deletions cmd/validate.go
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.")
davidgamero marked this conversation as resolved.
Show resolved Hide resolved
}
}

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
}
97 changes: 97 additions & 0 deletions cmd/validate_test.go
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)
}
12 changes: 12 additions & 0 deletions cmd/validate_test_helpers.go
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
}
85 changes: 75 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,52 +12,86 @@ require (
github.com/fatih/color v1.16.0
github.com/ghodss/yaml v1.0.0
github.com/hashicorp/go-version v1.6.0
github.com/instrumenta/kubeval v0.16.1
github.com/instrumenta/kubeval v0.16.0
github.com/ivanpirog/coloredcobra v1.0.1
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a
github.com/manifoldco/promptui v0.9.0
github.com/microsoftgraph/msgraph-sdk-go v1.38.0
github.com/open-policy-agent/frameworks/constraint v0.0.0-20240516222118-7d1bd0255f52
github.com/open-policy-agent/gatekeeper/v3 v3.16.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.9.0
go.uber.org/mock v0.4.0
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
golang.org/x/mod v0.17.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.14.4
k8s.io/api v0.30.0
k8s.io/cli-runtime v0.30.0
k8s.io/client-go v0.30.0
k8s.io/api v0.29.3
davidgamero marked this conversation as resolved.
Show resolved Hide resolved
k8s.io/apimachinery v0.29.3
k8s.io/cli-runtime v0.29.0
k8s.io/client-go v0.29.3
sigs.k8s.io/kustomize/api v0.17.1
sigs.k8s.io/kustomize/kyaml v0.17.0
)

require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cjlapao/common-go v0.0.39 // indirect
github.com/containerd/containerd v1.7.14 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/cli v25.0.1+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v25.0.5+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/glog v1.2.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/cel-go v0.17.7 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.7 // indirect
Expand All @@ -71,36 +105,67 @@ require (
github.com/microsoft/kiota-serialization-multipart-go v1.0.0 // indirect
github.com/microsoft/kiota-serialization-text-go v1.0.0 // indirect
github.com/microsoftgraph/msgraph-sdk-go-core v1.1.0 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/open-policy-agent/opa v0.63.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/std-uritemplate/std-uritemplate/go v0.0.55 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 // indirect
google.golang.org/grpc v1.62.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apimachinery v0.30.0 // indirect
k8s.io/apiextensions-apiserver v0.29.3 // indirect
k8s.io/apiserver v0.29.3 // indirect
k8s.io/component-base v0.29.3 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
oras.land/oras-go v1.2.5 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect
sigs.k8s.io/controller-runtime v0.17.3 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
Expand Down
Loading
Loading