From 97943423b4aaf11b334d7f0c7782d12f77d885f2 Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Mon, 25 Nov 2024 16:05:34 +0100 Subject: [PATCH] sast-coverity-check: do not require IMAGE_DIGEST parameter ... which is not used for anything Related: https://github.com/konflux-ci/build-definitions/pull/1653 --- pipelines/docker-build/README.md | 14 +- pipelines/maven-zip-build/patch.yaml | 3 - pipelines/template-build/template-build.yaml | 4 +- task/sast-coverity-check/0.2/MIGRATION.md | 7 + task/sast-coverity-check/0.2/README.md | 46 +++ .../0.2/sast-coverity-check.yaml | 276 ++++++++++++++++++ 6 files changed, 337 insertions(+), 13 deletions(-) create mode 100644 task/sast-coverity-check/0.2/MIGRATION.md create mode 100644 task/sast-coverity-check/0.2/README.md create mode 100644 task/sast-coverity-check/0.2/sast-coverity-check.yaml diff --git a/pipelines/docker-build/README.md b/pipelines/docker-build/README.md index 5d659560da..a9fc195bfd 100644 --- a/pipelines/docker-build/README.md +++ b/pipelines/docker-build/README.md @@ -160,11 +160,12 @@ This pipeline is pushed as a Tekton bundle to [quay.io](https://quay.io/reposito |image-digest| Image digest to scan| None| '$(tasks.build-image-index.results.IMAGE_DIGEST)'| |image-url| Image URL| None| '$(tasks.build-image-index.results.IMAGE_URL)'| |workdir| Directory that will be used for storing temporary files produced by this task. | /tmp| | -### sast-coverity-check:0.1 task parameters +### sast-coverity-check:0.2 task parameters |name|description|default value|already set by| |---|---|---|---| |AUTH_TOKEN_COVERITY_IMAGE| Name of secret which contains the authentication token for pulling the Coverity image.| auth-token-coverity-image| | |COV_ANALYZE_ARGS| Arguments to be appended to the cov-analyze command| --enable HARDCODED_CREDENTIALS --security --concurrency --spotbugs-max-mem=4096| | +|COV_CAPTURE_ARGS| Arguments to be appended to the coverity capture command| | | |COV_LICENSE| Name of secret which contains the Coverity license| cov-license| | |IMP_FINDINGS_ONLY| Report only important findings. Default is true. To report all findings, specify "false"| true| | |KFP_GIT_URL| URL from repository to download known false positives files| | | @@ -172,7 +173,6 @@ This pipeline is pushed as a Tekton bundle to [quay.io](https://quay.io/reposito |RECORD_EXCLUDED| Write excluded records in file. Useful for auditing (defaults to false).| false| | |caTrustConfigMapKey| The name of the key in the ConfigMap that contains the CA bundle data.| ca-bundle.crt| | |caTrustConfigMapName| The name of the ConfigMap to read CA bundle data from.| trusted-ca| | -|image-digest| Image digest to report findings for.| None| '$(tasks.build-image-index.results.IMAGE_DIGEST)'| |image-url| Image URL.| None| '$(tasks.build-image-index.results.IMAGE_URL)'| ### sast-shell-check:0.1 task parameters |name|description|default value|already set by| @@ -240,9 +240,9 @@ This pipeline is pushed as a Tekton bundle to [quay.io](https://quay.io/reposito |name|description|used in params (taskname:taskrefversion:taskparam) |---|---|---| |IMAGES| List of all referenced image manifests| | -|IMAGE_DIGEST| Digest of the image just built| deprecated-base-image-check:0.4:IMAGE_DIGEST ; clair-scan:0.2:image-digest ; sast-snyk-check:0.3:image-digest ; clamav-scan:0.2:image-digest ; sast-coverity-check:0.1:image-digest ; sast-shell-check:0.1:image-digest ; push-dockerfile:0.1:IMAGE_DIGEST ; rpms-signature-scan:0.2:image-digest| +|IMAGE_DIGEST| Digest of the image just built| deprecated-base-image-check:0.4:IMAGE_DIGEST ; clair-scan:0.2:image-digest ; sast-snyk-check:0.3:image-digest ; clamav-scan:0.2:image-digest ; sast-shell-check:0.1:image-digest ; push-dockerfile:0.1:IMAGE_DIGEST ; rpms-signature-scan:0.2:image-digest| |IMAGE_REF| Image reference of the built image containing both the repository and the digest| | -|IMAGE_URL| Image repository and tag where the built image was pushed| show-sbom:0.1:IMAGE_URL ; deprecated-base-image-check:0.4:IMAGE_URL ; clair-scan:0.2:image-url ; ecosystem-cert-preflight-checks:0.1:image-url ; sast-snyk-check:0.3:image-url ; clamav-scan:0.2:image-url ; sast-coverity-check:0.1:image-url ; sast-shell-check:0.1:image-url ; sast-unicode-check:0.1:image-url ; apply-tags:0.1:IMAGE ; push-dockerfile:0.1:IMAGE ; rpms-signature-scan:0.2:image-url| +|IMAGE_URL| Image repository and tag where the built image was pushed| show-sbom:0.1:IMAGE_URL ; deprecated-base-image-check:0.4:IMAGE_URL ; clair-scan:0.2:image-url ; ecosystem-cert-preflight-checks:0.1:image-url ; sast-snyk-check:0.3:image-url ; clamav-scan:0.2:image-url ; sast-coverity-check:0.2:image-url ; sast-shell-check:0.1:image-url ; sast-unicode-check:0.1:image-url ; apply-tags:0.1:IMAGE ; push-dockerfile:0.1:IMAGE ; rpms-signature-scan:0.2:image-url| |SBOM_BLOB_URL| Reference of SBOM blob digest to enable digest-based verification from provenance| | ### buildah:0.2 task results |name|description|used in params (taskname:taskrefversion:taskparam) @@ -302,7 +302,7 @@ This pipeline is pushed as a Tekton bundle to [quay.io](https://quay.io/reposito |IMAGES_PROCESSED| Images processed in the task.| | |RPMS_DATA| Information about signed and unsigned RPMs| | |TEST_OUTPUT| Tekton task test output.| | -### sast-coverity-check:0.1 task results +### sast-coverity-check:0.2 task results |name|description|used in params (taskname:taskrefversion:taskparam) |---|---|---| |TEST_OUTPUT| Tekton task test output.| | @@ -331,7 +331,7 @@ This pipeline is pushed as a Tekton bundle to [quay.io](https://quay.io/reposito |---|---|---|---| |git-auth| |True| clone-repository:0.1:basic-auth ; prefetch-dependencies:0.1:git-basic-auth| |netrc| |True| prefetch-dependencies:0.1:netrc| -|workspace| |False| show-summary:0.2:workspace ; clone-repository:0.1:output ; prefetch-dependencies:0.1:source ; build-container:0.2:source ; build-source-image:0.1:workspace ; sast-snyk-check:0.3:workspace ; sast-coverity-check:0.1:workspace ; sast-shell-check:0.1:workspace ; sast-unicode-check:0.1:workspace ; push-dockerfile:0.1:workspace| +|workspace| |False| show-summary:0.2:workspace ; clone-repository:0.1:output ; prefetch-dependencies:0.1:source ; build-container:0.2:source ; build-source-image:0.1:workspace ; sast-snyk-check:0.3:workspace ; sast-coverity-check:0.2:workspace ; sast-shell-check:0.1:workspace ; sast-unicode-check:0.1:workspace ; push-dockerfile:0.1:workspace| ## Available workspaces from tasks ### buildah:0.2 task workspaces |name|description|optional|workspace from pipeline @@ -353,7 +353,7 @@ This pipeline is pushed as a Tekton bundle to [quay.io](https://quay.io/reposito |name|description|optional|workspace from pipeline |---|---|---|---| |workspace| Workspace containing the source code from where the Dockerfile is discovered.| False| workspace| -### sast-coverity-check:0.1 task workspaces +### sast-coverity-check:0.2 task workspaces |name|description|optional|workspace from pipeline |---|---|---|---| |workspace| | False| workspace| diff --git a/pipelines/maven-zip-build/patch.yaml b/pipelines/maven-zip-build/patch.yaml index a0e21b2164..b1245cc5f6 100644 --- a/pipelines/maven-zip-build/patch.yaml +++ b/pipelines/maven-zip-build/patch.yaml @@ -120,9 +120,6 @@ # Replace the params set and runAfter of sast-coverity-check - op: replace path: /spec/tasks/5/params/0/value - value: "$(tasks.build-oci-artifact.results.IMAGE_DIGEST)" -- op: replace - path: /spec/tasks/5/params/1/value value: "$(tasks.build-oci-artifact.results.IMAGE_URL)" # Replace the params set and runAfter of coverity-availability-check - op: replace diff --git a/pipelines/template-build/template-build.yaml b/pipelines/template-build/template-build.yaml index a208bb6e0c..924fe52967 100644 --- a/pipelines/template-build/template-build.yaml +++ b/pipelines/template-build/template-build.yaml @@ -250,10 +250,8 @@ spec: - coverity-availability-check taskRef: name: sast-coverity-check - version: "0.1" + version: "0.2" params: - - name: image-digest - value: $(tasks.build-image-index.results.IMAGE_DIGEST) - name: image-url value: $(tasks.build-image-index.results.IMAGE_URL) workspaces: diff --git a/task/sast-coverity-check/0.2/MIGRATION.md b/task/sast-coverity-check/0.2/MIGRATION.md new file mode 100644 index 0000000000..3f647625a7 --- /dev/null +++ b/task/sast-coverity-check/0.2/MIGRATION.md @@ -0,0 +1,7 @@ +# Migration from 0.1 to 0.2 + +- The unused `IMAGE_DIGEST` parameter has been removed. + +## Action from users + +- The parameter definition can be removed for this task in the build pipeline. diff --git a/task/sast-coverity-check/0.2/README.md b/task/sast-coverity-check/0.2/README.md new file mode 100644 index 0000000000..5ce205aba2 --- /dev/null +++ b/task/sast-coverity-check/0.2/README.md @@ -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 ( `IMP_FINDINGS_ONLY`) is provided to override this configuration. +- The csdiff/v1 SARIF fingerprints are provided for all findings +- A parameter ( `KFP_GIT_URL`) is provided to remove false positives providing a known false positives repository. By default, no repository is provided. + +> NOTE: This task is executed only if there is a Coverity license set up in the environment. Please check coverity-availability-check task for more information. + +## Params: + +| name | description | default value | required | +|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------|---------------------------|----------| +| COV_CAPTURE_ARGS | Append arguments to the Coverity Capture CLI command | "" | no | +| COV_ANALYZE_ARGS | Append arguments to the cov-analyze CLI command | "" | no | +| COV_LICENSE | Name of secret which contains the Coverity license | cov-license | no | +| AUTH_TOKEN_COVERITY_IMAGE | Name of secret which contains the authentication token for pulling the Coverity image | auth-token-coverity-image | no | +| IMP_FINDINGS_ONLY | Report only important findings. Default is true. To report all findings, specify "false" | true | no | +| KFP_GIT_URL | Known False Positives git URL, optionally taking a revision delimited by #; If empty, filtering of known false positives is disabled. | "" | no | +| PROJECT_NAME | Name of the scanned project, used to find path exclusions. By default, the Konflux component name will be used. | "" | no | +| RECORD_EXCLUDED | If set to `true`, excluded findings will be written to a file named `excluded-findings.json` for auditing purposes. | false | no | + +## 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://sig-product-docs.synopsys.com/bundle/coverity-docs/page/cli/topics/options_reference.html diff --git a/task/sast-coverity-check/0.2/sast-coverity-check.yaml b/task/sast-coverity-check/0.2/sast-coverity-check.yaml new file mode 100644 index 0000000000..d567ac4613 --- /dev/null +++ b/task/sast-coverity-check/0.2/sast-coverity-check.yaml @@ -0,0 +1,276 @@ +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 buildless mode, which does not 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 + - name: caTrustConfigMapName + type: string + description: The name of the ConfigMap to read CA bundle data from. + default: trusted-ca + - name: caTrustConfigMapKey + type: string + description: The name of the key in the ConfigMap that contains the CA bundle data. + default: ca-bundle.crt + - description: Arguments to be appended to the coverity capture command + name: COV_CAPTURE_ARGS + type: string + default: "" + - description: Arguments to be appended to the cov-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: AUTH_TOKEN_COVERITY_IMAGE + description: Name of secret which contains the authentication token for pulling the Coverity image. + default: "auth-token-coverity-image" + - name: IMP_FINDINGS_ONLY + type: string + description: Report only important findings. Default is true. To report all findings, specify "false" + default: "true" + - name: KFP_GIT_URL + type: string + description: URL from repository to download known false positives files + # FIXME: Red Hat internal projects will default to https://gitlab.cee.redhat.com/osh/known-false-positives.git when KONFLUX-4530 is resolved + default: "" + - name: PROJECT_NAME + description: Name of the scanned project, used to find path exclusions. + By default, the Konflux component name will be used. + type: string + default: "" + - name: RECORD_EXCLUDED + type: string + description: Write excluded records in file. Useful for auditing (defaults to false). + default: "false" + volumes: + - name: cov-license + secret: + secretName: $(params.COV_LICENSE) + optional: false + - name: auth-token-coverity-image + secret: + secretName: $(params.AUTH_TOKEN_COVERITY_IMAGE) + optional: false + - name: trusted-ca + configMap: + name: $(params.caTrustConfigMapName) + items: + - key: $(params.caTrustConfigMapKey) + path: ca-bundle.crt + optional: true + steps: + - name: sast-coverity-check + # image: $(steps.secrets-check.results.image) + image: quay.io/redhat-user-workloads/sast-tenant/sast-scanner/coverity@sha256:d8e1266319d310443b183f8c14e083932b70f665fd72a61ff90b30e46b9398f0 + 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/cov" + readOnly: true + - name: trusted-ca + mountPath: /mnt/trusted-ca + 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: COV_LICENSE + value: $(params.COV_LICENSE) + - name: IMP_FINDINGS_ONLY + value: $(params.IMP_FINDINGS_ONLY) + - name: PROJECT_NAME + value: $(params.PROJECT_NAME) + - name: RECORD_EXCLUDED + value: $(params.RECORD_EXCLUDED) + - name: COMPONENT_LABEL + valueFrom: + fieldRef: + fieldPath: metadata.labels['appstudio.openshift.io/component'] + script: | + #!/usr/bin/env bash + set -eo pipefail + # shellcheck source=/dev/null + . /usr/local/share/konflux-test/utils.sh + trap 'handle_error $(results.TEST_OUTPUT.path)' EXIT + + echo 'Starting Coverity buildless scan' + + export HOME="/var/tmp/coverity/home" + + if [[ -z "${PROJECT_NAME}" ]]; then + PROJECT_NAME=${COMPONENT_LABEL} + fi + echo "The PROJECT_NAME used is: ${PROJECT_NAME}" + + COVERITY_DIR=/var/tmp/coverity/idir + COVERITY_RESULTS_FILE=$(workspaces.workspace.path)/coverity-buildless-results.json + COV_LICENSE_PATH=/etc/secrets/cov/cov-license + SOURCE_CODE_DIR=$(workspaces.workspace.path) + + # Installing Coverity license + cp "$COV_LICENSE_PATH" /opt/coverity/bin/license.dat + + # Installation of Red Hat certificates for cloning Red Hat internal repositories + ca_bundle=/mnt/trusted-ca/ca-bundle.crt + if [ -f "$ca_bundle" ]; then + echo "INFO: Using mounted CA bundle: $ca_bundle" + cp -vf $ca_bundle /etc/pki/ca-trust/source/anchors + update-ca-trust + fi + + # Create configuration file for coverity buildless + echo -e 'capture:\n build-command-inference: false' > "$SOURCE_CODE_DIR"/coverity.yml + + set +e -x + # Buildless scan + # shellcheck disable=SC2086 + env COV_HOST=konflux /opt/coverity/bin/coverity capture $COV_CAPTURE_ARGS --project-dir "$SOURCE_CODE_DIR" --dir "$COVERITY_DIR" + COV_CAPTURE_EXIT_CODE=$? + set -x + + 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..." + note="Task $(context.task.name) failed: For details, check Tekton task log." + ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note") + exit 1 + fi + + # Analysis phase + set -x + /opt/coverity/bin/cov-manage-emit --dir $COVERITY_DIR reset-host-name + # shellcheck disable=SC2086 + /opt/coverity/bin/cov-analyze $COV_ANALYZE_ARGS --dir="$COVERITY_DIR" + COV_ANALYZE_EXIT_CODE=$? + set +x + + if [[ "$COV_ANALYZE_EXIT_CODE" -eq 0 ]]; then + echo "cov-analyze scan finished successfully" + else + echo "cov-analyze scan failed with exit code ${COV_ANALYZE_EXIT_CODE}. Exiting..." + note="Task $(context.task.name) failed: For details, check Tekton task log." + ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note") + exit 1 + fi + set -e + + /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. + IMP_LEVEL=1 + if [ "${IMP_FINDINGS_ONLY}" == "false" ]; then + IMP_LEVEL=0 + fi + + (cd "$SOURCE_CODE_DIR" && csgrep --mode=json --imp-level="$IMP_LEVEL" --remove-duplicates --embed-context=3 "$COVERITY_RESULTS_FILE") \ + | csgrep --mode=json --strip-path-prefix="$SOURCE_CODE_DIR"/source/ \ + | csgrep --mode=json --strip-path-prefix="$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 + echo "KFP_GIT_URL variable not defined. False positives won't be filtered" + 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}" + --project-nvr="${PROJECT_NAME}" + ) + + if [ "${RECORD_EXCLUDED}" == "true" ]; then + CMD+=(--record-excluded="excluded-findings.json") + 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 + 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)"/coverity-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") + echo "${ERROR_OUTPUT}" | tee "$(results.TEST_OUTPUT.path)" + else + TEST_OUTPUT= + parse_test_output "$(context.task.name)" sarif "$(workspaces.workspace.path)"/coverity-results.sarif || true + note="Task $(context.task.name) failed: For details, check Tekton task log." + echo "${ERROR_OUTPUT}" | tee "$(results.TEST_OUTPUT.path)" + 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) + env: + - name: IMAGE_URL + value: $(params.image-url) + script: | + #!/usr/bin/env bash + + if [ -z "${IMAGE_URL}" ]; then + echo 'No image-url param provided. Skipping upload.' + exit 0 + fi + UPLOAD_FILES="coverity-results.sarif excluded-findings.json" + + for UPLOAD_FILE in ${UPLOAD_FILES}; do + if [ ! -f "${UPLOAD_FILE}" ]; then + echo "No ${UPLOAD_FILE} exists. Skipping upload." + continue + fi + if [ "${UPLOAD_FILES}" == "excluded-findings.json" ]; then + MEDIA_TYPE=application/json + else + MEDIA_TYPE=application/sarif+json + 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}" + done + workspaces: + - name: workspace