mirror of
https://github.com/Sea-Haven-Industries/shoc-pr-review-runner.git
synced 2026-09-30 08:43:11 +00:00
94 lines
3.7 KiB
Bash
94 lines
3.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# Pre-upload artifact hygiene (spec §25): scan every staged artifact for the
|
||
|
|
# run's secret values and for generic credential patterns, and fail the upload
|
||
|
|
# on any hit. Secrets must never reach console logs, evidence files, prompts, or
|
||
|
|
# uploaded artifacts.
|
||
|
|
#
|
||
|
|
# Matching is deliberately broader than a literal grep: log formatters wrap long
|
||
|
|
# values across lines, and encoders re-shape them, so each artifact is also
|
||
|
|
# scanned in a whitespace-stripped form and against derived encodings of each
|
||
|
|
# secret. Archives are refused rather than scanned opaquely.
|
||
|
|
#
|
||
|
|
# Reads: ARTIFACTS_DIR, plus whichever secrets are in scope for this job. At
|
||
|
|
# least one of GH_TOKEN / FIREWORKS_API_KEY must be present — an empty scan set
|
||
|
|
# would pass vacuously and produce a green signal that proves nothing.
|
||
|
|
|
||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
# shellcheck source=lib.sh
|
||
|
|
source "$SCRIPT_DIR/lib.sh"
|
||
|
|
|
||
|
|
if [ -z "${GH_TOKEN:-}" ] && [ -z "${FIREWORKS_API_KEY:-}" ]; then
|
||
|
|
die "redaction check has no secrets to scan for — refusing to report clean (set GH_TOKEN and/or FIREWORKS_API_KEY)"
|
||
|
|
fi
|
||
|
|
|
||
|
|
hits=0
|
||
|
|
scanned=()
|
||
|
|
|
||
|
|
# Normalized copy of the artifact tree: newlines and spaces stripped, so a value
|
||
|
|
# wrapped across lines by a log formatter still matches.
|
||
|
|
norm_dir="$(mktemp -d)"
|
||
|
|
trap 'rm -rf "$norm_dir"' EXIT
|
||
|
|
while IFS= read -r -d '' f; do
|
||
|
|
case "$f" in
|
||
|
|
*.zip|*.gz|*.tgz|*.tar|*.bz2|*.xz|*.7z)
|
||
|
|
log "SECRET LEAK RISK: archive staged for upload cannot be scanned: $f"
|
||
|
|
hits=$((hits + 1))
|
||
|
|
continue
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
tr -d '\n\r \t' <"$f" >"$norm_dir/$(printf '%s' "$f" | md5sum | cut -d' ' -f1)" 2>/dev/null || true
|
||
|
|
done < <(find "$ARTIFACTS_DIR" -type f -print0)
|
||
|
|
|
||
|
|
# scan_value <label> <value> — checks the value and its common derived forms.
|
||
|
|
scan_value() {
|
||
|
|
local label="$1" value="$2"
|
||
|
|
[ -n "$value" ] || return 0
|
||
|
|
scanned+=("$label")
|
||
|
|
local -a forms=()
|
||
|
|
forms+=("$value")
|
||
|
|
forms+=("$(printf '%s' "$value" | base64 | tr -d '\n')")
|
||
|
|
forms+=("$(printf 'x-access-token:%s' "$value" | base64 | tr -d '\n')")
|
||
|
|
# URL-encoded form (only the characters that actually appear in tokens).
|
||
|
|
forms+=("$(printf '%s' "$value" | sed 's|/|%2F|g; s|+|%2B|g; s|=|%3D|g')")
|
||
|
|
local form found
|
||
|
|
for form in "${forms[@]}"; do
|
||
|
|
[ -n "$form" ] || continue
|
||
|
|
found="$(grep -rlF -- "$form" "$ARTIFACTS_DIR" 2>/dev/null || true)"
|
||
|
|
if [ -n "$found" ]; then
|
||
|
|
log "SECRET LEAK: $label found in artifact file(s):"
|
||
|
|
printf '%s\n' "$found" >&2
|
||
|
|
hits=$((hits + 1))
|
||
|
|
fi
|
||
|
|
# Whitespace-stripped scan catches line-wrapped occurrences.
|
||
|
|
found="$(grep -rlF -- "$(printf '%s' "$form" | tr -d '\n\r \t')" "$norm_dir" 2>/dev/null || true)"
|
||
|
|
if [ -n "$found" ]; then
|
||
|
|
log "SECRET LEAK: $label found (line-wrapped or whitespace-split) in a staged artifact"
|
||
|
|
hits=$((hits + 1))
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
}
|
||
|
|
|
||
|
|
scan_value "GH_TOKEN (App installation token)" "${GH_TOKEN:-}"
|
||
|
|
scan_value "FIREWORKS_API_KEY" "${FIREWORKS_API_KEY:-}"
|
||
|
|
scan_value "SHOC_REVIEW_APP_PRIVATE_KEY" "${SHOC_REVIEW_APP_PRIVATE_KEY:-}"
|
||
|
|
|
||
|
|
# Generic credential patterns: catches secrets belonging to the PRODUCT repos
|
||
|
|
# (a PR touching .env or appsettings) that the runner knows nothing about.
|
||
|
|
generic_hits="$(grep -rlEI \
|
||
|
|
-e 'gh[pousr]_[A-Za-z0-9]{30,}' \
|
||
|
|
-e 'github_pat_[A-Za-z0-9_]{30,}' \
|
||
|
|
-e 'BEGIN [A-Z ]*PRIVATE KEY' \
|
||
|
|
-e 'AKIA[0-9A-Z]{16}' \
|
||
|
|
-e 'xox[baprs]-[A-Za-z0-9-]{10,}' \
|
||
|
|
"$ARTIFACTS_DIR" 2>/dev/null || true)"
|
||
|
|
if [ -n "$generic_hits" ]; then
|
||
|
|
log "SECRET LEAK: generic credential pattern found in artifact file(s):"
|
||
|
|
printf '%s\n' "$generic_hits" >&2
|
||
|
|
hits=$((hits + 1))
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [ "$hits" -gt 0 ]; then
|
||
|
|
die "artifact redaction check failed: $hits leak indicator(s) — artifacts will not be uploaded"
|
||
|
|
fi
|
||
|
|
log "artifact redaction check clean (scanned for: ${scanned[*]} + generic credential patterns)"
|