diff --git a/cve_bin_tool/cli.py b/cve_bin_tool/cli.py index a92d3e39a2..ddd1a2b154 100644 --- a/cve_bin_tool/cli.py +++ b/cve_bin_tool/cli.py @@ -186,7 +186,7 @@ def main(argv=None): "-f", "--format", action="store", - choices=["csv", "json", "console", "html", "pdf"], + choices=["csv", "json", "console", "html", "pdf", "md"], help="update output format (default: console)", default="console", ) diff --git a/cve_bin_tool/output_engine/__init__.py b/cve_bin_tool/output_engine/__init__.py index 26ce074a29..8a03dded7f 100644 --- a/cve_bin_tool/output_engine/__init__.py +++ b/cve_bin_tool/output_engine/__init__.py @@ -17,6 +17,7 @@ from ..version import VERSION from .console import output_console from .html import output_html +from .threats import output_threats from .util import ( add_extension_if_not, format_output, @@ -390,6 +391,22 @@ def output_cves(self, outfile, output_type="console"): self.logger, outfile, ) + elif output_type == "md": + if self.filename.endswith("THREATS.md"): + output_threats( + self.all_cve_data, + self.scanned_dir, + self.filename, + self.themes_dir, + self.total_files, + self.products_with_cve, + self.products_without_cve, + self.merge_report, + self.logger, + outfile, + ) + else: + raise NotImplementedError("Only generating THREATS.md currently supported. Attempted output to {self.filename!r}.") else: # console, or anything else that is unrecognised output_console( self.all_cve_data, diff --git a/cve_bin_tool/output_engine/threats.py b/cve_bin_tool/output_engine/threats.py new file mode 100644 index 0000000000..3d76d49710 --- /dev/null +++ b/cve_bin_tool/output_engine/threats.py @@ -0,0 +1,143 @@ +# Copyright (C) 2021 Intel Corporation +# SPDX-License-Identifier: GPL-3.0-or-later + +import os +from typing import Dict, List, Union + + +from ..merge import MergeReports + +from ..log import LOGGER +from ..util import CVEData, ProductInfo + + +def output_threats( + all_cve_data: Dict[ProductInfo, CVEData], + scanned_dir: str, + filename: str, + theme_dir: str, + total_files: int, + products_with_cve: int, + products_without_cve: int, + merge_report: Union[None, MergeReports], + logger: LOGGER, + outfile, +): + """Returns a THREATS.md report including depedencies found""" + from pprint import pprint + pprint(locals()) + + import textwrap + outfile.write( + textwrap.dedent( + f""" + # Threat Model + """ + ) + ) + + # ------------------ BEGIN MERMAID OUTPUT ------------------ + outfile.write( + textwrap.dedent( + """ + + ```mermaid + """ + ) + ) + + # Write out the mermaid diagram + import sys + import asyncio + import contextlib + import dffml + import dffml.cli.dataflow + + + # TODO Check if dataflow extra is installed. Build dataflows from scan + # results. Generate mermaid daigrams from flows. + import cve_bin_tool.scanners.dataflow + + # The overlayed keyword arguements of fields within to be created + field_modifications = { + "dataflow": {"default_factory": lambda: cve_bin_tool.scanners.dataflow.COLLECTOR_DATAFLOW}, + "simple": {"default": True}, + "stages": {"default_factory": lambda: [dffml.Stage.PROCESSING.value]}, + } + # Create a derived class + DiagramForMyDataFlow = dffml.cli.dataflow.Diagram.subclass( + "DiagramForMyDataFlow", field_modifications, + ) + print(DiagramForMyDataFlow) + # + print(DiagramForMyDataFlow.CONFIG) + # + with contextlib.redirect_stdout(outfile): + asyncio.run(DiagramForMyDataFlow._main()) + + + outfile.write( + textwrap.dedent( + """ + ``` + """ + ) + ) + # ------------------ END MERMAID OUTPUT ------------------ + + # ------------------ BEGIN OPEN ARCHITECTURE OUTPUT ------------------ + outfile.write( + textwrap.dedent( + f""" + ```json + """ + ) + ) + + # Write out the mermaid diagram + import sys + import asyncio + import contextlib + import dffml + import dffml.cli.dataflow + import dffml.service.dev + + + import dffml_config_yaml.configloader + + + # TODO Check if dataflow extra is installed. Build dataflows from scan + # results. Generate mermaid daigrams from flows. + import cve_bin_tool.scanners.dataflow + + # The overlayed keyword arguements of fields within to be created + field_modifications = { + "export": {"default_factory": lambda: "cve_bin_tool.scanners.dataflow:COLLECTOR_DATAFLOW"}, + # "configloader": {"default_factory": lambda: dffml_config_yaml.configloader.YamlConfigLoader}, + "configloader": {"default_factory": lambda: dffml.JSONConfigLoader}, + } + + # Create a derived class + ExportForMyDataFlow = dffml.service.dev.Export.subclass( + "ExportForMyDataFlow", field_modifications, + ) + print(ExportForMyDataFlow) + # + print(ExportForMyDataFlow.CONFIG) + # + import io + a_out = io.StringIO() + a_out.buffer = io.BytesIO() + with contextlib.redirect_stdout(a_out): + asyncio.run(ExportForMyDataFlow._main()) + + import json + outfile.write(json.dumps(json.loads(a_out.buffer.getvalue().decode()), indent=4)) + outfile.write( + textwrap.dedent( + """ + ``` + """ + ) + ) + # ------------------ END OPEN ARCHITECTURE OUTPUT ------------------ diff --git a/doc/DATA_FLOW_SCANNER.rst b/doc/DATA_FLOW_SCANNER.rst index a963e2e58e..4c550d67c8 100644 --- a/doc/DATA_FLOW_SCANNER.rst +++ b/doc/DATA_FLOW_SCANNER.rst @@ -7,16 +7,21 @@ shouldi were appropriate. References: -- https://intel.github.io/dffml/shouldi.html -- https://intel.github.io/dffml/examples/shouldi.html -- https://intel.github.io/dffml/examples/dataflows.html +- shouldi + + - https://intel.github.io/dffml/shouldi.html + - https://intel.github.io/dffml/examples/shouldi.html + - https://intel.github.io/dffml/examples/dataflows.html + +- Alice/Open Architecture + + - https://github.com/intel/dffml/discussions/1369 .. note:: Tested against development version of DFFML 9ddcdfd6f8de743f87d41b74d53fde2c182861c7 - Install ******* @@ -24,22 +29,31 @@ Install with extra .. code-block:: console - $ python -m pip install cve-bin-tool[dataflow] + $ python -m pip install cve-bin-tool[dataflow] + +Scan with Data Flow Orchestrator +******************************** + +Scan files as usual (alice is a shortname for the Open Architecture format). + +.. code-block:: console + + $ cve-bin-tool --engine dataflow . -Examples -******** +Output To Open Architecture Format +********************************** -Scan files as usual +When running the scan we can output to the Open Architecture format (aka Alice). .. code-block:: console - :test: - $ python -m cve_bin_tool.scanners.dataflow . + $ cve-bin-tool --engine dataflow --format alice --output-file scan.alice . + +Supplement Threat Model with Scan Data +************************************** -Scan a git repo. Currently runs ``shoudli`` scanning. (In future we can add -overlays to run the build then scan). +When running the scan we can output to the Open Architecture format (aka Alice). .. code-block:: console - :test: - $ python -m cve_bin_tool.scanners.dataflow https://github.com/intel/cve-bin-tool + $ cve-bin-tool --input-file scan.alice --format md --output-file THREATS.md