#!/usr/bin/env python3
"""Verify security-relevant dependency version floors (SR-2026-05-30-008).

cargo-audit / cargo-deny only see Rust crates — the **native** libraries that SQLCipher statically
bundles (SQLite, OpenSSL) are invisible to them, so we pin their floors here from `Cargo.lock`:

  * SQLite   >= 3.50.2  (CVE-2025-6965) — via `libsqlite3-sys`; the RUNTIME version is also asserted by
                          the `histdb` test `bundled_sqlite_meets_security_floor`.
  * OpenSSL  >= 3.5.5   — via the `openssl-src` build metadata (`300.x.y+<openssl-version>`).
  * curve25519-dalek >= 4.1.3      (timing fix)
  * rustls-webpki    >= 0.103.10   (cert-path build DoS fixes)

Exit non-zero on any violation, so CI breaks. Run: `python3 scripts/ci/check_dep_floors.py`
"""

import re
import sys
import tomllib

# crate -> (min_version, rationale)
FLOORS = {
    "curve25519-dalek": ("4.1.3", "timing side-channel fix"),
    "rustls-webpki": ("0.103.10", "certificate-path build DoS fixes"),
    "libsqlite3-sys": ("0.37.0", "bundles SQLite >= 3.50.2 (CVE-2025-6965)"),
}
OPENSSL_FLOOR = "3.5.5"  # bundled via SQLCipher's crypto provider (openssl-src)


def ver_tuple(v: str) -> tuple:
    return tuple(int(x) for x in re.findall(r"\d+", v))


def main() -> None:
    with open("Cargo.lock", "rb") as f:
        lock = tomllib.load(f)
    pkgs = {p["name"]: p["version"] for p in lock.get("package", [])}

    fails: list[str] = []

    for name, (floor, why) in FLOORS.items():
        v = pkgs.get(name)
        if v is None:
            fails.append(f"{name}: ABSENT (expected >= {floor} — {why})")
        elif ver_tuple(v) < ver_tuple(floor):
            fails.append(f"{name} = {v} < {floor} ({why})")
        else:
            print(f"ok  {name:18} = {v}  (>= {floor})")

    # OpenSSL version is encoded in openssl-src's build metadata, e.g. "300.6.0+3.6.2".
    osrc = pkgs.get("openssl-src")
    if osrc is None:
        fails.append("openssl-src: ABSENT (cannot verify the bundled OpenSSL version)")
    else:
        m = re.search(r"\+([\d.]+)", osrc)
        if not m:
            fails.append(f"openssl-src = {osrc}: missing +<openssl-version> build metadata")
        elif ver_tuple(m.group(1)) < ver_tuple(OPENSSL_FLOOR):
            fails.append(f"bundled OpenSSL {m.group(1)} < {OPENSSL_FLOOR} (openssl-src {osrc})")
        else:
            print(f"ok  bundled OpenSSL     = {m.group(1)}  (>= {OPENSSL_FLOOR}, via openssl-src {osrc})")

    if fails:
        print("\nVERSION FLOOR VIOLATIONS:", file=sys.stderr)
        for fail in fails:
            print(f"  ✗ {fail}", file=sys.stderr)
        sys.exit(1)
    print("\nall dependency version floors satisfied")


if __name__ == "__main__":
    main()
