1
1
{-# LANGUAGE OverloadedStrings #-}
2
+ {-# LANGUAGE RecordWildCards #-}
2
3
3
- module Security.Advisories.Convert.OSV
4
- ( convert
5
- )
6
- where
4
+ module Security.Advisories.Convert.OSV (
5
+ convert ,
6
+ convertWithLinks ,
7
+ DbLinks (.. ),
8
+ AffectedLinks (.. ),
9
+ haskellLinks ,
10
+ )
11
+ where
7
12
13
+ import Data.Aeson
8
14
import qualified Data.Text as T
9
15
import Data.Void
10
16
import Distribution.Pretty (prettyShow )
@@ -14,35 +20,36 @@ import qualified Security.OSV as OSV
14
20
15
21
convert :: Advisory -> OSV. Model Void Void Void Void
16
22
convert adv =
17
- ( OSV. newModel'
18
- (T. pack . printHsecId $ advisoryId adv)
19
- (advisoryModified adv)
20
- )
21
- { OSV. modelPublished = Just $ advisoryPublished adv
22
- , OSV. modelAliases = advisoryAliases adv
23
- , OSV. modelRelated = advisoryRelated adv
24
- , OSV. modelSummary = Just $ advisorySummary adv
25
- , OSV. modelDetails = Just $ advisoryDetails adv
26
- , OSV. modelReferences = advisoryReferences adv
27
- , OSV. modelAffected = fmap mkAffected (advisoryAffected adv)
28
- }
23
+ ( OSV. newModel'
24
+ (T. pack . printHsecId $ advisoryId adv)
25
+ (advisoryModified adv)
26
+ )
27
+ { OSV. modelPublished = Just $ advisoryPublished adv
28
+ , OSV. modelAliases = advisoryAliases adv
29
+ , OSV. modelRelated = advisoryRelated adv
30
+ , OSV. modelSummary = Just $ advisorySummary adv
31
+ , OSV. modelDetails = Just $ advisoryDetails adv
32
+ , OSV. modelReferences = advisoryReferences adv
33
+ , OSV. modelAffected = fmap mkAffected (advisoryAffected adv)
34
+ }
29
35
30
36
mkAffected :: Affected -> OSV. Affected Void Void Void
31
37
mkAffected aff =
32
- OSV. Affected
33
- { OSV. affectedPackage = mkPackage (affectedComponentIdentifier aff)
34
- , OSV. affectedRanges = pure $ mkRange (affectedVersions aff)
35
- , OSV. affectedSeverity = [OSV. Severity (affectedCVSS aff)]
36
- , OSV. affectedEcosystemSpecific = Nothing
37
- , OSV. affectedDatabaseSpecific = Nothing
38
- }
38
+ OSV. Affected
39
+ { OSV. affectedPackage = mkPackage (affectedComponentIdentifier aff)
40
+ , OSV. affectedRanges = pure $ mkRange (affectedVersions aff)
41
+ , OSV. affectedSeverity = [OSV. Severity (affectedCVSS aff)]
42
+ , OSV. affectedEcosystemSpecific = Nothing
43
+ , OSV. affectedDatabaseSpecific = Nothing
44
+ }
39
45
40
46
mkPackage :: ComponentIdentifier -> OSV. Package
41
- mkPackage ecosystem = OSV. Package
42
- { OSV. packageName = packageName
43
- , OSV. packageEcosystem = ecosystemName
44
- , OSV. packagePurl = Nothing
45
- }
47
+ mkPackage ecosystem =
48
+ OSV. Package
49
+ { OSV. packageName = packageName
50
+ , OSV. packageEcosystem = ecosystemName
51
+ , OSV. packagePurl = Nothing
52
+ }
46
53
where
47
54
(ecosystemName, packageName) = case ecosystem of
48
55
Hackage n -> (" Hackage" , n)
@@ -54,5 +61,64 @@ mkRange ranges =
54
61
where
55
62
mkEvs :: AffectedVersionRange -> [OSV. Event T. Text ]
56
63
mkEvs range =
57
- OSV. EventIntroduced (T. pack $ prettyShow $ affectedVersionRangeIntroduced range)
58
- : maybe [] (pure . OSV. EventFixed . T. pack . prettyShow) (affectedVersionRangeFixed range)
64
+ OSV. EventIntroduced (T. pack $ prettyShow $ affectedVersionRangeIntroduced range)
65
+ : maybe [] (pure . OSV. EventFixed . T. pack . prettyShow) (affectedVersionRangeFixed range)
66
+
67
+ convertWithLinks :: DbLinks -> Advisory -> OSV. Model DbLinks AffectedLinks Void Void
68
+ convertWithLinks links adv =
69
+ OSV. Model
70
+ { OSV. modelDatabaseSpecific = Just links
71
+ , OSV. modelAffected = mkAffectedWithLinks links (advisoryId adv) <$> advisoryAffected adv
72
+ , ..
73
+ }
74
+ where
75
+ OSV. Model {.. } = convert adv
76
+
77
+ data DbLinks = DbLinks
78
+ { dbLinksRepository :: T. Text
79
+ , dbLinksOSVs :: T. Text
80
+ , dbLinksHome :: T. Text
81
+ }
82
+
83
+ instance ToJSON DbLinks where
84
+ toJSON DbLinks {.. } =
85
+ object
86
+ [ " repository" .= dbLinksRepository
87
+ , " osvs" .= dbLinksOSVs
88
+ , " home" .= dbLinksHome
89
+ ]
90
+
91
+ haskellLinks :: DbLinks
92
+ haskellLinks =
93
+ DbLinks
94
+ { dbLinksRepository = " https://github.com/haskell/security-advisories"
95
+ , dbLinksOSVs = " https://raw.githubusercontent.com/haskell/security-advisories/refs/heads/generated/osv-export"
96
+ , dbLinksHome = " https://haskell.github.io/security-advisories"
97
+ }
98
+
99
+ data AffectedLinks = AffectedLinks
100
+ { affectedLinksOSV :: T. Text
101
+ , affectedLinksHumanLink :: T. Text
102
+ }
103
+
104
+ instance ToJSON AffectedLinks where
105
+ toJSON AffectedLinks {.. } =
106
+ object
107
+ [ " osv" .= affectedLinksOSV
108
+ , " human_link" .= affectedLinksHumanLink
109
+ ]
110
+
111
+ mkAffectedWithLinks :: DbLinks -> HsecId -> Affected -> OSV. Affected AffectedLinks Void Void
112
+ mkAffectedWithLinks links hsecId aff =
113
+ OSV. Affected
114
+ { OSV. affectedDatabaseSpecific =
115
+ Just
116
+ AffectedLinks
117
+ { affectedLinksOSV = stripSlash (dbLinksOSVs links) <> " /" <> T. pack (show $ hsecIdYear hsecId) <> " /" <> T. pack (printHsecId hsecId) <> " .json"
118
+ , affectedLinksHumanLink = stripSlash (dbLinksHome links) <> " /advisory/" <> T. pack (printHsecId hsecId) <> " .html"
119
+ }
120
+ , ..
121
+ }
122
+ where
123
+ OSV. Affected {.. } = mkAffected aff
124
+ stripSlash = T. dropWhileEnd (== ' /' )
0 commit comments