mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-06-11 05:46:05 +00:00
123 lines
4.1 KiB
Bash
Executable File
123 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run osv-scanner and fail when findings match the configured severity levels.
|
|
#
|
|
# Replaces `safety check --policy-file .safety-policy.yml`. Used by:
|
|
# - .github/actions/osv-scanner/action.yml (composite action)
|
|
# - .github/workflows/api-security.yml, sdk-security.yml, ui-security.yml
|
|
#
|
|
# Severity levels (comma-separated) are read from OSV_SEVERITY_LEVELS.
|
|
# Default: HIGH,CRITICAL,UNKNOWN — preserves prior .safety-policy.yml policy
|
|
# (ignore-cvss-severity-below: 7 + ignore-cvss-unknown-severity: False).
|
|
# osv-scanner has no native CVSS threshold (google/osv-scanner#1400, closed
|
|
# not-planned). Severity is derived from $group.max_severity (numeric CVSS
|
|
# score string) which osv-scanner emits per group.
|
|
#
|
|
# CVSS v3 score → categorical label:
|
|
# CRITICAL >= 9.0
|
|
# HIGH >= 7.0
|
|
# MEDIUM >= 4.0
|
|
# LOW > 0.0
|
|
# UNKNOWN no score available
|
|
#
|
|
# Per-vulnerability ignores (with reason + expiry) live in osv-scanner.toml at
|
|
# the repo root, if it exists. Without that file, osv-scanner uses defaults.
|
|
#
|
|
# Usage:
|
|
# osv-scan.sh [osv-scanner pass-through args...]
|
|
# Examples:
|
|
# osv-scan.sh --lockfile=uv.lock
|
|
# osv-scan.sh --recursive .
|
|
# OSV_SEVERITY_LEVELS=CRITICAL osv-scan.sh --lockfile=uv.lock
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT="$(git rev-parse --show-toplevel)"
|
|
CONFIG="${ROOT}/osv-scanner.toml"
|
|
SEVERITY_LEVELS="${OSV_SEVERITY_LEVELS:-HIGH,CRITICAL,UNKNOWN}"
|
|
|
|
for bin in osv-scanner jq; do
|
|
if ! command -v "${bin}" >/dev/null 2>&1; then
|
|
echo "error: ${bin} not found in PATH" >&2
|
|
exit 2
|
|
fi
|
|
done
|
|
|
|
SCAN_ARGS=()
|
|
if [ -f "${CONFIG}" ]; then
|
|
SCAN_ARGS+=(--config="${CONFIG}")
|
|
fi
|
|
|
|
# Exit codes: 0=clean, 1=findings, 127=no supported files, 128=internal error.
|
|
STDERR="$(mktemp)"
|
|
trap 'rm -f "${STDERR}"' EXIT
|
|
|
|
set +e
|
|
OUTPUT="$(osv-scanner scan source "${SCAN_ARGS[@]}" --format=json "$@" 2>"${STDERR}")"
|
|
RC=$?
|
|
set -e
|
|
|
|
case "${RC}" in
|
|
0|1) ;;
|
|
127) echo "osv-scanner: no supported lockfiles in scan target"; exit 0 ;;
|
|
*)
|
|
echo "osv-scanner: exited with code ${RC}" >&2
|
|
[ -s "${STDERR}" ] && cat "${STDERR}" >&2
|
|
exit "${RC}"
|
|
;;
|
|
esac
|
|
|
|
# Build a JSON array of normalized severity levels for jq.
|
|
SEVERITY_JSON="$(printf '%s' "${SEVERITY_LEVELS}" | jq -Rc '
|
|
split(",") | map(ascii_upcase | sub("^\\s+"; "") | sub("\\s+$"; ""))
|
|
')"
|
|
|
|
# Walk each vulnerability, look up its group's max_severity (numeric CVSS),
|
|
# map to a categorical label, then filter by OSV_SEVERITY_LEVELS.
|
|
FINDINGS="$(printf '%s' "${OUTPUT}" | jq --argjson sevs "${SEVERITY_JSON}" '
|
|
[ .results[]?.packages[]?
|
|
| . as $pkg
|
|
| ($pkg.groups // []) as $groups
|
|
| ($pkg.vulnerabilities // [])[]
|
|
| . as $vuln
|
|
| ([ $groups[] | select((.ids // []) | index($vuln.id)) ][0] // {}) as $group
|
|
| (($group.max_severity // "") | tonumber? // null) as $score
|
|
| (if $score == null then "UNKNOWN"
|
|
elif $score >= 9.0 then "CRITICAL"
|
|
elif $score >= 7.0 then "HIGH"
|
|
elif $score >= 4.0 then "MEDIUM"
|
|
elif $score > 0 then "LOW"
|
|
else "UNKNOWN"
|
|
end) as $label
|
|
| {
|
|
id: $vuln.id,
|
|
severity: $label,
|
|
score: $score,
|
|
summary: ($vuln.summary // null),
|
|
package: $pkg.package.name,
|
|
version: $pkg.package.version,
|
|
ecosystem: $pkg.package.ecosystem
|
|
}
|
|
| select(.severity as $s | $sevs | any(. == $s))
|
|
]
|
|
')"
|
|
|
|
COUNT="$(printf '%s' "${FINDINGS}" | jq 'length')"
|
|
|
|
# Write the findings JSON to OSV_REPORT_FILE so callers (e.g. the composite
|
|
# action's PR-comment step) can consume the same data the gate decision uses.
|
|
if [ -n "${OSV_REPORT_FILE:-}" ]; then
|
|
printf '%s' "${FINDINGS}" > "${OSV_REPORT_FILE}"
|
|
fi
|
|
|
|
if [ "${COUNT}" -gt 0 ]; then
|
|
echo "osv-scanner: ${COUNT} finding(s) at severity ${SEVERITY_LEVELS}"
|
|
printf '%s' "${FINDINGS}" | jq -r '
|
|
.[] | " [\(.severity)\(if .score then " \(.score)" else "" end)] \(.id) \(.ecosystem)/\(.package)@\(.version) — \(.summary // "(no summary)")"
|
|
'
|
|
echo
|
|
echo "To accept a finding, create osv-scanner.toml at the repo root with a reason and ignoreUntil."
|
|
exit 1
|
|
fi
|
|
|
|
echo "osv-scanner: no findings at severity levels: ${SEVERITY_LEVELS}"
|