1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 18:15:42 +01:00
gocsaf/csaf/validation.go
Sascha L. Teichmann 8a1ebe0b7a
Add aggregator; improve itest workflow
* Factor JSON evaluation and  construction base URLs out of of checker.
* Move json path matching to util.
* Add csaf_aggregator (as additional command)
* Improve itest workflow to checkout the branch where it is running on.

resolve #105
resolve  #72

Co-authored-by: tschmidtb51 <65305130+tschmidtb51@users.noreply.github.com>
Co-authored-by: Bernhard Reiter <bernhard@intevation.de>
Co-authored-by: Fadi Abbud <fadi.abbud@intevation.de>
2022-05-10 18:12:38 +02:00

163 lines
3.8 KiB
Go

// This file is Free Software under the MIT License
// without warranty, see README.md and LICENSES/MIT.txt for details.
//
// SPDX-License-Identifier: MIT
//
// SPDX-FileCopyrightText: 2021 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2021 Intevation GmbH <https://intevation.de>
package csaf
import (
"bytes"
_ "embed" // Used for embedding.
"sort"
"strings"
"sync"
"github.com/santhosh-tekuri/jsonschema/v5"
)
//go:embed schema/csaf_json_schema.json
var csafSchema []byte
//go:embed schema/cvss-v2.0.json
var cvss20 []byte
//go:embed schema/cvss-v3.0.json
var cvss30 []byte
//go:embed schema/cvss-v3.1.json
var cvss31 []byte
//go:embed schema/provider_json_schema.json
var providerSchema []byte
//go:embed schema/aggregator_json_schema.json
var aggregatorSchema []byte
var (
compiledCSAFSchema compiledSchema
compiledProviderSchema compiledSchema
compiledAggregatorSchema compiledSchema
)
func init() {
compiledCSAFSchema.compiler([]schemaData{
{"https://docs.oasis-open.org/csaf/csaf/v2.0/csaf_json_schema.json", csafSchema},
{"https://www.first.org/cvss/cvss-v2.0.json", cvss20},
{"https://www.first.org/cvss/cvss-v3.0.json", cvss30},
{"https://www.first.org/cvss/cvss-v3.1.json", cvss31},
})
compiledProviderSchema.compiler([]schemaData{
{"https://docs.oasis-open.org/csaf/csaf/v2.0/provider_json_schema.json", providerSchema},
{"https://docs.oasis-open.org/csaf/csaf/v2.0/csaf_json_schema.json", csafSchema},
})
compiledAggregatorSchema.compiler([]schemaData{
{"https://docs.oasis-open.org/csaf/csaf/v2.0/aggregator_json_schema.json", aggregatorSchema},
{"https://docs.oasis-open.org/csaf/csaf/v2.0/provider_json_schema.json", providerSchema},
{"https://docs.oasis-open.org/csaf/csaf/v2.0/csaf_json_schema.json", csafSchema},
})
}
type schemaData struct {
url string
data []byte
}
type compiledSchema struct {
once sync.Once
compile func()
err error
compiled *jsonschema.Schema
}
func (cs *compiledSchema) compiler(sds []schemaData) {
if len(sds) == 0 {
panic("missing schema data")
}
cs.compile = func() {
c := jsonschema.NewCompiler()
for _, s := range sds {
if cs.err = c.AddResource(
s.url, bytes.NewReader(s.data)); cs.err != nil {
return
}
}
cs.compiled, cs.err = c.Compile(sds[0].url)
}
}
func (cs *compiledSchema) validate(doc interface{}) ([]string, error) {
cs.once.Do(cs.compile)
if cs.err != nil {
return nil, cs.err
}
err := cs.compiled.Validate(doc)
if err == nil {
return nil, nil
}
valErr, ok := err.(*jsonschema.ValidationError)
if !ok {
return nil, err
}
basic := valErr.BasicOutput()
if basic.Valid {
return nil, nil
}
errs := basic.Errors
sort.Slice(errs, func(i, j int) bool {
pi := errs[i].InstanceLocation
pj := errs[j].InstanceLocation
if strings.HasPrefix(pj, pi) {
return true
}
if strings.HasPrefix(pi, pj) {
return false
}
if pi != pj {
return pi < pj
}
return errs[i].Error < errs[j].Error
})
res := make([]string, 0, len(errs))
for i := range errs {
e := &errs[i]
if e.Error == "" {
continue
}
loc := e.InstanceLocation
if loc == "" {
loc = e.AbsoluteKeywordLocation
}
res = append(res, loc+": "+e.Error)
}
return res, nil
}
// ValidateCSAF validates the document doc against the JSON schema
// of CSAF.
func ValidateCSAF(doc interface{}) ([]string, error) {
return compiledCSAFSchema.validate(doc)
}
// ValidateProviderMetadata validates the document doc against the JSON schema
// of provider metadata.
func ValidateProviderMetadata(doc interface{}) ([]string, error) {
return compiledProviderSchema.validate(doc)
}
// ValidateAggregator validates the document doc against the JSON schema
// of aggregator.
func ValidateAggregator(doc interface{}) ([]string, error) {
return compiledAggregatorSchema.validate(doc)
}