Skip to content

Commit

Permalink
TC-1841 cyclonedx 1.5 validation avoiding 1.3 default call (trustific…
Browse files Browse the repository at this point in the history
…ation#1955)

* TC-1841 cyclonedx 1.5 validation avoiding 1.3 default call

Signed-off-by: m-brophy <[email protected]>

* fix formatting errors

Signed-off-by: m-brophy <[email protected]>

* TC-1841 get_cyclonedx_spec_version (trustification#2)

Signed-off-by: mrizzi <[email protected]>

---------

Signed-off-by: m-brophy <[email protected]>
Signed-off-by: mrizzi <[email protected]>
Co-authored-by: Marco Rizzi <[email protected]>
  • Loading branch information
m-brophy and mrizzi authored Nov 5, 2024
1 parent d5cba58 commit 14f6783
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 2 deletions.
41 changes: 39 additions & 2 deletions bombastic/model/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use cyclonedx_bom::errors::JsonReadError;
use cyclonedx_bom::prelude::{Validate, ValidationResult};
use cyclonedx_bom::prelude::{SpecVersion, Validate, ValidationResult};
use cyclonedx_bom::validation::ValidationErrorsKind;
use serde_json::Value;
use std::collections::HashSet;
use std::fmt::Formatter;
use std::str::FromStr;
use tracing::{info_span, instrument};

#[derive(Debug)]
Expand Down Expand Up @@ -77,7 +79,8 @@ impl SBOM {
// the serial number is missing and this isn't what we want because
// serial number is mandatory for trustification to correlate properly
Some(_) => {
let result = bom.validate();
let spec_version = Self::get_cyclonedx_spec_version(data)?;
let result = bom.validate_version(spec_version);
match result.passed() {
true => return Ok(SBOM::CycloneDX(bom)),
false => {
Expand Down Expand Up @@ -118,6 +121,33 @@ impl SBOM {
Err(err)
}

fn get_cyclonedx_spec_version(data: &[u8]) -> Result<SpecVersion, Error> {
let mut err: Error = Default::default();
let spec_version_error: serde_json::Error = serde::de::Error::custom("No field 'specVersion' found");
let error = Some(JsonReadError::from(spec_version_error));
//workaround to deal with cyclonedx-rust-cargo validate() method
//validating against SpecVersion::V1_3, the default, in all cases
//we therefore have to discover the spec version from the json data
//to pass into validate_version() as the parsed bom doesn't contain this info
// let mut spec_version = SpecVersion::V1_3;
match serde_json::from_slice::<Value>(data) {
Ok(parsed_json) => match parsed_json.get("specVersion") {
Some(version) => match version.as_str() {
Some(version) => match SpecVersion::from_str(version) {
Ok(spec_version) => return Ok(spec_version),
Err(e) => err.cyclonedx = Some(JsonReadError::from(e)),
},
None => err.cyclonedx = error,
},
None => {
err.cyclonedx = error;
}
},
Err(e) => err.cyclonedx = Some(JsonReadError::from(e)),
}
Err(err)
}

fn get_validation_error_messages(validation_result: ValidationResult) -> HashSet<String> {
let mut result = HashSet::<String>::new();
validation_result.errors().for_each(|(_, error_kind)| match error_kind {
Expand Down Expand Up @@ -179,6 +209,13 @@ mod tests {
assert!(result.is_ok());
}

#[test]
fn parse_cdx_valid_15_license_id() {
let data = include_bytes!("../../testdata/cdx-1.5-valid-license-id.json");
let result = SBOM::parse(data);
assert!(result.is_ok());
}

#[test]
fn parse_cyclonedx_valid_14_newline() {
let data = include_bytes!("../../testdata/syft.cyclonedx.newline.json");
Expand Down
194 changes: 194 additions & 0 deletions bombastic/testdata/cdx-1.5-valid-license-id.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:d2525dbf-827b-45af-b074-c759ba9eebbb",
"version": 1,
"metadata": {
"timestamp": "2024-10-18T06:13:14Z",
"tools": {
"components": [
{
"type": "application",
"author": "anchore",
"name": "syft",
"version": "1.4.1"
},
{
"author": "red hat",
"name": "cachi2",
"type": "application"
}
]
},
"component": {
"bom-ref": "f259ee149f7c0477",
"type": "file",
"name": "/var/lib/containers/storage/vfs/dir/a0fa5b9d218b35edc7d814d3cd8e666cd7f3005f59b73b7291678ab24d43412c"
}
},
"components": [
{
"bom-ref": "pkg:pypi/[email protected]?package-id=6de7e16fa6904c51",
"type": "library",
"author": "Ben Bangert, Mike Bayer, Philip Jenvey, Alessandro Molina <[email protected], [email protected], [email protected]>",
"name": "Beaker",
"version": "1.12.1",
"licenses": [
{
"expression": "TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause"
}
],
"cpe": "cpe:2.3:a:beakerbrowser:beaker:1.12.1:*:*:*:*:python:*:*",
"purl": "pkg:pypi/[email protected]",
"properties": [
{
"name": "syft:package:foundBy",
"value": "python-installed-package-cataloger"
},
{
"name": "syft:package:language",
"value": "python"
},
{
"name": "syft:package:type",
"value": "python"
},
{
"name": "syft:package:metadataType",
"value": "python-package"
},
{
"name": "syft:location:0:path",
"value": "/usr/lib/python3.12/site-packages/Beaker-1.12.1-py3.12.egg-info/PKG-INFO"
},
{
"name": "syft:location:1:path",
"value": "/usr/lib/python3.12/site-packages/Beaker-1.12.1-py3.12.egg-info/top_level.txt"
}
]
},
{
"bom-ref": "pkg:pypi/[email protected]?package-id=365de27b8ece63b4",
"type": "library",
"author": "The Brotli Authors",
"name": "Brotli",
"version": "1.1.0",
"licenses": [
{
"license": {
"id": "TTWL"
}
}
],
"cpe": "cpe:2.3:a:brotli_authors_project:python-Brotli:1.1.0:*:*:*:*:*:*:*",
"purl": "pkg:pypi/[email protected]",
"properties": [
{
"name": "syft:package:foundBy",
"value": "python-installed-package-cataloger"
},
{
"name": "syft:package:language",
"value": "python"
},
{
"name": "syft:package:type",
"value": "python"
},
{
"name": "syft:package:metadataType",
"value": "python-package"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authors_project:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authorsproject:python-Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authorsproject:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authors_project:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authors:python-Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authors:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authorsproject:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python-Brotli:python-Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python-Brotli:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python_Brotli:python-Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python_Brotli:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:brotli_authors:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:Brotli:python-Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:Brotli:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python-Brotli:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python:python-Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python:python_Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python_Brotli:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:Brotli:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:python:Brotli:1.1.0:*:*:*:*:*:*:*"
},
{
"name": "syft:location:0:path",
"value": "/usr/lib64/python3.12/site-packages/Brotli-1.1.0-py3.12.egg-info/PKG-INFO"
},
{
"name": "syft:location:1:path",
"value": "/usr/lib64/python3.12/site-packages/Brotli-1.1.0-py3.12.egg-info/top_level.txt"
}
]
}
]
}

0 comments on commit 14f6783

Please sign in to comment.