from __future__ import annotations from dataclasses import dataclass from typing import Callable, Literal from .model import Outcome Expectation = Literal["zero_rows", "statement_rejected", "false", "documented_limit"] Query = Callable[[str], object] @dataclass(frozen=True) class E3Probe: probe_id: str sql_key: str expectation: Expectation @dataclass(frozen=True) class E3Result: probe_id: str outcome: Outcome reason: str PROBES = ( E3Probe("conformance-view-empty", "conformance", "zero_rows"), E3Probe("unset-guc-reads-none", "unset_guc", "zero_rows"), E3Probe("tenant-a-cannot-read-b", "wrong_tenant_read", "zero_rows"), E3Probe("tenant-a-cannot-insert-b", "wrong_tenant_insert", "statement_rejected"), E3Probe("runtime-lacks-bypassrls", "runtime_bypassrls", "false"), E3Probe("unsafe-definer-inventory-empty", "unsafe_definer", "zero_rows"), E3Probe("sql-compromise-reset", "reset_to_b", "documented_limit"), ) def evaluate(probe: E3Probe, *, rows: int = 0, rejected: bool = False, boolean: bool | None = None) -> E3Result: if probe.expectation == "documented_limit": return E3Result(probe.probe_id, "inconclusive", "E3-B observation records the documented SQL-compromise limit") passed = { "zero_rows": rows == 0, "statement_rejected": rejected, "false": boolean is False, }[probe.expectation] if passed: return E3Result(probe.probe_id, "pass", f"expectation met: {probe.expectation}") return E3Result(probe.probe_id, "finding", f"expectation failed: {probe.expectation}") CADENCE = { "interval": "24h", "maximum_detection_window": "24h plus run and reporting latency", "reset_triggers": [ "schema migration", "role or grant change", "RLS policy change", "security-definer function change", "posture mechanism change", ], "triggered_run_deadline": "before deployment promotion", }