Skip to content

Add SARIF 2.1.0 export for a retained pull-request review - #40

Open
heyeddi wants to merge 1 commit into
prooflinedev:mainfrom
heyeddi:cursor/sarif-review-export-e1fd
Open

heyeddi wants to merge 1 commit into
prooflinedev:mainfrom
heyeddi:cursor/sarif-review-export-e1fd

Conversation

@heyeddi

@heyeddi heyeddi commented Nov 10, 2026

Copy link
Copy Markdown

What

review_sarif projects one retained pull-request review into a SARIF 2.1.0 document. Both clients already return the review; this is the closed projection the CLI writes with proofline findings --sarif.

import json
from pathlib import Path
from proofline import review_sarif

outcome = client.wait_for_review(organization_id, review_id)
if outcome.review is None:
    raise SystemExit(outcome.reason)
Path("proofline.sarif").write_text(
    json.dumps(
        review_sarif(
            outcome.review,
            organization_id,
            review_id=review_id,
            review_url=outcome.review_url,
        )
    ),
    encoding="utf-8",
)

Why

The CLI already defines this document for GitHub code scanning and other SARIF 2.1.0 consumers, and neither SDK exposes it, so every Python caller would have to rebuild the projection. The rules are easy to get wrong: a location counts only when it is a verified file at the reviewed head, an unknown severity or risk domain is refused, a partial CODE record still contributes findings but makes the invocation unsuccessful, and a withheld or off-commit CODE record contributes none.

The projection follows the CLI rather than inventing a second one:

  • Severities map to SARIF error and warning. Anything else, including a severity this build does not know, refuses the export.
  • Risk domains come from the public environment catalog, plus the CODE categories when the CODE record is usable.
  • The first verified location is primary. Later distinct locations are related. Companion repositories, other commits, and paths that leave the repository are retained as evidence with a location status and are not emitted as artifacts.
  • Gap notifications name assessment, CODE, and review reasons. executionSuccessful is true only for a complete review with no notifications.
  • SUPERSEDED is an incomplete result, matching the CLI. wait_for_review still reports that status as STOPPED.
  • World evidence values and the raw API document are not copied. SARIF message text escapes braces and embedded-link characters once.

A deployment, patch, or other subject, a head that is not a 40- or 64-character commit SHA, or a review id that does not match the record raises SarifExportError and returns no document.

No generated client, OpenAPI document, or workflow file is changed.

How it's tested

tests/test_sarif.py covers:

  • identity, severity, fingerprint, message escaping, and percent-encoded locations
  • duplicate locations, rejected paths, companion files, and non-code evidence
  • CODE findings beside environment assessments, partial CODE records, withheld records, and a head that does not match
  • gap notifications for incomplete, running, failed, stopped, and superseded reviews
  • refusals for the wrong review, an unpinned head, a non-pull-request subject, an unknown severity, and an unknown domain
  • a review parsed by ProoflineClient.get_review

python3 scripts/check.py passed: generation freshness, operation contracts, ruff check, ruff format --check, mypy, pytest (143 passed), and wheel plus sdist install smoke tests.

Project a review the caller already holds with the same closed rules as
the CLI findings --sarif command, including locations, gaps, and refusals.

Co-authored-by: Edmundo Sanchez <eddi@heyeddi.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant