lcert_verify.report

Report emitters: one verification result, several output formats.

This module exists so that every consumer — the CLI, the MCP server, a CI job, a future HTTP service — renders the same result object rather than each re-deriving what a verdict means. Adding a format means adding one function here, not touching every call site.

Every emitter preserves the abstention discipline: UNVERIFIED must never be rendered as a pass in any format. Where a format has only pass/fail (JUnit), an abstention is a failure with the reason attached, never a success.

def verdict_meta(verdict: str) -> tuple:
def to_json(res: dict, *, indent: int = 2) -> str:

Full result as JSON. The canonical machine format.

def to_jsonl(res: dict, *, source: str = '') -> str:

One line per certificate — convenient for streaming into a log pipeline.

def to_sarif( res: dict, *, source: str = 'bundle.json', tool_version: str = '1.0.0') -> str:

SARIF 2.1.0 — renders in GitHub code scanning and most IDE problem panes.

An abstention is emitted at warning level with the reason, never suppressed: a reader scanning the Security tab must see that no assertion was made.

def to_junit(res: dict, *, source: str = 'bundle.json') -> str:

JUnit XML — appears in the test report of essentially every CI system.

JUnit has no 'abstained' state. An abstention is therefore a failure with the reason attached: reporting it as a pass would be exactly the confident wrong answer this project exists to avoid.

EMITTERS = {'json': <function to_json>, 'jsonl': <function to_jsonl>, 'sarif': <function to_sarif>, 'junit': <function to_junit>}
def emit(res: dict, fmt: str, **kw) -> str: