75 lines
1.9 KiB
Bash
Executable File
75 lines
1.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
|
|
main() {
|
|
cd "$ROOT_DIR"
|
|
|
|
python - <<'PY'
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
root = Path.cwd()
|
|
failures: list[str] = []
|
|
|
|
|
|
def fail(message: str) -> None:
|
|
failures.append(message)
|
|
|
|
|
|
tracked = subprocess.check_output(["git", "ls-files"], text=True).splitlines()
|
|
for path in tracked:
|
|
name = Path(path).name
|
|
if name == ".env" or (name.startswith(".env.") and name not in {".env.example"}):
|
|
fail(f"{path}: environment files must not be tracked")
|
|
if re.search(r"\.(pem|key|p12|pfx)$", name):
|
|
fail(f"{path}: private key/certificate material must not be tracked")
|
|
|
|
secret_patterns = [
|
|
("private key block", re.compile(r"BEGIN [A-Z ]*PRIVATE KEY")),
|
|
("AWS access key", re.compile(r"AKIA[0-9A-Z]{16}")),
|
|
("Google API key", re.compile(r"AIza[0-9A-Za-z_-]{35}")),
|
|
("OpenAI-style secret key", re.compile(r"sk-[A-Za-z0-9]{32,}")),
|
|
("Slack token", re.compile(r"xox[baprs]-[A-Za-z0-9-]{10,}")),
|
|
("GitHub token", re.compile(r"gh[pousr]_[A-Za-z0-9_]{30,}")),
|
|
]
|
|
skip_parts = {
|
|
".git",
|
|
".venv",
|
|
"node_modules",
|
|
"dist",
|
|
"build",
|
|
".pytest_cache",
|
|
".mypy_cache",
|
|
"__pycache__",
|
|
}
|
|
|
|
for path in root.rglob("*"):
|
|
if not path.is_file():
|
|
continue
|
|
if skip_parts.intersection(path.relative_to(root).parts):
|
|
continue
|
|
try:
|
|
text = path.read_text(encoding="utf-8")
|
|
except UnicodeDecodeError:
|
|
continue
|
|
rel = path.relative_to(root)
|
|
for label, pattern in secret_patterns:
|
|
for match in pattern.finditer(text):
|
|
line_no = text.count("\n", 0, match.start()) + 1
|
|
fail(f"{rel}:{line_no}: possible {label} committed to repository")
|
|
|
|
if failures:
|
|
for message in failures:
|
|
print(f"fail: {message}")
|
|
raise SystemExit(f"security check failed: {len(failures)} failure(s)")
|
|
|
|
print("security check passed")
|
|
PY
|
|
}
|
|
|
|
main "$@"
|