Skip to content

Commit 33b45c9

Browse files
committed
refactoring: move isVersionAffectedBy and isVersionRangeAffectedBy to Security.Advisories.Core (hsec-core) (#253)
1 parent d338c7a commit 33b45c9

File tree

7 files changed

+56
-50
lines changed

7 files changed

+56
-50
lines changed

code/hsec-core/hsec-core.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,11 @@ test-suite spec
4848
type: exitcode-stdio-1.0
4949
hs-source-dirs: test
5050
main-is: Spec.hs
51+
other-modules:
52+
Spec.QueriesSpec
5153
build-depends:
5254
, base
55+
, Cabal-syntax
5356
, cvss
5457
, hsec-core
5558
, tasty <2

code/hsec-core/src/Security/Advisories/Core/Advisory.hs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ module Security.Advisories.Core.Advisory
1414
, GHCComponent(..)
1515
, ghcComponentToText
1616
, ghcComponentFromText
17+
-- * Queries
18+
, isVersionAffectedBy
19+
, isVersionRangeAffectedBy
1720
)
1821
where
1922

2023
import Data.Text (Text)
2124
import Data.Time (UTCTime)
2225
import Distribution.Types.Version (Version)
23-
import Distribution.Types.VersionRange (VersionRange)
26+
import Distribution.Types.VersionInterval (asVersionIntervals)
27+
import Distribution.Types.VersionRange (VersionRange, anyVersion, earlierVersion, intersectVersionRanges, noVersion, orLaterVersion, unionVersionRanges, withinRange)
2428

2529
import Text.Pandoc.Definition (Pandoc)
2630

@@ -147,3 +151,42 @@ data AffectedVersionRange = AffectedVersionRange
147151
affectedVersionRangeFixed :: Maybe Version
148152
}
149153
deriving stock (Eq, Show)
154+
155+
-- * Queries
156+
157+
-- | Check whether a component and a version is concerned by an advisory
158+
--
159+
-- Since @0.2.1.0@
160+
isVersionAffectedBy :: ComponentIdentifier -> Version -> Advisory -> Bool
161+
isVersionAffectedBy = isAffectedByHelper withinRange
162+
163+
-- | Check whether a component and a version range is concerned by an advisory
164+
--
165+
-- Since @0.2.1.0@
166+
isVersionRangeAffectedBy :: ComponentIdentifier -> VersionRange -> Advisory -> Bool
167+
isVersionRangeAffectedBy = isAffectedByHelper $
168+
\queryVersionRange affectedVersionRange ->
169+
isSomeVersion (affectedVersionRange `intersectVersionRanges` queryVersionRange)
170+
where
171+
isSomeVersion :: VersionRange -> Bool
172+
isSomeVersion range
173+
| [] <- asVersionIntervals range = False
174+
| otherwise = True
175+
176+
-- | Helper function for 'isVersionAffectedBy' and 'isVersionRangeAffectedBy'
177+
isAffectedByHelper :: (a -> VersionRange -> Bool) -> ComponentIdentifier -> a -> Advisory -> Bool
178+
isAffectedByHelper checkWithRange queryComponent queryVersionish =
179+
any checkAffected . advisoryAffected
180+
where
181+
checkAffected :: Affected -> Bool
182+
checkAffected affected =
183+
affectedComponentIdentifier affected == queryComponent && checkWithRange queryVersionish (fromAffected affected)
184+
185+
fromAffected :: Affected -> VersionRange
186+
fromAffected = foldr (unionVersionRanges . fromAffectedVersionRange) noVersion . affectedVersions
187+
188+
fromAffectedVersionRange :: AffectedVersionRange -> VersionRange
189+
fromAffectedVersionRange avr = intersectVersionRanges
190+
(orLaterVersion (affectedVersionRangeIntroduced avr))
191+
(maybe anyVersion earlierVersion (affectedVersionRangeFixed avr))
192+

code/hsec-core/test/Spec.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
module Main where
22

33
import Test.Tasty
4+
import qualified Spec.QueriesSpec as QueriesSpec
45

56
main :: IO ()
67
main =
78
defaultMain $
89
testGroup
910
"Tests"
10-
[]
11+
[QueriesSpec.spec]

code/hsec-tools/test/Spec/QueriesSpec.hs renamed to code/hsec-core/test/Spec/QueriesSpec.hs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import Test.Tasty.HUnit
1717
import Security.CVSS (parseCVSS)
1818
import Security.Advisories.Core.Advisory
1919
import Security.Advisories.Core.HsecId
20-
import Security.Advisories.Queries
2120

2221
spec :: TestTree
2322
spec =
@@ -37,7 +36,7 @@ spec =
3736
in testCase (title actual query) $
3837
let query' = versionRange query
3938
affectedVersion' = versionRange actual
40-
in isVersionRangeAffectedBy packageName query' (mkAdvisory affectedVersion')
39+
in isVersionRangeAffectedBy component query' (mkAdvisory affectedVersion')
4140
@?= expected
4241
]
4342

@@ -115,7 +114,7 @@ mkAdvisory versionRange =
115114
, advisoryRelated = [ "CVE-2022-YYYY" , "CVE-2022-ZZZZ" ]
116115
, advisoryAffected =
117116
[ Affected
118-
{ affectedComponentIdentifier = Hackage packageName
117+
{ affectedComponentIdentifier = component
119118
, affectedCVSS = cvss
120119
, affectedVersions = mkAffectedVersions versionRange
121120
, affectedArchitectures = Nothing
@@ -186,8 +185,8 @@ mkAffectedVersions vr =
186185
, high <- mkAffectedVersions y
187186
]
188187

189-
packageName :: Text
190-
packageName = "package-name"
188+
component :: ComponentIdentifier
189+
component = Hackage "package-name"
191190

192191
-- | Parse 'VersionRange' as given to the CLI
193192
parseVersionRange :: Maybe Text -> Either Text VersionRange

code/hsec-tools/hsec-tools.cabal

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ test-suite spec
133133
other-modules:
134134
Paths_hsec_tools
135135
Spec.FormatSpec
136-
Spec.QueriesSpec
137136
build-depends:
138137
, aeson-pretty <2
139138
, base
Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,19 @@
11
module Security.Advisories.Queries
22
( listVersionAffectedBy
33
, listVersionRangeAffectedBy
4-
, isVersionAffectedBy
5-
, isVersionRangeAffectedBy
64
)
75
where
86

97
import Control.Monad.IO.Class (MonadIO)
108
import Data.Text (Text)
119
import Distribution.Types.Version (Version)
12-
import Distribution.Types.VersionInterval (asVersionIntervals)
13-
import Distribution.Types.VersionRange (VersionRange, anyVersion, earlierVersion, intersectVersionRanges, noVersion, orLaterVersion, unionVersionRanges, withinRange)
10+
import Distribution.Types.VersionRange (VersionRange)
1411
import Validation (Validation(..))
1512

1613
import Security.Advisories.Core.Advisory
1714
import Security.Advisories.Filesystem
1815
import Security.Advisories.Parse
1916

20-
-- | Check whether a package and a version is concerned by an advisory
21-
isVersionAffectedBy :: Text -> Version -> Advisory -> Bool
22-
isVersionAffectedBy = isAffectedByHelper withinRange
23-
24-
-- | Check whether a package and a version range is concerned by an advisory
25-
isVersionRangeAffectedBy :: Text -> VersionRange -> Advisory -> Bool
26-
isVersionRangeAffectedBy = isAffectedByHelper $
27-
\queryVersionRange affectedVersionRange ->
28-
isSomeVersion (affectedVersionRange `intersectVersionRanges` queryVersionRange)
29-
where
30-
isSomeVersion :: VersionRange -> Bool
31-
isSomeVersion range
32-
| [] <- asVersionIntervals range = False
33-
| otherwise = True
34-
35-
-- | Helper function for 'isVersionAffectedBy' and 'isVersionRangeAffectedBy'
36-
isAffectedByHelper :: (a -> VersionRange -> Bool) -> Text -> a -> Advisory -> Bool
37-
isAffectedByHelper checkWithRange queryPackageName queryVersionish =
38-
any checkAffected . advisoryAffected
39-
where
40-
checkAffected :: Affected -> Bool
41-
checkAffected affected = case affectedComponentIdentifier affected of
42-
Hackage pkg -> queryPackageName == pkg && checkWithRange queryVersionish (fromAffected affected)
43-
-- TODO: support GHC ecosystem query, e.g. by adding a cli flag
44-
_ -> False
45-
46-
fromAffected :: Affected -> VersionRange
47-
fromAffected = foldr (unionVersionRanges . fromAffectedVersionRange) noVersion . affectedVersions
48-
49-
fromAffectedVersionRange :: AffectedVersionRange -> VersionRange
50-
fromAffectedVersionRange avr = intersectVersionRanges
51-
(orLaterVersion (affectedVersionRangeIntroduced avr))
52-
(maybe anyVersion earlierVersion (affectedVersionRangeFixed avr))
53-
5417
type QueryResult = Validation [(FilePath, ParseAdvisoryError)] [Advisory]
5518

5619
-- | List the advisories matching a package name and a version
@@ -68,7 +31,7 @@ listVersionRangeAffectedBy = listAffectedByHelper isVersionRangeAffectedBy
6831
-- | Helper function for 'listVersionAffectedBy' and 'listVersionRangeAffectedBy'
6932
listAffectedByHelper
7033
:: (MonadIO m)
71-
=> (Text -> a -> Advisory -> Bool) -> FilePath -> Text -> a -> m QueryResult
34+
=> (ComponentIdentifier -> a -> Advisory -> Bool) -> FilePath -> Text -> a -> m QueryResult
7235
listAffectedByHelper checkAffectedBy root queryPackageName queryVersionish =
73-
fmap (filter (checkAffectedBy queryPackageName queryVersionish)) <$>
36+
fmap (filter (checkAffectedBy (Hackage queryPackageName) queryVersionish)) <$>
7437
listAdvisories root

code/hsec-tools/test/Spec.hs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import Paths_hsec_tools (getDataFileName)
1313
import qualified Security.Advisories.Convert.OSV as OSV
1414
import Security.Advisories.Parse
1515
import qualified Spec.FormatSpec as FormatSpec
16-
import qualified Spec.QueriesSpec as QueriesSpec
1716
import System.Directory (listDirectory)
1817
import Test.Tasty (defaultMain, testGroup, TestTree)
1918
import Test.Tasty.Golden (goldenVsString)
@@ -26,7 +25,6 @@ main = do
2625
testGroup
2726
"Tests"
2827
[ goldenTestsSpec goldenFiles
29-
, QueriesSpec.spec
3028
, FormatSpec.spec
3129
]
3230

0 commit comments

Comments
 (0)