From b04f11b8a81096f862e012586af4199338021453 Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Fri, 23 Oct 2026 11:55:37 +0530 Subject: [PATCH 1/2] fix: keep scan reports private and accessible to the runner Run the container as the invoking UID/GID with a writable temporary home. Finalize SARIF even after scanner failure, preserve the scanner exit status, and use private temporary files with explicit finalization errors. Add report and container-boundary regressions and exercise the local action in scan workflows. Signed-off-by: Gaurav Chaudhary --- .github/workflows/example-scan-image.yaml | 3 +- .github/workflows/example-scan.yaml | 3 +- .github/workflows/test.yaml | 4 + action.yml | 4 + entrypoint.sh | 47 +++++-- tests/action_test.sh | 8 ++ tests/report-container_test.sh | 128 ++++++++++++++++++ tests/report_test.sh | 150 ++++++++++++++++++++++ 8 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 tests/report-container_test.sh create mode 100644 tests/report_test.sh diff --git a/.github/workflows/example-scan-image.yaml b/.github/workflows/example-scan-image.yaml index ada24d4..aa398ab 100644 --- a/.github/workflows/example-scan-image.yaml +++ b/.github/workflows/example-scan-image.yaml @@ -9,7 +9,8 @@ jobs: security-events: write steps: - uses: actions/checkout@v3 - - uses: kubescape/github-action@main + # Exercise this checkout's action implementation in repository CI. + - uses: ./ continue-on-error: true with: image: quay.io/kubescape/kubescape:v3.0.3 diff --git a/.github/workflows/example-scan.yaml b/.github/workflows/example-scan.yaml index 6ab2fdf..21f0ee5 100644 --- a/.github/workflows/example-scan.yaml +++ b/.github/workflows/example-scan.yaml @@ -9,7 +9,8 @@ jobs: security-events: write steps: - uses: actions/checkout@v3 - - uses: kubescape/github-action@main + # Exercise this checkout's action implementation in repository CI. + - uses: ./ continue-on-error: true with: format: sarif diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d4017e9..9c6acd3 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -19,3 +19,7 @@ jobs: run: bash tests/entrypoint_test.sh - name: Run action command-construction tests run: bash tests/action_test.sh + - name: Run report finalization tests + run: bash tests/report_test.sh + - name: Run container report-access tests + run: bash tests/report-container_test.sh diff --git a/action.yml b/action.yml index 4231eb8..d062349 100644 --- a/action.yml +++ b/action.yml @@ -179,7 +179,11 @@ runs: INPUT_ARTIFACTS: ${{ inputs.artifacts }} KUBESCAPE_VERSION: ${{ steps.resolve_version.outputs.version }} run: | + # Reports stay owner-only; create them as the runner that consumes them. + # Numeric users need a writable HOME even without an /etc/passwd entry. docker run --rm \ + --user "$(id -u):$(id -g)" \ + -e HOME=/tmp \ -e GITHUB_ACTIONS=true \ -e GITHUB_WORKSPACE=/github/workspace \ -e GITHUB_REPOSITORY \ diff --git a/entrypoint.sh b/entrypoint.sh index 0f5621d..c720c84 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -129,10 +129,11 @@ fi # Do not log arguments containing account or registry credentials. echo "Running Kubescape scan" -"${scan_command[@]}" +scan_status=0 +"${scan_command[@]}" || scan_status=$? -# Post-processing for SARIF to ensure relative paths and remove results with empty URIs -if contains "${output_formats}" "sarif"; then +# Use a subshell so its temporary-file cleanup cannot affect the caller's traps. +normalize_sarif() ( actual_sarif="${output_file}" if [ ! -f "${actual_sarif}" ] && [ -f "${output_file}.sarif" ]; then actual_sarif="${output_file}.sarif" @@ -140,10 +141,13 @@ if contains "${output_formats}" "sarif"; then if [ -f "${actual_sarif}" ]; then echo "Normalizing paths and filtering invalid results in ${actual_sarif}..." + # mktemp keeps report contents private regardless of the caller's umask. + sarif_temp=$(mktemp -- "${actual_sarif}.XXXXXX") || exit 1 + trap 'rm -f -- "${sarif_temp}"' EXIT # 1. Clean up URIs # 2. Filter out results that have an empty URI (which GitHub rejects) - jq ' + if ! jq -e ' walk(if type == "object" and has("uri") and (.uri | type == "string") then .uri |= sub("^file:///github/workspace/"; "") | .uri |= sub("^/github/workspace/"; "") | @@ -155,21 +159,44 @@ if contains "${output_formats}" "sarif"; then .locations[0].physicalLocation.artifactLocation.uri != "" and .locations[0].physicalLocation.artifactLocation.uri != null )) - ' "${actual_sarif}" > "${actual_sarif}.tmp" && mv "${actual_sarif}.tmp" "${actual_sarif}" + ' -- "${actual_sarif}" > "${sarif_temp}"; then + echo "Failed to normalize SARIF file ${actual_sarif}" >&2 + exit 1 + fi + mv -f -- "${sarif_temp}" "${actual_sarif}" || exit 1 echo "Processing complete. Final URI list:" - jq -r '.runs[].results[].locations[0].physicalLocation.artifactLocation.uri' "${actual_sarif}" | head -n 20 + jq -r '.runs[].results[].locations[0].physicalLocation.artifactLocation.uri' -- "${actual_sarif}" | head -n 20 else - echo "Warning: SARIF file ${output_file} not found." + echo "SARIF file ${output_file} not found." >&2 + exit 1 fi +) + +# Threshold failures may still produce useful reports. Finalize them before +# returning the scanner's status, without turning a failed scan into success. +finalization_status=0 +if contains "${output_formats}" "sarif"; then + normalize_sarif || finalization_status=$? fi -if [ "$should_fix_files" = "true" ]; then +if contains "${output_formats}" "json"; then json_file="${output_file}" if [ ! -f "${json_file}" ] && [ -f "${output_file}.json" ]; then json_file="${output_file}.json" fi - if [ -f "${json_file}" ]; then - kubescape fix --no-confirm "${json_file}" + if [ ! -f "${json_file}" ]; then + echo "JSON file ${output_file} not found." >&2 + finalization_status=1 fi fi + +if [ "${scan_status}" -ne 0 ]; then + exit "${scan_status}" +fi +if [ "${finalization_status}" -ne 0 ]; then + exit "${finalization_status}" +fi +if [ "$should_fix_files" = "true" ]; then + kubescape fix --no-confirm "${json_file}" +fi diff --git a/tests/action_test.sh b/tests/action_test.sh index 40ebf50..57afb06 100644 --- a/tests/action_test.sh +++ b/tests/action_test.sh @@ -88,6 +88,14 @@ else fail "composite action keeps inputs data-only" fi +if grep -Fxq -- '--user' "${args_file}" && + grep -Fxq -- "$(id -u):$(id -g)" "${args_file}" && + grep -Fxq -- 'HOME=/tmp' "${args_file}"; then + pass "container uses the runner identity with a writable home" +else + fail "container uses the runner identity with a writable home" +fi + # Version input must not introduce shell code or container tag syntax. version_script="${test_root}/version.sh" awk ' diff --git a/tests/report-container_test.sh b/tests/report-container_test.sh new file mode 100644 index 0000000..f2e84bb --- /dev/null +++ b/tests/report-container_test.sh @@ -0,0 +1,128 @@ +#!/bin/bash + +# Exercise the composite action's actual run script across a container/runner +# filesystem boundary. The scanner fixture models the CLI's 0600/0750 policy; +# tests/report_test.sh covers finalization failures separately. +set -euo pipefail +repo_root=${REPO_UNDER_TEST:-$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd -P)} +runtime=${CONTAINER_RUNTIME:-docker} +test_root=$(mktemp -d) +image= +cleanup() { + if [ -n "$image" ]; then + "$runtime" image rm "$image" > /dev/null 2>&1 || true + fi + if [ "$runtime" = podman ]; then + podman unshare rm -rf -- "$test_root" + else + rm -rf -- "$test_root" + fi +} +trap cleanup EXIT +mkdir -p "${test_root}/context" "${test_root}/bin" +cp "${repo_root}/entrypoint.sh" "${test_root}/context/entrypoint.sh" +cat > "${test_root}/context/Dockerfile" <<'DOCKERFILE' +FROM alpine:latest +RUN apk add --no-cache bash git jq +COPY entrypoint.sh /entrypoint.sh +COPY kubescape /usr/local/bin/kubescape +ENTRYPOINT ["/entrypoint.sh"] +DOCKERFILE +cat > "${test_root}/context/kubescape" <<'SCANNER' +#!/bin/bash +set -e +umask "${TEST_UMASK:-0022}" +if [ "$1" = fix ]; then + printf '%s\n' fixed >> manifests/pod.yaml + exit 0 +fi +output=results +threshold= +while [ "$#" -gt 0 ]; do + case "$1" in + --output) output=$2; shift ;; + --severity-threshold) threshold=$2; shift ;; + esac + shift +done +mkdir -p "$HOME/.cache" "$(dirname -- "$output")" +if [ "${TEST_UMASK:-0022}" = 0077 ]; then + chmod 700 "$(dirname -- "$output")" +else + chmod 750 "$(dirname -- "$output")" +fi +printf '%s\n' cached > "$HOME/.cache/scanner" +printf '%s\n' '{"runs":[{"results":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"/github/workspace/manifests/pod.yaml"}}}]}]}]}' > "${output}.sarif" +printf '%s\n' '{}' > "${output}.json" +chmod 600 "${output}.sarif" "${output}.json" +[ "$threshold" != high ] +SCANNER +chmod +x "${test_root}/context/kubescape" +image="kubescape-action:report-test-$$" +"$runtime" build -q -t "$image" "${test_root}/context" + +awk ' + /^ - name: Run Kubescape scan$/ { in_step=1; next } + in_step && /^ run: \|$/ { in_run=1; next } + in_run && /^ / { sub(/^ /, ""); print; next } + in_run { exit } +' "${repo_root}/action.yml" > "${test_root}/run.sh" + +# Podman keep-id models a rootful Docker bind mount: explicit --user wins; +# without it, force the image's root default rather than keep-id's user default. +cat > "${test_root}/bin/docker" <<'RUNTIME' +#!/bin/bash +command=$1 +shift +if [ "$CONTAINER_RUNTIME" = podman ]; then + exec podman "$command" --security-opt label=disable --userns=keep-id --user 0:0 \ + -e "TEST_UMASK=$TEST_UMASK" "$@" +fi +exec "$CONTAINER_RUNTIME" "$command" -e "TEST_UMASK=$TEST_UMASK" "$@" +RUNTIME +chmod +x "${test_root}/bin/docker" + +for threshold in critical high autofix; do + for mask in 0022 0077; do + workspace="${test_root}/${threshold}-${mask}" + mkdir -p "${workspace}/manifests" + # Allow both baseline root and candidate runner to create outputs, so a + # baseline failure is report access, not inability to start the scan. + chmod 777 "$workspace" + printf '%s\n' original > "${workspace}/manifests/pod.yaml" + report='reports with spaces/nested/results' + status=0 + ( + export CONTAINER_RUNTIME=$runtime PATH="${test_root}/bin:${PATH}" + export TEST_UMASK=$mask + export GITHUB_WORKSPACE=$workspace KUBESCAPE_VERSION="report-test-$$" + export INPUT_ACCOUNT='' INPUT_ACCESSKEY='' INPUT_SERVER='' INPUT_FAILEDTHRESHOLD='' + export INPUT_COMPLIANCETHRESHOLD='' INPUT_EXCEPTIONS='' INPUT_CONTROLSCONFIG='' + export INPUT_ARTIFACTS='' INPUT_FRAMEWORKS=nsa INPUT_CONTROLS='' INPUT_FILES=manifests + export INPUT_IMAGE='' INPUT_REGISTRYUSERNAME='' INPUT_REGISTRYPASSWORD='' + export INPUT_VERBOSE=false INPUT_SEVERITYTHRESHOLD=$threshold + export INPUT_FORMAT=sarif,json INPUT_OUTPUTFILE=$report INPUT_FIXFILES=false + if [ "$threshold" = autofix ]; then + export INPUT_FIXFILES=true + fi + umask "$mask" + bash "${test_root}/run.sh" + ) > "${workspace}/log" 2>&1 || status=$? + expected_status=0 + [ "$threshold" != high ] || expected_status=1 + [ "$status" -eq "$expected_status" ] || { cat "${workspace}/log"; exit 1; } + for extension in sarif json; do + file="${workspace}/${report}.${extension}" + [ "$(stat -c '%a:%u:%g' "$file")" = "600:$(id -u):$(id -g)" ] + jq -e . "$file" > /dev/null + done + jq -e '.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri == "manifests/pod.yaml"' \ + "${workspace}/${report}.sarif" > /dev/null + if [ "$threshold" = autofix ]; then + grep -Fxq fixed "${workspace}/manifests/pod.yaml" + else + [ "$(cat "${workspace}/manifests/pod.yaml")" = original ] + fi + printf 'ok - runner reads private nested SARIF/JSON after %s scan (umask %s)\n' "$threshold" "$mask" + done +done diff --git a/tests/report_test.sh b/tests/report_test.sh new file mode 100644 index 0000000..1d507e3 --- /dev/null +++ b/tests/report_test.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +set -uo pipefail + +repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd -P) +entrypoint=${ENTRYPOINT_UNDER_TEST:-${repo_root}/entrypoint.sh} +test_root=$(mktemp -d) +trap 'rm -rf "${test_root}"' EXIT +passed=0 +failed=0 + +check() { + local description=$1 + shift + if "$@" > /dev/null; then + printf 'ok - %s\n' "$description" + passed=$((passed + 1)) + else + printf 'not ok - %s\n' "$description" + failed=$((failed + 1)) + fi +} + +mkdir -p "${test_root}/bin" +# The CLI is an external boundary. Model its private report modes and status; +# all report processing below executes the real action entrypoint and jq. +cat > "${test_root}/bin/kubescape" <<'STUB' +#!/bin/bash +set -e +if [ "$1" = fix ]; then + printf '%s\n' "$@" > fix-args + exit "${FIX_EXIT:-0}" +fi +output=results +formats=sarif +while [ "$#" -gt 0 ]; do + case "$1" in + --output) output=$2; shift ;; + --format) formats=$2; shift ;; + esac + shift +done +if [ "${REPORT_BEHAVIOR:-valid}" != missing ]; then + mkdir -p -m 750 -- "$(dirname -- "$output")" + if [[ "$formats" == *sarif* ]]; then + printf '%s\n' '{"runs":[{"results":[{"locations":[{"physicalLocation":{"artifactLocation":{"uri":"/github/workspace/manifests/pod.yaml"}}}]}]}]}' > "${output}.sarif" + chmod 600 -- "${output}.sarif" + if [ "${REPORT_BEHAVIOR:-valid}" = invalid ]; then + printf '%s\n' 'not JSON' > "${output}.sarif" + elif [ "${REPORT_BEHAVIOR:-valid}" = empty ]; then + : > "${output}.sarif" + fi + fi + if [[ "$formats" == *json* ]]; then + printf '%s\n' '{}' > "${output}.json" + chmod 600 -- "${output}.json" + fi +fi +exit "${SCANNER_EXIT:-0}" +STUB +chmod +x "${test_root}/bin/kubescape" + +run_case() { + local name=$1 scanner_exit=$2 behavior=${3:-valid} format=${4:-sarif} + local output=${5:-results} mask=${6:-0022} fix=${7:-false} fix_exit=${8:-0} + workspace="${test_root}/${name}" + mkdir -p "$workspace" + status=0 + ( + cd "$workspace" || exit 1 + umask "$mask" + export PATH="${test_root}/bin:${PATH}" SCANNER_EXIT=$scanner_exit + export REPORT_BEHAVIOR=$behavior FIX_EXIT=$fix_exit + export INPUT_ACCOUNT='' INPUT_ACCESSKEY='' INPUT_SERVER='' INPUT_FAILEDTHRESHOLD='' + export INPUT_COMPLIANCETHRESHOLD='' INPUT_EXCEPTIONS='' INPUT_CONTROLSCONFIG='' + export INPUT_ARTIFACTS='' INPUT_FRAMEWORKS=nsa INPUT_CONTROLS='' INPUT_FILES=. + export INPUT_IMAGE='' INPUT_REGISTRYUSERNAME='' INPUT_REGISTRYPASSWORD='' + export INPUT_SEVERITYTHRESHOLD=high INPUT_VERBOSE=false + export INPUT_FORMAT=$format INPUT_OUTPUTFILE=$output INPUT_FIXFILES=$fix + bash "$entrypoint" + ) > "${workspace}/log" 2>&1 || status=$? +} + +run_case threshold 1 +check "threshold failure keeps the scanner status" test "$status" -eq 1 +check "threshold failure still normalizes the produced SARIF" jq -e \ + '.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri == "manifests/pod.yaml"' \ + "${workspace}/results.sarif" + +run_case success 0 +check "successful scan stays successful" test "$status" -eq 0 +check "normalization preserves owner-only SARIF access" test \ + "$(stat -c %a "${workspace}/results.sarif")" = 600 + +run_case malformed 0 invalid +check "malformed SARIF fails an otherwise successful scan" test "$status" -ne 0 +check "failed normalization leaves the original report intact" grep -Fxq 'not JSON' "${workspace}/results.sarif" +check "failed normalization cleans up temporary files" test \ + "$(find "$workspace" -name 'results.sarif.*' | wc -l)" -eq 0 + +run_case scanner_and_normalizer_fail 9 invalid +check "scanner status takes precedence over a normalization error" test "$status" -eq 9 + +run_case missing 0 missing +check "missing requested SARIF fails an otherwise successful scan" test "$status" -ne 0 +run_case missing_scanner_failure 7 missing +check "failure without a report preserves the scanner status" test "$status" -eq 7 + +run_case json_only 0 valid json +check "JSON-only scan stays successful and private" test \ + "$status:$(stat -c %a "${workspace}/results.json")" = 0:600 +run_case missing_json 0 missing json +check "missing requested JSON fails an otherwise successful scan" test "$status" -ne 0 + +for mask in 0022 0077; do + run_case "nested_${mask}" 0 valid sarif,json 'reports with spaces/nested/results' "$mask" + report="${workspace}/reports with spaces/nested/results" + check "nested reports succeed under umask ${mask}" test "$status" -eq 0 + for extension in sarif json; do + check "nested ${extension} stays private under umask ${mask}" test \ + "$(stat -c %a "${report}.${extension}")" = 600 + check "nested ${extension} is valid JSON under umask ${mask}" jq -e . "${report}.${extension}" + done +done + +run_case autofix 0 valid sarif results 0022 true +check "autofix still succeeds and requests JSON automatically" test "$status" -eq 0 +check "autofix receives the generated report" grep -Fxq 'results.json' "${workspace}/fix-args" +check "autofix JSON stays private" test "$(stat -c %a "${workspace}/results.json")" = 600 +run_case failed_autofix 0 valid sarif results 0022 true 6 +check "autofix errors are not swallowed" test "$status" -eq 6 +run_case failed_scan_with_autofix 3 valid sarif results 0022 true +check "failed scan with autofix preserves its status" test "$status" -eq 3 +check "failed scan does not run autofix" test ! -e "${workspace}/fix-args" + +run_case leading_dash 0 valid sarif -report +check "leading-dash report names normalize successfully" test "$status" -eq 0 +check "leading-dash report paths are actually normalized" jq -e \ + '.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri == "manifests/pod.yaml"' \ + "${workspace}/-report.sarif" + +run_case empty_report 0 empty +check "empty SARIF fails an otherwise successful scan" test "$status" -ne 0 +run_case empty_report_failed_scan 7 empty +check "empty SARIF does not mask the scanner failure" test "$status" -eq 7 +check "empty SARIF is reported as a normalization failure" grep -Fq \ + 'Failed to normalize SARIF' "${workspace}/log" + +printf '%s passed, %s failed\n' "$passed" "$failed" +[ "$failed" -eq 0 ] From 83e2342c8ba2d5985875de989a534bd887259e0d Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Fri, 23 Oct 2026 12:25:06 +0530 Subject: [PATCH 2/2] fix: exercise local autofix action and resolve test runtime Run the unprivileged autofix scan against the checked-out action so its JSON reports use the runner identity. Resolve the container test runtime before shadowing Docker on PATH to avoid recursive shim execution. Add workflow-selection and bounded default-Docker dispatch regressions. Signed-off-by: Gaurav Chaudhary --- .github/workflows/example-fix-pr-review.yaml | 3 +- tests/action_test.sh | 41 ++++++++++++++++++++ tests/report-container_test.sh | 13 ++++--- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/.github/workflows/example-fix-pr-review.yaml b/.github/workflows/example-fix-pr-review.yaml index 3fe0101..2e3022d 100644 --- a/.github/workflows/example-fix-pr-review.yaml +++ b/.github/workflows/example-fix-pr-review.yaml @@ -16,7 +16,8 @@ jobs: persist-credentials: false # Scan the workspace rather than interpolating changed filenames into inputs. # Fork contents are analyzed without repository secrets or write permissions. - - uses: kubescape/github-action@main + # Exercise this checkout's action implementation in repository CI. + - uses: ./ with: files: . fixFiles: true diff --git a/tests/action_test.sh b/tests/action_test.sh index 57afb06..4c7f72a 100644 --- a/tests/action_test.sh +++ b/tests/action_test.sh @@ -96,6 +96,47 @@ else fail "container uses the runner identity with a writable home" fi +# All report-producing CI examples must exercise the checkout under test rather +# than a separately downloaded upstream action that may not contain the fix. +for workflow in example-scan.yaml example-scan-image.yaml example-fix-pr-review.yaml; do + workflow_file="${repo_root}/.github/workflows/${workflow}" + if grep -Eq '^ - uses: \./$' "$workflow_file" && + ! grep -Eq '^ - uses: kubescape/github-action@' "$workflow_file"; then + pass "${workflow} scans with the checked-out action" + else + fail "${workflow} scans with the checked-out action" + fi +done + +# Exercise the container test's default Docker route without a daemon. The fake +# runtime stops the first run deliberately; reaching it proves that the inner +# Docker shim delegates instead of resolving itself again through PATH. +probe_bin="${test_root}/runtime-probe/bin" +probe_args="${test_root}/runtime-probe/args" +mkdir -p "$probe_bin" +cat > "${probe_bin}/docker" <<'PROBE' +#!/bin/bash +if [ "$1" = run ]; then + printf '%s\n' "$@" > "$PROBE_ARGS_FILE" + exit 88 +fi +exit 0 +PROBE +chmod +x "${probe_bin}/docker" +probe_status=0 +timeout 5s env -u CONTAINER_RUNTIME \ + PATH="${probe_bin}:${PATH}" PROBE_ARGS_FILE="$probe_args" \ + bash "${repo_root}/tests/report-container_test.sh" \ + > "${test_root}/runtime-probe/log" 2>&1 || probe_status=$? +if [ "$probe_status" -eq 1 ] && [ -f "$probe_args" ] && + [ "$(grep -Fxc -- run "$probe_args")" -eq 1 ] && + grep -Fxq -- 'TEST_UMASK=0022' "$probe_args" && + grep -Fxq -- 'INPUT_OUTPUTFILE=reports with spaces/nested/results' "$probe_args"; then + pass "default Docker container test reaches the configured runtime once" +else + fail "default Docker container test reaches the configured runtime once" +fi + # Version input must not introduce shell code or container tag syntax. version_script="${test_root}/version.sh" awk ' diff --git a/tests/report-container_test.sh b/tests/report-container_test.sh index f2e84bb..719aadc 100644 --- a/tests/report-container_test.sh +++ b/tests/report-container_test.sh @@ -6,14 +6,16 @@ set -euo pipefail repo_root=${REPO_UNDER_TEST:-$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd -P)} runtime=${CONTAINER_RUNTIME:-docker} +# Resolve before the scan subshell shadows docker on PATH with its test shim. +runtime_bin=$(command -v "$runtime") test_root=$(mktemp -d) image= cleanup() { if [ -n "$image" ]; then - "$runtime" image rm "$image" > /dev/null 2>&1 || true + "$runtime_bin" image rm "$image" > /dev/null 2>&1 || true fi if [ "$runtime" = podman ]; then - podman unshare rm -rf -- "$test_root" + "$runtime_bin" unshare rm -rf -- "$test_root" else rm -rf -- "$test_root" fi @@ -59,7 +61,7 @@ chmod 600 "${output}.sarif" "${output}.json" SCANNER chmod +x "${test_root}/context/kubescape" image="kubescape-action:report-test-$$" -"$runtime" build -q -t "$image" "${test_root}/context" +"$runtime_bin" build -q -t "$image" "${test_root}/context" awk ' /^ - name: Run Kubescape scan$/ { in_step=1; next } @@ -75,10 +77,10 @@ cat > "${test_root}/bin/docker" <<'RUNTIME' command=$1 shift if [ "$CONTAINER_RUNTIME" = podman ]; then - exec podman "$command" --security-opt label=disable --userns=keep-id --user 0:0 \ + exec "$CONTAINER_RUNTIME_BIN" "$command" --security-opt label=disable --userns=keep-id --user 0:0 \ -e "TEST_UMASK=$TEST_UMASK" "$@" fi -exec "$CONTAINER_RUNTIME" "$command" -e "TEST_UMASK=$TEST_UMASK" "$@" +exec "$CONTAINER_RUNTIME_BIN" "$command" -e "TEST_UMASK=$TEST_UMASK" "$@" RUNTIME chmod +x "${test_root}/bin/docker" @@ -94,6 +96,7 @@ for threshold in critical high autofix; do status=0 ( export CONTAINER_RUNTIME=$runtime PATH="${test_root}/bin:${PATH}" + export CONTAINER_RUNTIME_BIN=$runtime_bin export TEST_UMASK=$mask export GITHUB_WORKSPACE=$workspace KUBESCAPE_VERSION="report-test-$$" export INPUT_ACCOUNT='' INPUT_ACCESSKEY='' INPUT_SERVER='' INPUT_FAILEDTHRESHOLD=''