Open-Source Wikis

/

Gitleaks

/

Systems

/

report

gitleaks/gitleaks

report

Active contributors: Zachary Rice, Richard Gomez

Purpose

report/ defines Finding (the structured representation of a leak) and the Reporter interface plus five built-in implementations: JSON, CSV, JUnit, SARIF, and a Go text/template renderer.

Directory layout

report/
├── report.go         # Reporter interface (a single `Write` method)
├── finding.go        # Finding + RequiredFinding types, redaction
├── constants.go      # driver/version constants for SARIF
├── json.go           # JsonReporter
├── csv.go            # CsvReporter
├── junit.go          # JunitReporter
├── sarif.go          # SarifReporter (the most fully-typed one)
└── template.go       # TemplateReporter using text/template + sprig

Key abstractions

Symbol File Description
Reporter report.go One method: Write(w io.WriteCloser, findings []Finding) error
Finding finding.go The structured leak: rule ID, file, line/column, match, secret, commit metadata, fingerprint, tags
RequiredFinding finding.go A subset of Finding carried inside a primary finding when composite rules fire
Finding.Redact(percent) finding.go Mask a percentage of the secret (or replace with REDACTED at 100)
JsonReporter, CsvReporter, JunitReporter, SarifReporter per file The four built-ins
TemplateReporter template.go text/template-based custom output
NewTemplateReporter(path) template.go Loads a template file, registers sprig functions, returns the reporter
StdoutReportPath (constant) -, used to direct output to stdout instead of a file

How it works

The reporter is selected in cmd/root.go's Detector(...) constructor. The selection logic:

  1. If --report-format is set, use that.
  2. Otherwise, infer from the --report-path extension: .csv, .json, .sarif are auto-detected. Other extensions fail.
  3. If --report-format=template, the --report-template flag must point at a Go template file.

The chosen reporter is stored on Detector.Reporter. After scanning, findingSummaryAndExit opens the report path (or stdout if it's -) and calls reporter.Write(file, findings).

graph LR
    Flags[--report-format<br/>--report-path] --> Sel[reporter selection]
    Sel --> JR[JsonReporter]
    Sel --> CR[CsvReporter]
    Sel --> JU[JunitReporter]
    Sel --> SA[SarifReporter]
    Sel --> TP[TemplateReporter]
    Findings[Detector.findings] --> Wr[reporter.Write]
    Wr --> Out[file or stdout]

JSON

JsonReporter (report/json.go) is a one-line implementation — json.NewEncoder(w).SetIndent("", " ").Encode(findings). It's the most common format and is what baselines consume.

CSV

CsvReporter (report/csv.go) writes a header row and one data row per finding using encoding/csv.

JUnit

JunitReporter (report/junit.go) emits a JUnit XML test report so CI systems can surface findings in their test output. Each finding becomes a failing test case keyed on the rule ID.

SARIF

SarifReporter (report/sarif.go) is the most fully-typed reporter — it builds a SARIF 2.1.0 document conforming to the schema at https://json.schemastore.org/sarif-2.1.0.json. Notable details:

  • The tool.driver.rules array is populated from Config.GetOrderedRules() so ordering is stable across runs.
  • partialFingerprints carries commit metadata (sha, email, message, date, author) so SARIF consumers like GitHub Code Scanning can deduplicate across runs.
  • Empty rule lists are explicitly rendered as [] (not null) for consumers that don't tolerate null.

Template

TemplateReporter (report/template.go) takes a --report-template path, reads its contents, parses it as a Go text/template, and registers the Masterminds/sprig function map minus env, expandenv, and getHostByName (these are removed for security; templates shouldn't have access to environment variables or the network).

Finding

type Finding struct {
    RuleID, Description string
    StartLine, EndLine, StartColumn, EndColumn int
    Line, Match, Secret string
    File, SymlinkFile, Commit string
    Link string `json:",omitempty"`
    Entropy float32
    Author, Email, Date, Message string
    Tags []string
    Fingerprint string
    Fragment *sources.Fragment `json:",omitempty"`
    requiredFindings []*RequiredFinding   // unexported; printed via PrintRequiredFindings
}

A few choices worth noting:

  • Line is excluded from JSON output (json:"-") because it can leak surrounding context the user didn't intend to share.
  • Fragment is included as a pointer so it can be nil — it's there for library consumers who want extra context (e.g., for ML-based post-filtering, mentioned in the comment as "eventually ML validation").
  • requiredFindings is unexported "during experimental phase" per the comment; only PrintRequiredFindings and AddRequiredFindings see it from outside.

Redaction

Finding.Redact(percent):

  • For percent ≥ 100, replaces Secret with the literal string REDACTED.
  • For percent < 100, keeps the first (1 - percent/100) * len(Secret) characters and appends ....
  • Replaces every occurrence of the original secret in Line and Match with the masked version, so logs and printed findings don't accidentally leak the value.

The --redact flag in cmd/root.go accepts a uint between 0 and 100; passing the flag with no value defaults to 100 (rootCmd.Flag("redact").NoOptDefVal = "100").

Integration points

  • detect/ populates the []Finding and stores the reporter on Detector.Reporter.
  • cmd/root.go chooses the reporter and opens the output writer.
  • config/ is consulted by the SARIF reporter through Config.GetOrderedRules().
  • Masterminds/sprig powers the template reporter's function map.

Entry points for modification

  • Adding a new format: implement Reporter with a Write(w, findings) method, and register it in cmd/root.go's reporter switch (case "yourformat": reporter = ...). Keep extension inference in mind.
  • Adding a Finding field: thread it through Finding, populate it in detect/detect.go's detectRule (or wherever the finding originates), and update each reporter that should surface it. Note that the JSON tags on Finding are inferred from struct field names — name new fields carefully, since they become public schema.
  • Tightening template safety: template.go already removes env, expandenv, and getHostByName from the sprig function map. If you need to remove more (e.g., file I/O helpers), delete(funcMap, "name") after the sprig import.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

report – Gitleaks wiki | Factory