parlov docs

parlov-output

Output formatting layer — terminal table rendering, structured JSON with DTO layer, and SARIF v2.1.0 document generation.

Implemented

Version: 0.6.0 | Files: 4 | Lines: 1,047 | Dependencies: comfy-table, parlov-core, serde, serde-sarif, serde_json

The output formatting layer. Transforms OracleResult and ScanFinding values into human-readable tables, machine-readable JSON, and SARIF v2.1.0 for security tooling integration. Pure synchronous computation — no I/O.


Public API

Render Functions

Two families of render functions: single-finding (from existence subcommand) and scan-level (from scan subcommand).

Single-finding renderers:

FunctionSignatureOutput
render_table(&OracleResult) -> StringANSI-colored terminal table
render_json(&str, &OracleResult, &str, &str, &str) -> Result<String>Structured JSON
render_sarif(&str, &OracleResult, &str, &str) -> Result<String>SARIF v2.1.0 document

render_json parameters: target_url, result, strategy_id, strategy_name, method. render_sarif parameters: target_url, result, strategy_id, method. Context needed for JSON/SARIF that isn't carried on OracleResult itself.

Scan-level renderers:

FunctionSignatureOutput
render_scan_table(&[ScanFinding]) -> StringMulti-row terminal table
render_scan_json(&str, &[ScanFinding]) -> Result<String>Array of findings as JSON
render_scan_sarif(&str, &[ScanFinding]) -> Result<String>Full SARIF document with all findings

ScanFinding

The intermediate struct that bridges the scan runner and the output layer:

pub struct ScanFinding {
    pub target_url: String,
    pub strategy_id: String,
    pub strategy_name: String,
    pub method: String,
    pub result: OracleResult,
}

Internal Architecture

JSON Output (json.rs)

Internal DTO structs that shape the JSON output:

DTOPurpose
SingleFindingOutputTop-level wrapper for single-finding JSON
ScanOutputTop-level wrapper for scan JSON, contains findings[]
FindingOutputPer-finding body (target, method, strategy, result)
StrategyOutputStrategy metadata (id, name)
ResultOutputAnalysis result (oracle_class, verdict, confidence, severity, impact_class)
TechniqueOutputTechnique metadata (id, vector, normative_strength)
MatchedPatternOutputPattern match context (label, leaks, rfc_basis)
EvidenceOutputStructured reasons and signals arrays

The DTO layer exists to decouple the JSON schema from internal OracleResult field layout. This lets the output format evolve independently.

SARIF Output (sarif.rs)

Produces SARIF v2.1.0 documents compliant with the OASIS standard. Key internal functions:

FunctionPurpose
verdict_level(OracleVerdict) -> &strMaps verdict to SARIF level (error/warning/note)
build_rule(OracleResult) -> serde_json::ValueBuilds a SARIF rule from the oracle result
build_sarif_result(...)Builds a SARIF result with message, level, fingerprints
build_sarif_document(...)Assembles the complete SARIF envelope (schema, version, runs, tool, results)

SARIF mapping details:

  • Confirmed -> level "error"
  • Likely -> level "warning"
  • Inconclusive -> level "note"
  • NotPresent -> level "note"
  • fingerprints uses key "oracleFingerprint/v1" with the deterministic finding_id from parlov-core
  • partialFingerprints uses key "techniqueTargetHash/v1" for technique+target deduplication
  • ruleId is derived from technique_id
  • Tool name: "parlov", semantic version from Cargo.toml

Table Output (table.rs)

Terminal table rendering using comfy-table. Features:

  • ANSI color coding by verdict (green=NotPresent, yellow=Likely, red=Confirmed)
  • Severity column with color coding
  • Confidence as integer with optional impact class (e.g. "85 (High)")
  • Primary evidence extraction
  • Scan tables include strategy name and method columns
  • Snapshot-tested against golden files

Output Format Examples

JSON (single finding)

{
  "schema_version": "0.6.0",
  "target_url": "https://api.example.com/users/9999",
  "finding": {
    "finding_id": "a1b2c3d4e5f6",
    "strategy": { "id": "accept-elicit", "name": "Accept header", "method": "GET" },
    "result": {
      "oracle_class": "Existence",
      "verdict": "Confirmed",
      "severity": "Medium",
      "confidence": 85,
      "impact_class": "High"
    },
    "technique": { "id": "accept", "vector": "StatusCodeDiff", "normative_strength": "Should" },
    "matched_pattern": { "label": "OK/Not Found", "leaks": null, "rfc_basis": "RFC 9110 §15.5.5" },
    "evidence": {
      "reasons": [],
      "signals": []
    }
  }
}

SARIF (single finding)

{
  "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json",
  "version": "2.1.0",
  "runs": [{
    "tool": { "driver": { "name": "parlov", "version": "0.6.0", "rules": [] } },
    "results": [{
      "ruleId": "accept",
      "level": "error",
      "message": { "text": "Existence Confirmed (confidence 85): 200 vs 404" },
      "fingerprints": { "oracleFingerprint/v1": "a1b2c3d4e5f6" },
      "partialFingerprints": { "techniqueTargetHash/v1": "f6e5d4c3b2a1" }
    }]
  }]
}

Extension Points

Adding a new output format: Add a new module (e.g. csv.rs), implement a render_* function that takes &OracleResult or &[ScanFinding], and wire it into the CLI's OutputFormat enum in the parlov binary crate.

Evolving JSON schema: Modify the DTO structs in json.rs. The DTO layer insulates the JSON schema from OracleResult field changes. Add snapshot tests for new fields.

On this page