#!/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