From 651d3b2c503431eb57c60e088dbaf7446514ecb9 Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sun, 15 Nov 2020 20:23:37 +0100 Subject: [PATCH] fail early when a broken -schema-location template is given --- acceptance.bats | 7 +++++++ cmd/kubeconform/main.go | 6 +++++- examples/main.go | 5 ++++- pkg/registry/registry.go | 12 +++++++++--- pkg/validator/validator.go | 10 +++++++--- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/acceptance.bats b/acceptance.bats index 398c529..7d698e8 100755 --- a/acceptance.bats +++ b/acceptance.bats @@ -128,6 +128,13 @@ [ "$status" -eq 1 ] } +@test "Fail early when passing a non valid -schema-location template" { + run bin/kubeconform -schema-location 'foo {{ .Foo }}' fixtures/valid.yaml + [[ "$output" = failed\ initialising* ]] + [[ `echo "$output" | wc -l` -eq 1 ]] + [ "$status" -eq 1 ] +} + @test "Pass with a valid input when validating against openshift manifests" { run bin/kubeconform -kubernetes-version 3.8.0 -schema-location 'https://raw.githubusercontent.com/garethr/openshift-json-schema/master/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}.json' -summary fixtures/valid.yaml [ "$status" -eq 0 ] diff --git a/cmd/kubeconform/main.go b/cmd/kubeconform/main.go index 9769b15..713139b 100644 --- a/cmd/kubeconform/main.go +++ b/cmd/kubeconform/main.go @@ -65,7 +65,7 @@ func realMain() int { return 1 } - v := validator.New(cfg.SchemaLocations, validator.Opts{ + v, err := validator.New(cfg.SchemaLocations, validator.Opts{ SkipTLS: cfg.SkipTLS, SkipKinds: cfg.SkipKinds, RejectKinds: cfg.RejectKinds, @@ -73,6 +73,10 @@ func realMain() int { Strict: cfg.Strict, IgnoreMissingSchemas: cfg.IgnoreMissingSchemas, }) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return 1 + } validationResults := make(chan validator.Result) ctx := context.Background() diff --git a/examples/main.go b/examples/main.go index bb0e498..ba7338a 100644 --- a/examples/main.go +++ b/examples/main.go @@ -16,7 +16,10 @@ func main() { log.Fatalf("failed opening %s: %s", filepath, err) } - v := validator.New(nil, validator.Opts{Strict: true}) + v, err := validator.New(nil, validator.Opts{Strict: true}) + if err != nil { + log.Fatalf("failed initializing validator: %s", err) + } for i, res := range v.Validate(filepath, f) { // A file might contain multiple resources // File starts with ---, the parser assumes a first empty resource if res.Status == validator.Invalid { diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index 6ddfbb7..6bc7152 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -2,6 +2,7 @@ package registry import ( "bytes" + "fmt" "strings" "text/template" ) @@ -67,14 +68,19 @@ func schemaPath(tpl, resourceKind, resourceAPIVersion, k8sVersion string, strict return buf.String(), nil } -func New(schemaLocation string, strict bool, skipTLS bool) Registry { +func New(schemaLocation string, strict bool, skipTLS bool) (Registry, error) { if !strings.HasSuffix(schemaLocation, "json") { // If we dont specify a full templated path, we assume the paths of kubernetesjsonschema.dev schemaLocation += "/{{ .NormalizedKubernetesVersion }}-standalone{{ .StrictSuffix }}/{{ .ResourceKind }}{{ .KindSuffix }}.json" } + // We try a fake compilation of the schemaLocation template to ensure it is valid + if _, err := schemaPath(schemaLocation, "Deployment", "v1", "1.18.0", true); err != nil { + return nil, fmt.Errorf("failed initialising schema location registry: %s", err) + } + if strings.HasPrefix(schemaLocation, "http") { - return newHTTPRegistry(schemaLocation, strict, skipTLS) + return newHTTPRegistry(schemaLocation, strict, skipTLS), nil } else { - return newLocalRegistry(schemaLocation, strict) + return newLocalRegistry(schemaLocation, strict), nil } } diff --git a/pkg/validator/validator.go b/pkg/validator/validator.go index 0eead1d..4b65cd0 100644 --- a/pkg/validator/validator.go +++ b/pkg/validator/validator.go @@ -51,7 +51,7 @@ type Opts struct { } // New returns a new Validator -func New(schemaLocations []string, opts Opts) Validator { +func New(schemaLocations []string, opts Opts) (Validator, error) { // Default to kubernetesjsonschema.dev if schemaLocations == nil || len(schemaLocations) == 0 { schemaLocations = []string{"https://kubernetesjsonschema.dev"} @@ -59,7 +59,11 @@ func New(schemaLocations []string, opts Opts) Validator { registries := []registry.Registry{} for _, schemaLocation := range schemaLocations { - registries = append(registries, registry.New(schemaLocation, opts.Strict, opts.SkipTLS)) + reg, err := registry.New(schemaLocation, opts.Strict, opts.SkipTLS) + if err != nil { + return nil, err + } + registries = append(registries, reg) } if opts.KubernetesVersion == "" { @@ -78,7 +82,7 @@ func New(schemaLocations []string, opts Opts) Validator { schemaDownload: downloadSchema, schemaCache: cache.New(), regs: registries, - } + }, nil } type v struct {