| #!/usr/bin/env bash |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| set -euo pipefail |
|
|
| |
| |
| |
| PATTERN='[0-9]{6}[+-][0-9]{4}|[0-9]{8}-[0-9]{4}' |
|
|
| |
| staged_files=$(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null | \ |
| grep -E '\.(py|txt|md|json|csv|yaml|yml|toml|sh)$' || true) |
|
|
| if [ -z "$staged_files" ]; then |
| exit 0 |
| fi |
|
|
| |
| |
| |
| |
| |
| |
| |
| _grep_supports_P() { |
| local six="123456" four="7890" |
| printf '%s-%s\n' "$six" "$four" | grep -qP '[0-9]{6}-[0-9]{4}' 2>/dev/null |
| } |
|
|
| |
| |
| |
| |
| _scan_file_grep() { |
| local f="$1" |
| ! grep -qP "$PATTERN" "$f" 2>/dev/null |
| } |
|
|
| _scan_file_python() { |
| local f="$1" |
| python3 - "$f" <<'PYEOF' |
| import re, sys |
| pattern = re.compile(r'[0-9]{6}[+-][0-9]{4}|[0-9]{8}-[0-9]{4}') |
| with open(sys.argv[1], errors='replace') as fh: |
| sys.exit(0 if not pattern.search(fh.read()) else 1) |
| PYEOF |
| } |
|
|
| _get_matches_grep() { |
| local f="$1" |
| grep -nP "$PATTERN" "$f" 2>/dev/null | head -3 || true |
| } |
|
|
| _get_matches_python() { |
| local f="$1" |
| python3 - "$f" <<'PYEOF' |
| import re, sys |
| pattern = re.compile(r'[0-9]{6}[+-][0-9]{4}|[0-9]{8}-[0-9]{4}') |
| with open(sys.argv[1], errors='replace') as fh: |
| for i, line in enumerate(fh, 1): |
| if pattern.search(line): |
| print(f"{i}:{line.rstrip()}") |
| PYEOF |
| } |
|
|
| |
| if _grep_supports_P; then |
| SCAN_CMD=_scan_file_grep |
| MATCH_CMD=_get_matches_grep |
| else |
| SCAN_CMD=_scan_file_python |
| MATCH_CMD=_get_matches_python |
| fi |
|
|
| found=0 |
| while IFS= read -r file; do |
| if [ -f "$file" ] && ! $SCAN_CMD "$file"; then |
| echo "ERROR: Possible personnummer found in: $file" |
| $MATCH_CMD "$file" |
| found=1 |
| fi |
| done <<< "$staged_files" |
|
|
| if [ "$found" -eq 1 ]; then |
| echo "" |
| echo "COMMIT BLOCKED: Remove or redact personnummer patterns before committing." |
| echo "Pattern matched: YYMMDD-XXXX, YYYYMMDD-XXXX, or YYMMDD+XXXX" |
| echo "" |
| echo "NOTE: Image files (PNG/JPG) are NOT scanned β verify PNG/JPG redaction visually." |
| echo " Real letters must live in data/letters/private/ (gitignored), never in public/." |
| exit 1 |
| fi |
|
|
| exit 0 |
|
|