From f02071f84348c3ca8f61b45812a4eb4760c277b0 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 09:43:49 -0700 Subject: [PATCH 01/18] init commit --- code/go/go.mod | 4 ++ code/go/go.sum | 7 ++ code/go/internal/pkgpath/files.go | 67 +++++++++++++++++++ .../validator/semantic/kibana_object_ids.go | 17 +++++ 4 files changed, 95 insertions(+) create mode 100644 code/go/internal/pkgpath/files.go create mode 100644 code/go/internal/validator/semantic/kibana_object_ids.go diff --git a/code/go/go.mod b/code/go/go.mod index 720148a67..79ee18408 100644 --- a/code/go/go.mod +++ b/code/go/go.mod @@ -4,7 +4,9 @@ go 1.15 require ( github.com/Masterminds/semver/v3 v3.1.0 + github.com/PaesslerAG/jsonpath v0.1.1 github.com/creasty/defaults v1.5.1 + github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/stretchr/testify v1.6.1 @@ -12,3 +14,5 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c ) + +replace github.com/elastic/package-spec/code/go/internal/pkgpath => ./internal/pkgpath diff --git a/code/go/go.sum b/code/go/go.sum index 84cee445e..d48fd468e 100644 --- a/code/go/go.sum +++ b/code/go/go.sum @@ -1,9 +1,16 @@ github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8= +github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= +github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk= +github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= github.com/creasty/defaults v1.5.1 h1:j8WexcS3d/t4ZmllX4GEkl4wIB/trOr035ajcLHCISM= github.com/creasty/defaults v1.5.1/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/code/go/internal/pkgpath/files.go b/code/go/internal/pkgpath/files.go new file mode 100644 index 000000000..2728bc20f --- /dev/null +++ b/code/go/internal/pkgpath/files.go @@ -0,0 +1,67 @@ +package pkgpath + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/PaesslerAG/jsonpath" + "github.com/joeshaw/multierror" + "github.com/pkg/errors" + "gopkg.in/yaml.v3" +) + +type File struct { + os.FileInfo +} + +func Files(glob string) ([]File, error) { + paths, err := filepath.Glob(glob) + if err != nil { + return nil, err + } + + var errs multierror.Errors + var files = make([]File, 0) + for _, path := range paths { + info, err := os.Stat(path) + if err != nil { + errs = append(errs, err) + continue + } + + file := File{info} + files = append(files, file) + } + + return files, errs.Err() +} + +func (f File) Values(path string) (interface{}, error) { + fileName := f.Name() + fileExt := filepath.Ext(fileName) + + if fileExt != "json" && fileExt != "yaml" && fileExt != "yml" { + return nil, fmt.Errorf("cannot extract values from file type = %s", fileExt) + } + + contents, err := ioutil.ReadFile(fileName) + if err != nil { + return nil, errors.Wrap(err, "reading file content failed") + } + + var v interface{} + if fileExt == "yaml" || fileExt == "yml" { + if err := yaml.Unmarshal(contents, &v); err != nil { + return nil, errors.Wrapf(err, "unmarshalling YAML file failed (path: %s)", fileName) + } + } else if fileExt == "json" { + if err := json.Unmarshal(contents, &v); err != nil { + return nil, errors.Wrapf(err, "unmarshalling JSON file failed (path: %s)", fileName) + } + } + + return jsonpath.Get(path, v) +} diff --git a/code/go/internal/validator/semantic/kibana_object_ids.go b/code/go/internal/validator/semantic/kibana_object_ids.go new file mode 100644 index 000000000..311d5397d --- /dev/null +++ b/code/go/internal/validator/semantic/kibana_object_ids.go @@ -0,0 +1,17 @@ +package semantic + +import ( + "path/filepath" + + "github.com/elastic/package-spec/code/go/internal/pkgpath" +) + +func ValidateKibanaObjectIDs(pkgRoot string) error { + filePaths := filepath.Join(pkgRoot, "kibana", "dashboard", "*.json") + _, err := pkgpath.Files(filePaths) + if err != nil { + return err + } + + return nil +} From b35eb59d12e593068ae266d895f90b2cb21c3943 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 10:34:27 -0700 Subject: [PATCH 02/18] Fleshing out --- code/go/go.mod | 4 +-- .../validator/semantic/kibana_object_ids.go | 27 ++++++++++++++++--- code/go/internal/validator/spec.go | 10 ++++++- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/code/go/go.mod b/code/go/go.mod index 79ee18408..812e102d5 100644 --- a/code/go/go.mod +++ b/code/go/go.mod @@ -13,6 +13,4 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 github.com/xeipuuv/gojsonschema v1.2.0 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c -) - -replace github.com/elastic/package-spec/code/go/internal/pkgpath => ./internal/pkgpath +) \ No newline at end of file diff --git a/code/go/internal/validator/semantic/kibana_object_ids.go b/code/go/internal/validator/semantic/kibana_object_ids.go index 311d5397d..359c97d92 100644 --- a/code/go/internal/validator/semantic/kibana_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_object_ids.go @@ -1,17 +1,38 @@ package semantic import ( + "fmt" "path/filepath" + "strings" + + "github.com/elastic/package-spec/code/go/internal/validator" + + "github.com/pkg/errors" "github.com/elastic/package-spec/code/go/internal/pkgpath" ) func ValidateKibanaObjectIDs(pkgRoot string) error { filePaths := filepath.Join(pkgRoot, "kibana", "dashboard", "*.json") - _, err := pkgpath.Files(filePaths) + dashboardFiles, err := pkgpath.Files(filePaths) if err != nil { - return err + return errors.Wrap(err, "unable to find dashboard files") + } + + var errs validator.ValidationErrors + for _, dashboardFile := range dashboardFiles { + name := dashboardFile.Name() + dashboardID, err := dashboardFile.Values("$.id") + if err != nil { + return errors.Wrap(err, "unable to get dashboard ID") + } + + fileID := strings.TrimRight(name, ".json") + if fileID != dashboardID { + err := fmt.Errorf("dashboard file '%s' defines non-matching ID '%s'", name, dashboardID) + errs = append(errs, err) + } } - return nil + return errs } diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index 25fd437b8..a7cec0025 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -5,6 +5,8 @@ import ( "path" "strconv" + "github.com/elastic/package-spec/code/go/internal/validator/semantic" + "github.com/Masterminds/semver/v3" "github.com/pkg/errors" "github.com/rakyll/statik/fs" @@ -54,5 +56,11 @@ func (s Spec) ValidatePackage(pkg Package) ValidationErrors { return errs } - return rootSpec.validate(pkg.Name, pkg.RootPath) + // Syntactic validations + errs = rootSpec.validate(pkg.Name, pkg.RootPath) + + // Semantic validations + errs = append(errs, semantic.ValidateKibanaObjectIDs(pkg.RootPath)...) + + return errs } From 2d3f943a4822676553917c706d13fa1b2825e387 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:01:16 -0700 Subject: [PATCH 03/18] Adding godoc comments --- .../semantic/kibana_matching_object_ids.go | 41 +++++++++++++++++++ .../semantic/kibana_no_dangling_object_ids.go | 11 +++++ .../validator/semantic/kibana_object_ids.go | 38 ----------------- 3 files changed, 52 insertions(+), 38 deletions(-) create mode 100644 code/go/internal/validator/semantic/kibana_matching_object_ids.go create mode 100644 code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go delete mode 100644 code/go/internal/validator/semantic/kibana_object_ids.go diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go new file mode 100644 index 000000000..397c172f9 --- /dev/null +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -0,0 +1,41 @@ +package semantic + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/elastic/package-spec/code/go/internal/pkgpath" + "github.com/elastic/package-spec/code/go/internal/validator" + + "github.com/pkg/errors" +) + +// ValidateKibanaObjectIDs returns validation errors if there are any Kibana +// object files that define IDs not matching the file's name. That is, it returns +// validation errors if a Kibana object file, foo.json, in the package defines +// an object ID other than foo inside it. +func ValidateKibanaObjectIDs(pkgRoot string) error { + filePaths := filepath.Join(pkgRoot, "kibana", "*", "*.json") + objectFiles, err := pkgpath.Files(filePaths) + if err != nil { + return errors.Wrap(err, "unable to find Kibana object files") + } + + var errs validator.ValidationErrors + for _, objectFile := range objectFiles { + name := objectFile.Name() + objectID, err := objectFile.Values("$.id") + if err != nil { + return errors.Wrap(err, "unable to get Kibana object ID") + } + + fileID := strings.TrimRight(name, ".json") + if fileID != objectID { + err := fmt.Errorf("kibana object file '%s' defines non-matching ID '%s'", name, objectID) + errs = append(errs, err) + } + } + + return errs +} diff --git a/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go b/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go new file mode 100644 index 000000000..214708ae2 --- /dev/null +++ b/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go @@ -0,0 +1,11 @@ +package semantic + +// ValidateKibanaNoDanglingObjectIDs returns validation errors if there are any +// dangling references to Kibana objects in any Kibana object files. That is, it +// returns validation errors if a Kibana object file in the package references another +// Kibana object with ID i, but no Kibana object file for object ID i is found in the +// package. +func ValidateKibanaNoDanglingObjectIDs(pkgRoot string) error { + // TODO: will be implemented in follow up PR + return nil +} diff --git a/code/go/internal/validator/semantic/kibana_object_ids.go b/code/go/internal/validator/semantic/kibana_object_ids.go deleted file mode 100644 index 359c97d92..000000000 --- a/code/go/internal/validator/semantic/kibana_object_ids.go +++ /dev/null @@ -1,38 +0,0 @@ -package semantic - -import ( - "fmt" - "path/filepath" - "strings" - - "github.com/elastic/package-spec/code/go/internal/validator" - - "github.com/pkg/errors" - - "github.com/elastic/package-spec/code/go/internal/pkgpath" -) - -func ValidateKibanaObjectIDs(pkgRoot string) error { - filePaths := filepath.Join(pkgRoot, "kibana", "dashboard", "*.json") - dashboardFiles, err := pkgpath.Files(filePaths) - if err != nil { - return errors.Wrap(err, "unable to find dashboard files") - } - - var errs validator.ValidationErrors - for _, dashboardFile := range dashboardFiles { - name := dashboardFile.Name() - dashboardID, err := dashboardFile.Values("$.id") - if err != nil { - return errors.Wrap(err, "unable to get dashboard ID") - } - - fileID := strings.TrimRight(name, ".json") - if fileID != dashboardID { - err := fmt.Errorf("dashboard file '%s' defines non-matching ID '%s'", name, dashboardID) - errs = append(errs, err) - } - } - - return errs -} From 87bc111791908a499565beb20d811d1870986e74 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:01:51 -0700 Subject: [PATCH 04/18] Adding license headers --- code/go/internal/pkgpath/files.go | 4 ++++ .../internal/validator/semantic/kibana_matching_object_ids.go | 4 ++++ .../validator/semantic/kibana_no_dangling_object_ids.go | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/code/go/internal/pkgpath/files.go b/code/go/internal/pkgpath/files.go index 2728bc20f..500567201 100644 --- a/code/go/internal/pkgpath/files.go +++ b/code/go/internal/pkgpath/files.go @@ -1,3 +1,7 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + package pkgpath import ( diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index 397c172f9..b861db038 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -1,3 +1,7 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + package semantic import ( diff --git a/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go b/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go index 214708ae2..9d048a6d4 100644 --- a/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go @@ -1,3 +1,7 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + package semantic // ValidateKibanaNoDanglingObjectIDs returns validation errors if there are any From 01353b09b0ac84396ce02e15e7caad7a4c50321e Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:04:22 -0700 Subject: [PATCH 05/18] Refactoring to avoid import cycle --- code/go/internal/{validator => errors}/errors.go | 2 +- .../go/internal/{validator => errors}/errors_test.go | 2 +- code/go/internal/validator/folder_item_spec.go | 12 +++++++----- code/go/internal/validator/folder_spec.go | 6 ++++-- .../validator/semantic/kibana_matching_object_ids.go | 6 +++--- code/go/internal/validator/spec.go | 6 ++++-- code/go/pkg/validator/errors.go | 4 ++-- code/go/pkg/validator/validator_test.go | 10 +++++----- 8 files changed, 27 insertions(+), 21 deletions(-) rename code/go/internal/{validator => errors}/errors.go (96%) rename code/go/internal/{validator => errors}/errors_test.go (97%) diff --git a/code/go/internal/validator/errors.go b/code/go/internal/errors/errors.go similarity index 96% rename from code/go/internal/validator/errors.go rename to code/go/internal/errors/errors.go index 780e024e6..e0b46ba1d 100644 --- a/code/go/internal/validator/errors.go +++ b/code/go/internal/errors/errors.go @@ -1,4 +1,4 @@ -package validator +package errors import ( "fmt" diff --git a/code/go/internal/validator/errors_test.go b/code/go/internal/errors/errors_test.go similarity index 97% rename from code/go/internal/validator/errors_test.go rename to code/go/internal/errors/errors_test.go index 6523d6c26..59c8f0d20 100644 --- a/code/go/internal/validator/errors_test.go +++ b/code/go/internal/errors/errors_test.go @@ -1,4 +1,4 @@ -package validator +package errors import ( "errors" diff --git a/code/go/internal/validator/folder_item_spec.go b/code/go/internal/validator/folder_item_spec.go index 627d5b60c..c0f6965ee 100644 --- a/code/go/internal/validator/folder_item_spec.go +++ b/code/go/internal/validator/folder_item_spec.go @@ -8,6 +8,8 @@ import ( "regexp" "sync" + errors2 "github.com/elastic/package-spec/code/go/internal/errors" + "github.com/pkg/errors" "github.com/xeipuuv/gojsonschema" @@ -15,7 +17,7 @@ import ( ) const ( - relativePathFormat = "relative-path" + relativePathFormat = "relative-path" dataStreamNameFormat = "data-stream-name" ) @@ -67,11 +69,11 @@ func (s *folderItemSpec) isSameType(file os.FileInfo) bool { return false } -func (s *folderItemSpec) validate(fs http.FileSystem, folderSpecPath string, itemPath string) ValidationErrors { +func (s *folderItemSpec) validate(fs http.FileSystem, folderSpecPath string, itemPath string) errors2.ValidationErrors { // loading item content itemData, err := loadItemContent(itemPath, s.ContentMediaType) if err != nil { - return ValidationErrors{err} + return errors2.ValidationErrors{err} } var schemaLoader gojsonschema.JSONLoader @@ -98,14 +100,14 @@ func (s *folderItemSpec) validate(fs http.FileSystem, folderSpecPath string, ite loadDataStreamNameFormatChecker(filepath.Dir(itemPath)) result, err := gojsonschema.Validate(schemaLoader, documentLoader) if err != nil { - return ValidationErrors{err} + return errors2.ValidationErrors{err} } if result.Valid() { return nil // item content is valid according to the loaded schema } - var errs ValidationErrors + var errs errors2.ValidationErrors for _, re := range result.Errors() { errs = append(errs, fmt.Errorf("field %s: %s", re.Field(), adjustErrorDescription(re.Description()))) } diff --git a/code/go/internal/validator/folder_spec.go b/code/go/internal/validator/folder_spec.go index d4b39b31e..a1fbb74c4 100644 --- a/code/go/internal/validator/folder_spec.go +++ b/code/go/internal/validator/folder_spec.go @@ -9,6 +9,8 @@ import ( "regexp" "strings" + errors2 "github.com/elastic/package-spec/code/go/internal/errors" + "github.com/pkg/errors" "gopkg.in/yaml.v3" ) @@ -60,8 +62,8 @@ func newFolderSpec(fs http.FileSystem, specPath string) (*folderSpec, error) { return &spec, nil } -func (s *folderSpec) validate(packageName string, folderPath string) ValidationErrors { - var errs ValidationErrors +func (s *folderSpec) validate(packageName string, folderPath string) errors2.ValidationErrors { + var errs errors2.ValidationErrors files, err := ioutil.ReadDir(folderPath) if err != nil { errs = append(errs, errors.Wrapf(err, "could not read folder [%s]", folderPath)) diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index b861db038..eeed6738a 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -9,9 +9,9 @@ import ( "path/filepath" "strings" - "github.com/elastic/package-spec/code/go/internal/pkgpath" - "github.com/elastic/package-spec/code/go/internal/validator" + errors2 "github.com/elastic/package-spec/code/go/internal/errors" + "github.com/elastic/package-spec/code/go/internal/pkgpath" "github.com/pkg/errors" ) @@ -26,7 +26,7 @@ func ValidateKibanaObjectIDs(pkgRoot string) error { return errors.Wrap(err, "unable to find Kibana object files") } - var errs validator.ValidationErrors + var errs errors2.ValidationErrors for _, objectFile := range objectFiles { name := objectFile.Name() objectID, err := objectFile.Values("$.id") diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index a7cec0025..a335dcb8b 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -5,6 +5,8 @@ import ( "path" "strconv" + errors2 "github.com/elastic/package-spec/code/go/internal/errors" + "github.com/elastic/package-spec/code/go/internal/validator/semantic" "github.com/Masterminds/semver/v3" @@ -46,8 +48,8 @@ func NewSpec(version semver.Version) (*Spec, error) { } // ValidatePackage validates the given Package against the Spec -func (s Spec) ValidatePackage(pkg Package) ValidationErrors { - var errs ValidationErrors +func (s Spec) ValidatePackage(pkg Package) errors2.ValidationErrors { + var errs errors2.ValidationErrors rootSpecPath := path.Join(s.specPath, "spec.yml") rootSpec, err := newFolderSpec(s.fs, rootSpecPath) diff --git a/code/go/pkg/validator/errors.go b/code/go/pkg/validator/errors.go index 20fbf0d75..f8cf25c8f 100644 --- a/code/go/pkg/validator/errors.go +++ b/code/go/pkg/validator/errors.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/elastic/package-spec/code/go/internal/validator" + "github.com/elastic/package-spec/code/go/internal/errors" ) // ValidationErrors is an Error that contains a iterable collection of validation error messages. -type ValidationErrors validator.ValidationErrors +type ValidationErrors errors.ValidationErrors diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index 15146d27c..d64e2dc2a 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -5,9 +5,9 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/require" + "github.com/elastic/package-spec/code/go/internal/errors" - "github.com/elastic/package-spec/code/go/internal/validator" + "github.com/stretchr/testify/require" ) func TestValidateFile(t *testing.T) { @@ -39,7 +39,7 @@ func TestValidateFile(t *testing.T) { }, }, "input_template": {}, - "input_groups": {}, + "input_groups": {}, "input_groups_bad_data_stream": { "manifest.yml", []string{ @@ -59,7 +59,7 @@ func TestValidateFile(t *testing.T) { } else { require.Error(t, errs) require.Len(t, errs, len(test.expectedErrContains)) - vErrs, ok := errs.(validator.ValidationErrors) + vErrs, ok := errs.(errors.ValidationErrors) require.True(t, ok) var errMessages []string @@ -128,7 +128,7 @@ func requireErrorMessage(t *testing.T, pkgName string, invalidItemsPerFolder map errs := ValidateFromPath(pkgRootPath) require.Error(t, errs) - vErrs, ok := errs.(validator.ValidationErrors) + vErrs, ok := errs.(errors.ValidationErrors) require.True(t, ok) var errMessages []string From d87e426cb34732ed1e363f0393c054ad84a4bb36 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:05:20 -0700 Subject: [PATCH 06/18] Renaming import alias --- code/go/internal/validator/folder_item_spec.go | 10 +++++----- code/go/internal/validator/folder_spec.go | 6 +++--- .../validator/semantic/kibana_matching_object_ids.go | 4 ++-- code/go/internal/validator/spec.go | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/go/internal/validator/folder_item_spec.go b/code/go/internal/validator/folder_item_spec.go index c0f6965ee..5131e19f5 100644 --- a/code/go/internal/validator/folder_item_spec.go +++ b/code/go/internal/validator/folder_item_spec.go @@ -8,7 +8,7 @@ import ( "regexp" "sync" - errors2 "github.com/elastic/package-spec/code/go/internal/errors" + ve "github.com/elastic/package-spec/code/go/internal/errors" "github.com/pkg/errors" "github.com/xeipuuv/gojsonschema" @@ -69,11 +69,11 @@ func (s *folderItemSpec) isSameType(file os.FileInfo) bool { return false } -func (s *folderItemSpec) validate(fs http.FileSystem, folderSpecPath string, itemPath string) errors2.ValidationErrors { +func (s *folderItemSpec) validate(fs http.FileSystem, folderSpecPath string, itemPath string) ve.ValidationErrors { // loading item content itemData, err := loadItemContent(itemPath, s.ContentMediaType) if err != nil { - return errors2.ValidationErrors{err} + return ve.ValidationErrors{err} } var schemaLoader gojsonschema.JSONLoader @@ -100,14 +100,14 @@ func (s *folderItemSpec) validate(fs http.FileSystem, folderSpecPath string, ite loadDataStreamNameFormatChecker(filepath.Dir(itemPath)) result, err := gojsonschema.Validate(schemaLoader, documentLoader) if err != nil { - return errors2.ValidationErrors{err} + return ve.ValidationErrors{err} } if result.Valid() { return nil // item content is valid according to the loaded schema } - var errs errors2.ValidationErrors + var errs ve.ValidationErrors for _, re := range result.Errors() { errs = append(errs, fmt.Errorf("field %s: %s", re.Field(), adjustErrorDescription(re.Description()))) } diff --git a/code/go/internal/validator/folder_spec.go b/code/go/internal/validator/folder_spec.go index a1fbb74c4..5e8aa0a9c 100644 --- a/code/go/internal/validator/folder_spec.go +++ b/code/go/internal/validator/folder_spec.go @@ -9,7 +9,7 @@ import ( "regexp" "strings" - errors2 "github.com/elastic/package-spec/code/go/internal/errors" + ve "github.com/elastic/package-spec/code/go/internal/errors" "github.com/pkg/errors" "gopkg.in/yaml.v3" @@ -62,8 +62,8 @@ func newFolderSpec(fs http.FileSystem, specPath string) (*folderSpec, error) { return &spec, nil } -func (s *folderSpec) validate(packageName string, folderPath string) errors2.ValidationErrors { - var errs errors2.ValidationErrors +func (s *folderSpec) validate(packageName string, folderPath string) ve.ValidationErrors { + var errs ve.ValidationErrors files, err := ioutil.ReadDir(folderPath) if err != nil { errs = append(errs, errors.Wrapf(err, "could not read folder [%s]", folderPath)) diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index eeed6738a..f053542cd 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - errors2 "github.com/elastic/package-spec/code/go/internal/errors" + ve "github.com/elastic/package-spec/code/go/internal/errors" "github.com/elastic/package-spec/code/go/internal/pkgpath" "github.com/pkg/errors" @@ -26,7 +26,7 @@ func ValidateKibanaObjectIDs(pkgRoot string) error { return errors.Wrap(err, "unable to find Kibana object files") } - var errs errors2.ValidationErrors + var errs ve.ValidationErrors for _, objectFile := range objectFiles { name := objectFile.Name() objectID, err := objectFile.Values("$.id") diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index a335dcb8b..d1e3ba582 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -5,7 +5,7 @@ import ( "path" "strconv" - errors2 "github.com/elastic/package-spec/code/go/internal/errors" + ve "github.com/elastic/package-spec/code/go/internal/errors" "github.com/elastic/package-spec/code/go/internal/validator/semantic" @@ -48,8 +48,8 @@ func NewSpec(version semver.Version) (*Spec, error) { } // ValidatePackage validates the given Package against the Spec -func (s Spec) ValidatePackage(pkg Package) errors2.ValidationErrors { - var errs errors2.ValidationErrors +func (s Spec) ValidatePackage(pkg Package) ve.ValidationErrors { + var errs ve.ValidationErrors rootSpecPath := path.Join(s.specPath, "spec.yml") rootSpec, err := newFolderSpec(s.fs, rootSpecPath) From 1ea625daaa16a62bc3fca6a6fae0dd5b5218b05d Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:07:17 -0700 Subject: [PATCH 07/18] Adding godoc comments --- code/go/internal/pkgpath/files.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/go/internal/pkgpath/files.go b/code/go/internal/pkgpath/files.go index 500567201..55f0d3318 100644 --- a/code/go/internal/pkgpath/files.go +++ b/code/go/internal/pkgpath/files.go @@ -17,10 +17,12 @@ import ( "gopkg.in/yaml.v3" ) +// File represents a file in the package. type File struct { os.FileInfo } +// Files finds files for the given glob func Files(glob string) ([]File, error) { paths, err := filepath.Glob(glob) if err != nil { @@ -43,6 +45,9 @@ func Files(glob string) ([]File, error) { return files, errs.Err() } +// Values returns values within the file matching the given path. Paths +// should be expressed using JSONPath syntax. This method is only supported +// for YAML and JSON files. func (f File) Values(path string) (interface{}, error) { fileName := f.Name() fileExt := filepath.Ext(fileName) From 30c3dc148993a3752ebc93227794b99f1663efc3 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:16:03 -0700 Subject: [PATCH 08/18] Fixing return type --- .../validator/semantic/kibana_matching_object_ids.go | 8 +++++--- .../validator/semantic/kibana_no_dangling_object_ids.go | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index f053542cd..279af1573 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -19,14 +19,16 @@ import ( // object files that define IDs not matching the file's name. That is, it returns // validation errors if a Kibana object file, foo.json, in the package defines // an object ID other than foo inside it. -func ValidateKibanaObjectIDs(pkgRoot string) error { +func ValidateKibanaObjectIDs(pkgRoot string) ve.ValidationErrors { + var errs ve.ValidationErrors + filePaths := filepath.Join(pkgRoot, "kibana", "*", "*.json") objectFiles, err := pkgpath.Files(filePaths) if err != nil { - return errors.Wrap(err, "unable to find Kibana object files") + errs = append(errs, errors.Wrap(err, "error finding Kibana object files")) + return errs } - var errs ve.ValidationErrors for _, objectFile := range objectFiles { name := objectFile.Name() objectID, err := objectFile.Values("$.id") diff --git a/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go b/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go index 9d048a6d4..d8ac5900e 100644 --- a/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_no_dangling_object_ids.go @@ -4,12 +4,14 @@ package semantic +import "github.com/elastic/package-spec/code/go/internal/errors" + // ValidateKibanaNoDanglingObjectIDs returns validation errors if there are any // dangling references to Kibana objects in any Kibana object files. That is, it // returns validation errors if a Kibana object file in the package references another // Kibana object with ID i, but no Kibana object file for object ID i is found in the // package. -func ValidateKibanaNoDanglingObjectIDs(pkgRoot string) error { +func ValidateKibanaNoDanglingObjectIDs(pkgRoot string) errors.ValidationErrors { // TODO: will be implemented in follow up PR return nil } From 2ea4e974b45a91e355216a403cf66f041a7b431e Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:17:24 -0700 Subject: [PATCH 09/18] Fixing types --- .../internal/validator/semantic/kibana_matching_object_ids.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index 279af1573..aad74ed92 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -33,7 +33,8 @@ func ValidateKibanaObjectIDs(pkgRoot string) ve.ValidationErrors { name := objectFile.Name() objectID, err := objectFile.Values("$.id") if err != nil { - return errors.Wrap(err, "unable to get Kibana object ID") + errs = append(errs, errors.Wrapf(err, "unable to get Kibana object ID in file '%s'", name)) + continue } fileID := strings.TrimRight(name, ".json") From 2acdcf7cd222ab99cc5faa2df264c6219e364cc1 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:40:43 -0700 Subject: [PATCH 10/18] Updating test fixtures --- code/go/internal/pkgpath/files.go | 13 ++++++++++--- .../semantic/kibana_matching_object_ids.go | 17 ++++++++++++----- .../kibana/dashboard/good-dashboard-abc-1.json | 4 +++- .../good/kibana/lens/good-lens-abc-1.json | 4 +++- .../good/kibana/map/good-map-abc-1.json | 4 +++- .../kibana/ml_module/good-ml-module-abc-1.json | 2 +- .../good/kibana/search/good-search-abc-1.json | 4 +++- ...> 000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json} | 0 .../visualization/good-visualization-abc-1.json | 4 +++- 9 files changed, 38 insertions(+), 14 deletions(-) rename test/packages/good/kibana/security_rule/{rule-000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json => 000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json} (100%) diff --git a/code/go/internal/pkgpath/files.go b/code/go/internal/pkgpath/files.go index 55f0d3318..82f5b2379 100644 --- a/code/go/internal/pkgpath/files.go +++ b/code/go/internal/pkgpath/files.go @@ -10,6 +10,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "github.com/PaesslerAG/jsonpath" "github.com/joeshaw/multierror" @@ -19,6 +20,7 @@ import ( // File represents a file in the package. type File struct { + path string os.FileInfo } @@ -38,7 +40,7 @@ func Files(glob string) ([]File, error) { continue } - file := File{info} + file := File{path, info} files = append(files, file) } @@ -50,13 +52,13 @@ func Files(glob string) ([]File, error) { // for YAML and JSON files. func (f File) Values(path string) (interface{}, error) { fileName := f.Name() - fileExt := filepath.Ext(fileName) + fileExt := strings.TrimLeft(filepath.Ext(fileName), ".") if fileExt != "json" && fileExt != "yaml" && fileExt != "yml" { return nil, fmt.Errorf("cannot extract values from file type = %s", fileExt) } - contents, err := ioutil.ReadFile(fileName) + contents, err := ioutil.ReadFile(f.path) if err != nil { return nil, errors.Wrap(err, "reading file content failed") } @@ -74,3 +76,8 @@ func (f File) Values(path string) (interface{}, error) { return jsonpath.Get(path, v) } + +// Path returns the complete path to the file. +func (f File) Path() string { + return f.path +} diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index aad74ed92..e46818927 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -30,16 +30,23 @@ func ValidateKibanaObjectIDs(pkgRoot string) ve.ValidationErrors { } for _, objectFile := range objectFiles { - name := objectFile.Name() - objectID, err := objectFile.Values("$.id") + filePath := objectFile.Path() + + idPath := "$.id" + // Special case: object is of type 'security_rule' + if filepath.Base(filepath.Dir(filePath)) == "security_rule" { + idPath = "$.rule_id" + } + + objectID, err := objectFile.Values(idPath) if err != nil { - errs = append(errs, errors.Wrapf(err, "unable to get Kibana object ID in file '%s'", name)) + errs = append(errs, errors.Wrapf(err, "unable to get Kibana object ID in file '%s'", filePath)) continue } - fileID := strings.TrimRight(name, ".json") + fileID := strings.TrimRight(filepath.Base(filePath), ".json") if fileID != objectID { - err := fmt.Errorf("kibana object file '%s' defines non-matching ID '%s'", name, objectID) + err := fmt.Errorf("kibana object file '%s' defines non-matching ID '%s'", filePath, objectID) errs = append(errs, err) } } diff --git a/test/packages/good/kibana/dashboard/good-dashboard-abc-1.json b/test/packages/good/kibana/dashboard/good-dashboard-abc-1.json index 9e26dfeeb..d26f62d27 100644 --- a/test/packages/good/kibana/dashboard/good-dashboard-abc-1.json +++ b/test/packages/good/kibana/dashboard/good-dashboard-abc-1.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "good-dashboard-abc-1" +} \ No newline at end of file diff --git a/test/packages/good/kibana/lens/good-lens-abc-1.json b/test/packages/good/kibana/lens/good-lens-abc-1.json index 9e26dfeeb..1f21e8afd 100644 --- a/test/packages/good/kibana/lens/good-lens-abc-1.json +++ b/test/packages/good/kibana/lens/good-lens-abc-1.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "good-lens-abc-1" +} \ No newline at end of file diff --git a/test/packages/good/kibana/map/good-map-abc-1.json b/test/packages/good/kibana/map/good-map-abc-1.json index 9e26dfeeb..d6944ebe0 100644 --- a/test/packages/good/kibana/map/good-map-abc-1.json +++ b/test/packages/good/kibana/map/good-map-abc-1.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "good-map-abc-1" +} \ No newline at end of file diff --git a/test/packages/good/kibana/ml_module/good-ml-module-abc-1.json b/test/packages/good/kibana/ml_module/good-ml-module-abc-1.json index ca1a15bce..ef80cbdf6 100644 --- a/test/packages/good/kibana/ml_module/good-ml-module-abc-1.json +++ b/test/packages/good/kibana/ml_module/good-ml-module-abc-1.json @@ -394,7 +394,7 @@ } ] }, - "id": "nginx-Logs-ml", + "id": "good-ml-module-abc-1", "migrationVersion": { "search": "7.9.3" }, diff --git a/test/packages/good/kibana/search/good-search-abc-1.json b/test/packages/good/kibana/search/good-search-abc-1.json index 9e26dfeeb..647d0e61b 100644 --- a/test/packages/good/kibana/search/good-search-abc-1.json +++ b/test/packages/good/kibana/search/good-search-abc-1.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "good-search-abc-1" +} \ No newline at end of file diff --git a/test/packages/good/kibana/security_rule/rule-000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json b/test/packages/good/kibana/security_rule/000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json similarity index 100% rename from test/packages/good/kibana/security_rule/rule-000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json rename to test/packages/good/kibana/security_rule/000047bb-b27a-47ec-8b62-ef1a5d2c9e19.json diff --git a/test/packages/good/kibana/visualization/good-visualization-abc-1.json b/test/packages/good/kibana/visualization/good-visualization-abc-1.json index 9e26dfeeb..aa5d6db46 100644 --- a/test/packages/good/kibana/visualization/good-visualization-abc-1.json +++ b/test/packages/good/kibana/visualization/good-visualization-abc-1.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "good-visualization-abc-1" +} \ No newline at end of file From 772d80fe7a5b45fd3648057066dcfe906b344114 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:52:12 -0700 Subject: [PATCH 11/18] Fixing trim logic --- .../internal/validator/semantic/kibana_matching_object_ids.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index e46818927..2394ff0b3 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -44,7 +44,7 @@ func ValidateKibanaObjectIDs(pkgRoot string) ve.ValidationErrors { continue } - fileID := strings.TrimRight(filepath.Base(filePath), ".json") + fileID := strings.Replace(filepath.Base(filePath), filepath.Ext(filePath), "", -1) if fileID != objectID { err := fmt.Errorf("kibana object file '%s' defines non-matching ID '%s'", filePath, objectID) errs = append(errs, err) From 5494aa836ba4e744cf52e4b93d8f1b65efee146a Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 11:52:20 -0700 Subject: [PATCH 12/18] Updating test fixtures --- .../dashboard/b7e55b73-97cc-44fd-8555-d01b7e13e70d.json | 4 +++- .../kibana/dashboard/bad-Foobaz-ECS.json | 4 +++- .../wrong_kibana_filename/kibana/dashboard/bad-ecs.json | 4 +++- .../kibana/dashboard/bad-foobar-ecs.json | 4 +++- .../kibana/map/06149856-cbc1-4988-a93a-815915c4408e.json | 4 +++- .../kibana/search/691240b5-7ec9-4fd7-8750-4ef97944f960.json | 4 +++- .../visualization/defa1bcc-1ab6-4069-adec-8c997b069a5e.json | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/test/packages/wrong_kibana_filename/kibana/dashboard/b7e55b73-97cc-44fd-8555-d01b7e13e70d.json b/test/packages/wrong_kibana_filename/kibana/dashboard/b7e55b73-97cc-44fd-8555-d01b7e13e70d.json index 9e26dfeeb..8057bf1d2 100644 --- a/test/packages/wrong_kibana_filename/kibana/dashboard/b7e55b73-97cc-44fd-8555-d01b7e13e70d.json +++ b/test/packages/wrong_kibana_filename/kibana/dashboard/b7e55b73-97cc-44fd-8555-d01b7e13e70d.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "b7e55b73-97cc-44fd-8555-d01b7e13e70d" +} \ No newline at end of file diff --git a/test/packages/wrong_kibana_filename/kibana/dashboard/bad-Foobaz-ECS.json b/test/packages/wrong_kibana_filename/kibana/dashboard/bad-Foobaz-ECS.json index 9e26dfeeb..8f17072ae 100644 --- a/test/packages/wrong_kibana_filename/kibana/dashboard/bad-Foobaz-ECS.json +++ b/test/packages/wrong_kibana_filename/kibana/dashboard/bad-Foobaz-ECS.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "bad-Foobaz-ECS" +} \ No newline at end of file diff --git a/test/packages/wrong_kibana_filename/kibana/dashboard/bad-ecs.json b/test/packages/wrong_kibana_filename/kibana/dashboard/bad-ecs.json index 9e26dfeeb..854c29052 100644 --- a/test/packages/wrong_kibana_filename/kibana/dashboard/bad-ecs.json +++ b/test/packages/wrong_kibana_filename/kibana/dashboard/bad-ecs.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "bad-ecs" +} \ No newline at end of file diff --git a/test/packages/wrong_kibana_filename/kibana/dashboard/bad-foobar-ecs.json b/test/packages/wrong_kibana_filename/kibana/dashboard/bad-foobar-ecs.json index 9e26dfeeb..2e1fa1675 100644 --- a/test/packages/wrong_kibana_filename/kibana/dashboard/bad-foobar-ecs.json +++ b/test/packages/wrong_kibana_filename/kibana/dashboard/bad-foobar-ecs.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "bad-foobar-ecs" +} \ No newline at end of file diff --git a/test/packages/wrong_kibana_filename/kibana/map/06149856-cbc1-4988-a93a-815915c4408e.json b/test/packages/wrong_kibana_filename/kibana/map/06149856-cbc1-4988-a93a-815915c4408e.json index 9e26dfeeb..fb3c2bd05 100644 --- a/test/packages/wrong_kibana_filename/kibana/map/06149856-cbc1-4988-a93a-815915c4408e.json +++ b/test/packages/wrong_kibana_filename/kibana/map/06149856-cbc1-4988-a93a-815915c4408e.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "06149856-cbc1-4988-a93a-815915c4408e" +} \ No newline at end of file diff --git a/test/packages/wrong_kibana_filename/kibana/search/691240b5-7ec9-4fd7-8750-4ef97944f960.json b/test/packages/wrong_kibana_filename/kibana/search/691240b5-7ec9-4fd7-8750-4ef97944f960.json index 9e26dfeeb..f27241c9e 100644 --- a/test/packages/wrong_kibana_filename/kibana/search/691240b5-7ec9-4fd7-8750-4ef97944f960.json +++ b/test/packages/wrong_kibana_filename/kibana/search/691240b5-7ec9-4fd7-8750-4ef97944f960.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "691240b5-7ec9-4fd7-8750-4ef97944f960" +} \ No newline at end of file diff --git a/test/packages/wrong_kibana_filename/kibana/visualization/defa1bcc-1ab6-4069-adec-8c997b069a5e.json b/test/packages/wrong_kibana_filename/kibana/visualization/defa1bcc-1ab6-4069-adec-8c997b069a5e.json index 9e26dfeeb..7ee00144f 100644 --- a/test/packages/wrong_kibana_filename/kibana/visualization/defa1bcc-1ab6-4069-adec-8c997b069a5e.json +++ b/test/packages/wrong_kibana_filename/kibana/visualization/defa1bcc-1ab6-4069-adec-8c997b069a5e.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "id": "defa1bcc-1ab6-4069-adec-8c997b069a5e" +} \ No newline at end of file From e81b84e5a0484eca1c078fcc7128f0ae3a82c0a4 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Tue, 20 Apr 2021 12:14:05 -0700 Subject: [PATCH 13/18] Add test --- .../semantic/kibana_matching_object_ids.go | 4 +- code/go/pkg/validator/validator_test.go | 41 +++++++++++++++++++ test/packages/bad_kibana_ids/changelog.yml | 5 +++ test/packages/bad_kibana_ids/docs/README.md | 1 + .../dashboard/bad_kibana_ids-bar-baz.json | 3 ++ .../security_rule/bad_kibana_ids-bar-baz.json | 3 ++ test/packages/bad_kibana_ids/manifest.yml | 8 ++++ 7 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 test/packages/bad_kibana_ids/changelog.yml create mode 100644 test/packages/bad_kibana_ids/docs/README.md create mode 100644 test/packages/bad_kibana_ids/kibana/dashboard/bad_kibana_ids-bar-baz.json create mode 100644 test/packages/bad_kibana_ids/kibana/security_rule/bad_kibana_ids-bar-baz.json create mode 100644 test/packages/bad_kibana_ids/manifest.yml diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index 2394ff0b3..d8a209182 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -40,13 +40,13 @@ func ValidateKibanaObjectIDs(pkgRoot string) ve.ValidationErrors { objectID, err := objectFile.Values(idPath) if err != nil { - errs = append(errs, errors.Wrapf(err, "unable to get Kibana object ID in file '%s'", filePath)) + errs = append(errs, errors.Wrapf(err, "unable to get Kibana object ID in file [%s]", filePath)) continue } fileID := strings.Replace(filepath.Base(filePath), filepath.Ext(filePath), "", -1) if fileID != objectID { - err := fmt.Errorf("kibana object file '%s' defines non-matching ID '%s'", filePath, objectID) + err := fmt.Errorf("kibana object file [%s] defines non-matching ID [%s]", filePath, objectID) errs = append(errs, err) } } diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index d64e2dc2a..53e547544 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -123,6 +123,47 @@ func TestValidateItemNotExpected(t *testing.T) { } } +func TestValidateBadKibanaIDs(t *testing.T) { + tests := map[string]map[string][]string{ + "bad_kibana_ids": { + "kibana/dashboard": []string{ + "bad_kibana_ids-bar-baz.json", + }, + "kibana/security_rule": []string{ + "bad_kibana_ids-bar-baz.json", + }, + }, + } + + for pkgName, invalidItemsPerFolder := range tests { + t.Run(pkgName, func(t *testing.T) { + pkgRootPath := filepath.Join("..", "..", "..", "..", "test", "packages", pkgName) + + errs := ValidateFromPath(pkgRootPath) + require.Error(t, errs) + vErrs, ok := errs.(errors.ValidationErrors) + require.True(t, ok) + + var errMessages []string + for _, vErr := range vErrs { + errMessages = append(errMessages, vErr.Error()) + } + + var c int + for itemFolder, invalidItems := range invalidItemsPerFolder { + for _, invalidItem := range invalidItems { + objectFilePath := filepath.Join(pkgRootPath, itemFolder, invalidItem) + expected := fmt.Sprintf("kibana object file [%s] defines non-matching ID", objectFilePath) + require.Contains(t, errMessages[c], expected) + c++ + } + } + require.Len(t, errs, c) + + }) + } +} + func requireErrorMessage(t *testing.T, pkgName string, invalidItemsPerFolder map[string][]string, expectedErrorMessage string) { pkgRootPath := filepath.Join("..", "..", "..", "..", "test", "packages", pkgName) diff --git a/test/packages/bad_kibana_ids/changelog.yml b/test/packages/bad_kibana_ids/changelog.yml new file mode 100644 index 000000000..abc579b2e --- /dev/null +++ b/test/packages/bad_kibana_ids/changelog.yml @@ -0,0 +1,5 @@ +- version: 1.0.4 + changes: + - description: initial release + type: enhancement + link: https://github.com/elastic/package-spec/pull/160 \ No newline at end of file diff --git a/test/packages/bad_kibana_ids/docs/README.md b/test/packages/bad_kibana_ids/docs/README.md new file mode 100644 index 000000000..1c9bf4968 --- /dev/null +++ b/test/packages/bad_kibana_ids/docs/README.md @@ -0,0 +1 @@ +Main \ No newline at end of file diff --git a/test/packages/bad_kibana_ids/kibana/dashboard/bad_kibana_ids-bar-baz.json b/test/packages/bad_kibana_ids/kibana/dashboard/bad_kibana_ids-bar-baz.json new file mode 100644 index 000000000..9e30a8a23 --- /dev/null +++ b/test/packages/bad_kibana_ids/kibana/dashboard/bad_kibana_ids-bar-baz.json @@ -0,0 +1,3 @@ +{ + "id": "something-else" +} \ No newline at end of file diff --git a/test/packages/bad_kibana_ids/kibana/security_rule/bad_kibana_ids-bar-baz.json b/test/packages/bad_kibana_ids/kibana/security_rule/bad_kibana_ids-bar-baz.json new file mode 100644 index 000000000..a22a8ae5a --- /dev/null +++ b/test/packages/bad_kibana_ids/kibana/security_rule/bad_kibana_ids-bar-baz.json @@ -0,0 +1,3 @@ +{ + "rule_id": "something-else" +} \ No newline at end of file diff --git a/test/packages/bad_kibana_ids/manifest.yml b/test/packages/bad_kibana_ids/manifest.yml new file mode 100644 index 000000000..6341731f0 --- /dev/null +++ b/test/packages/bad_kibana_ids/manifest.yml @@ -0,0 +1,8 @@ +format_version: 1.0.4 +name: bad_kibana_ids +title: Bad Kibana IDs +description: This package contains Kibana object files with non-matching IDs +version: 0.1.2 +release: beta +owner: + github: elastic/foobar \ No newline at end of file From a114b838a6da9f8eb248b73943aaf781025c5411 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 21 Apr 2021 12:22:55 -0700 Subject: [PATCH 14/18] Adding explanatory comment --- .../validator/semantic/kibana_matching_object_ids.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/go/internal/validator/semantic/kibana_matching_object_ids.go b/code/go/internal/validator/semantic/kibana_matching_object_ids.go index d8a209182..c188f64dc 100644 --- a/code/go/internal/validator/semantic/kibana_matching_object_ids.go +++ b/code/go/internal/validator/semantic/kibana_matching_object_ids.go @@ -44,7 +44,10 @@ func ValidateKibanaObjectIDs(pkgRoot string) ve.ValidationErrors { continue } - fileID := strings.Replace(filepath.Base(filePath), filepath.Ext(filePath), "", -1) + // fileID == filename without the extension == expected ID of Kibana object defined inside file. + fileName := filepath.Base(filePath) + fileExt := filepath.Ext(filePath) + fileID := strings.Replace(fileName, fileExt, "", -1) if fileID != objectID { err := fmt.Errorf("kibana object file [%s] defines non-matching ID [%s]", filePath, objectID) errs = append(errs, err) From e0aa08096fa1771ac34db83d57e4bb03550d7b1d Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 21 Apr 2021 12:38:06 -0700 Subject: [PATCH 15/18] Adding validationRules type --- code/go/internal/validator/spec.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index d1e3ba582..5febecf12 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -24,6 +24,8 @@ type Spec struct { specPath string } +type validationRules []func(pkgRoot string) ve.ValidationErrors + // NewSpec creates a new Spec for the given version func NewSpec(version semver.Version) (*Spec, error) { majorVersion := strconv.FormatUint(version.Major(), 10) @@ -62,7 +64,20 @@ func (s Spec) ValidatePackage(pkg Package) ve.ValidationErrors { errs = rootSpec.validate(pkg.Name, pkg.RootPath) // Semantic validations - errs = append(errs, semantic.ValidateKibanaObjectIDs(pkg.RootPath)...) + rules := validationRules{ + semantic.ValidateKibanaObjectIDs, + } + errs = append(errs, rules.validate(pkg.RootPath)...) + + return errs +} + +func (vr validationRules) validate(pkgRoot string) ve.ValidationErrors { + var errs ve.ValidationErrors + for _, validationRule := range vr { + err := validationRule(pkgRoot) + errs = append(errs, err) + } return errs } From 4230c1a123210e4ef833ff71844f0954b571d557 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 21 Apr 2021 13:05:01 -0700 Subject: [PATCH 16/18] Introduce Append method on ValidationErrors type --- code/go/internal/errors/errors.go | 12 ++++++++++++ code/go/internal/validator/spec.go | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/code/go/internal/errors/errors.go b/code/go/internal/errors/errors.go index e0b46ba1d..49d588cd9 100644 --- a/code/go/internal/errors/errors.go +++ b/code/go/internal/errors/errors.go @@ -25,3 +25,15 @@ func (ve ValidationErrors) Error() string { return message.String() } + +func (ve *ValidationErrors) Append(moreErrs ValidationErrors) { + fmt.Println("len moreErrs = ", len(moreErrs)) + if len(moreErrs) == 0 { + return + } + + errs := *ve + errs = append(errs, moreErrs...) + + *ve = errs +} diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index 5febecf12..b8a0db5a5 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -61,13 +61,13 @@ func (s Spec) ValidatePackage(pkg Package) ve.ValidationErrors { } // Syntactic validations - errs = rootSpec.validate(pkg.Name, pkg.RootPath) + errs.Append(rootSpec.validate(pkg.Name, pkg.RootPath)) // Semantic validations rules := validationRules{ semantic.ValidateKibanaObjectIDs, } - errs = append(errs, rules.validate(pkg.RootPath)...) + errs.Append(rules.validate(pkg.RootPath)) return errs } @@ -76,7 +76,7 @@ func (vr validationRules) validate(pkgRoot string) ve.ValidationErrors { var errs ve.ValidationErrors for _, validationRule := range vr { err := validationRule(pkgRoot) - errs = append(errs, err) + errs.Append(err) } return errs From 5b0ad65118d1696610947385e6ec4a3796d05b50 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 21 Apr 2021 13:06:33 -0700 Subject: [PATCH 17/18] Removing debugging statement --- code/go/internal/errors/errors.go | 1 - 1 file changed, 1 deletion(-) diff --git a/code/go/internal/errors/errors.go b/code/go/internal/errors/errors.go index 49d588cd9..21e79837d 100644 --- a/code/go/internal/errors/errors.go +++ b/code/go/internal/errors/errors.go @@ -27,7 +27,6 @@ func (ve ValidationErrors) Error() string { } func (ve *ValidationErrors) Append(moreErrs ValidationErrors) { - fmt.Println("len moreErrs = ", len(moreErrs)) if len(moreErrs) == 0 { return } From 63a6d6d59bca90a89e7fb5ed51d5fcae242e7aba Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 21 Apr 2021 13:11:33 -0700 Subject: [PATCH 18/18] Adding godoc comment --- code/go/internal/errors/errors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/code/go/internal/errors/errors.go b/code/go/internal/errors/errors.go index 21e79837d..7f4b5dcc1 100644 --- a/code/go/internal/errors/errors.go +++ b/code/go/internal/errors/errors.go @@ -26,6 +26,7 @@ func (ve ValidationErrors) Error() string { return message.String() } +// Append adds more validation errors. func (ve *ValidationErrors) Append(moreErrs ValidationErrors) { if len(moreErrs) == 0 { return