diff --git a/ChangeLog.md b/ChangeLog.md index 7805f18..3494b09 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -12,6 +12,8 @@ If one of the values is missing and `--forceerror` has been specified, error code 97 is returned. * `bom show` command also lists license information in verbose mode, but only for CycloneDX 1.6 and later. +* `bom validate` now also uses `-v` and `--forceerror` and uses the same `bom show` functionality + to check for missing purl or source code url. ## 2.6.0 diff --git a/capycli/bom/bom_validate.py b/capycli/bom/bom_validate.py index 4b98c66..de8c997 100644 --- a/capycli/bom/bom_validate.py +++ b/capycli/bom/bom_validate.py @@ -13,8 +13,9 @@ import capycli.common.json_support import capycli.common.script_base from capycli import get_logger +from capycli.bom.show_bom import ShowBom from capycli.common.capycli_bom_support import CaPyCliBom -from capycli.common.print import print_text +from capycli.common.print import print_green, print_text from capycli.main.exceptions import CaPyCliException from capycli.main.result_codes import ResultCode @@ -22,13 +23,17 @@ class BomValidate(capycli.common.script_base.ScriptBase): - def validate(self, inputfile: str, spec_version: str) -> None: + def __init__(self) -> None: + self.has_error: bool = False + self.verbose: bool = False + + def validate(self, inputfile: str, spec_version: str) -> bool: """Main validation method.""" try: if not spec_version: print_text("No CycloneDX spec version specified, defaulting to 1.6") spec_version = "1.6" - CaPyCliBom.validate_sbom(inputfile, spec_version) + return CaPyCliBom.validate_sbom(inputfile, spec_version, False) except CaPyCliException as error: LOG.error(f"Error processing input file: {str(error)}") sys.exit(ResultCode.RESULT_GENERAL_ERROR) @@ -51,6 +56,8 @@ def display_help(self) -> None: print(" -h, --help Show this help message and exit") print(" -i INPUTFILE Input BOM filename (JSON)") print(" -version SpecVersion CycloneDX spec version to validate against: allowed are 1.4, 1.5, and 1.6") + print(" -v be verbose (show more details about purl, download URL, and license)") + print(" --forceerror force an error exit code in case of validation errors or warnings") def run(self, args: Any) -> None: """Main method()""" @@ -65,4 +72,26 @@ def run(self, args: Any) -> None: global LOG LOG = get_logger(__name__) - self.validate(args.inputfile, args.version) + if args.verbose: + self.verbose = True + + self.has_error = not self.validate(args.inputfile, args.version) + if not self.has_error: + print_green("JSON file successfully validated against CycloneDX.") + + if self.verbose: + try: + bom = CaPyCliBom.read_sbom(args.inputfile) + except Exception as ex: + LOG.error("Error reading SBOM: " + repr(ex)) + sys.exit(ResultCode.RESULT_ERROR_READING_BOM) + + show_bom = ShowBom() + show_bom.verbose = self.verbose + print_text("Siemens Standard BOM checks") + show_bom.display_bom(bom) + if show_bom.has_error: + self.has_error = True + + if args.force_error and self.has_error: + sys.exit(ResultCode.RESULT_PREREQUISITE_ERROR) diff --git a/capycli/bom/show_bom.py b/capycli/bom/show_bom.py index 191efb0..ed2d332 100644 --- a/capycli/bom/show_bom.py +++ b/capycli/bom/show_bom.py @@ -106,8 +106,8 @@ def run(self, args: Any) -> None: print("optional arguments:") print("-h, --help show this help message and exit") print("-i INPUTFILE input file to read from (JSON)") - print("-v be verbose") - print("--forceerror force an error exit code in case of prerequisite errors") + print("-v be verbose (show more details about purl, download URL, and license)") + print("--forceerror force an error exit code in case of prerequisite errors or warnings") return if not args.inputfile: diff --git a/capycli/common/capycli_bom_support.py b/capycli/common/capycli_bom_support.py index 68aace0..4c60b68 100644 --- a/capycli/common/capycli_bom_support.py +++ b/capycli/common/capycli_bom_support.py @@ -549,7 +549,7 @@ def _string_to_schema_version(cls, spec_version: str) -> SchemaVersion: return SchemaVersion.V1_6 @classmethod - def validate_sbom(cls, inputfile: str, spec_version: str) -> bool: + def validate_sbom(cls, inputfile: str, spec_version: str, show_success: bool = True) -> bool: """Validate the given SBOM file against the given CycloneDX spec. version.""" LOG.debug(f"Validating SBOM from file {inputfile}") with open(inputfile) as fin: @@ -564,7 +564,8 @@ def validate_sbom(cls, inputfile: str, spec_version: str) -> bool: if validation_errors: raise CaPyCliException("JSON validation error: " + repr(validation_errors)) - print_green("JSON file successfully validated.") + if show_success: + print_green("JSON file successfully validated.") return True except MissingOptionalDependencyException as error: print_yellow('JSON-validation was skipped due to', error)