From c4e8d679bb37255933198ef46bb5f858bfee94d0 Mon Sep 17 00:00:00 2001 From: Ivanna Lisetska Date: Thu, 16 May 2024 17:36:28 -0600 Subject: [PATCH 1/2] fixed the annotation --- README.md | 22 +++++++----------- lib/snyk.sh | 43 +++++++--------------------------- tests/snyk.bats | 62 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 65 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index c129e30..1668ddf 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # Snyk Buildkite Plugin [![Build status](https://badge.buildkite.com/1d5cd674308d9572db45ebcb52aec5a32fd38b6763c3705b42.svg)](https://buildkite.com/buildkite/plugins-snyk) -A Buildkite plugin that runs [Snyk](https://snyk.io) tests in your Buildkite pipelines. The plugin requires a few dependencies install on your agents in order to function: +A Buildkite plugin that runs [Snyk](https://snyk.io) tests in your Buildkite pipelines. The plugin requires a few dependencies installed on your agents in order to function: [Snyk CLI](https://docs.snyk.io/snyk-cli/getting-started-with-the-snyk-cli) [snyk-to-html](https://docs.snyk.io/snyk-cli/scan-and-maintain-projects-using-the-cli/cli-tools/snyk-to-html) -Refer to the documentation for these tools to ensure they are installed on your agents before running the plugin. If you are using the [Buildkite Elastic CI Stack for AWS](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview), you will need to customise the [bootstrap script](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview) used by the stack. +Refer to the documentation for these tools to ensure they are installed on your agents before running the plugin. If you are using the [Buildkite Elastic CI Stack for AWS](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview), you will need to customize the [bootstrap script](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview) used by the stack. ## Options -These are all the options available to configure this plugin's behaviour. +These are all the options available to configure this plugin's behavior. ### Required @@ -19,7 +19,7 @@ The type of scan that the plugin will perform. Currently supported options are ` ### Optional -#### `token-env` (string) +#### `token-env` (string) The environment variable the plugin will reference to set `SNYK_TOKEN`. (default: `SNYK_TOKEN`) #### `org` (string) @@ -29,15 +29,14 @@ Your Snyk Organization slug, sets `SNYK_CFG_ORG`. The image and tag (example: `alpine:latest`) to pass to the container scan tool. #### `annotate` (bool) -Annotate the build according to the scan results. (default: FALSE) +Annotate the build according to the scan results. If set to `false`, no annotation will be created even if vulnerabilities are detected. (default: `false`) #### `block` (bool) -Optionally block the build on vulnerability detection - +Optionally block the build on vulnerability detection. ## Examples -Here are a few examples of using the plugin to scan within your Buildkite pipeline +Here are a few examples of using the plugin to scan within your Buildkite pipeline: ```yaml steps: @@ -47,10 +46,9 @@ steps: - snyk#v0.1.0: scan: 'oss' annotate: true - ``` -### And with other options as well +### And with other options as well: ```yaml steps: @@ -62,7 +60,6 @@ steps: annotate: true ``` - Scanning a docker container image by image name and tag: ```yaml @@ -74,7 +71,6 @@ steps: scan: 'container' annotate: true image: 'alpine:latest' - ``` Block a build when a vulnerability is detected: @@ -105,4 +101,4 @@ bk local run ## 📜 License -The package is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). +The package is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). \ No newline at end of file diff --git a/lib/snyk.sh b/lib/snyk.sh index 911876a..726eacd 100644 --- a/lib/snyk.sh +++ b/lib/snyk.sh @@ -2,10 +2,7 @@ set -euo pipefail - function configure_plugin() { - - # PLUGIN_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)/.." # Set token for the SNYK cli (either Service Account or User token) if [ -z "${BUILDKITE_PLUGIN_SNYK_TOKEN_ENV:-}" ]; then export SNYK_TOKEN="${SNYK_TOKEN?No token set}" @@ -34,14 +31,13 @@ function configure_plugin() { fi # Check for annotate attribute in plugin config - if ! [[ "${BUILDKITE_PLUGIN_SNYK_ANNOTATE}" ]]; then + if [[ "${BUILDKITE_PLUGIN_SNYK_ANNOTATE:-}" == "false" ]]; then annotate=false else annotate=true fi } -# Snyk Scans based on the provided scan tool function snyk_scan() { case "${scan_tool}" in oss) @@ -59,21 +55,16 @@ function snyk_scan() { } function snyk_oss_test () { - json_output_file="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-oss.json" echo "--- Running Snyk OSS scan" - # capture the exit code to use for formatting the annotation later (https://docs.snyk.io/snyk-cli/commands/code-test#exit-codes) - # and checking if we need to block the build exit_code=0 snyk test --json-file-output="${json_output_file}" || exit_code=$? - upload_results "${json_output_file}" "oss" - # Only create the annotation if annotate: true is added to the plugin config, default is "false" - if [[ "${annotate}" ]]; then + if [[ "${annotate}" == "true" ]]; then annotate_build "${exit_code}" "oss" fi @@ -82,22 +73,18 @@ function snyk_oss_test () { fi } -# Runs Snyk Code tests function snyk_code_test () { json_output_file="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-code.json" echo "--- Running Snyk Code scan" - # capture the exit code to use for formatting the annotation later (https://docs.snyk.io/snyk-cli/commands/code-test#exit-codes) exit_code=0 snyk code test --json-file-output="${json_output_file}" || exit_code=$? - - # because snyk code doesn't always create a json file, we need to check if one exists + if [ -f "${json_output_file}" ]; then upload_results "${json_output_file}" "code" - # Only create the annotation if annotate: true is added to the plugin config, default is "false" - if [[ "${annotate}" ]]; then + if [[ "${annotate}" == "true" ]]; then annotate_build "${exit_code:0}" "code" fi fi @@ -105,23 +92,19 @@ function snyk_code_test () { if [[ "${exit_code}" != 0 && "${BUILDKITE_PLUGIN_SNYK_BLOCK:-}" == true ]]; then block_build fi - } -# Run container test against a container image built as part of the job -# TODO: implement container tests entirely function snyk_container_test() { json_output_file="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-container.json" echo "--- Running Snyk Container scan" if [[ -n "${CONTAINER_IMAGE}" ]]; then exit_code=0 snyk container test "${CONTAINER_IMAGE:-}" --json-file-output="${json_output_file}" || exit_code=$? - + upload_results "${json_output_file}" "container" - # Only create the annotation if annotate: true is added to the plugin config, default is "false" - if [[ "${annotate}" ]]; then - annotate_build "${exit_code}" "container" + if [[ "${annotate}" == "true" ]]; then + annotate_build "${exit_code}" "container" fi else echo "no container image provided" @@ -133,8 +116,6 @@ function snyk_container_test() { fi } - -# Blocks the build if BUILDKITE_PLUGIN_SNYK_BLOCK=true and vulnerabilities are detected function block_build() { echo "Snyk detected vulnerabilities in the test, blocking build" @@ -144,23 +125,18 @@ function block_build() { EOF } - -# Format the JSON results from the test into nice HTML and add a build artifact function upload_results() { json_result_file=$1 ctx=$2 html_artifact="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-${ctx}.html" - # convert the json results to an HTML file snyk-to-html -i "${json_result_file}" -o "${html_artifact}" echo "--- Uploading artifacts" buildkite-agent artifact upload "${html_artifact}" } - -# format the output into an annotation with a link to the full report as an artifact function annotate_build() { exit_code=$1 ctx=$2 @@ -174,14 +150,13 @@ function annotate_build() { style="success" message="

Snyk test completed and uploaded the results as a build artifact.

" fi - + annotation=$(cat << EOF

Snyk ${ctx} test

${message} View Complete Scan Result EOF ) - + buildkite-agent annotate "${annotation}" --style "${style}" --context "${ctx}" } - diff --git a/tests/snyk.bats b/tests/snyk.bats index aecd757..467f0a0 100644 --- a/tests/snyk.bats +++ b/tests/snyk.bats @@ -20,6 +20,11 @@ setup() { export BUILDKITE_PLUGIN_SNYK_ANNOTATE=false } +teardown() { + unstub snyk || true + unstub snyk-to-html || true + unstub buildkite-agent || true +} @test "missing snyk token causes plugin to fail" { unset BUILDKITE_PLUGIN_SNYK_TOKEN_ENV @@ -32,11 +37,6 @@ setup() { refute_output --partial 'Running plugin' } -@test "setting token env attribute sets snyk token" { - -} - - @test "oss option runs Snyk OSS scan" { BUILDKITE_PLUGIN_SNYK_SCAN='oss' @@ -54,10 +54,6 @@ setup() { assert_success assert_output --partial 'Scanning OSS' - - unstub snyk - unstub snyk-to-html - unstub buildkite-agent } @test "code option runs Snyk code scan" { @@ -70,8 +66,6 @@ setup() { assert_success assert_output --partial 'Scanning Code' - - unstub snyk } @test "container option runs Snyk container scan" { @@ -91,8 +85,46 @@ setup() { assert_success assert_output --partial 'Scanning Container llama' +} + +@test "snyk plugin does not annotate when annotate is false" { + export BUILDKITE_PLUGIN_SNYK_ANNOTATE=false + BUILDKITE_PLUGIN_SNYK_SCAN='oss' - unstub snyk - unstub snyk-to-html - unstub buildkite-agent -} \ No newline at end of file + stub snyk \ + "test --json-file-output=${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-oss.json : echo 'Scanning OSS'" + + stub snyk-to-html \ + "-i ${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-oss.json -o ${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-oss.html : echo 'created artifact'" + + stub buildkite-agent \ + "artifact upload ${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-oss.html : exit 0" \ + "annotate \* \* \* \* \* : exit 0" + + run "$PWD"/hooks/post-command + + assert_success + assert_output --partial 'Scanning OSS' + refute_output --partial 'annotate' +} + +@test "snyk plugin annotates when annotate is true" { + export BUILDKITE_PLUGIN_SNYK_ANNOTATE=true + BUILDKITE_PLUGIN_SNYK_SCAN='oss' + + stub snyk \ + "test --json-file-output=${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-oss.json : echo 'Scanning OSS'" + + stub snyk-to-html \ + "-i ${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-oss.json -o ${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-oss.html : echo 'created artifact'" + + stub buildkite-agent \ + "artifact upload ${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-oss.html : exit 0" \ + "annotate \* \* \* \* \* : echo 'Annotation created'" + + run "$PWD"/hooks/post-command + + assert_success + assert_output --partial 'Scanning OSS' + assert_output --partial 'Annotation created' +} From 4ff6e3c3cf697271d33241cebf0b0020e7fb66fe Mon Sep 17 00:00:00 2001 From: Ivanna Lisetska Date: Thu, 16 May 2024 18:07:22 -0600 Subject: [PATCH 2/2] fix annotation --- README.md | 6 +++--- lib/snyk.sh | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1668ddf..a6aae91 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # Snyk Buildkite Plugin [![Build status](https://badge.buildkite.com/1d5cd674308d9572db45ebcb52aec5a32fd38b6763c3705b42.svg)](https://buildkite.com/buildkite/plugins-snyk) -A Buildkite plugin that runs [Snyk](https://snyk.io) tests in your Buildkite pipelines. The plugin requires a few dependencies installed on your agents in order to function: +A Buildkite plugin that runs [Snyk](https://snyk.io) tests in your Buildkite pipelines. The plugin requires a few dependencies install on your agents in order to function: [Snyk CLI](https://docs.snyk.io/snyk-cli/getting-started-with-the-snyk-cli) [snyk-to-html](https://docs.snyk.io/snyk-cli/scan-and-maintain-projects-using-the-cli/cli-tools/snyk-to-html) -Refer to the documentation for these tools to ensure they are installed on your agents before running the plugin. If you are using the [Buildkite Elastic CI Stack for AWS](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview), you will need to customize the [bootstrap script](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview) used by the stack. +Refer to the documentation for these tools to ensure they are installed on your agents before running the plugin. If you are using the [Buildkite Elastic CI Stack for AWS](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview), you will need to customise the [bootstrap script](https://buildkite.com/docs/agent/v3/elastic-ci-aws/elastic-ci-stack-overview) used by the stack. ## Options -These are all the options available to configure this plugin's behavior. +These are all the options available to configure this plugin's behaviour. ### Required diff --git a/lib/snyk.sh b/lib/snyk.sh index 726eacd..df5d61e 100644 --- a/lib/snyk.sh +++ b/lib/snyk.sh @@ -3,6 +3,8 @@ set -euo pipefail function configure_plugin() { + + # PLUGIN_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)/.." # Set token for the SNYK cli (either Service Account or User token) if [ -z "${BUILDKITE_PLUGIN_SNYK_TOKEN_ENV:-}" ]; then export SNYK_TOKEN="${SNYK_TOKEN?No token set}" @@ -38,6 +40,7 @@ function configure_plugin() { fi } +# Snyk Scans based on the provided scan tool function snyk_scan() { case "${scan_tool}" in oss) @@ -59,11 +62,15 @@ function snyk_oss_test () { echo "--- Running Snyk OSS scan" + # capture the exit code to use for formatting the annotation later (https://docs.snyk.io/snyk-cli/commands/code-test#exit-codes) + # and checking if we need to block the build + exit_code=0 snyk test --json-file-output="${json_output_file}" || exit_code=$? upload_results "${json_output_file}" "oss" + # Only create the annotation if annotate: true is added to the plugin config, default is "false" if [[ "${annotate}" == "true" ]]; then annotate_build "${exit_code}" "oss" fi @@ -73,14 +80,17 @@ function snyk_oss_test () { fi } +# Runs Snyk Code tests function snyk_code_test () { json_output_file="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-code.json" echo "--- Running Snyk Code scan" + # capture the exit code to use for formatting the annotation later (https://docs.snyk.io/snyk-cli/commands/code-test#exit-codes) exit_code=0 snyk code test --json-file-output="${json_output_file}" || exit_code=$? + # because snyk code doesn't always create a json file, we need to check if one exists if [ -f "${json_output_file}" ]; then upload_results "${json_output_file}" "code" @@ -94,6 +104,8 @@ function snyk_code_test () { fi } +# Run container test against a container image built as part of the job +# TODO: implement container tests entirely function snyk_container_test() { json_output_file="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-snyk-container.json" echo "--- Running Snyk Container scan" @@ -102,7 +114,8 @@ function snyk_container_test() { snyk container test "${CONTAINER_IMAGE:-}" --json-file-output="${json_output_file}" || exit_code=$? upload_results "${json_output_file}" "container" - + + # Only create the annotation if annotate: true is added to the plugin config, default is "false" if [[ "${annotate}" == "true" ]]; then annotate_build "${exit_code}" "container" fi @@ -116,6 +129,7 @@ function snyk_container_test() { fi } +# Blocks the build if BUILDKITE_PLUGIN_SNYK_BLOCK=true and vulnerabilities are detected function block_build() { echo "Snyk detected vulnerabilities in the test, blocking build" @@ -131,12 +145,14 @@ function upload_results() { html_artifact="${BUILDKITE_PIPELINE_SLUG}-${BUILDKITE_BUILD_NUMBER}-${ctx}.html" + # convert the json results to an HTML file snyk-to-html -i "${json_result_file}" -o "${html_artifact}" echo "--- Uploading artifacts" buildkite-agent artifact upload "${html_artifact}" } +# format the output into an annotation with a link to the full report as an artifact function annotate_build() { exit_code=$1 ctx=$2