mirror of
https://github.com/lunchcat/sif.git
synced 2026-06-12 11:01:24 -07:00
1237f3f09e
scan results live in ~two dozen structs with no shared shape, so every consumer that wants "what did this run turn up" reimplements the type-switch. add internal/finding: an ordered Severity (info<low<medium< high<critical, with parse/compare) and Flatten, the single type-switch that collapses every scan result struct into flat, severity-ranked Findings keyed module:identifier for stable dedup/diff. wire collectFindings off Flatten in the run loop so notify and diff (later bundles) build on one normalization path instead of re-deriving it; the report path keeps emitting raw json blobs unchanged. expose JavascriptScanResult.SupabaseFindings so the js internals stay private. the guard test iterates a representative instance of every ResultType and fails if Flatten lacks a case (falls through to :unhandled) - so a new scanner can't ship without a Flatten case landing too.
79 lines
3.1 KiB
Go
79 lines
3.1 KiB
Go
/*
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
: :
|
|
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
|
|
: ▄█ █ █▀ · BSD 3-Clause License :
|
|
: :
|
|
: (c) 2022-2026 vmfunc, xyzeva, :
|
|
: lunchcat alumni & contributors :
|
|
: :
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
*/
|
|
|
|
package finding
|
|
|
|
import "strings"
|
|
|
|
// Severity is an ordered severity rank shared by every normalized finding.
|
|
// the order matters: notify gates on a threshold and diff sorts by it, so the
|
|
// underlying ints have to compare info < low < medium < high < critical.
|
|
type Severity int
|
|
|
|
// severity ranks, lowest to highest. SeverityUnknown sorts below everything so
|
|
// an unrecognized scanner string never silently outranks a real critical.
|
|
const (
|
|
SeverityUnknown Severity = iota
|
|
SeverityInfo
|
|
SeverityLow
|
|
SeverityMedium
|
|
SeverityHigh
|
|
SeverityCritical
|
|
)
|
|
|
|
// severityNames maps each rank to its canonical lowercase string. the wire
|
|
// format scanners emit ("info"/"low"/...) round-trips through this table.
|
|
var severityNames = map[Severity]string{
|
|
SeverityUnknown: "unknown",
|
|
SeverityInfo: "info",
|
|
SeverityLow: "low",
|
|
SeverityMedium: "medium",
|
|
SeverityHigh: "high",
|
|
SeverityCritical: "critical",
|
|
}
|
|
|
|
// String renders the canonical lowercase name for the rank.
|
|
func (s Severity) String() string {
|
|
if name, ok := severityNames[s]; ok {
|
|
return name
|
|
}
|
|
return severityNames[SeverityUnknown]
|
|
}
|
|
|
|
// ParseSeverity maps a scanner's free-form severity string onto a rank. it's
|
|
// case/space insensitive and folds the common synonyms ("informational",
|
|
// "warning", "moderate") so the dozen scanners that each picked their own
|
|
// spelling all land on the same ladder. an empty or unrecognized value is
|
|
// SeverityUnknown rather than a guess.
|
|
func ParseSeverity(raw string) Severity {
|
|
switch strings.ToLower(strings.TrimSpace(raw)) {
|
|
case "critical":
|
|
return SeverityCritical
|
|
case "high":
|
|
return SeverityHigh
|
|
case "medium", "moderate", "warning":
|
|
return SeverityMedium
|
|
case "low":
|
|
return SeverityLow
|
|
case "info", "informational", "information", "none":
|
|
return SeverityInfo
|
|
default:
|
|
return SeverityUnknown
|
|
}
|
|
}
|
|
|
|
// AtLeast reports whether s is at or above threshold; notify uses it to drop
|
|
// findings below the configured floor.
|
|
func (s Severity) AtLeast(threshold Severity) bool {
|
|
return s >= threshold
|
|
}
|