diff --git a/.github/workflows/action-test.yml b/.github/workflows/action-test.yml index 79d355d..cd6b82d 100644 --- a/.github/workflows/action-test.yml +++ b/.github/workflows/action-test.yml @@ -142,10 +142,19 @@ jobs: set -uo pipefail mkdir -p _fx printf 'AWS_ACCESS_KEY_ID=%s%s\n' 'AKIA' 'IOSFODNN7EXAMPLE' > _fx/leak.env - # leakwatch exits 1 on findings; `|| true` so the capture doesn't abort - # the step under bash -e (GitHub's default shell flags). - out="$("${RUNNER_TEMP}/leakwatch" scan fs _fx --format github --no-verify 2>/dev/null || true)" + # leakwatch exits 1 on findings (expected here); capture the code so the + # step doesn't abort under bash -e, but still fail on a real error (>=2). + # Explicit if/else makes the exit-code capture obvious (an assignment's + # status mirrors its command substitution). + if out="$("${RUNNER_TEMP}/leakwatch" scan fs _fx --format github --no-verify 2>/dev/null)"; then + rc=0 + else + rc=$? + fi echo "$out" + if [ "$rc" -ge 2 ]; then + echo "::error::leakwatch exited with $rc (a hard error, not findings)"; exit 1 + fi echo "$out" | grep -q '^::error .*aws-access-key-id' \ - || { echo "::error::expected an ::error annotation for aws-access-key-id"; exit 1; } + || { echo "::error::expected an ::error annotation for aws-access-key-id (exit was $rc)"; exit 1; } echo "OK: --format github emitted an inline annotation" diff --git a/action.yml b/action.yml index 035af68..b20166c 100644 --- a/action.yml +++ b/action.yml @@ -289,12 +289,12 @@ runs: # Do NOT echo the assembled args: path/extra-args may carry credentials # (tokens, authenticated URLs) that GitHub log masking would not catch. echo "Running leakwatch scan (type=${INPUT_SCAN_TYPE}, format=${INPUT_FORMAT})" - # GitHub invokes bash with -e; findings legitimately exit 1, so disable - # errexit around the scan and map the exit code ourselves below (otherwise - # the step would abort here and fail-on-findings: false would be ignored). - set +e - leakwatch "${ARGS[@]}" - EXIT_CODE=$? + # GitHub invokes bash with -e, and findings legitimately exit 1. Capture + # the exit code without disabling errexit globally (via `|| EXIT_CODE=$?`), + # so later commands in this step still fail fast. Without this, the step + # would abort here and fail-on-findings: false would be ignored. + EXIT_CODE=0 + leakwatch "${ARGS[@]}" || EXIT_CODE=$? # ---- Job summary ------------------------------------------------------ if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then @@ -310,7 +310,17 @@ runs: echo "" echo "| Level | Detector | Location |" echo "| --- | --- | --- |" - jq -r '.runs[].results[] | "| \(.level) | \(.ruleId) | \((.locations[0].physicalLocation.artifactLocation.uri // "-"))\(if .locations[0].physicalLocation.region.startLine then ":" + (.locations[0].physicalLocation.region.startLine | tostring) else "" end) |"' "$OUT" 2>/dev/null | head -50 + # Render to a temp file first, then take the first 50 lines from + # it. Piping jq directly into `head` would give jq a SIGPIPE once + # head closes (after 50 lines), and under pipefail that non-zero + # status would trip the fallback even though the table rendered. + tbl="$(mktemp)" + if jq -r '.runs[].results[] | "| \(.level) | \(.ruleId) | \((.locations[0].physicalLocation.artifactLocation.uri // "-"))\(if .locations[0].physicalLocation.region.startLine then ":" + (.locations[0].physicalLocation.region.startLine | tostring) else "" end) |"' "$OUT" > "$tbl" 2>/dev/null && [ -s "$tbl" ]; then + head -n 50 "$tbl" + else + echo "_(could not render the findings table; see the SARIF artifact)_" + fi + rm -f "$tbl" if [ "${total:-0}" -gt 50 ] 2>/dev/null; then echo "" echo "_…showing the first 50 of ${total} findings._"