Skip to content

feat: SARIF/JSON output for CI code scanning (closes #8)#9

Merged
bamdadd merged 4 commits into
mainfrom
feat/8-sarif-json-output
Jul 22, 2026
Merged

feat: SARIF/JSON output for CI code scanning (closes #8)#9
bamdadd merged 4 commits into
mainfrom
feat/8-sarif-json-output

Conversation

@bamdadd

@bamdadd bamdadd commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Closes #8.

Adds --format {text,json,sarif} to taintline check, keeping the deterministic,
zero-LLM, zero-dependency contract.

What

  • taintline.report — three pure serializers of a Verdict:
    • text — the existing human report (default; byte-identical to today).
    • json — a stable, sorted view of the findings for scripting.
    • sarifSARIF 2.1.0 for GitHub code scanning: one result per finding,
      detector → ruleId, severity → level (error/warning), span ids in the
      message + properties.span_ids + per-location logicalLocations, and the
      trace path as the artifactLocation.uri. Includes $schema, version,
      runs[].tool.driver (name taintline, rules), results[] — accepted by
      github/codeql-action/upload-sarif.
  • --format on check (default text); exit still gates on --fail-on
    regardless of format, so a SARIF run both surfaces findings and fails the build.

Deterministic, no LLM

Object keys are emitted sorted and findings are already contract-sorted, so output
is byte-identical across runs and independent of PYTHONHASHSEED. No network, no
timestamps, no rng. Zero new runtime deps.

Tests (tests/test_report.py)

  • SARIF has the expected taint result (ruleId/level=error/message/
    logicalLocations/span_ids) and all required SARIF 2.1.0 fields
    (structural validation — kept offline/zero-dep per the issue's fallback).
  • JSON and SARIF are byte-identical across five PYTHONHASHSEED values
    (subprocess), mirroring the existing determinism harness.
  • Default text output confirmed unchanged.

Docs

README ## Output formats & GitHub code scanning with the --format sarif
upload-sarif snippet (continue-on-error + if: always() so findings upload
even when the gate trips).

Gates: ruff check ., ruff format --check ., mypy src, pytest all green (45 tests).

bamdadd added 4 commits July 22, 2026 16:19
New taintline.report module. to_text is the existing human report; to_json is a
stable sorted view of the findings; to_sarif emits SARIF 2.1.0 for GitHub code
scanning (one result per finding, detector->ruleId, severity->level, span ids in
the message + properties + per-location logicalLocations, trace path as the
artifactLocation). All three are pure, offline and byte-deterministic: object keys
emitted sorted and findings already contract-sorted, so nothing depends on
PYTHONHASHSEED. Typed SARIF nodes, no loose dict assembly.
Thread a keyword-only fmt + trace_uri through run_check and dispatch to the new
serializers; default stays text and byte-identical to today (render now delegates
to report.to_text). Exit still gates on --fail-on regardless of format, so a SARIF
run both surfaces findings and fails the build. main passes the trace path as the
SARIF artifact uri.
A seeded taint trace: assert the SARIF has the expected taint result
(ruleId/level=error/message/logicalLocations/span_ids) and all required SARIF
2.1.0 fields ($schema, version, runs[].tool.driver, results[] with ruleId in the
declared rules, valid level, message.text, artifactLocation). JSON + SARIF are
byte-identical across five PYTHONHASHSEED values (subprocess). Default output
confirmed unchanged (text == to_text, not JSON).
@bamdadd
bamdadd merged commit ae5e945 into main Jul 22, 2026
1 check passed
@bamdadd
bamdadd deleted the feat/8-sarif-json-output branch July 22, 2026 15:30
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.

Add SARIF/JSON output for CI code-scanning annotations

1 participant