pre-push(17.2): name every skipped check in plain words

One terminal line per distinct coverage reason (push/explain.py): hex-encoded
paths decoded, per-question sha256 tokens dropped and counted, unknown reasons
still printed; the JSON artifact keeps the raw values. A changed language with
no engine frontend and no quick rules is recorded and printed as "language not
covered: <lang> (...)", in pre-push and in `ousast scan`. The scan report
renders the eight degradations cli.py recorded but never showed, and any
reason without a sentence. The hook forwards OUSAST_COMPARISON_BASE.
Requirement 9.2.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
Marius Ciepluch
2026-10-02 22:10:33 +02:00
co-authored by Claude Opus 5.5
parent bf07cd4d1d
commit f555dee640
11 changed files with 445 additions and 15 deletions
+11
View File
@@ -18,6 +18,7 @@ from typing import Literal
from openultrasast.model.contracts import ChangeContext, ExecutionBudget
from openultrasast.model.scan import ModelScanResult
from openultrasast.push.contracts import PushComparison, PushResolution, PushResult, SnapshotManifest
from openultrasast.push.explain import explain
from openultrasast.push.policy import AdmissionResult, _context_boundaries
from openultrasast.redaction import redact_secrets
@@ -187,6 +188,10 @@ def _save(report: PushReport, target: Path, budget: ExecutionBudget) -> str | No
process.close()
# Distinct skip kinds shown in the terminal; the artifact keeps every reason.
_SKIP_LINES = 12
def _short(value: str, limit: int = 180) -> str:
# Bound before escaping: repository-controlled names/witnesses cannot add lines
# or terminal escapes. Full spelling and every witness remain in the artifact.
@@ -260,8 +265,14 @@ def render_report(report: PushReport, *, artifact: Path | None, error: str | Non
notices = []
if report.result.coverage_status in ("incomplete", "unavailable"):
reasons = report.admission.coverage_reasons
# One plain line per distinct skipped check (Requirement 9.2); the artifact keeps the raw values.
deadline = report.timings.get("deadline_seconds")
for skipped in explain(reasons, deadline=float(deadline) if deadline is not None else None)[:_SKIP_LINES]:
lines.append("Skipped: " + _short(skipped, 400))
if any("deadline" in reason for reason in reasons):
notices.append("Analysis did not finish. Rerun with a longer analysis deadline.")
elif any(reason in ("cpg_build_failed", "cpg_unavailable") for reason in reasons):
notices.append("Engine checks did not run. Install Joern, or run the hook through ops/ousast-docker. Review the details.")
elif any("capability" in reason for reason in reasons):
notices.append("Some checks are not enabled for normal alerts. Review capability coverage in the details.")
else: