Skip to content

Commit

Permalink
export generic scanner results in SARIF to Defect Dojo (RedHatProduct…
Browse files Browse the repository at this point in the history
…Security#167)

* inline can include redirection shell charaters. updated the generic template, explicitly specifing container.type is none

* export generic scanner result to DefectDojo

* test case updated now the generic_cli is a 'string' type
  • Loading branch information
jeremychoi authored Feb 12, 2024
1 parent fac00c1 commit 9a0def3
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 33 deletions.
81 changes: 58 additions & 23 deletions config/config-template-generic-scan.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# This is a configuration template file to perform scans using user-defined container images
# This is a configuration template file to perform scans using user-defined container images or scripts
#
# Author: Red Hat Product Security
#

config:
# WARNING: `configVersion` indicates the schema version of the config file.
Expand All @@ -10,51 +9,87 @@ config:
# It is intended to keep backward compatibility (newer RapiDAST running an older config)
configVersion: 5

# (Optional) configure to export scan results to OWASP Defect Dojo
#defectDojo:
#url: "https://mydefectdojo.example.com/"
# ssl: True|False|/path/to/CA/bundle (default: True). for SSL verification
#ssl: True
#authorization:
#username: "rapidast"
#password: "password"
# or
#token: "abc"

# `application` contains data related to the application, not to the scans.
application:
shortName: "MyApp-1.0"

# `general` is a section that will be applied to all scanners.
general:

container:
# This configures what technology is to be used for RapiDAST to run each scanner.
# Currently supported: `podman` and `none`
# none: Default. RapiDAST runs each scanner in the same host or inside the RapiDAST image container
# podman: RapiDAST orchestrates each scanner on its own using podman
# When undefined, relies on rapidast-defaults.yaml, or `none` if nothing is set
#type: "none"
type: "none"

# `scanners' is a section that configures scanning options
scanners:
generic_1:
# This is a generic scanner configuration, defined by the user
# Multiple items can be defined with "generic_<random_str>" named
# This config can be combined into ZAP scan config file if the 'podman' container type is used for it too

# A path to file or directory where results are stored on the host. Note this needs to be used along with the 'volumes' configuration
# results: "/path/to/results" # if None or "*stdout", the command's standard output is selected
# results:
# An absolute path to file or directory where results are stored on the host.
# if it is "*stdout" or unspecified, the command's standard output will be selected
# When container.type is 'podman', this needs to be used along with the container.volumes configuration below
# If the result needs to be sent to DefectDojo, this must be a SARIF format file
#results: "/path/to/results"

# this config is used when container.type is not 'podman'
# toolDir: scanners/generic/tools
# inline: "<command to run>"
#toolDir: scanners/generic/tools
inline: "<command to run>"

# this config is only used when container.type is 'podman'
# container:
#parameters:
# Mandatory: image name to run
#image: "<container image name>"
#container:
#parameters:
# Mandatory: image name to run
#image: "<container image name>"

# Optional: command to run. By default, the image's ENTRYPOINT will be run
#command: "<command to run in the container>"

# Optional: command to run. By default, the image's ENTRYPOINT will be run
#command: "<command to run in the container>"
# Optional: inject into an existing Pod
#podName: "mypod"

# Optional: inject into an existing Pod
#podName: "mypod"
# Optional: list of expected return codes, anything else will be considered as an error. by default: [0]
#validReturns: [ 0, 1 ]

# Optional: list of expected return codes, anything else will be considered as an error. by default: [0]
#validReturns: [ 0, 1 ]
# Optional: list of volume to mount, e.g.: to retrieve results on the host
#volumes:
# - "<host/path>:<guest/path>:Z" # for Linux
# - "<host/path>:<guest/path>" # for Mac

# Optional: list of volume to mount, e.g.: to retrieve results on the host
#volumes:
# - "<host/path>:<guest/path>:Z" # for Linux
# - "<host/path>:<guest/path>" # for Mac
# (Optional) configure to export scan results to OWASP Defect Dojo.
# `config.defectDojo` must be configured first.
#defectDojoExport:
#type: "reimport" # choose between: import, reimport, False (disable export). Default (or other content): re-import if test is set
# Parameters contain data that will directly be sent as parameters to DefectDojo's import/reimport endpoints.
# For example: commit tag, version, push_to_jira, etc.
# See https://demo.defectdojo.org/api/v2/doc/ for a list of possibilities
# The minimum set of data is whatever is needed to identify which engagement/test needs to be chosen.
# If neither a test ID (`test` parameter), nor product_name and engagement_name were provided, sane default will be attempted:
# - product_name chosen from either application.productName or application.shortName
# - engagement_name: "RapiDAST" [this way the same engagement will always be chosen, regardless of the scanner]
#parameters:
#product_name: "My Product"
#engagement_name: "RapiDAST"
# - or -
#engagement: 3 # engagement ID
# - or -
#test_title: "generic"
# - or -
#test: 5 # test ID, that will force "reimport" mode
# additional options, see https://demo.defectdojo.org/api/v2/doc/ for list
#auto_create_context: False # Optional. set to True to auto-create engagement (requires pr
3 changes: 1 addition & 2 deletions helm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ RapiDAST scans can be performed by using the Helm chart included in the reposito

The Helm chart uses the official RapiDAST image: `quay.io/redhatproductsecurity/rapidast:latest` based on the code in the `main` branch.

If you want to run a scan with the custom RapiDAST image(e.g. using the latest code in the `development` branch), you'll need to [build your own image](https://github.com/RedHatProductSecurity/rapidast#build-a-rapidast-image) and push it to your container registry. And update [the image section](https://github.com/RedHatProductSecurity/rapidast/blob/development/helm/chart/values.yaml#L5) of your `chart/values.yaml` file, according to your image name and tag.
If you want to run a scan with the custom RapiDAST image(e.g. using the latest code in the `development` branch), you'll need to [build your own image](https://github.com/RedHatProductSecurity/rapidast#build-a-rapidast-image) and push it to your container registry. And update [the image section](https://github.com/RedHatProductSecurity/rapidast/blob/development/helm/chart/values.yaml#L5) of your `chart/values.yaml` file, according to your image name and tag.

In addition, `values.yaml` contains various configuration items including a RapiDAST config template and default scan policy. Either you modify it for your environment or override by using `--set-file`, `--set` or `-f`.

Expand Down Expand Up @@ -45,4 +45,3 @@ rapidast]$ bash helm/results.sh rapidast-pvc /tmp/results/
When running on OpenShift, make sure that your namespace you are running on has proper privileges for running a pod/container

You'll need to set `secContext: '{"privileged": true}'` at [https://github.com/RedHatProductSecurity/rapidast/blob/development/helm/chart/values.yaml#L14](https://github.com/RedHatProductSecurity/rapidast/blob/development/helm/chart/values.yaml#L14)

38 changes: 36 additions & 2 deletions scanners/generic/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ def postprocess(self):
# pylint: disable=broad-exception-caught
except Exception as excp:
logging.error(f"Unable to save results: {excp}")
# pylint: disable=attribute-defined-outside-init
# it's a false positive: it's defined in the RapidastScanner class
self.state = State.ERROR

def cleanup(self):
Expand All @@ -89,9 +91,41 @@ def data_for_defect_dojo(self):
To "cancel", return the (None, None) tuple
Currently, this plugin does not support DD
"""
return None, None
if not self._should_export_to_defect_dojo():
return None, None
logging.debug("Preparing data for Defect Dojo")

sarif_filename = os.path.basename(self.my_conf("results"))

filename = f"{self.results_dir}/{sarif_filename}"
logging.debug(f"export {filename} to defect dojo")

# default, mandatory values (which can be overloaded)
data = {
"scan_type": "SARIF",
"active": True,
"verified": False,
}

# lists of configured import parameters
params_root = "defectDojoExport.parameters"
import_params = self.my_conf(params_root, default={}).keys()

# overload that list onto the defaults
for param in import_params:
data[param] = self.my_conf(f"{params_root}.{param}")

if data.get("test") is None:
# No test ID provided, so we need to make sure there is enough info
# But we can't make it default (they should not be filled if there is a test ID
if not data.get("product_name"):
data["product_name"] = self.config.get(
"application.ProductName"
) or self.config.get("application.shortName")
if not data.get("engagement_name"):
data["engagement_name"] = "RapiDAST"
return data, filename

###############################################################
# PROTECTED METHODS #
Expand Down
7 changes: 3 additions & 4 deletions scanners/generic/generic_none.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import pprint
import shlex
import subprocess

from scanners import State
Expand Down Expand Up @@ -89,7 +88,8 @@ def run(self):

logging.info(f"Running a generic scan with the following command:\n{cli}")

# run the command in the tool_dir
# run the command in the tool_dir(cwd)
# shell=True is required to run the command in case it contains shell metacharacters such as redirectons

scanning_stdout_results = ""
with subprocess.Popen(
Expand All @@ -98,6 +98,7 @@ def run(self):
stdout=stdout_store,
bufsize=1,
universal_newlines=True,
shell=True,
) as scanning:
if stdout_store:
logging.debug("Storing standard output")
Expand Down Expand Up @@ -168,7 +169,5 @@ def _setup_generic_cli(self):
"""

self.generic_cli = self.my_conf("inline")
if isinstance(self.generic_cli, str):
self.generic_cli = shlex.split(self.generic_cli)

logging.debug(f"generic will run with: {self.generic_cli}")
1 change: 0 additions & 1 deletion scanners/generic/tools/generic_sample_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,4 @@ cat <<DELIM
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0"
}
DELIM
2 changes: 1 addition & 1 deletion tests/scanners/generic/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_generic_none_inline(test_config):

scanner = GenericNone(config=test_config)
scanner.setup()
assert scanner.generic_cli[0] == "tmp_cmd"
assert scanner.generic_cli == "tmp_cmd"


def test_generic_none_tool_dir(test_config):
Expand Down

0 comments on commit 9a0def3

Please sign in to comment.