diff --git a/Dockerfile b/Dockerfile index afe1c11..727d3ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,7 @@ FROM us.gcr.io/ksoc-public/image-scan:0.0.2 +RUN apk add --no-cache jq + COPY entrypoint.sh /entrypoint.sh COPY output_with_summary.tmpl /output_with_summary.tmpl diff --git a/README.md b/README.md index f9fafc1..40a9f70 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ This action is using Grype to scan for CVEs in given image. ## Example Usage +Build a local image and scan it for CVEs. It will fail the workflow if any CVE with `medium` severity is found. It will ignore CVEs with IDs `CVE-2021-1234` and `CVE-2021-5678`. Default output format will be used (`table`) which will be printed to the standard output of the action. + ```yaml name: ksoc-image-scan @@ -15,29 +17,75 @@ on: jobs: ksoc-image-scan: permissions: + # only required for workflows in private repositories + actions: read contents: read runs-on: ubuntu-latest steps: - - name: build local container + - name: Build Local Container uses: docker/build-push-action@v4 with: tags: localbuild/testimage:latest push: false load: true - name: KSOC Image Scan - uses: ksoclabs/image-scan-action@v0.0.3 + uses: ksoclabs/image-scan-action@v0.0.4 with: - fail_on_severity: "medium" + fail_on_severity: medium ignore_cves: | CVE-2021-1234 CVE-2021-5678 - image: "localbuild/testimage:latest" + image: localbuild/testimage:latest ``` -Above example shows how to build a local image and scan it for CVEs. It will fail the workflow if any CVE with `medium` severity is found. If `fail_on_severity` input is not provided, the action won't fail. +This action also supports SARIF output format. Note the additional permission `security-events: write` which is required to upload security report. + +```yaml +name: ksoc-image-scan + +on: + pull_request: + +jobs: + ksoc-image-scan: + permissions: + # required for all workflows + security-events: write + # only required for workflows in private repositories + actions: read + contents: read + runs-on: ubuntu-latest + steps: + - name: Build Local Container + uses: docker/build-push-action@v4 + with: + tags: localbuild/testimage:latest + push: false + load: true + - name: KSOC Image Scan + id: scan + uses: ksoclabs/image-scan-action@v0.0.4 + with: + fail_on_severity: medium + format: sarif + ignore_cves: | + CVE-2021-1234 + CVE-2021-5678 + image: localbuild/testimage:latest + - name: Upload Image Scan SARIF Report + if: success() || failure() + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: ${{ steps.scan.outputs.sarif }} +``` ## Inputs - `fail_on_severity`: The severity level that will cause the action to fail. If not provided, the action doesn't fail. Possible values are `negligible`, `low`, `medium`, `high` and `critical`. +- `format`: The output format of the action. Possible values are `table` and `sarif`. If not provided, the default value is `table`. - `ignore_cves`: A multiline string of CVEs to ignore. Each line should contain a single CVE ID. If not provided, no CVEs will be ignored. - `image`: The image to scan. This is a required input. + +## Outputs + +- `sarif`: Location of the SARIF output file of the action. This output is only available if `format` input is set to `sarif`. diff --git a/action.yaml b/action.yaml index 9cba0b0..07da0e4 100644 --- a/action.yaml +++ b/action.yaml @@ -9,17 +9,25 @@ inputs: fail_on_severity: required: false description: "The severity level at which to fail the workflow. Valid values are: negligible, low, medium, high, critical." + format: + required: false + description: "The format of the output. Valid values are: table, sarif." + default: table ignore_cves: required: false description: "List of CVEs to ignore." image: required: false description: "Image to scan." +outputs: + sarif: + description: "Path to a SARIF report file for the image" runs: using: docker image: Dockerfile env: FAIL_ON_SEVERITY: ${{ inputs.fail_on_severity }} + FORMAT: ${{ inputs.format }} IGNORE_CVES: ${{ inputs.ignore_cves }} IMAGE: ${{ inputs.image }} diff --git a/entrypoint.sh b/entrypoint.sh index 8316d49..cc10922 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,7 +1,18 @@ #!/bin/sh -l +SARIF_OUTPUT_FILE_NAME="./sarif_output.json" + [ -z ${FAIL_ON_SEVERITY} ] || PARAM_FAIL_ON_SEVERITY="-f ${FAIL_ON_SEVERITY}" +# Handle "table" and "sarif" output formats. +if [ "${FORMAT}" = "table" ]; then + PARAM_FORMAT="-o template -t /output_with_summary.tmpl" +elif [ "${FORMAT}" = "sarif" ]; then + PARAM_FORMAT="-o sarif --file $SARIF_OUTPUT_FILE_NAME" + echo "sarif=$SARIF_OUTPUT_FILE_NAME" >> $GITHUB_OUTPUT +fi + +# Ignoring CVEs requires a config file. if [ ! -z "${IGNORE_CVES}" ]; then echo "ignore:" > /config.yaml echo "Ignored CVEs:" @@ -12,4 +23,14 @@ if [ ! -z "${IGNORE_CVES}" ]; then PARAM_CONFIG="-c /config.yaml" fi -/grype --add-cpes-if-none -o template -t /output_with_summary.tmpl ${PARAM_CONFIG} ${PARAM_FAIL_ON_SEVERITY} ${IMAGE} +/grype --add-cpes-if-none ${PARAM_FORMAT} ${PARAM_CONFIG} ${PARAM_FAIL_ON_SEVERITY} ${IMAGE} +exit_code=$? + +# Add KSOC Image Scan reference to the SARIF report. +if [ "${FORMAT}" = "sarif" ]; then + tmp=$(mktemp) + jq '.runs[].tool.driver.name = "KSOC Image Scan using Grype"' $SARIF_OUTPUT_FILE_NAME > "$tmp" && mv "$tmp" $SARIF_OUTPUT_FILE_NAME + chmod 644 $SARIF_OUTPUT_FILE_NAME +fi + +exit $exit_code