Skip to content

Commit

Permalink
sast: initial task for Coverity Buildless
Browse files Browse the repository at this point in the history
Solves: https://issues.redhat.com/browse/OSH-740

Initial version of the Coverity Buildless task. The code will be scanned using coverity buildless mode, then the results are processuing using csgrep and the results are later filtered using csfilter-kfp.
  • Loading branch information
jperezdealgaba committed Sep 20, 2024
1 parent d42191e commit f65c313
Show file tree
Hide file tree
Showing 3 changed files with 277 additions and 0 deletions.
46 changes: 46 additions & 0 deletions task/sast-coverity-check/0.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# sast-coverity-check task

## Description:

The sast-coverity-check task uses Coverity tool to perform Static Application Security Testing (SAST). In this task, we use the buildless mode, where Coverity has the ability to capture source code without the need of building the product.

The documentation for this mode can be found here: https://sig-product-docs.synopsys.com/bundle/coverity-docs/page/commands/topics/coverity_capture.html

The characteristics of these tasks are:

- Perform buildless scanning with Coverity
- The whole source code is scanned (by scanning `$(workspaces.source.path)` )
- Only important findings are reported by default. A parameter ( `SEVERITY_THRESHOLD`) is provided to override this configuration.
- The csdiff/v1 SARIF fingerprints are provided for all findings
- [Known false positives](https://gitlab.cee.redhat.com/osh/known-false-positives/) are eliminated by default. A parameter ( `KFP_GIT_URL`) is provided to disable this feature or to configure a custom known false positives repository.

> NOTE: This task is executed only if there is a Coverity license set up in the environment. The Coverity license can be used by Red Hat employees only and it needs to be protected such that external users cannot access the license.
## Params:

| name | description |
|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| COV_CAPTURE_ARGS | Append arguments to the Coverity Capture CLI command |
| COV_ANALYZE_ARGS | Append arguments to the cov-analyze CLI command |
| COV_LICENSE | Name of secret which contains the Coverity license |
| SEVERITY_THRESHOLD | Report only vulnerabilities at the specified level or higher. Default is 1 (Report important findings). To report all findings, specify "0" |
| KFP_GIT_URL | Known False Positives git URL, optionally taking a revision delimited by #; If empty, filtering of known false positives is disabled. |
| PROJECT_NVR | Name-Version-Release (NVR) of the scanned project, used to find path exclusions (it is optional) |
| RECORD_EXCLUDED | File to store all excluded findings to (it is optional) |

## Results:

| name | description |
|-------------------|--------------------------|
| TEST_OUTPUT | Tekton task test output. |

## Source repository for image:

// TODO: Add reference to private repo for the container image once the task is migrated to repo


## Additional links:

* https://sig-product-docs.synopsys.com/bundle/coverity-docs/page/commands/topics/coverity_capture.html
* https://scan.coverity.com/
* https://sig-product-docs.synopsys.com/bundle/coverity-docs/page/cli/topics/options_reference.html
226 changes: 226 additions & 0 deletions task/sast-coverity-check/0.1/sast-coverity-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
apiVersion: tekton.dev/v1
kind: Task
metadata:
labels:
app.kubernetes.io/version: "0.1"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: "konflux"
name: sast-coverity-check
spec:
description: >-
Scans source code for security vulnerabilities, including common issues such as SQL injection, cross-site scripting (XSS), and code injection attacks using Coverity. At the moment, this task only uses the captureless mode doesn't build the project in order to analyze it.
results:
- description: Tekton task test output.
name: TEST_OUTPUT
params:
- description: Image URL.
name: image-url
type: string
# In a future 0.2 version of the task, drop the default to make this required
default: ""
- description: Image digest to report findings for.
name: image-digest
type: string
# In a future 0.2 version of the task, drop the default to make this required
default: ""
- description: Arguments to be appenden to the coverity capture command
name: COV_CAPTURE_ARGS
type: string
default: ""
- description: Arguments to be appenden to the coverity analyze command
name: COV_ANALYZE_ARGS
type: string
default: "--enable HARDCODED_CREDENTIALS --security --concurrency --spotbugs-max-mem=4096"
- name: COV_LICENSE
description: Name of secret which contains the Coverity license
default: cov-license
- name: SEVERITY_THRESHOLD
type: string
description: Report only vulnerabilities at the specified level or higher. Default is 1 (report only important findings)
default: "1"
- name: KFP_GIT_URL
type: string
description: URL from repository to download known false positives files
default: "https://gitlab.cee.redhat.com/osh/known-false-positives.git"
- name: PROJECT_NVR
type: string
description: Name-Version-Release (NVR) of the scanned project, used to find path exclusions (it is optional)
default: ""
- name: RECORD_EXCLUDED
type: string
description: File to store all excluded findings to (it is optional)
default: ""
volumes:
- name: cov-license
secret:
secretName: $(params.COV_LICENSE)
optional: false
steps:
- name: sast-coverity-check
# TODO: Change image
image: quay.io/redhat-user-workloads/sast-tenant/sast-scanner/coverity@sha256:ce98d4a80a2b77cd1b51fb11d563515226331fdf9521daa1b82da5b0a99e8d22
computeResources:
requests:
memory: "16Gi"
cpu: "8"
limits:
memory: "32Gi"
cpu: "16"
# per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting
# the cluster will set imagePullPolicy to IfNotPresent
workingDir: $(workspaces.workspace.path)/hacbs/$(context.task.name)
volumeMounts:
- name: cov-license
mountPath: "/etc/secrets"
readOnly: true
env:
- name: COV_ANALYZE_ARGS
value: $(params.COV_ANALYZE_ARGS)
- name: COV_CAPTURE_ARGS
value: $(params.COV_CAPTURE_ARGS)
- name: KFP_GIT_URL
value: $(params.KFP_GIT_URL)
- name: SEVERITY_THRESHOLD
value: $(params.SEVERITY_THRESHOLD)
- name: PROJECT_NVR
value: $(params.PROJECT_NVR)
- name: RECORD_EXCLUDED
value: $(params.RECORD_EXCLUDED)
script: |
#!/usr/bin/env bash
set -eo pipefail
. /usr/local/share/konflux-test/utils.sh
trap 'handle_error $(results.TEST_OUTPUT.path)' EXIT
echo 'Starting Coverity buildless scan'
SOURCE_CODE_DIR=$(workspaces.workspace.path)
COVERITY_DIR=/tmp/cov-scan/cov
COVERITY_RESULTS_FILE=coverity-buildless-results.js
COV_LICENSE_PATH=/etc/secrets/cov-license
# Installing Coverity license
cp /etc/secrets/cov-license /opt/coverity/bin/license.dat
if test -z "$(find /opt -name 'license.dat')"; then
echo "No license file for Coverity was detected. Exiting..."
exit 1
fi
# Installation of Red Hat certificates for cloning Red Hat internal repositories
curl -sS https://certs.corp.redhat.com/certs/2015-IT-Root-CA.pem > /etc/pki/ca-trust/source/anchors/2015-RH-IT-Root-CA.crt
curl -sS https://certs.corp.redhat.com/certs/2022-IT-Root-CA.pem > /etc/pki/ca-trust/source/anchors/2022-IT-Root-CA.pem
update-ca-trust
# Create configuration file for coverity buildless
echo -e 'capture:\n build-command-inference: false' > $SOURCE_CODE_DIR/coverity.yml
# Captureless scan
env COV_HOST=konflux HOME=/tmp/cov-scan/home /opt/coverity/bin/coverity capture $COV_CAPTURE_ARGS --project-dir $SOURCE_CODE_DIR --dir $COVERITY_DIR
COV_CAPTURE_EXIT_CODE=$?
if [[ "$COV_CAPTURE_EXIT_CODE" -eq 0 ]]; then
echo "Coverity capture scan finished successfully"
else
echo "Coverity capture command failed with exit code ${COV_CAPTURE_EXIT_CODE}. Exiting..."
exit 1
fi
# Analysis phase
/opt/coverity/bin/cov-manage-emit --dir $COVERITY_DIR reset-host-name
/opt/coverity/bin/cov-analyze $COV_ANALYZE_ARGS --dir=$COVERITY_DIR
COV_ANALYZE_EXIT_CODE=$?
if [[ "$COV_ANALYZE_EXIT_CODE" -eq 0 ]]; then
echo "Coverity analyze scan finished successfully"
else
echo "Coverity analyze scan failed with exit code ${COV_ANALYZE_EXIT_CODE}. Exiting..."
exit 1
fi
/opt/coverity/bin/cov-format-errors --dir=$COVERITY_DIR --json-output-v10 $COVERITY_RESULTS_FILE
# We parse the results, embed context, remove duplicates and store them in SARIF format.
csgrep --mode=json --imp-level="$SEVERITY_THRESHOLD" --prepend-path-prefix=$SOURCE_CODE_DIR/ $COVERITY_RESULTS_FILE \
| csgrep --mode=json --remove-duplicates --embed-context 3 \
| csgrep --mode=json --strip-path-prefix="$SOURCE_CODE_DIR"/source/ \
| csgrep --mode=json --strip-path-prefix="/tmp/cov-scan/home" \
> sast_coverity_buildless_check_all_findings.json
echo "Results:"
(set -x; csgrep --mode=evtstat sast_coverity_buildless_check_all_findings.json)
# We check if the KFP_GIT_URL variable is set to apply the filters or not
if [[ -z "${KFP_GIT_URL}" ]]; then
mv sast_coverity_buildless_check_all_findings.json filtered_sast_coverity_buildless_check_all_findings.json
else
echo "Filtering false positives in results files using csfilter-kfp..."
CMD=(
csfilter-kfp
--verbose
--kfp-git-url="${KFP_GIT_URL}"
)
if [[ -n "${PROJECT_NVR}" ]]; then
CMD+=(--project-nvr="${PROJECT_NVR}")
fi
if [[ -n "${RECORD_EXCLUDED}" ]]; then
CMD+=(--record-excluded="${RECORD_EXCLUDED}")
fi
"${CMD[@]}" sast_coverity_buildless_check_all_findings.json > filtered_sast_coverity_buildless_check_all_findings.json
status=$?
if [ "$status" -ne 0 ]; then
echo "Error: failed to filter known false positives" >&2
return 1
else
echo "Message: Succeed to filter known false positives" >&2
SCAN_RESULT="filtered_sast_unicode_check_out.json"
fi
echo "Results after filtering:"
(set -x; csgrep --mode=evtstat filtered_sast_coverity_buildless_check_all_findings.json)
fi
csgrep --mode=sarif filtered_sast_coverity_buildless_check_all_findings.json > $(workspaces.workspace.path)/hacbs/$(context.task.name)/coverity-buildless-results.sarif
if [[ -z "$(csgrep --mode=evtstat filtered_sast_coverity_buildless_check_all_findings.json)" ]]; then
note="Task $(context.task.name) success: No finding was detected"
ERROR_OUTPUT=$(make_result_json -r SUCCESS -t "$note")
else
TEST_OUTPUT=
parse_test_output $(context.task.name) sarif $(workspaces.workspace.path)/hacbs/$(context.task.name)/coverity-buildless-results.sarif || true
note="Task $(context.task.name) failed: For details, check Tekton task log."
ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note")
fi
echo "${TEST_OUTPUT:-${ERROR_OUTPUT}}" | tee $(results.TEST_OUTPUT.path)
- name: upload
image: quay.io/konflux-ci/oras:latest@sha256:99737f436051e6d3866eb8a8706463c35abf72c87f05090ff42ff642f6729661
workingDir: $(workspaces.workspace.path)/hacbs/$(context.task.name)
env:
- name: IMAGE_URL
value: $(params.image-url)
- name: IMAGE_DIGEST
value: $(params.image-digest)
script: |
#!/usr/bin/env bash
UPLOAD_FILE=coverity-buildless-results.sarif
MEDIA_TYPE=application/sarif+json
if [ -z "${IMAGE_URL}" ] || [ -z "${IMAGE_DIGEST}" ]; then
echo 'No image-url or image-digest param provided. Skipping upload.'
exit 0;
fi
UPLOAD_FILES="coverity-buildless-results.sarif record_excluded.json"
for UPLOAD_FILE in ${UPLOAD_FILES}; do
if [ ! -f "${UPLOAD_FILE}" ]; then
echo "No ${UPLOAD_FILE} exists. Skipping upload."
exit 0;
fi
echo "Selecting auth"
select-oci-auth $IMAGE_URL > $HOME/auth.json
echo "Attaching to ${IMAGE_URL}"
oras attach --no-tty --registry-config "$HOME/auth.json" --artifact-type "${MEDIA_TYPE}" "${IMAGE_URL}" "${UPLOAD_FILE}:${MEDIA_TYPE}"
workspaces:
- name: workspace
5 changes: 5 additions & 0 deletions task/sast-coverity-check/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# See the OWNERS docs: https://go.k8s.io/owners
approvers:
- integration-team
reviewers:
- integration-team

0 comments on commit f65c313

Please sign in to comment.