Add strict Python and checked JavaScript tooling, explicit source-scope checks and real rejection probes to CI. Preserve existing runtime behavior and document the limited bundle and test portability changes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Co-Authored-By: Codex GPT-6 <noreply@openai.com> Signed-off-by: James Maes <james@kof22.com>
109 lines
4.2 KiB
Python
109 lines
4.2 KiB
Python
# Copyright 2026 Kingsrook, LLC
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""Reject missing/malformed CodeQL evidence before enforcing the severity gate."""
|
|
|
|
import json
|
|
import math
|
|
import os
|
|
from pathlib import Path
|
|
from typing import TypedDict
|
|
|
|
RuleProperties = TypedDict("RuleProperties", {"security-severity": str | float | None}, total=False)
|
|
|
|
|
|
class Rule(TypedDict):
|
|
"""Keep the rule identity and optional severity metadata used by the gate."""
|
|
|
|
id: str
|
|
properties: RuleProperties
|
|
|
|
|
|
class Component(TypedDict, total=False):
|
|
"""Describe CodeQL driver or extension rule metadata."""
|
|
|
|
name: str
|
|
rules: list[Rule]
|
|
|
|
|
|
class Tool(TypedDict, total=False):
|
|
"""Group the driver and optional extension rule catalogs."""
|
|
|
|
driver: Component
|
|
extensions: list[Component]
|
|
|
|
|
|
class Result(TypedDict, total=False):
|
|
"""Describe only the result fields consumed by the severity gate."""
|
|
|
|
ruleId: str
|
|
rule: dict[str, str]
|
|
suppressions: list[object]
|
|
|
|
|
|
class Run(TypedDict, total=False):
|
|
"""Retain invocation success and findings for one analyzed language."""
|
|
|
|
tool: Tool
|
|
results: list[Result]
|
|
invocations: list[dict[str, bool]]
|
|
|
|
|
|
class Report(TypedDict, total=False):
|
|
"""Represent SARIF fields while retaining the explicit runtime validation."""
|
|
|
|
version: str
|
|
runs: list[Run]
|
|
|
|
|
|
MAX_SEVERITY = 10
|
|
|
|
|
|
def check(directory: str | Path, language: str, threshold: float) -> bool: # noqa: PLR0912 -- Keep the ordered evidence checks together; none may be skipped.
|
|
"""Validate complete CodeQL evidence and report findings at the threshold."""
|
|
if not math.isfinite(threshold) or not 0 <= threshold <= MAX_SEVERITY:
|
|
raise ValueError("Invalid security severity threshold")
|
|
canonical = {"java-kotlin": "java", "javascript-typescript": "javascript", "c-cpp": "cpp"}.get(language, language)
|
|
files = sorted(Path(directory).glob("*.sarif"))
|
|
if not canonical or not any(path.name == canonical + ".sarif" for path in files):
|
|
raise ValueError("Missing expected CodeQL SARIF report for " + language)
|
|
blocking: list[tuple[float, str]] = []
|
|
for path in files:
|
|
report: Report = json.loads(path.read_text(encoding="utf-8"))
|
|
runs = report.get("runs")
|
|
if report.get("version") != "2.1.0" or not isinstance(runs, list) or not runs:
|
|
raise ValueError("Invalid or empty SARIF runs: " + path.name)
|
|
for run in runs:
|
|
driver = run.get("tool", {}).get("driver", {})
|
|
results = run.get("results")
|
|
if driver.get("name") != "CodeQL" or not isinstance(driver.get("rules"), list) or not isinstance(results, list):
|
|
raise ValueError("Missing CodeQL tool/rules/results evidence: " + path.name)
|
|
rules: dict[str, Rule] = {}
|
|
for component in [driver, *run.get("tool", {}).get("extensions", [])]:
|
|
for rule in component.get("rules", []):
|
|
rules[rule["id"]] = rule
|
|
if not rules:
|
|
raise ValueError("CodeQL report has no analyzed rule metadata: " + path.name)
|
|
for invocation in run.get("invocations", []):
|
|
if invocation.get("executionSuccessful") is False:
|
|
raise ValueError("CodeQL invocation failed: " + path.name)
|
|
for result in results:
|
|
rule_id = result.get("ruleId") or result.get("rule", {}).get("id")
|
|
if rule_id not in rules:
|
|
raise ValueError("Result references missing rule metadata: " + path.name)
|
|
if result.get("suppressions"):
|
|
continue
|
|
severity = float(rules[rule_id].get("properties", {}).get("security-severity", 0) or 0)
|
|
if not math.isfinite(severity) or not 0 <= severity <= MAX_SEVERITY:
|
|
raise ValueError("Invalid rule severity: " + rule_id)
|
|
if severity >= threshold:
|
|
blocking.append((severity, rule_id))
|
|
for severity, rule_id in sorted(blocking, reverse=True):
|
|
print(f"::error title=CodeQL security finding::{rule_id} ({severity})")
|
|
print(f"Validated {len(files)} SARIF report(s); {len(blocking)} blocking result(s)")
|
|
return bool(blocking)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(1 if check(os.environ["SARIF_DIR"], os.environ["EXPECTED_LANGUAGE"], float(os.environ["THRESHOLD"])) else 0)
|