Documentation
¶
Index ¶
- func FormatCSV(data *ReportData, w io.Writer) error
- func FormatHTML(data *ReportData, w io.Writer) error
- func FormatJSON(data *ReportData, w io.Writer) error
- func FormatMarkdown(data *ReportData, w io.Writer) error
- func FormatReviewHTML(data *ReviewData, w io.Writer) error
- func FormatSARIF(data *ReportData, w io.Writer) error
- type AnalysisService
- type AnnotationCoverage
- type CategoryStats
- type ComparisonData
- type ComparisonEntry
- type ComparisonMetrics
- type CrossRunHit
- type ExperimentInfo
- type FindingCard
- type MatchInfo
- type MetricDeltas
- type MetricsSummary
- type NearFinding
- type NearMiss
- type ProjectComparisonEntry
- type ProjectComparisonN
- type ProjectInfo
- type ProjectResult
- type ReportData
- type ReviewData
- type ReviewMeta
- type ReviewOptions
- type ReviewStore
- type ScannerInfo
- type ScannerMetrics
- type ScannerResult
- type Service
- type SourceContext
- type SourceLine
- type Store
- type UnmatchedFinding
- type VulnCard
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 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 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 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 ReviewOptions ¶
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 ¶
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 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
}