← back to AgentAbrams
snippets/redact_lint.py
79 lines
#!/usr/bin/env python3
"""
redact_lint.py — lightweight linter to flag obvious sensitive patterns in markdown.
This is not a substitute for human review.
It is a "seatbelt," not a self-driving car.
Usage:
python3 snippets/redact_lint.py posts/2026-02-22.md
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
PATTERNS = {
"email": re.compile(
r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b", re.IGNORECASE
),
"phone_us": re.compile(
r"\b(\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b"
),
"aws_access_key": re.compile(r"\bAKIA[0-9A-Z]{16}\b"),
"private_key_header": re.compile(
r"-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----"
),
"slack_token": re.compile(r"\bxox[bpras]-[0-9a-zA-Z-]+\b"),
"generic_secret_assignment": re.compile(
r"""(?:api[_-]?key|secret|token|password|credential)[\s]*[=:]\s*['"][^'"]{8,}['"]""",
re.IGNORECASE,
),
"ip_address": re.compile(
r"\b(?:\d{1,3}\.){3}\d{1,3}\b"
),
"connection_string": re.compile(
r"(?:postgres|mysql|mongodb|redis)(?:ql)?://[^\s]+", re.IGNORECASE
),
}
def lint_text(text: str) -> list[tuple[str, str]]:
findings: list[tuple[str, str]] = []
for name, rx in PATTERNS.items():
for m in rx.finditer(text):
start = max(0, m.start() - 24)
end = min(len(text), m.end() + 24)
snippet = text[start:end].replace("\n", " ")
findings.append((name, snippet))
return findings
def main() -> int:
if len(sys.argv) != 2:
print("Usage: redact_lint.py path/to/file.md", file=sys.stderr)
return 2
path = Path(sys.argv[1])
if not path.exists():
print(f"File not found: {path}", file=sys.stderr)
return 2
text = path.read_text(encoding="utf-8", errors="replace")
findings = lint_text(text)
if not findings:
print(f"OK: {path} — no obvious sensitive patterns found.")
return 0
print(f"WARNING: {path} — potential sensitive content detected:")
for name, snippet in findings:
print(f" [{name}]: ...{snippet}...")
return 1
if __name__ == "__main__":
raise SystemExit(main())