diff --git a/.github/actions/kosli-attest-veracode-executed/action.yml b/.github/actions/kosli-attest-veracode-executed/action.yml new file mode 100644 index 0000000..84d2d30 --- /dev/null +++ b/.github/actions/kosli-attest-veracode-executed/action.yml @@ -0,0 +1,35 @@ +name: Kosli Attest Veracode scan executed + +# Attest veracode executed +# https://docs.kosli.com/client_reference/kosli_attest_custom/ + + +inputs: + # The Following environment variables must be set in your GitHub action + # before using this composite + # env: + # KOSLI_ORG: kosli + # KOSLI_FLOW: your-flow-name + # KOSLI_TRAIL: your-trail-name (often git-commit-sha) + # KOSLI_API_TOKEN: "${{ secrets.KOSLI_API_TOKEN }}" + # KOSLI_CLI_VERSION: 2.11.6 + veracode-summary-file: + description: "Veracode summary file (output from create-veracode-summary-file.sh)" + required: true + +runs: + using: "composite" + steps: + - name: Setup Kosli cli + uses: kosli-dev/setup-cli-action@v2 + with: + version: + ${{ env.KOSLI_CLI_VERSION }} + + - name: Attest Veracode scan executed + shell: bash + run: | + kosli attest custom \ + --type=veracode-executed \ + --name veracode-executed \ + --attestation-data ${{ inputs.veracode-summary-file }} diff --git a/.github/workflows/build-backend.yml b/.github/workflows/build-backend.yml index f8802e2..d864afb 100644 --- a/.github/workflows/build-backend.yml +++ b/.github/workflows/build-backend.yml @@ -79,6 +79,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Run veracode scan + # We have not set up veracode, we just use some saved result files + run: cp testfiles/veracode-scan-no-errors.json static-scan-backend.json + + - name: Create veracode summary + run: ./scripts/create-veracode-summary-file.sh static-scan-backend.json static-scan-summary-backend.json + + - name: Attest veracode executed + if: ${{ github.ref == 'refs/heads/main' }} + uses: ./.github/actions/kosli-attest-veracode-executed + with: + veracode-summary-file: static-scan-summary-backend.json + + assert-artifacts: name: Assert artifacts if: ${{ github.ref == 'refs/heads/main' && always() }} diff --git a/.github/workflows/setup-kosli.yml b/.github/workflows/setup-kosli.yml index 3728f28..3fb7f3b 100644 --- a/.github/workflows/setup-kosli.yml +++ b/.github/workflows/setup-kosli.yml @@ -54,13 +54,12 @@ jobs: # --template-file kosli-release-template.yml ### Custom attestation types ### -# - name: Create approval-veracode attestation type -# run: -# kosli create attestation-type approval-veracode -# --description "Approval from Jira. Must have at least 1 approver and all approvers must have APPROVED it" -# --schema approval-veracode-schema.json -# --jq '(.approvers | length) > 0' -# --jq '[.approvers[].status == "APPROVED"] | all' + - name: Create veracode-executed attestation type + run: + kosli create attestation-type veracode-executed + --description "Attest that veracode scan was executed" + --schema kosli-setup/veracode-scan-schema.json + --jq '.scan_status == "SUCCESS"' ### environments ### diff --git a/apps/backend/backend-content.txt b/apps/backend/backend-content.txt index 1abdd24..8700813 100644 --- a/apps/backend/backend-content.txt +++ b/apps/backend/backend-content.txt @@ -1,4 +1,4 @@ This is just a file to test out that changes to back-end source code can trigger a build, reporting to Kosli -counter=3 +counter=4 diff --git a/kosli-setup/veracode-scan-schema.json b/kosli-setup/veracode-scan-schema.json new file mode 100644 index 0000000..4b0633a --- /dev/null +++ b/kosli-setup/veracode-scan-schema.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "required": ["scan_status", "severity_summary", "gob_summary"], + "properties": { + "severity_summary": { + "type": "object", + "required": ["severity_1", "severity_2", "severity_3", "severity_4", "severity_5"], + "properties": { + "severity_1": { "type": "integer", "minimum": 0 }, + "severity_2": { "type": "integer", "minimum": 0 }, + "severity_3": { "type": "integer", "minimum": 0 }, + "severity_4": { "type": "integer", "minimum": 0 }, + "severity_5": { "type": "integer", "minimum": 0 } + } + }, + "gob_summary": { + "type": "object", + "required": ["gob_a", "gob_b", "gob_c", "gob_d"], + "properties": { + "gob_a": { "type": "integer", "minimum": 0 }, + "gob_b": { "type": "integer", "minimum": 0 }, + "gob_c": { "type": "integer", "minimum": 0 }, + "gob_d": { "type": "integer", "minimum": 0 } + } + }, + "_links": { + "type": "object", + "properties": { + "root": { "$ref": "#/$defs/link" }, + "self": { "$ref": "#/$defs/link" }, + "help": { "$ref": "#/$defs/link" }, + "create": { "$ref": "#/$defs/link" }, + "start": { "$ref": "#/$defs/link" }, + "details": { "$ref": "#/$defs/link" }, + "upload": { "$ref": "#/$defs/link" }, + "cancel": { "$ref": "#/$defs/link" } + }, + "additionalProperties": false + }, + "scan_id": { "type": "string", "format": "uuid" }, + "scan_status": { "type": "string" }, + "message": { "type": "string" }, + "modules": { + "type": "array", + "items": { "type": "string" } + }, + "modules_count": { "type": "integer", "minimum": 0 }, + "selected_modules": { + "type": "array", + "items": { "type": "string" } + } + }, + "$defs": { + "link": { + "type": "object", + "required": ["href", "name", "templated"], + "properties": { + "href": { "type": "string" }, + "name": { "type": "string" }, + "templated": { "type": "boolean" } + } + } + }, + "additionalProperties": false +} diff --git a/kosli-source-template.yml b/kosli-source-template.yml deleted file mode 100644 index 609ba6f..0000000 --- a/kosli-source-template.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: 1 -trail: - attestations: - - name: work-reference - type: jira - - name: pull-request - type: pull_request diff --git a/scripts/create-veracode-summary-file.sh b/scripts/create-veracode-summary-file.sh new file mode 100755 index 0000000..f605b6f --- /dev/null +++ b/scripts/create-veracode-summary-file.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -Eeu + +SCRIPT_NAME=creat-veracode-summary-file.sh +ROOT_DIR=$(dirname $(readlink -f $0))/.. +INPUT_FILE="" +OUTPUT_FILE="" + +function print_help +{ + cat < [VERACODE-RESULT-FILE.json] [VERACODE-SUMMARY-FILE.json] + +Convert a veracode scan json file with a listing of all found issues +to a json file with a summary of how many findings there are for +each severity and gob (Grace of service) + +Options are: + -h Print this help menu +EOF +} + +function check_arguments +{ + while getopts "h" opt; do + case $opt in + h) + print_help + exit 1 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + esac + done + + # Remove options from command line + shift $((OPTIND-1)) + + if [ $# -ne 2 ]; then + echo "Missing file arguments" + exit 1 + fi + INPUT_FILE=$1; shift + OUTPUT_FILE=$1; shift +} + +main() +{ + check_arguments "$@" + # Count how many of each severity and gob. If there is no .findings, which is when there are + # no errors, we report 0 on all severity and gob. + jq '{ + severity_summary: { + severity_1: (.findings // [] | map(select(.severity == 1)) | length), + severity_2: (.findings // [] | map(select(.severity == 2)) | length), + severity_3: (.findings // [] | map(select(.severity == 3)) | length), + severity_4: (.findings // [] | map(select(.severity == 4)) | length), + severity_5: (.findings // [] | map(select(.severity == 5)) | length) + }, + gob_summary: { + gob_a: (.findings // [] | map(select(.gob == "A")) | length), + gob_b: (.findings // [] | map(select(.gob == "B")) | length), + gob_c: (.findings // [] | map(select(.gob == "C")) | length), + gob_d: (.findings // [] | map(select(.gob == "D")) | length) + } + } + del(.findings)' ${INPUT_FILE} > ${OUTPUT_FILE} + +} + +main "$@" diff --git a/testfiles/veracode-scan-errors-1.json b/testfiles/veracode-scan-errors-1.json new file mode 100644 index 0000000..40838d5 --- /dev/null +++ b/testfiles/veracode-scan-errors-1.json @@ -0,0 +1,150 @@ +{ + "_links": { + "root": { + "href": "/", + "name": "", + "templated": false + }, + "self": { + "href": "/scans/3f9bef4a-7ca6-4938-a64e-019192360bbb/findings", + "name": "", + "templated": false + }, + "help": { + "href": "https://docs.veracode.com/", + "name": "", + "templated": false + }, + "create": { + "href": "", + "name": "", + "templated": false + }, + "start": { + "href": "", + "name": "", + "templated": false + }, + "details": { + "href": "", + "name": "", + "templated": false + }, + "upload": { + "href": "", + "name": "", + "templated": false + }, + "cancel": { + "href": "", + "name": "", + "templated": false + } + }, + "scan_id": "3f9bef4a-7ca6-4938-a64e-019192360bbb", + "scan_status": "SUCCESS", + "message": "Scan successful. Results size: 476605 bytes", + "modules": [ + "JS files within example.zip" + ], + "modules_count": 1, + "findings": [ + { + "title": "console.error", + "issue_id": 1007, + "gob": "D", + "severity": 1, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1003, + "gob": "D", + "severity": 2, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1004, + "gob": "B", + "severity": 3, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1005, + "gob": "B", + "severity": 3, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1006, + "gob": "C", + "severity": 3, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1001, + "gob": "B", + "severity": 4, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1002, + "gob": "B", + "severity": 4, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + }, + { + "title": "console.error", + "issue_id": 1002, + "gob": "A", + "severity": 5, + "issue_type_id": "taint", + "issue_type": "Improper Output Neutralization for Logs", + "cwe_id": "117", + "display_text": "some message", + "stack_dumps": {}, + "flaw_details_link": "https://downloads.veracode.com/securityscan/cwe/v4/java/117.html" + } + ], + "selected_modules": [] +} \ No newline at end of file diff --git a/testfiles/veracode-scan-no-errors.json b/testfiles/veracode-scan-no-errors.json new file mode 100644 index 0000000..31f3971 --- /dev/null +++ b/testfiles/veracode-scan-no-errors.json @@ -0,0 +1,52 @@ +{ + "_links": { + "root": { + "href": "/", + "name": "", + "templated": false + }, + "self": { + "href": "/scans/3f9bef4a-7ca6-4938-a64e-019192360bbb/findings", + "name": "", + "templated": false + }, + "help": { + "href": "https://docs.veracode.com/", + "name": "", + "templated": false + }, + "create": { + "href": "", + "name": "", + "templated": false + }, + "start": { + "href": "", + "name": "", + "templated": false + }, + "details": { + "href": "", + "name": "", + "templated": false + }, + "upload": { + "href": "", + "name": "", + "templated": false + }, + "cancel": { + "href": "", + "name": "", + "templated": false + } + }, + "scan_id": "3f9bef4a-7ca6-4938-a64e-019192360bbb", + "scan_status": "SUCCESS", + "message": "Scan successful. Results size: 476605 bytes", + "modules": [ + "JS files within example.zip" + ], + "modules_count": 1, + "selected_modules": [] +} \ No newline at end of file