From f97619eaf355a0b29c64b9ccd962a20492ebf178 Mon Sep 17 00:00:00 2001 From: Ruud Senden <8635138+rsenden@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:03:16 +0200 Subject: [PATCH] feat: Add ssc-scan action, supporting both SC-SAST & Debricked --- internal/fod-login/action.yml | 4 +-- internal/run-script-js/action.yml | 11 ++----- internal/run-script-js/main.js | 16 ++------- internal/run-script-js/post.js | 14 ++++++++ internal/run-script/action.yml | 13 ++------ .../run-script/{util => scripts}/common.sh | 7 +++- .../scripts}/fod-login.sh | 3 +- .../scripts}/fod-logout.sh | 3 +- .../scripts}/sc-sast-login.sh | 3 +- .../scripts}/sc-sast-logout.sh | 3 +- .../scripts}/ssc-login.sh | 3 +- .../scripts}/ssc-logout.sh | 3 +- internal/run-script/scripts/ssc-scan.sh | 33 +++++++++++++++++++ internal/sc-sast-login/action.yml | 4 +-- internal/ssc-login/action.yml | 4 +-- ssc-scan/action.yml | 25 ++++++++++++++ 16 files changed, 104 insertions(+), 45 deletions(-) create mode 100644 internal/run-script-js/post.js rename internal/run-script/{util => scripts}/common.sh (80%) rename internal/{fod-login => run-script/scripts}/fod-login.sh (84%) rename internal/{fod-login => run-script/scripts}/fod-logout.sh (70%) rename internal/{sc-sast-login => run-script/scripts}/sc-sast-login.sh (72%) rename internal/{sc-sast-login => run-script/scripts}/sc-sast-logout.sh (64%) rename internal/{ssc-login => run-script/scripts}/ssc-login.sh (80%) rename internal/{ssc-login => run-script/scripts}/ssc-logout.sh (85%) create mode 100755 internal/run-script/scripts/ssc-scan.sh create mode 100644 ssc-scan/action.yml diff --git a/internal/fod-login/action.yml b/internal/fod-login/action.yml index 82a3275..4e8963d 100644 --- a/internal/fod-login/action.yml +++ b/internal/fod-login/action.yml @@ -11,8 +11,8 @@ runs: if: ${{ !env._FOD_LOGGED_IN }} with: dir: ${{ github.action_path }} - script: ./fod-login.sh - post: ./fod-logout.sh + script: fod-login.sh + post: fod-logout.sh branding: icon: 'shield' diff --git a/internal/run-script-js/action.yml b/internal/run-script-js/action.yml index b1055b9..1eafef1 100644 --- a/internal/run-script-js/action.yml +++ b/internal/run-script-js/action.yml @@ -10,17 +10,10 @@ inputs: description: 'Script to run on job completion' required: false dir: - description: 'Directory where scripts are located, should usually be set to github.action_path' + description: 'Directory where scripts are located, set automatically by internal/run-script action' required: true - util: - description: 'Directory where utility scripts are located, set automatically by internal/run-script action' - required: true - key: - description: 'Name of the state variable used to detect the post step.' - required: false - default: POST runs: using: 'node20' main: 'main.js' - post: 'main.js' + post: 'post.js' diff --git a/internal/run-script-js/main.js b/internal/run-script-js/main.js index 57d111c..075ad0b 100644 --- a/internal/run-script-js/main.js +++ b/internal/run-script-js/main.js @@ -1,12 +1,9 @@ const { spawn } = require("child_process"); -const { appendFileSync } = require("fs"); -const { EOL } = require("os"); function run(script) { if ( script ) { - const dir = process.env.INPUT_DIR; - const utilDir = process.env.INPUT_UTIL; - const subprocess = spawn(`bash -c -o pipefail -v 'export UTIL_DIR=${utilDir}; ${dir}/${script}'`, + const scriptDir = process.env.INPUT_DIR; + const subprocess = spawn(`bash -c -o pipefail -v 'export UTIL_DIR=${scriptDir}; ${scriptDir}/${script}'`, { stdio: "inherit", shell: true }); subprocess.on("exit", (exitCode) => { process.exitCode = exitCode; @@ -14,11 +11,4 @@ function run(script) { } } -const key = process.env.INPUT_KEY.toUpperCase(); - -if ( process.env[`STATE_${key}`] !== undefined ) { // Are we in the 'post' step? - run(process.env.INPUT_POST); -} else { // Otherwise, this is the main step - appendFileSync(process.env.GITHUB_STATE, `${key}=true${EOL}`); - run(process.env.INPUT_SCRIPT); -} +run(process.env.INPUT_SCRIPT); diff --git a/internal/run-script-js/post.js b/internal/run-script-js/post.js new file mode 100644 index 0000000..c4c0fe8 --- /dev/null +++ b/internal/run-script-js/post.js @@ -0,0 +1,14 @@ +const { spawn } = require("child_process"); + +function run(script) { + if ( script ) { + const utilDir = process.env.INPUT_UTIL; + const subprocess = spawn(`bash -c -o pipefail -v 'export UTIL_DIR=${utilDir}; ${script}'`, + { stdio: "inherit", shell: true }); + subprocess.on("exit", (exitCode) => { + process.exitCode = exitCode; + }); + } +} + +run(process.env.INPUT_POST); diff --git a/internal/run-script/action.yml b/internal/run-script/action.yml index ad8ed16..11dff86 100644 --- a/internal/run-script/action.yml +++ b/internal/run-script/action.yml @@ -15,21 +15,14 @@ inputs: runs: using: composite steps: - # github.action_path uses platform-specific path format, like D:\... for Windows. - # The run-script-js action requires the path to be in bash format, so we convert - # the paths to bash format before invoking the run-script-js action. - - run: echo "BASH_SCRIPT_DIR=$(pwd)" >> $GITHUB_ENV - shell: bash - working-directory: ${{ inputs.dir }} - - run: echo "BASH_UTIL_DIR=$(pwd)/util" >> $GITHUB_ENV + - run: echo "_RUN_SCRIPTS_DIR=$(pwd)/scripts" >> $GITHUB_ENV shell: bash working-directory: ${{ github.action_path }} - uses: fortify/github-action/internal/run-script-js@feat-1.3.0 with: - util: ${{ env.BASH_UTIL_DIR }} - dir: ${{ env.BASH_SCRIPT_DIR }} + dir: ${{ env._RUN_SCRIPTS_DIR }} script: ${{ inputs.script }} - post: ${{ inputs.post }} + post: ${{ inputs.post }} branding: icon: 'shield' diff --git a/internal/run-script/util/common.sh b/internal/run-script/scripts/common.sh similarity index 80% rename from internal/run-script/util/common.sh rename to internal/run-script/scripts/common.sh index bbf6126..a033a0f 100644 --- a/internal/run-script/util/common.sh +++ b/internal/run-script/scripts/common.sh @@ -5,4 +5,9 @@ fi if [ -z "$FCLI_CMD" ]; then echo "ERROR: fortify/github-action/setup must be run to set up fcli before running this action" exit 1; -fi \ No newline at end of file +fi + +function run { + echo RUN: "$@" + "$@" +} diff --git a/internal/fod-login/fod-login.sh b/internal/run-script/scripts/fod-login.sh similarity index 84% rename from internal/fod-login/fod-login.sh rename to internal/run-script/scripts/fod-login.sh index 4e8c7a2..8b6c9c4 100755 --- a/internal/fod-login/fod-login.sh +++ b/internal/run-script/scripts/fod-login.sh @@ -12,5 +12,6 @@ else echo "ERROR: Either FOD_CLIENT_ID and FOD_CLIENT_SECRET, or FOD_TENANT, FOD_USER and FOD_PASSWORD environment variables must be set" exit 1; fi -${FCLI_CMD} fod session login --url "${FOD_URL}" "${_FOD_AUTH_OPTS[@]}" ${EXTRA_FOD_LOGIN_OPTS} || exit 1 +run ${FCLI_CMD} fod session login --url "${FOD_URL}" "${_FOD_AUTH_OPTS[@]}" ${EXTRA_FOD_LOGIN_OPTS} \ + || exit 1 echo '_FOD_LOGGED_IN=true' >> $GITHUB_ENV \ No newline at end of file diff --git a/internal/fod-login/fod-logout.sh b/internal/run-script/scripts/fod-logout.sh similarity index 70% rename from internal/fod-login/fod-logout.sh rename to internal/run-script/scripts/fod-logout.sh index 9efbef9..405c9e2 100755 --- a/internal/fod-login/fod-logout.sh +++ b/internal/run-script/scripts/fod-logout.sh @@ -3,5 +3,6 @@ if [[ "${_FOD_LOGGED_IN}" == "true" ]]; then echo '_FOD_LOGGED_IN=false' >> $GITHUB_ENV - ${FCLI_CMD} fod session logout || exit 1 + run ${FCLI_CMD} fod session logout \ + || exit 1 fi \ No newline at end of file diff --git a/internal/sc-sast-login/sc-sast-login.sh b/internal/run-script/scripts/sc-sast-login.sh similarity index 72% rename from internal/sc-sast-login/sc-sast-login.sh rename to internal/run-script/scripts/sc-sast-login.sh index 90cdf76..dbe761f 100755 --- a/internal/sc-sast-login/sc-sast-login.sh +++ b/internal/run-script/scripts/sc-sast-login.sh @@ -10,5 +10,6 @@ fi if [ -z "SSC_TOKEN" ]; then echo "ERROR: SSC_TOKEN environment variable must be set"; exit 1; fi -${FCLI_CMD} sc-sast session login --ssc-url "${SSC_URL}" -t "${SSC_TOKEN}" -c "${SC_SAST_TOKEN}" ${EXTRA_SC_SAST_LOGIN_OPTS} +run ${FCLI_CMD} sc-sast session login --ssc-url "${SSC_URL}" -t "${SSC_TOKEN}" -c "${SC_SAST_TOKEN}" ${EXTRA_SC_SAST_LOGIN_OPTS} \ + || exit 1 echo '_SC_SAST_LOGGED_IN=true' >> $GITHUB_ENV \ No newline at end of file diff --git a/internal/sc-sast-login/sc-sast-logout.sh b/internal/run-script/scripts/sc-sast-logout.sh similarity index 64% rename from internal/sc-sast-login/sc-sast-logout.sh rename to internal/run-script/scripts/sc-sast-logout.sh index a6f814a..dea2b55 100755 --- a/internal/sc-sast-login/sc-sast-logout.sh +++ b/internal/run-script/scripts/sc-sast-logout.sh @@ -3,5 +3,6 @@ if [[ "${_SC_SAST_LOGGED_IN}" == "true" ]]; then echo '_SC_SAST_LOGGED_IN=false' >> $GITHUB_ENV - ${FCLI_CMD} sc-sast session logout --no-revoke-token || exit 1 + run ${FCLI_CMD} sc-sast session logout --no-revoke-token \ + || exit 1 fi \ No newline at end of file diff --git a/internal/ssc-login/ssc-login.sh b/internal/run-script/scripts/ssc-login.sh similarity index 80% rename from internal/ssc-login/ssc-login.sh rename to internal/run-script/scripts/ssc-login.sh index 037a333..b8b506a 100755 --- a/internal/ssc-login/ssc-login.sh +++ b/internal/run-script/scripts/ssc-login.sh @@ -11,5 +11,6 @@ elif [ -n "${SSC_USER}" -a -n "${SSC_PASSWORD}" ]; then else echo "ERROR: Either SSC_TOKEN, or SSC_USER and SSC_PASSWORD environment variables must be set"; exit 1; fi -${FCLI_CMD} ssc session login --url "${SSC_URL}" "${_SSC_AUTH_OPTS[@]}" ${EXTRA_SSC_LOGIN_OPTS} +run ${FCLI_CMD} ssc session login --url "${SSC_URL}" "${_SSC_AUTH_OPTS[@]}" ${EXTRA_SSC_LOGIN_OPTS} \ + || exit 1 echo '_SSC_LOGGED_IN=true' >> $GITHUB_ENV \ No newline at end of file diff --git a/internal/ssc-login/ssc-logout.sh b/internal/run-script/scripts/ssc-logout.sh similarity index 85% rename from internal/ssc-login/ssc-logout.sh rename to internal/run-script/scripts/ssc-logout.sh index 5dbff85..0818f46 100755 --- a/internal/ssc-login/ssc-logout.sh +++ b/internal/run-script/scripts/ssc-logout.sh @@ -10,5 +10,6 @@ if [[ "${_SSC_LOGGED_IN}" == "true" ]]; then else echo "ERROR: Either SSC_TOKEN, or SSC_USER and SSC_PASSWORD environment variables must be set"; exit 1; fi - ${FCLI_CMD} ssc session logout "${_SSC_LOGOUT_OPTS[@]}" || exit 1 + run ${FCLI_CMD} ssc session logout "${_SSC_LOGOUT_OPTS[@]}" \ + || exit 1 fi \ No newline at end of file diff --git a/internal/run-script/scripts/ssc-scan.sh b/internal/run-script/scripts/ssc-scan.sh new file mode 100755 index 0000000..b2dad30 --- /dev/null +++ b/internal/run-script/scripts/ssc-scan.sh @@ -0,0 +1,33 @@ +#!/bin/bash +. ${UTIL_DIR}/common.sh + +# This script assumes that fcli and Debricked CLI have already been installed, +# and that any necessary fcli sessions have been created. +# TODO Check prerequisites like SSC_APPVERSION, DEBRICKED_TOKEN, ... + +if [ "${DO_SC_SAST_SCAN}" == "true" ]; then + run ${FCLI_CMD} sc-sast scan start --publish-to "${SSC_APPVERSION}" -p package.zip -v "${SC_SAST_SENSOR_VERSION}" --store sc_sast_scan ${EXTRA_SC_SAST_SCAN_OPTS} \ + || exit 1 +fi +if [ "${DO_DEBRICKED_SCAN}" == "true" ]; then + # Debricked may return non-zero exit code on automation rule failures, in which case + # we still want to run subsequent steps, hence we temporarily ignore the exit code, + run ${DEBRICKED_CLI_CMD} scan -t "${DEBRICKED_TOKEN}" -i "Fortify GitHub Action" \ + || FAIL_ON_EXIT=true + run ${FCLI_CMD} ssc artifact import-debricked --av "${SSC_APPVERSION}" --repository "${GITHUB_REPOSITORY}" --branch "${GITHUB_HEAD_REF:-$GITHUB_REF_NAME}" -t "${DEBRICKED_TOKEN}" --store debricked_scan \ + || exit 1 +fi +if [ "${DO_WAIT}" == "true" ] || [ "${DO_EXPORT}" == "true" ]; then + if [ "${DO_SC_SAST_SCAN}" == "true" ]; then + run ${FCLI_CMD} sc-sast scan wait-for ::sc_sast_scan:: \ + || exit 1 + fi + if [ "${DO_DEBRICKED_SCAN}" == "true" ]; then + run ${FCLI_CMD} ssc artifact wait-for ::debricked_scan:: \ + || exit 1 + fi +fi +if [ "${FAIL_ON_EXIT}" == "true" ]; then + echo "Earlier failures detected" + exit 1 +fi diff --git a/internal/sc-sast-login/action.yml b/internal/sc-sast-login/action.yml index 1d6010e..950cace 100644 --- a/internal/sc-sast-login/action.yml +++ b/internal/sc-sast-login/action.yml @@ -15,8 +15,8 @@ runs: if: ${{ !env._SC_SAST_LOGGED_IN }} with: dir: ${{ github.action_path }} - script: ./sc-sast-login.sh - post: ./sc-sast-logout.sh + script: sc-sast-login.sh + post: sc-sast-logout.sh branding: icon: 'shield' diff --git a/internal/ssc-login/action.yml b/internal/ssc-login/action.yml index 7e5412a..38c90a4 100644 --- a/internal/ssc-login/action.yml +++ b/internal/ssc-login/action.yml @@ -11,8 +11,8 @@ runs: if: ${{ !env._SSC_LOGGED_IN }} with: dir: ${{ github.action_path }} - script: ./ssc-login.sh - post: ./ssc-logout.sh + script: ssc-login.sh + post: ssc-logout.sh branding: icon: 'shield' color: 'blue' diff --git a/ssc-scan/action.yml b/ssc-scan/action.yml new file mode 100644 index 0000000..7b15573 --- /dev/null +++ b/ssc-scan/action.yml @@ -0,0 +1,25 @@ +name: 'Perform SAST scan' +description: 'Perform a SAST scan on ScanCentral SAST' +author: 'Fortify' +runs: + using: composite + steps: + - uses: fortify/github-action/setup@feat-1.3.0 + with: + export-path: false + fcli: action-default + debricked-cli: ${{ env.DO_DEBRICKED_SCAN=='true' && 'action-default' || 'skip' }} + - uses: fortify/github-action/internal/ssc-login@feat-1.3.0 + - uses: fortify/github-action/internal/sc-sast-login@feat-1.3.0 + - uses: fortify/github-action/package@feat-1.3.0 + - uses: fortify/github-action/internal/run-script@feat-1.3.0 + with: + dir: ${{ github.action_path }} + script: ssc-scan.sh + - if: env.DO_EXPORT == 'true' + uses: fortify/github-action/ssc-export@feat-1.3.0 + +branding: + icon: 'shield' + color: 'blue' +