Files
Open_Ultra_SAST/src/openultrasast/model/report.py
T
Marius CiepluchandClaude Fable 5.1 0d7d3f0dc9 chore: format the whole tree and lint the scratch measurement scripts; CI has been red since 25ae4b4
CI runs ruff format --check and ruff check over the whole repository; 29 files had drifted from the formatter and
four measurement scripts carried lint findings, so every push since 25ae4b4 failed before pytest ran.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-14 02:49:44 +02:00

64 lines
2.6 KiB
Python

"""Report model coverage for the scanned regions."""
from __future__ import annotations
from collections.abc import Sequence
__all__ = []
def coverage_rows(regions: Sequence[object]) -> list[dict[str, object]]:
"""What each family actually modelled for the languages scanned, and what it cannot decide (Req 5.6).
Derived, not asserted: the count is the size of the fact table the arbiter used, so it cannot drift from
what the engine really looked for. The `limits` string is authored, reviewed and committed in
`families.toml`, because "cannot decide an overflow expressed as an index" is a statement about an
abstraction and no table can produce it.
Reported for every family that was OFFERED to a region, not only those that produced findings -- a family
that ran and found nothing is exactly the case a reader is most likely to misread, and the one Req 5.6
exists for.
"""
from .specs import config_specs, dominance_specs, taint_specs
from .taxonomy import load_families
taxonomy = load_families()
limits = {family.id: family.limits for family in taxonomy.families}
described = {family.id: family.description for family in taxonomy.families}
offered: dict[tuple[str, str], int] = {}
for region in regions:
language = str(getattr(region, "language", ""))
for family in getattr(region, "families", ()):
offered.setdefault((language, str(family)), 0)
offered[(language, str(family))] += 1
rows: list[dict[str, object]] = []
for (language, family), region_count in sorted(offered.items()):
modelled = _modelled_count(language, family, taint_specs, dominance_specs, config_specs)
rows.append(
{
"language": language,
"family": family,
"regions": region_count,
"modelled": modelled,
"description": described.get(family, ""),
"limits": limits.get(family, ""),
}
)
return rows
def _modelled_count(language: str, family: str, taint_specs, dominance_specs, config_specs) -> int: # type: ignore[no-untyped-def]
"""How many operations the arbiter for this family can even see in this language."""
spec = taint_specs(language=language).get(family)
if spec is not None:
return len(spec.sinks)
spec = dominance_specs(language=language).get(family)
if spec is not None:
return len(spec.operations)
spec = config_specs(language=language).get(family)
if spec is not None:
return len(spec.settings)
return 0