feat: harden community production foundation through story 1.5
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fail closed when PostgreSQL migration authority escapes its canonical module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MAX_FILE_BYTES = 2 * 1024 * 1024
|
||||
DDL = re.compile(
|
||||
r"(?is)\b(?:create|alter|drop|truncate|comment\s+on|grant|revoke)\s+"
|
||||
r"(?:(?:or\s+replace|unique|temporary|temp|unlogged)\s+)*"
|
||||
r"(?:table|index|schema|view|materialized\s+view|type|sequence|function|procedure|"
|
||||
r"trigger|extension|domain|policy|role)\b"
|
||||
)
|
||||
RUNNER = re.compile(
|
||||
r"(?is)pg_advisory_(?:xact_)?lock|sqlx\s*::\s*migrate|_sqlx_migrations|"
|
||||
r"include_(?:str|bytes)!\s*\([^)]*\.sql|"
|
||||
r"(?:insert\s+into|update|delete\s+from)\s+__crank_(?:core_|mcp_|ext_)?migrations"
|
||||
)
|
||||
|
||||
|
||||
def canonical(path: Path, root: Path) -> bool:
|
||||
relative = path.relative_to(root).as_posix()
|
||||
return relative == "crates/crank-registry/src/migrations.rs" or relative.startswith(
|
||||
"crates/crank-registry/src/migrations/"
|
||||
)
|
||||
|
||||
|
||||
def candidates(root: Path) -> list[Path]:
|
||||
result: list[Path] = []
|
||||
for base_name in ("apps", "crates"):
|
||||
base = root / base_name
|
||||
if not base.exists():
|
||||
continue
|
||||
for path in base.rglob("*"):
|
||||
if path.suffix not in {".rs", ".sql"}:
|
||||
continue
|
||||
if "crank-test-support" in path.relative_to(root).parts:
|
||||
continue
|
||||
if path.is_symlink() or not path.is_file():
|
||||
raise ValueError("production Rust/SQL path must be a regular non-symlink file")
|
||||
if "/tests/" in f"/{path.relative_to(root).as_posix()}/":
|
||||
continue
|
||||
result.append(path)
|
||||
return sorted(result)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--root", type=Path, default=Path("."))
|
||||
args = parser.parse_args()
|
||||
root = args.root.resolve()
|
||||
try:
|
||||
files = candidates(root)
|
||||
violations: list[str] = []
|
||||
for path in files:
|
||||
if canonical(path, root):
|
||||
continue
|
||||
data = path.read_bytes()
|
||||
if len(data) > MAX_FILE_BYTES:
|
||||
raise ValueError("production Rust/SQL file exceeds scanner limit")
|
||||
text = data.decode("utf-8")
|
||||
if DDL.search(text) or RUNNER.search(text):
|
||||
violations.append(path.relative_to(root).as_posix())
|
||||
except (OSError, UnicodeDecodeError, ValueError) as error:
|
||||
print(f"migration boundary check failed: {error}", file=sys.stderr)
|
||||
return 1
|
||||
if violations:
|
||||
for path in violations:
|
||||
print(f"migration boundary violation: {path}", file=sys.stderr)
|
||||
return 1
|
||||
print(f"migration boundary check passed: files={len(files)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user