Files
claude-regelwerk/.vault-tools/geheimnis-scan/push_scan.py
T
Pascal MichelandClaude Opus 5 5c997a23e2 Automatischer Push: 4 Datei(en) geändert
- .claude/skills/plane-abgleich/SKILL.md
- .vault-tools/geheimnis-scan/LIESMICH.md
- .vault-tools/geheimnis-scan/datei_scan.py
- .vault-tools/geheimnis-scan/push_scan.py

Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-16 04:00:01 +02:00

63 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Durchsucht die ausgehenden Commits eines Repos (Bereich a..b) nach Geheimnis-Mustern.
Ersteller: Claude (Opus 5.5) · Erstellt: 2026-10-15 · Doku: LIESMICH.md
Gezeigt werden nur hinzugefügte Zeilen. Werte, die wie Geheimnisse aussehen, nur als
Länge; dazu Datei und Muster. Aufruf: python -I -X utf8 push_scan.py <repo> <bereich>
Bereich ohne Basis (neuer Zweig auf dem Remote): "<zweig> --not --remotes=origin".
"""
import re
import subprocess
import sys
from collections import Counter, defaultdict
repo, bereich = sys.argv[1], sys.argv[2:]
log = subprocess.run(
["git", "-C", repo, "log", "-p", "--no-color", "--format=COMMIT %h", *bereich],
capture_output=True, text=True, encoding="utf-8", errors="replace", check=True,
).stdout
# Muster mit Wert: nur Länge ausgeben
GEHEIM = {
"zuweisung": re.compile(r"(?i)\b(pass(?:wor[dt])?|kennwort|pwd|token|secret|api[_-]?key|client[_-]?secret|private[_-]?key)\b[\"']?\s*[:=]\s*[\"']([^\"'\s$<{]{8,})[\"']"),
"privater_schluessel": re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----"),
"gitea_github_token": re.compile(r"\b(?:ghp_[A-Za-z0-9]{30,}|gh[ousr]_[A-Za-z0-9]{30,}|glpat-[A-Za-z0-9_-]{20,})\b"),
"url_mit_zugang": re.compile(r"https?://[^/\s:@]+:[^/\s@]+@"),
"hash_shadow": re.compile(r"\$(?:6|5|y|2[aby])\$[^\s:\"']{20,}"),
}
# Muster ohne Geheimnis: Zählung je Wert
ZAEHLEN = {
"private_ipv4": re.compile(r"\b(?:10\.\d{1,3}|192\.168|172\.(?:1[6-9]|2\d|3[01]))\.\d{1,3}\.\d{1,3}\b"),
"firma": re.compile(r"\b[A-ZÄÖÜ][\w&.-]+(?:\s+[A-ZÄÖÜ][\w&.-]+){0,2}\s+(?:GmbH|AG|KG|UG|e\.V\.)\b"),
}
datei = "?"
commits = 0
geheim = defaultdict(list)
zaehl = {k: Counter() for k in ZAEHLEN}
for zeile in log.splitlines():
if zeile.startswith("COMMIT "):
commits += 1
continue
if zeile.startswith("+++ b/"):
datei = zeile[6:]
continue
if not zeile.startswith("+") or zeile.startswith("+++"):
continue
for name, muster in GEHEIM.items():
for m in muster.finditer(zeile):
wert = m.groups()[-1] if m.groups() else m.group(0)
geheim[name].append((datei, len(wert)))
for name, muster in ZAEHLEN.items():
for m in muster.finditer(zeile):
zaehl[name][m.group(0)] += 1
print(f"Commits im Bereich: {commits}")
for name in GEHEIM:
treffer = geheim.get(name, [])
print(f"[geheim] {name}: {len(treffer)}")
for d, laenge in sorted(set(treffer))[:15]:
print(f" {d} (Wertlänge {laenge})")
for name, c in zaehl.items():
print(f"[zaehl] {name}: {sum(c.values())} Treffer, {len(c)} verschieden: " + ", ".join(f"{w} ×{n}" for w, n in c.most_common(12)))