def report_to_cyclonedx(report: Report) -> Bom: bom = Bom() for failed_check in report.failed_checks: component = Component.for_file( absolute_file_path=failed_check.file_abs_path, path_for_bom=failed_check.file_path) component.add_vulnerability( Vulnerability( id=failed_check.check_id, source_name='checkov', description= f'Resource: {failed_check.resource}. {failed_check.check_name}', advisories=[failed_check.guideline])) bom.add_component(component=component) return bom
def get_cyclonedx_bom(self) -> Bom: bom = Bom() if sys.version_info >= (3, 8, 0): from importlib.metadata import version as meta_version else: from importlib_metadata import version as meta_version try: this_tool = Tool(vendor='bridgecrew', name='checkov', version=meta_version('checkov')) except Exception: # Unable to determine current version of 'checkov' this_tool = Tool(vendor='bridgecrew', name='checkov', version='UNKNOWN') bom.get_metadata().add_tool(this_tool) for check in itertools.chain(self.passed_checks, self.skipped_checks): component = Component.for_file( absolute_file_path=check.file_abs_path, path_for_bom=check.file_path) if bom.has_component(component=component): component = bom.get_component_by_purl( purl=component.get_purl()) bom.add_component(component=component) for failed_check in self.failed_checks: component = Component.for_file( absolute_file_path=failed_check.file_abs_path, path_for_bom=failed_check.file_path) if bom.has_component(component=component): component = bom.get_component_by_purl( purl=component.get_purl()) component.add_vulnerability( Vulnerability( id=failed_check.check_id, source_name='checkov', description= f'Resource: {failed_check.resource}. {failed_check.check_name}', recommendations=[failed_check.guideline])) bom.add_component(component=component) return bom
def __init__(self) -> None: """Start the report.""" self._bom = Bom() self._bom.metadata.add_tool(self.dfetch_tool)
class SbomReporter(Reporter): """Reporter for generating SBoM's.""" url_splitter = re.compile(r"([^\/)]+)") github_url = re.compile(r"github.com\/(?P<group>.+)\/(?P<repo>[^\s\.]+)[\.]?") dfetch_tool = Tool(vendor="dfetch-org", name="dfetch", version=dfetch.__version__) name = "SBoM" def __init__(self) -> None: """Start the report.""" self._bom = Bom() self._bom.metadata.add_tool(self.dfetch_tool) def add_project( self, project: ProjectEntry, license_name: str, version: str ) -> None: """Add a project to the report.""" match = self.github_url.search(project.remote_url) if match: component = Component( name=project.name, version=version, component_type=ComponentType.LIBRARY, purl=PackageURL( type="github", name=match.group("repo"), version=version, namespace=match.group("group"), subpath=project.source or None, ), ) else: parts = self._split_url(project.remote_url) component = Component( name=project.name, version=version, component_type=ComponentType.LIBRARY, purl=PackageURL( type="generic", version=version, qualifiers=f"download_url={project.remote_url}", namespace=parts[0], subpath=project.source or None, ), ) component.add_external_reference( ExternalReference( reference_type=ExternalReferenceType.VCS, url=project.remote_url, ) ) component.licenses += [LicenseChoice(license_expression=license_name)] self._bom.add_component(component) @staticmethod def _split_url(url: str) -> List[str]: """Split the url in elements.""" return [ part.group() for part in SbomReporter.url_splitter.finditer(url) if not part.group().endswith(":") # Skip protocol specifiers ] def dump_to_file(self, outfile: str) -> bool: """Dump the SBoM to file.""" output_format = ( OutputFormat.XML if outfile.endswith(".xml") else OutputFormat.JSON ) outputter = cast(Json, get_instance(bom=self._bom, output_format=output_format)) parsed = json.loads(outputter.output_as_string()) outputter._json_output = json.dumps( # pylint: disable=protected-access parsed, indent=4 ) outputter.output_to_file(outfile, allow_overwrite=True) return True