diff --git a/task/sast-snyk-check/0.3/MIGRATION.md b/task/sast-snyk-check/0.3/MIGRATION.md new file mode 100644 index 0000000000..3734fc3b84 --- /dev/null +++ b/task/sast-snyk-check/0.3/MIGRATION.md @@ -0,0 +1,15 @@ +# Migration from 0.2 to 0.3 + +Version 0.3: + +- The `--severity-threshold` argument has been introduced and enabled by default with "high" value. Only high or superior vulnerabilities will be shown. Possible values for this argument are: `low`, `medium` and `high`. +- The results are parsed using `csgrep` and they are uploaded as results with a generated fingerprint. +- There are no default arguments as "--all-projects --exclude=test*,vendor,deps" are ignored by Snyk Code +- The results are uploaded as SARIF files to the registry +- SARIF produced by Snyk Code is not included in the CI log. +- The findings are filtered using the known-false-positives repository (https://gitlab.cee.redhat.com/osh/known-false-positives/) +- The KFP_GIT_URL environment variable has been introduced to indicate the repository to filter false positives. If this variable is left empty, the results won't be filtered. + +## Action from users + +Renovate bot PR will be created with warning icon for a sast-snyk-check which is expected, no action from users are required. diff --git a/task/sast-snyk-check/0.3/README.md b/task/sast-snyk-check/0.3/README.md new file mode 100644 index 0000000000..7b5d91fe3f --- /dev/null +++ b/task/sast-snyk-check/0.3/README.md @@ -0,0 +1,37 @@ +# sast-snyk-check task + +## Description: + +The sast-snyk-check task uses Snyk Code tool to perform Static Application Security Testing (SAST) for Snyk, a popular cloud-native application security platform. + +Snyk's SAST tool uses a combination of static analysis and machine learning techniques to scan an application's source code for potential security vulnerabilities, including common issues such as SQL injection, cross-site scripting (XSS), and code injection attacks. + +> NOTE: This task is executed only if the user provides a Snyk token stored in a secret in their namespace. The name of the secret then needs to be supplied in the `snyk-secret` pipeline parameter. + +## Params: + +| name | description | +|--------------------|--------------------------------------------------------------------------------------------------------------| +| SNYK_SECRET | Name of secret which contains Snyk token. | +| ARGS | Append arguments. | +| SEVERITY_THRESHOLD | Only vulnerabilities of the specified level or higher are reported (Possible values are low, medium or high) | +| KFP_GIT_URL | Link to the known-false-positives repository. If left blank, results won't be filtered | + +## How to obtain a snyk-token and enable snyk task on the pipeline: + +Follow the steps given [here](https://redhat-appstudio.github.io/docs.appstudio.io/Documentation/main/how-to-guides/testing_applications/enable_snyk_check_for_a_product/) + +## Results: + +| name | description | +|-----------------------|--------------------------| +| TEST_OUTPUT | Tekton task test output. | + +## Source repository for image: + +https://github.com/konflux-ci/konflux-test + +## Additional links: + +* https://snyk.io/product/snyk-code/ +* https://snyk.io/ diff --git a/task/sast-snyk-check/0.3/sast-snyk-check.yaml b/task/sast-snyk-check/0.3/sast-snyk-check.yaml new file mode 100644 index 0000000000..f0f5b08149 --- /dev/null +++ b/task/sast-snyk-check/0.3/sast-snyk-check.yaml @@ -0,0 +1,165 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + labels: + app.kubernetes.io/version: "0.3" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: "konflux" + name: sast-snyk-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 Snyk Code, a Static Application Security Testing (SAST) tool. + results: + - description: Tekton task test output. + name: TEST_OUTPUT + params: + - name: SNYK_SECRET + description: Name of secret which contains Snyk token. + default: snyk-secret + - name: ARGS + type: string + description: Append arguments. + default: "" + - description: Image URL. + name: image-url + type: string + # In a future 0.4 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.4 version of the task, drop the default to make this required + default: "" + - name: SEVERITY_THRESHOLD + type: string + description: Report only vulnerabilities at the specified level or higher (Options are low, medium or high). + default: "high" + - 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" + + volumes: + - name: snyk-secret + secret: + secretName: $(params.SNYK_SECRET) + optional: true + steps: + - name: sast-snyk-check + image: quay.io/redhat-appstudio/konflux-test:v1.4.6@sha256:5f298d8d990dfa82023e50029b71b08e19c3c9cedb181dfc4bc86c9ecad8700c + # 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: snyk-secret + mountPath: "/etc/secrets" + readOnly: true + env: + - name: SNYK_SECRET + value: $(params.SNYK_SECRET) + - name: ARGS + value: $(params.ARGS) + - name: SEVERITY_THRESHOLD + value: $(params.SEVERITY_THRESHOLD) + - name: KFP_GIT_URL + value: $(params.KFP_GIT_URL) + script: | + #!/usr/bin/env bash + set -euo pipefail + . /utils.sh + trap 'handle_error $(results.TEST_OUTPUT.path)' EXIT + + # 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 + + SNYK_TOKEN_PATH="/etc/secrets/snyk_token" + + if [ -f "${SNYK_TOKEN_PATH}" ] && [ -s "${SNYK_TOKEN_PATH}" ]; then + # SNYK token is provided + SNYK_TOKEN="$(cat ${SNYK_TOKEN_PATH})" + export SNYK_TOKEN + else + to_enable_snyk='[here](https://redhat-appstudio.github.io/docs.appstudio.io/Documentation/main/how-to-guides/testing_applications/enable_snyk_check_for_a_product/)' + note="Task $(context.task.name) skipped: If you wish to use the Snyk code SAST task, please create a secret name snyk-secret with the key "snyk_token" containing the Snyk token by following the steps given ${to_enable_snyk}" + TEST_OUTPUT=$(make_result_json -r SKIPPED -t "$note") + echo "${TEST_OUTPUT}" | tee "$(results.TEST_OUTPUT.path)" + exit 0 + fi + + SNYK_EXIT_CODE=0 + SOURCE_CODE_DIR=$(workspaces.workspace.path) + # shellcheck disable=SC2086 + # We do want to expand ARGS (it can be multiple CLI flags, not just one) + snyk code test $ARGS --severity-threshold=$SEVERITY_THRESHOLD "$SOURCE_CODE_DIR" --max-depth=1 --sarif-file-output=sast_snyk_check_out.json 1>&2>> stdout.txt || SNYK_EXIT_CODE=$? + test_not_skipped=0 + SKIP_MSG="We found 0 supported files" + grep -q "$SKIP_MSG" stdout.txt || test_not_skipped=$? + + # In order to generate csdiff/v1, we need to add the whole path of the source code as Snyk only provides an URI to embed the context + set -x + csgrep --mode=json --prepend-path-prefix="$SOURCE_CODE_DIR"/ sast_snyk_check_out.json | csgrep --mode=json --embed-context 3 | csgrep --mode=json --strip-path-prefix="$SOURCE_CODE_DIR"/source/ > sast_snyk_check_out_all_findings.json + set +x + + # 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_snyk_check_out_all_findings.json filtered_sast_snyk_check_out.json + else + echo "Filtering false positives in results files using csfilter-kfp..." + csfilter-kfp --verbose --kfp-git-url="$KFP_GIT_URL" sast_snyk_check_out_all_findings.json > filtered_sast_snyk_check_out.json + fi + + csgrep --mode=sarif filtered_sast_snyk_check_out.json > sast_snyk_check_out.sarif + + if [[ "$SNYK_EXIT_CODE" -eq 0 ]] || [[ "$SNYK_EXIT_CODE" -eq 1 ]]; then + cat sast_snyk_check_out.json + TEST_OUTPUT= + parse_test_output '$(context.task.name)' sarif sast_snyk_check_out.sarif || true + + # When the test is skipped, the "SNYK_EXIT_CODE" is 3 and it can also be 3 in some other situation + elif [[ "$test_not_skipped" -eq 0 ]]; then + note="Task $(context.task.name) success: Snyk code test found zero supported files." + ERROR_OUTPUT=$(make_result_json -r SUCCESS -t "$note") + else + echo "sast-snyk-check test failed because of the following issues:" + cat stdout.txt + 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:f4b891ee3038a5f13cd92ff4f473faad5601c2434d1c6b9bccdfc134d9d5f820 + 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=sast_snyk_check_out.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 + + 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} via the OCI 1.1 Referrers API" + oras attach --no-tty --registry-config "$HOME/auth.json" --distribution-spec v1.1-referrers-api --artifact-type "${MEDIA_TYPE}" "${IMAGE_URL}" "${UPLOAD_FILE}:${MEDIA_TYPE}" + echo "Attaching to ${IMAGE_URL} via the OCI 1.1 Referrers Tag" + oras attach --no-tty --registry-config "$HOME/auth.json" --distribution-spec v1.1-referrers-tag --artifact-type "${MEDIA_TYPE}" "${IMAGE_URL}" "${UPLOAD_FILE}:${MEDIA_TYPE}" + workspaces: + - name: workspace