report

package
v0.0.0-...-0979862 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FormatCSV

func FormatCSV(data *ReportData, w io.Writer) error

FormatCSV writes the report as CSV format.

func FormatHTML

func FormatHTML(data *ReportData, w io.Writer) error

FormatHTML writes the report as a standalone HTML page.

func FormatJSON

func FormatJSON(data *ReportData, w io.Writer) error

FormatJSON writes the report as pretty-printed JSON.

func FormatMarkdown

func FormatMarkdown(data *ReportData, w io.Writer) error

FormatMarkdown writes the report as human-readable Markdown.

func FormatReviewHTML

func FormatReviewHTML(data *ReviewData, w io.Writer) error

FormatReviewHTML writes a self-contained HTML triage page.

func FormatSARIF

func FormatSARIF(data *ReportData, w io.Writer) error

FormatSARIF writes the report as SARIF 2.1.0 JSON format.

Types

type AnalysisService

type AnalysisService interface {
	AnalyzeRun(ctx context.Context, runID int64) (*analysis.Metrics, error)
	AnalyzeRunWithCategories(ctx context.Context, runID int64) (*analysis.Metrics, map[string]*analysis.CategoryMetrics, error)
	AnalyzeRunDetail(ctx context.Context, runID int64) (*analysis.RunDetail, error)
}

AnalysisService defines the analysis methods needed by the report service.

type AnnotationCoverage

type AnnotationCoverage struct {
	ID             int64   `json:"id"`
	FilePath       string  `json:"file_path"`
	StartLine      int     `json:"start_line"`
	EndLine        int     `json:"end_line,omitempty"`
	CWEID          string  `json:"cwe_id,omitempty"`
	Category       string  `json:"category"`
	Severity       string  `json:"severity"`
	Description    string  `json:"description,omitempty"`
	Status         string  `json:"status"`               // valid, invalid, disputed
	Matched        bool    `json:"matched"`              // was it triggered?
	MatchType      string  `json:"match_type,omitempty"` // exact, fuzzy, category
	Confidence     float64 `json:"confidence,omitempty"`
	Classification string  `json:"classification"` // TP, FP, TN, FN
}

AnnotationCoverage shows how each annotation was handled in a run.

type CategoryStats

type CategoryStats struct {
	Category  string  `json:"category"`
	TP        int     `json:"tp"`
	FP        int     `json:"fp"`
	FN        int     `json:"fn"`
	TN        int     `json:"tn"`
	Precision float64 `json:"precision"`
	Recall    float64 `json:"recall"`
	F1        float64 `json:"f1"`
	Accuracy  float64 `json:"accuracy"`
}

CategoryStats contains per-category metrics breakdown.

type ComparisonData

type ComparisonData struct {
	BaselineIndex int                  `json:"baseline_index,omitempty"`
	Entries       []ComparisonEntry    `json:"entries"`
	ByProject     []ProjectComparisonN `json:"by_project,omitempty"`
}

ComparisonData contains side-by-side scanner comparison for N scanners.

type ComparisonEntry

type ComparisonEntry struct {
	Scanner ScannerInfo       `json:"scanner"`
	Metrics ComparisonMetrics `json:"metrics"`
	Delta   *MetricDeltas     `json:"delta,omitempty"` // nil for baseline scanner
}

ComparisonEntry holds one scanner's comparison data.

type ComparisonMetrics

type ComparisonMetrics struct {
	Precision   float64 `json:"precision"`
	Recall      float64 `json:"recall"`
	F1          float64 `json:"f1"`
	Accuracy    float64 `json:"accuracy"`
	DurationMs  float64 `json:"duration_ms"`
	MemoryBytes float64 `json:"memory_bytes"`
}

ComparisonMetrics contains metrics for comparison.

type CrossRunHit

type CrossRunHit struct {
	RunID     int64
	Scanner   string
	Iteration int
	Matched   bool // did that run's finding at this location get a match?
}

type ExperimentInfo

type ExperimentInfo struct {
	ID          int64  `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Iterations  int    `json:"iterations"`
}

ExperimentInfo contains experiment metadata.

type FindingCard

type FindingCard struct {
	Finding     store.Finding
	RuleName    string                    // human-readable rule title (SARIF mode); empty if unavailable
	Context     *SourceContext            // ±N lines from disk; nil if unreadable
	Match       *MatchInfo                // nil for unmatched
	Disposition *store.FindingDisposition // nil if unset
	NearMiss    *NearMiss                 // unmatched only; nil if nothing close
	CrossRun    []CrossRunHit             // --cross-run only
	TriageCmd   string                    // prefilled CLI; unmatched only
}

FindingCard is one triage card. Every nil pointer field degrades gracefully in the template — SARIF-standalone mode populates almost nothing beyond Finding, RuleName, and Context.

type MatchInfo

type MatchInfo struct {
	MatchType  string
	Confidence float64
	VulnName   string
	Evidence   store.Evidence
}

type MetricDeltas

type MetricDeltas struct {
	Precision   float64 `json:"precision"`
	Recall      float64 `json:"recall"`
	F1          float64 `json:"f1"`
	Accuracy    float64 `json:"accuracy"`
	DurationMs  float64 `json:"duration_ms"`
	MemoryBytes float64 `json:"memory_bytes"`
}

MetricDeltas contains deltas between a scanner and the baseline.

type MetricsSummary

type MetricsSummary struct {
	TotalRuns      int     `json:"total_runs"`
	TotalFindings  int     `json:"total_findings"`
	TotalTP        int     `json:"total_tp"`
	TotalFP        int     `json:"total_fp"`
	TotalFN        int     `json:"total_fn"`
	TotalTN        int     `json:"total_tn"`
	AvgPrecision   float64 `json:"avg_precision"`
	AvgRecall      float64 `json:"avg_recall"`
	AvgF1          float64 `json:"avg_f1"`
	AvgAccuracy    float64 `json:"avg_accuracy"`
	AvgDurationMs  float64 `json:"avg_duration_ms"`
	AvgMemoryBytes float64 `json:"avg_memory_bytes"`
}

MetricsSummary contains aggregate metrics across all scanners/projects.

type NearFinding

type NearFinding struct {
	Finding   store.Finding
	LineDelta int
	Why       string
}

type NearMiss

type NearMiss struct {
	Evidence  store.Evidence
	VulnName  string
	LineDelta int
	CWEDist   int // from cwe.Distance; -1 = unrelated
	Why       string
}

NearMiss explains why the closest evidence didn't match. This is the "is this a matching artifact or a real new thing?" helper.

type ProjectComparisonEntry

type ProjectComparisonEntry struct {
	ScannerName string   `json:"scanner_name"`
	F1          float64  `json:"f1"`
	DeltaF1     *float64 `json:"delta_f1,omitempty"`
}

ProjectComparisonEntry holds one scanner's per-project comparison data.

type ProjectComparisonN

type ProjectComparisonN struct {
	ProjectName string                   `json:"project_name"`
	ProjectID   int64                    `json:"project_id"`
	Entries     []ProjectComparisonEntry `json:"entries"`
}

ProjectComparisonN contains per-project comparison data for N scanners.

type ProjectInfo

type ProjectInfo struct {
	ID       int64  `json:"id"`
	Name     string `json:"name"`
	Language string `json:"language,omitempty"`
}

ProjectInfo contains project metadata.

type ProjectResult

type ProjectResult struct {
	ProjectName       string               `json:"project_name"`
	ProjectID         int64                `json:"project_id"`
	TP                int                  `json:"tp"`
	FP                int                  `json:"fp"`
	FN                int                  `json:"fn"`
	TN                int                  `json:"tn"`
	Precision         float64              `json:"precision"`
	Recall            float64              `json:"recall"`
	F1                float64              `json:"f1"`
	Accuracy          float64              `json:"accuracy"`
	DurationMs        int64                `json:"duration_ms"`
	MemoryBytes       int64                `json:"memory_bytes"`
	Annotations       []AnnotationCoverage `json:"annotations,omitempty"`
	UnmatchedFindings []UnmatchedFinding   `json:"unmatched_findings,omitempty"`
}

ProjectResult contains per-project results for a scanner.

type ReportData

type ReportData struct {
	Title       string          `json:"title"`
	GeneratedAt time.Time       `json:"generated_at"`
	Experiment  ExperimentInfo  `json:"experiment"`
	Scanners    []ScannerInfo   `json:"scanners"`
	Projects    []ProjectInfo   `json:"projects"`
	Summary     MetricsSummary  `json:"summary"`
	ByScanner   []ScannerResult `json:"by_scanner"`
	ByCategory  []CategoryStats `json:"by_category"`
	Comparison  *ComparisonData `json:"comparison,omitempty"`
}

ReportData contains all data needed to generate a benchmark report.

type ReviewData

type ReviewData struct {
	Mode        string // "run" | "sarif"
	Meta        ReviewMeta
	Summary     *analysis.Metrics // nil in sarif mode
	Unmatched   []FindingCard     // triage targets
	Matched     []FindingCard     // verification view, low-confidence first
	Unsatisfied []VulnCard        // FN vulns — nil in sarif mode
	CrossRun    bool              // was --cross-run requested? lets the template say "only this run" when CrossRunHit is empty
	GeneratedAt time.Time
}

ReviewData is the finding-centric triage view. Unlike ReportData it is single-run (or single-SARIF) and puts unmatched findings first and loudest — those are the ones that need a human call.

func BuildReviewFromRun

func BuildReviewFromRun(ctx context.Context, st ReviewStore, asvc *analysis.Service, runID int64, opts ReviewOptions) (*ReviewData, error)

BuildReviewFromRun assembles a ReviewData from a stored run. The analysis service is run first so matches and metrics reflect current matcher logic; the store is then read directly for the card details that AnalyzeRunDetail doesn't carry (full disposition structs, evidence rows, vuln CWE sets).

func BuildReviewFromSARIF

func BuildReviewFromSARIF(path, sourceRoot string, contextLines int) (*ReviewData, error)

BuildReviewFromSARIF renders a SARIF file without any DB context. No match info, no dispositions, no near-miss — just findings grouped by file with messages and (if --source-root given) code context.

type ReviewMeta

type ReviewMeta struct {
	RunID       int64
	Scanner     string
	Project     string
	ProjectPath string
	ToolName    string // sarif mode: tool.driver.name
	ToolVersion string
	SourceRoot  string // sarif mode: --source-root
}

type ReviewOptions

type ReviewOptions struct {
	ContextLines int  // ±N lines around finding; default 5
	CrossRun     bool // look up sibling runs in the same experiment
}

type ReviewStore

type ReviewStore interface {
	GetRun(ctx context.Context, id int64) (*store.Run, error)
	GetScanner(ctx context.Context, id int64) (*store.Scanner, error)
	GetProject(ctx context.Context, id int64) (*store.CorpusProject, error)
	ListFindingsByRun(ctx context.Context, runID int64) ([]store.Finding, error)
	ListFindingMatchesByRun(ctx context.Context, runID int64) ([]store.FindingMatch, error)
	ListDispositionsByRun(ctx context.Context, runID int64) ([]store.FindingDisposition, error)
	ListEvidenceByProject(ctx context.Context, projectID int64) ([]store.Evidence, error)
	ListVulnerabilitiesByProject(ctx context.Context, projectID int64) ([]store.Vulnerability, error)
	ListVulnCWEs(ctx context.Context, projectID int64) (map[int64][]string, error)
	ListUnsatisfiedVulns(ctx context.Context, runID, projectID int64) ([]store.Vulnerability, error)
	ListRunsByExperiment(ctx context.Context, experimentID int64) ([]store.Run, error)
}

ReviewStore is the subset of *store.Store the run-mode builder reads. It's wide because triage cards pull from the whole schema — finding, disposition, evidence, vuln, CWE set, sibling runs. In practice the CLI passes globalStore directly.

type ScannerInfo

type ScannerInfo struct {
	ID      int64  `json:"id"`
	Name    string `json:"name"`
	Version string `json:"version"`
}

ScannerInfo contains scanner metadata.

type ScannerMetrics

type ScannerMetrics struct {
	TP              int     `json:"tp"`
	FP              int     `json:"fp"`
	FN              int     `json:"fn"`
	TN              int     `json:"tn"`
	Precision       float64 `json:"precision"`
	Recall          float64 `json:"recall"`
	F1              float64 `json:"f1"`
	Accuracy        float64 `json:"accuracy"`
	PrecisionStdDev float64 `json:"precision_stddev,omitempty"`
	RecallStdDev    float64 `json:"recall_stddev,omitempty"`
	F1StdDev        float64 `json:"f1_stddev,omitempty"`
	DurationMean    float64 `json:"duration_mean_ms,omitempty"`
	MemoryMean      float64 `json:"memory_mean_bytes,omitempty"`
}

ScannerMetrics contains aggregated metrics for a scanner.

type ScannerResult

type ScannerResult struct {
	ScannerName string          `json:"scanner_name"`
	ScannerID   int64           `json:"scanner_id"`
	RunCount    int             `json:"run_count"`
	Metrics     ScannerMetrics  `json:"metrics"`
	ByProject   []ProjectResult `json:"by_project"`
}

ScannerResult contains per-scanner results with metrics.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides report generation functionality.

func NewService

func NewService(s Store, a AnalysisService) *Service

NewService creates a report service with the given dependencies.

func (*Service) GenerateReportData

func (s *Service) GenerateReportData(ctx context.Context, experimentID int64) (*ReportData, error)

GenerateReportData assembles all data for a report from an experiment.

type SourceContext

type SourceContext struct {
	Lines    []SourceLine
	Language string // for CSS class, best-effort from extension
}

type SourceLine

type SourceLine struct {
	N      int
	Text   string
	Target bool // inside the finding's [StartLine, EndLine]
}

type Store

type Store interface {
	GetExperiment(ctx context.Context, id int64) (*store.Experiment, error)
	ListExperimentScanners(ctx context.Context, experimentID int64) ([]store.Scanner, error)
	ListExperimentProjects(ctx context.Context, experimentID int64) ([]store.CorpusProject, error)
	ListRunsByExperiment(ctx context.Context, experimentID int64) ([]store.Run, error)
	GetScanner(ctx context.Context, id int64) (*store.Scanner, error)
	GetProject(ctx context.Context, id int64) (*store.CorpusProject, error)
}

Store defines the store methods needed by the report service.

type UnmatchedFinding

type UnmatchedFinding struct {
	FilePath  string `json:"file_path"`
	StartLine int    `json:"start_line"`
	CWEID     string `json:"cwe_id,omitempty"`
	RuleID    string `json:"rule_id,omitempty"`
	Severity  string `json:"severity,omitempty"`
	Message   string `json:"message,omitempty"`
}

UnmatchedFinding shows a finding that didn't match any annotation.

type VulnCard

type VulnCard struct {
	Vuln           store.Vulnerability
	Evidence       []store.Evidence
	CWEs           []string
	NearestFinding *NearFinding // nil if nothing in any evidence file
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL