summaryrefslogtreecommitdiff
path: root/octosentry/SeverityMapping.swift
blob: 5befb460de2d1e7cf3eea48e9f13b03d96acf936 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//
//  SeverityMapping.swift
//  octosentry
//
//  Normalizes each GitHub alert source's native severity vocabulary into
//  the shared SecurityEventSeverity scale. Kept as a single auditable
//  source file per the spec (§4) rather than scattered across the client.
//

import Foundation

nonisolated enum SeverityMapping {
    /// Dependabot alerts report CVSS-derived severity on the vulnerability object.
    static func dependabot(_ nativeSeverity: String) -> SecurityEventSeverity {
        switch nativeSeverity.lowercased() {
        case "critical": .critical
        case "high": .high
        case "moderate", "medium": .medium
        case "low": .low
        default: .medium
        }
    }

    /// Code scanning alerts expose `rule.security_severity_level` (CVSS-derived) when
    /// present, falling back to `rule.severity` (note/warning/error) otherwise.
    static func codeScanning(securitySeverityLevel: String?, ruleSeverity: String?) -> SecurityEventSeverity {
        if let securitySeverityLevel {
            switch securitySeverityLevel.lowercased() {
            case "critical": return .critical
            case "high": return .high
            case "medium": return .medium
            case "low": return .low
            default: break
            }
        }
        switch ruleSeverity?.lowercased() {
        case "error": return .high
        case "warning": return .medium
        case "note": return .low
        default: return .medium
        }
    }

    /// Secret scanning has no native severity field. Per spec: validated/active
    /// secrets are treated as critical, unvalidated ones as high.
    static func secretScanning(validity: String?) -> SecurityEventSeverity {
        switch validity?.lowercased() {
        case "active": .critical
        default: .high
        }
    }
}