Skip to content
go-sarif

go · zero deps · sarif 2.1.0

Emit SARIF for code scanning.

Map your analyzer's findings to a standards-compliant SARIF 2.1.0 document that GitHub Code Scanning, GitLab, and other CI systems ingest — standard library only, one Write call.

MIT licensed · no third-party dependencies · standard library only

sarif.go
sarif.Write(os.Stdout,
    sarif.Tool{Name: "mytool", Version: "1.2.3"},
    []sarif.Rule{{ID: "complexity", Name: "CyclomaticComplexity"}},
    []sarif.Result{{RuleID: "complexity", Level: "error",
        Message: "F is too complex", URI: "pkg/a.go",
        StartLine: 10, EndLine: 42}})  // one call → valid SARIF

what you get

SARIF output, without the schema wrangling.

Three small structs and a single Write produce the document CI code-scanning tools expect — you describe the findings, it handles the SARIF.

Standards-compliant SARIF 2.1.0

Emits the exact document CI code-scanning ingests — the OASIS SARIF 2.1.0 schema that GitHub, GitLab, and others parse without translation.

Zero dependencies

Built on the Go standard library only. No third-party imports, no version churn — just encoding/json under the hood.

Three structs, one call

Tool, Rule, and Result describe the run; a single Write serializes them to a valid SARIF log.

Line-level or file-level

Attach a region to each finding, or emit a file-level result when StartLine <= 0 — both are valid, and you pick per finding.

Portable URIs

Artifact URIs are emitted with forward slashes per RFC 3986 — safe and consistent across Windows and POSIX toolchains.

Sensible defaults

Level defaults to warning when unset, and an empty result set still writes a valid run — no special-casing the zero-finding path.

usage

Describe findings, then Write.

Build a Tool, your Rule set, and a slice of Result values, then hand them to Write. Regions are line-level by default; drop them for a file-level result.

// Line-level finding with a region
sarif.Write(os.Stdout,
    sarif.Tool{Name: "mytool", Version: "1.2.3"},
    []sarif.Rule{{ID: "complexity", Name: "CyclomaticComplexity"}},
    []sarif.Result{{RuleID: "complexity", Level: "error",
        Message: "F is too complex", URI: "pkg/a.go",
        StartLine: 10, EndLine: 42}})
// File-level result — StartLine 0, level defaults to warning
sarif.Write(os.Stdout,
    sarif.Tool{Name: "mytool", Version: "1.2.3"},
    []sarif.Rule{{ID: "license", Name: "MissingLicense"}},
    []sarif.Result{{RuleID: "license",
        Message: "no LICENSE file found", URI: "pkg/a.go",
        StartLine: 0}})  // no region ⇒ whole file
  • Write
  • Tool
  • Rule
  • Result
  • Level: warning (default)
  • StartLine / EndLine
  • SARIF 2.1.0

install

Add it to your module.

One import, no transitive dependencies — standard library only.

go get go get github.com/richardwooding/go-sarif
import import sarif "github.com/richardwooding/go-sarif"

Extracted from file-search-on. Full API on the Go Reference.