diff --git a/cmd/csaf_validator/main.go b/cmd/csaf_validator/main.go index b07c2f4..b3a0855 100644 --- a/cmd/csaf_validator/main.go +++ b/cmd/csaf_validator/main.go @@ -22,6 +22,13 @@ import ( "github.com/gocsaf/csaf/v3/util" ) +const ( + exitCodeSchemaInvalid = 2 << iota + exitCodeNoRemoteValidator + exitCodeFailedRemoteValidation + exitCodeAllValid = 0 +) + type options struct { Version bool `long:"version" description:"Display version of the binary"` RemoteValidator string `long:"validator" description:"URL to validate documents remotely" value-name:"URL"` @@ -53,6 +60,7 @@ func main() { // run validates the given files. func run(opts *options, files []string) error { + exitCode := exitCodeAllValid var validator csaf.RemoteValidator eval := util.NewPathEval() @@ -69,6 +77,9 @@ func run(opts *options, files []string) error { "preparing remote validator failed: %w", err) } defer validator.Close() + } else { + exitCode |= exitCodeNoRemoteValidator + log.Printf("warn: no remote validator specified") } // Select amount level of output for remote validation. @@ -96,7 +107,7 @@ func run(opts *options, files []string) error { log.Printf("error: loading %q as JSON failed: %v\n", file, err) continue } - // Validate agsinst Schema. + // Validate against Schema. validationErrs, err := csaf.ValidateCSAF(doc) if err != nil { log.Printf("error: validating %q against schema failed: %v\n", @@ -104,6 +115,7 @@ func run(opts *options, files []string) error { } if len(validationErrs) > 0 { + exitCode |= exitCodeSchemaInvalid fmt.Printf("schema validation errors of %q\n", file) for _, vErr := range validationErrs { fmt.Printf(" * %s\n", vErr) @@ -112,10 +124,9 @@ func run(opts *options, files []string) error { fmt.Printf("%q passes the schema validation.\n", file) } - // Check filename agains ID + // Check filename against ID if err := util.IDMatchesFilename(eval, doc, filepath.Base(file)); err != nil { log.Printf("%s: %s.\n", file, err) - continue } // Validate against remote validator. @@ -130,12 +141,15 @@ func run(opts *options, files []string) error { if rvr.Valid { passes = "passes" } else { + exitCode |= exitCodeFailedRemoteValidation passes = "does not pass" } fmt.Printf("%q %s remote validation.\n", file, passes) } } + // Exit code is based on validation results + os.Exit(exitCode) return nil } diff --git a/docs/csaf_validator.md b/docs/csaf_validator.md index dfa0c9a..87ec831 100644 --- a/docs/csaf_validator.md +++ b/docs/csaf_validator.md @@ -2,6 +2,16 @@ is a tool to validate local advisories files against the JSON Schema and an optional remote validator. +### Exit codes + +If no fatal error occurs the program will exit with an exit code `n` with the following conditions: + +- `n == 0`: all valid +- `(n & 1) > 0`: a general error occurred, all other flags are unset (see logs for more information) +- `(n & 2) > 0`: schema validation failed +- `(n & 4) > 0`: no remote validator configured +- `(n & 8) > 0`: failure in remote validation + ### Usage ```