diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.4.0.0
+
+* Introduce `OsvId` and use it in `Advisory.{aliases,related}`
+
 ## 0.3.0.2
 
 * Update `cvss` dependency bounds
diff --git a/hsec-core.cabal b/hsec-core.cabal
--- a/hsec-core.cabal
+++ b/hsec-core.cabal
@@ -1,37 +1,48 @@
-cabal-version:      2.4
-name:               hsec-core
-version:            0.3.0.1
+cabal-version:   2.4
+name:            hsec-core
+version:         0.4.0.0
 
 -- A short (one-line) description of the package.
-synopsis:           Core package representing Haskell advisories
+synopsis:        Core package representing Haskell advisories
 
 -- A longer description of the package.
-description:        Core package representing Haskell advisories.
+description:     Core package representing Haskell advisories.
 
 -- A URL where users can report bugs.
 -- bug-reports:
 
 -- The license under which the package is released.
-license:            BSD-3-Clause
-author:             Haskell Security Response Team
-maintainer:         security-advisories@haskell.org
+license:         BSD-3-Clause
+author:          Haskell Security Response Team
+maintainer:      security-advisories@haskell.org
 
 -- A copyright notice.
 -- copyright:
-category:           Data
-extra-doc-files:    CHANGELOG.md, README.md
+category:        Data
+extra-doc-files:
+  CHANGELOG.md
+  README.md
 
 tested-with:
-  GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.6 || ==9.8.3 || ==9.10.1 || ==9.12.1
+  GHC ==8.10.7
+   || ==9.0.2
+   || ==9.2.8
+   || ==9.4.8
+   || ==9.6.6
+   || ==9.8.3
+   || ==9.10.1
+   || ==9.12.1
 
 library
   exposed-modules:
     Security.Advisories.Core.Advisory
     Security.Advisories.Core.HsecId
+    Security.Advisories.Core.OsvId
 
   build-depends:
     , base          >=4.14    && <5
     , Cabal-syntax  >=3.8.1.0 && <3.15
+    , containers    >=0.6     && <0.8
     , cvss          >=0.2     && <0.4
     , network-uri   >=2.6.3.0 && <2.8
     , osv           >=0.1     && <0.3
@@ -39,6 +50,7 @@
     , safe          >=0.3     && <0.4
     , text          >=1.2     && <3
     , time          >=1.9     && <1.15
+
   hs-source-dirs:   src
   default-language: Haskell2010
   ghc-options:
@@ -49,15 +61,14 @@
   type:             exitcode-stdio-1.0
   hs-source-dirs:   test
   main-is:          Spec.hs
-  other-modules:
-    Spec.QueriesSpec
+  other-modules:    Spec.QueriesSpec
   build-depends:
     , base
     , Cabal-syntax
     , cvss
     , hsec-core
-    , tasty        <2
-    , tasty-hunit  <0.11
+    , tasty         <2
+    , tasty-hunit   <0.11
     , text
 
   default-language: Haskell2010
diff --git a/src/Security/Advisories/Core/Advisory.hs b/src/Security/Advisories/Core/Advisory.hs
--- a/src/Security/Advisories/Core/Advisory.hs
+++ b/src/Security/Advisories/Core/Advisory.hs
@@ -1,30 +1,34 @@
-{-# LANGUAGE DerivingVia, OverloadedStrings, QuasiQuotes #-}
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
 
 module Security.Advisories.Core.Advisory
-  ( Advisory(..)
+  ( Advisory (..),
+
     -- * Supporting types
-  , Affected(..)
-  , CAPEC(..)
-  , CWE(..)
-  , Architecture(..)
-  , AffectedVersionRange(..)
-  , OS(..)
-  , Keyword(..)
-  , ComponentIdentifier(..)
-  , GHCComponent(..)
-  , RepositoryURL(..)
-  , RepositoryName(..)
-  , PackageName
-  , mkPackageName
-  , unPackageName
-  , ghcComponentToText
-  , ghcComponentFromText
-  , hackage
+    Affected (..),
+    CAPEC (..),
+    CWE (..),
+    Architecture (..),
+    AffectedVersionRange (..),
+    OS (..),
+    Keyword (..),
+    ComponentIdentifier (..),
+    GHCComponent (..),
+    RepositoryURL (..),
+    RepositoryName (..),
+    PackageName,
+    mkPackageName,
+    unPackageName,
+    ghcComponentToText,
+    ghcComponentFromText,
+    hackage,
+
     -- * Queries
-  , isVersionAffectedBy
-  , isVersionRangeAffectedBy
+    isVersionAffectedBy,
+    isVersionRangeAffectedBy,
   )
-  where
+where
 
 import Data.Text (Text)
 import Data.Time (UTCTime)
@@ -34,30 +38,30 @@
 import Distribution.Types.VersionRange (VersionRange, anyVersion, earlierVersion, intersectVersionRanges, noVersion, orLaterVersion, unionVersionRanges, withinRange)
 import Network.URI (URI)
 import Network.URI.Static (uri)
-
-import Text.Pandoc.Definition (Pandoc)
-
 import Security.Advisories.Core.HsecId (HsecId)
+import Security.Advisories.Core.OsvId (OsvId)
 import qualified Security.CVSS as CVSS
 import Security.OSV (Reference)
+import Text.Pandoc.Definition (Pandoc)
 
 data Advisory = Advisory
-  { advisoryId :: HsecId
-  , advisoryModified :: UTCTime
-  , advisoryPublished :: UTCTime
-  , advisoryCAPECs :: [CAPEC]
-  , advisoryCWEs :: [CWE]
-  , advisoryKeywords :: [Keyword]
-  , advisoryAliases :: [Text]
-  , advisoryRelated :: [Text]
-  , advisoryAffected :: [Affected]
-  , advisoryReferences :: [Reference]
-  , advisoryPandoc :: Pandoc  -- ^ Parsed document, without TOML front matter
-  , advisoryHtml :: Text
-  , advisorySummary :: Text
-    -- ^ A one-line, English textual summary of the vulnerability
-  , advisoryDetails :: Text
-    -- ^ Details of the vulnerability (CommonMark), without TOML front matter
+  { advisoryId :: HsecId,
+    advisoryModified :: UTCTime,
+    advisoryPublished :: UTCTime,
+    advisoryCAPECs :: [CAPEC],
+    advisoryCWEs :: [CWE],
+    advisoryKeywords :: [Keyword],
+    advisoryAliases :: [OsvId],
+    advisoryRelated :: [OsvId],
+    advisoryAffected :: [Affected],
+    advisoryReferences :: [Reference],
+    -- | Parsed document, without TOML front matter
+    advisoryPandoc :: Pandoc,
+    advisoryHtml :: Text,
+    -- | A one-line, English textual summary of the vulnerability
+    advisorySummary :: Text,
+    -- | Details of the vulnerability (CommonMark), without TOML front matter
+    advisoryDetails :: Text
   }
   deriving stock (Show)
 
@@ -73,11 +77,11 @@
     (RepositoryName "hackage")
 
 newtype RepositoryURL
-  = RepositoryURL { unRepositoryURL :: URI }
+  = RepositoryURL {unRepositoryURL :: URI}
   deriving stock (Eq, Ord, Show)
 
 newtype RepositoryName
-  = RepositoryName { unRepositoryName :: Text }
+  = RepositoryName {unRepositoryName :: Text}
   deriving stock (Eq, Ord, Show)
 
 -- Keep this list in sync with the 'ghcComponentFromText' below
@@ -114,12 +118,12 @@
 -- | An affected package (or package component).  An 'Advisory' must
 -- mention one or more packages.
 data Affected = Affected
-  { affectedComponentIdentifier :: ComponentIdentifier
-  , affectedCVSS :: CVSS.CVSS
-  , affectedVersions :: [AffectedVersionRange]
-  , affectedArchitectures :: Maybe [Architecture]
-  , affectedOS :: Maybe [OS]
-  , affectedDeclarations :: [(Text, VersionRange)]
+  { affectedComponentIdentifier :: ComponentIdentifier,
+    affectedCVSS :: CVSS.CVSS,
+    affectedVersions :: [AffectedVersionRange],
+    affectedArchitectures :: Maybe [Architecture],
+    affectedOS :: Maybe [OS],
+    affectedDeclarations :: [(Text, VersionRange)]
   }
   deriving stock (Eq, Show)
 
@@ -201,17 +205,17 @@
 -- | Helper function for 'isVersionAffectedBy' and 'isVersionRangeAffectedBy'
 isAffectedByHelper :: (a -> VersionRange -> Bool) -> ComponentIdentifier -> a -> Advisory -> Bool
 isAffectedByHelper checkWithRange queryComponent queryVersionish =
-    any checkAffected . advisoryAffected
-    where
-      checkAffected :: Affected -> Bool
-      checkAffected affected =
-        affectedComponentIdentifier affected == queryComponent && checkWithRange queryVersionish (fromAffected affected)
+  any checkAffected . advisoryAffected
+  where
+    checkAffected :: Affected -> Bool
+    checkAffected affected =
+      affectedComponentIdentifier affected == queryComponent && checkWithRange queryVersionish (fromAffected affected)
 
-      fromAffected :: Affected -> VersionRange
-      fromAffected = foldr (unionVersionRanges . fromAffectedVersionRange) noVersion . affectedVersions
+    fromAffected :: Affected -> VersionRange
+    fromAffected = foldr (unionVersionRanges . fromAffectedVersionRange) noVersion . affectedVersions
 
-      fromAffectedVersionRange :: AffectedVersionRange -> VersionRange
-      fromAffectedVersionRange avr = intersectVersionRanges
+    fromAffectedVersionRange :: AffectedVersionRange -> VersionRange
+    fromAffectedVersionRange avr =
+      intersectVersionRanges
         (orLaterVersion (affectedVersionRangeIntroduced avr))
         (maybe anyVersion earlierVersion (affectedVersionRangeFixed avr))
-
diff --git a/src/Security/Advisories/Core/OsvId.hs b/src/Security/Advisories/Core/OsvId.hs
new file mode 100644
--- /dev/null
+++ b/src/Security/Advisories/Core/OsvId.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Security.Advisories.Core.OsvId
+  ( OsvId,
+    parseOsvId,
+    printOsvId,
+    osvIdPrefix,
+  )
+where
+
+import qualified Data.List as L
+import Data.Maybe (listToMaybe)
+import qualified Data.Set as Set
+import Data.Text (Text)
+import qualified Data.Text as T
+
+newtype OsvId = OsvId Text
+  deriving (Eq, Ord, Show)
+
+knownPrefixes :: Set.Set Text
+knownPrefixes =
+  Set.fromList
+    [ "ASB-A",
+      "PUB-A",
+      "ALSA",
+      "ALBA",
+      "ALEA",
+      "ALPINE",
+      "BELL",
+      "BIT",
+      "CGA",
+      "CleanStart",
+      "CURL",
+      "CVE",
+      "DEBIAN",
+      "DHI",
+      "DRUPAL",
+      "DSA",
+      "DLA",
+      "DTSA",
+      "ECHO",
+      "EEF",
+      "ELA",
+      "GHSA",
+      "GO",
+      "GSD",
+      "HSEC",
+      "JLSEC",
+      "KUBE",
+      "LBSEC",
+      "LSN",
+      "MGASA",
+      "MAL",
+      "MINI",
+      "OESA",
+      "OSEC",
+      "OSV",
+      "PHSA",
+      "PSF",
+      "PYSEC",
+      "RHSA",
+      "RHBA",
+      "RHEA",
+      "RLSA",
+      "RXSA",
+      "RSEC",
+      "ROOT",
+      "RUSTSEC",
+      "SUSE-SU",
+      "SUSE-RU",
+      "SUSE-FU",
+      "SUSE-OU",
+      "openSUSE-SU",
+      "UBUNTU",
+      "USN",
+      "V8"
+    ]
+
+sortedPrefixes :: [Text]
+sortedPrefixes = L.reverse . L.sortOn T.length $ Set.toList knownPrefixes
+
+parseOsvId :: Text -> Maybe OsvId
+parseOsvId t = do
+  prefix <- findPrefix t
+  let rest = T.drop (T.length prefix + 1) t
+  guard (not (T.null rest))
+  pure (OsvId t)
+  where
+    findPrefix txt =
+      listToMaybe $
+        filter (\p -> T.isPrefixOf (p <> "-") txt) sortedPrefixes
+
+    guard True = Just ()
+    guard False = Nothing
+
+printOsvId :: OsvId -> Text
+printOsvId (OsvId t) = t
+
+osvIdPrefix :: OsvId -> Text
+osvIdPrefix (OsvId t) = case findPrefix t of
+  Just p -> p
+  Nothing -> T.takeWhile (/= '-') t
+  where
+    findPrefix txt =
+      listToMaybe $
+        filter (\p -> T.isPrefixOf (p <> "-") txt) sortedPrefixes
diff --git a/test/Spec/QueriesSpec.hs b/test/Spec/QueriesSpec.hs
--- a/test/Spec/QueriesSpec.hs
+++ b/test/Spec/QueriesSpec.hs
@@ -6,188 +6,189 @@
 import Data.Bifunctor (first)
 import Data.Either (fromRight)
 import Data.Maybe (fromMaybe)
+import qualified Data.Maybe as Maybe
 import Data.Text (Text)
 import qualified Data.Text as T
 import Distribution.Parsec (eitherParsec)
-import Distribution.Types.Version (version0, alterVersion)
-import Distribution.Types.VersionRange (VersionRange, VersionRangeF(..), anyVersion, projectVersionRange)
-import Test.Tasty
-import Test.Tasty.HUnit
-
-import Security.CVSS (parseCVSS)
+import Distribution.Types.Version (alterVersion, version0)
+import Distribution.Types.VersionRange (VersionRange, VersionRangeF (..), anyVersion, projectVersionRange)
 import Security.Advisories.Core.Advisory
 import Security.Advisories.Core.HsecId
+import Security.Advisories.Core.OsvId (parseOsvId)
+import Security.CVSS (parseCVSS)
+import Test.Tasty
+import Test.Tasty.HUnit
 
 spec :: TestTree
 spec =
-  testGroup "Queries" [
-    testGroup "isAffectedBy" $
-      flip concatMap cases $ map $ \(actual, query, expected) ->
-        let title x y =
-              if expected
-                then show x <> " is vulnerable to " <> show y
-                else show x <> " is not vulnerable to " <> show y
-            versionRange x =
-              either (\e -> error $ "Cannot parse version range " <> show x <> " : " <> show e) id $
-                parseVersionRange $
-                  if x == ""
-                    then Nothing
-                    else Just x
-         in testCase (title actual query) $
-              let query' = versionRange query
-                  affectedVersion' = versionRange actual
-              in isVersionRangeAffectedBy component query' (mkAdvisory affectedVersion')
-                    @?= expected
-  ]
+  testGroup
+    "Queries"
+    [ testGroup "isAffectedBy" $
+        flip concatMap cases $
+          map $ \(actual, query, expected) ->
+            let title x y =
+                  if expected
+                    then show x <> " is vulnerable to " <> show y
+                    else show x <> " is not vulnerable to " <> show y
+                versionRange x =
+                  either (\e -> error $ "Cannot parse version range " <> show x <> " : " <> show e) id $
+                    parseVersionRange $
+                      if x == ""
+                        then Nothing
+                        else Just x
+             in testCase (title actual query) $
+                  let query' = versionRange query
+                      affectedVersion' = versionRange actual
+                   in isVersionRangeAffectedBy component query' (mkAdvisory affectedVersion')
+                        @?= expected
+    ]
 
 cases :: [[(Text, Text, Bool)]]
 cases =
-  [
-    reversible ("", "", True)
-  , reversible ("", "==1", True)
-  , reversible ("==1.1", "<=2", True)
-  , reversible ("==1.1", ">1", True)
-  , reversible ("==1", "==1", True)
-  , reversible ("==2||==1", "==1", True)
-  , reversible ("==1.1", "<=2&&>1", True)
-  , reversible ("^>=1", ">1&&<1.2", True)
-  , reversible (">=1", "==2", True)
-  , reversible (">=1", "==1", True)
-  , reversible ("==2", ">=2", True)
-  , reversible ("==2", ">1", True)
-  , reversible (">5", ">=2", True)
-  , reversible (">5", ">2", True)
-  , reversible ("==5", ">=2", True)
-  , reversible ("==5", ">2", True)
-  , reversible (">=5", ">2", True)
-  , reversible ("<=5", ">2", True)
-  , reversible ("<=5", "<=2", True)
-  , reversible ("<5", ">=2", True)
-  , reversible (">=2", "==5", True)
-  , reversible (">2", "==5", True)
-  , reversible (">5", ">=5", True)
-  , reversible ("^>=1.1", ">1", True)
-  , reversible ("^>=1.1", "<2", True)
-  , reversible ("^>=1.1", "<=1.2", True)
-  , reversible ("^>=1.1", ">1.1", True)
-  , reversible ("^>=1.1", ">=1.1.5", True)
-  , reversible ("^>=1.1", ">=1", True)
-  , reversible ("==1.1", "<1", False)
-  , reversible ("==2.1", "<=2", False)
-  , reversible ("==1", ">1.1", False)
-  , reversible ("==2", "==1", False)
-  , reversible ("==2||==1", ">3", False)
-  , notReversible ("<=2&&>1", "==3", True)
-  , reversible (">=2", "==1.1", False)
-  , reversible (">=1.1", "==1", False)
-  , reversible ("==2", ">=2.1", False)
-  , notReversible (">1", "==1", False)
-  , reversible ("<2", ">=2", False)
-  , reversible ("==2", ">=5", False)
-  , reversible ("==2", ">5", False)
-  , reversible ("<=2", ">5", False)
-  , reversible ("<=2", ">5", False)
-  , reversible ("<2", ">=5", False)
-  , reversible (">=2", "==1.1", False)
-  , reversible ("<2", "==5", False)
-  , reversible ("<5", ">=5", False)
-  , reversible ("^>=1.1", "<1", False)
-  , reversible ("^>=1.1", "<1.1", False)
-  , reversible ("^>=1.1", ">=1.2", False)
-  , reversible ("^>=1.1", "<=1", False)
-  , reversible ("^>=1.1", ">2", False)
-  , reversible ("^>=1", ">=2", False)
+  [ reversible ("", "", True),
+    reversible ("", "==1", True),
+    reversible ("==1.1", "<=2", True),
+    reversible ("==1.1", ">1", True),
+    reversible ("==1", "==1", True),
+    reversible ("==2||==1", "==1", True),
+    reversible ("==1.1", "<=2&&>1", True),
+    reversible ("^>=1", ">1&&<1.2", True),
+    reversible (">=1", "==2", True),
+    reversible (">=1", "==1", True),
+    reversible ("==2", ">=2", True),
+    reversible ("==2", ">1", True),
+    reversible (">5", ">=2", True),
+    reversible (">5", ">2", True),
+    reversible ("==5", ">=2", True),
+    reversible ("==5", ">2", True),
+    reversible (">=5", ">2", True),
+    reversible ("<=5", ">2", True),
+    reversible ("<=5", "<=2", True),
+    reversible ("<5", ">=2", True),
+    reversible (">=2", "==5", True),
+    reversible (">2", "==5", True),
+    reversible (">5", ">=5", True),
+    reversible ("^>=1.1", ">1", True),
+    reversible ("^>=1.1", "<2", True),
+    reversible ("^>=1.1", "<=1.2", True),
+    reversible ("^>=1.1", ">1.1", True),
+    reversible ("^>=1.1", ">=1.1.5", True),
+    reversible ("^>=1.1", ">=1", True),
+    reversible ("==1.1", "<1", False),
+    reversible ("==2.1", "<=2", False),
+    reversible ("==1", ">1.1", False),
+    reversible ("==2", "==1", False),
+    reversible ("==2||==1", ">3", False),
+    notReversible ("<=2&&>1", "==3", True),
+    reversible (">=2", "==1.1", False),
+    reversible (">=1.1", "==1", False),
+    reversible ("==2", ">=2.1", False),
+    notReversible (">1", "==1", False),
+    reversible ("<2", ">=2", False),
+    reversible ("==2", ">=5", False),
+    reversible ("==2", ">5", False),
+    reversible ("<=2", ">5", False),
+    reversible ("<=2", ">5", False),
+    reversible ("<2", ">=5", False),
+    reversible (">=2", "==1.1", False),
+    reversible ("<2", "==5", False),
+    reversible ("<5", ">=5", False),
+    reversible ("^>=1.1", "<1", False),
+    reversible ("^>=1.1", "<1.1", False),
+    reversible ("^>=1.1", ">=1.2", False),
+    reversible ("^>=1.1", "<=1", False),
+    reversible ("^>=1.1", ">2", False),
+    reversible ("^>=1", ">=2", False)
   ]
-  where reversible (query, affectedVersion, expected) = [(query, affectedVersion, expected), (query, affectedVersion, expected)]
-        notReversible (query, affectedVersion, expected) = [(query, affectedVersion, expected), (affectedVersion, query, not expected)]
+  where
+    reversible (query, affectedVersion, expected) = [(query, affectedVersion, expected), (query, affectedVersion, expected)]
+    notReversible (query, affectedVersion, expected) = [(query, affectedVersion, expected), (affectedVersion, query, not expected)]
 
 mkAdvisory :: VersionRange -> Advisory
 mkAdvisory versionRange =
-   Advisory
-     { advisoryId = fromMaybe (error "Cannot mkHsecId") $ mkHsecId 2023 42
-     , advisoryModified = read "2023-01-01T00:00:00"
-     , advisoryPublished = read "2023-01-01T00:00:00"
-     , advisoryCAPECs = []
-     , advisoryCWEs = []
-     , advisoryKeywords = []
-     , advisoryAliases = [ "CVE-2022-XXXX" ]
-     , advisoryRelated = [ "CVE-2022-YYYY" , "CVE-2022-ZZZZ" ]
-     , advisoryAffected =
-         [ Affected
-             { affectedComponentIdentifier = component
-             , affectedCVSS = cvss
-             , affectedVersions = mkAffectedVersions versionRange
-             , affectedArchitectures = Nothing
-             , affectedOS = Nothing
-             , affectedDeclarations = []
-             }
-         ]
-     , advisoryReferences = []
-     , advisoryPandoc = mempty
-     , advisoryHtml = ""
-     , advisorySummary = ""
-     , advisoryDetails = ""
-     }
+  Advisory
+    { advisoryId = fromMaybe (error "Cannot mkHsecId") $ mkHsecId 2023 42,
+      advisoryModified = read "2023-01-01T00:00:00",
+      advisoryPublished = read "2023-01-01T00:00:00",
+      advisoryCAPECs = [],
+      advisoryCWEs = [],
+      advisoryKeywords = [],
+      advisoryAliases = Maybe.fromJust . traverse parseOsvId $ ["CVE-2022-1234"],
+      advisoryRelated = Maybe.fromJust . traverse parseOsvId $ ["CVE-2022-5678", "CVE-2022-9012"],
+      advisoryAffected =
+        [ Affected
+            { affectedComponentIdentifier = component,
+              affectedCVSS = cvss,
+              affectedVersions = mkAffectedVersions versionRange,
+              affectedArchitectures = Nothing,
+              affectedOS = Nothing,
+              affectedDeclarations = []
+            }
+        ],
+      advisoryReferences = [],
+      advisoryPandoc = mempty,
+      advisoryHtml = "",
+      advisorySummary = "",
+      advisoryDetails = ""
+    }
   where
     cvss = fromRight (error "Cannot parseCVSS") (parseCVSS "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
 
 mkAffectedVersions :: VersionRange -> [AffectedVersionRange]
 mkAffectedVersions vr =
-  let
-    fixed from to =
-      AffectedVersionRange
-        { affectedVersionRangeIntroduced = from
-        , affectedVersionRangeFixed = Just to
-        }
-    onlyFixed to =
-      AffectedVersionRange
-        { affectedVersionRangeIntroduced = version0
-        , affectedVersionRangeFixed = Just to
-        }
-    vulnerable from =
-      AffectedVersionRange
-        { affectedVersionRangeIntroduced = from
-        , affectedVersionRangeFixed = Nothing
-        }
-    nextMinor =
-      \case
-        [] -> [1]
-        [x] -> [x, 1]
-        [x, y] -> [x, y, 1]
-        [x, y, z] -> [x, y, z, 1]
-        [w, x, y, z] -> [w, x, y, z + 1]
-        xs -> xs ++ [1]
-    previousMinor =
-      \case
-        [] -> [0]
-        [x] -> [x - 1 , 99]
-        [x, y] -> [x, y - 1, 99]
-        [x, y, z] -> [x, y, z - 1, 99]
-        [w, x, y, z] -> [w, x, y, z - 1]
-        _ -> error "TODO"
-    mkMajorBoundVersion =
-      \case
-        [] -> [0]
-        [x] -> [x, 1]
-        (x:y:_) -> [x, y + 1]
-  in
-  case projectVersionRange vr of
-    ThisVersionF x -> [fixed x $ alterVersion (<> [0,0,1]) x]
-    LaterVersionF x -> [vulnerable $ alterVersion nextMinor x]
-    OrLaterVersionF x -> [vulnerable x]
-    EarlierVersionF x -> [onlyFixed $ alterVersion previousMinor x]
-    OrEarlierVersionF x -> [onlyFixed x]
-    MajorBoundVersionF x -> [fixed x $ alterVersion mkMajorBoundVersion x]
-    UnionVersionRangesF x y -> mkAffectedVersions x <> mkAffectedVersions y
-    IntersectVersionRangesF x y ->
-      [ low { affectedVersionRangeFixed = affectedVersionRangeFixed high }
-      | low <- mkAffectedVersions x
-      , high <- mkAffectedVersions y
-      ]
+  let fixed from to =
+        AffectedVersionRange
+          { affectedVersionRangeIntroduced = from,
+            affectedVersionRangeFixed = Just to
+          }
+      onlyFixed to =
+        AffectedVersionRange
+          { affectedVersionRangeIntroduced = version0,
+            affectedVersionRangeFixed = Just to
+          }
+      vulnerable from =
+        AffectedVersionRange
+          { affectedVersionRangeIntroduced = from,
+            affectedVersionRangeFixed = Nothing
+          }
+      nextMinor =
+        \case
+          [] -> [1]
+          [x] -> [x, 1]
+          [x, y] -> [x, y, 1]
+          [x, y, z] -> [x, y, z, 1]
+          [w, x, y, z] -> [w, x, y, z + 1]
+          xs -> xs ++ [1]
+      previousMinor =
+        \case
+          [] -> [0]
+          [x] -> [x - 1, 99]
+          [x, y] -> [x, y - 1, 99]
+          [x, y, z] -> [x, y, z - 1, 99]
+          [w, x, y, z] -> [w, x, y, z - 1]
+          _ -> error "TODO"
+      mkMajorBoundVersion =
+        \case
+          [] -> [0]
+          [x] -> [x, 1]
+          (x : y : _) -> [x, y + 1]
+   in case projectVersionRange vr of
+        ThisVersionF x -> [fixed x $ alterVersion (<> [0, 0, 1]) x]
+        LaterVersionF x -> [vulnerable $ alterVersion nextMinor x]
+        OrLaterVersionF x -> [vulnerable x]
+        EarlierVersionF x -> [onlyFixed $ alterVersion previousMinor x]
+        OrEarlierVersionF x -> [onlyFixed x]
+        MajorBoundVersionF x -> [fixed x $ alterVersion mkMajorBoundVersion x]
+        UnionVersionRangesF x y -> mkAffectedVersions x <> mkAffectedVersions y
+        IntersectVersionRangesF x y ->
+          [ low {affectedVersionRangeFixed = affectedVersionRangeFixed high}
+            | low <- mkAffectedVersions x,
+              high <- mkAffectedVersions y
+          ]
 
 component :: ComponentIdentifier
 component = hackage $ mkPackageName "package-name"
 
 -- | Parse 'VersionRange' as given to the CLI
 parseVersionRange :: Maybe Text -> Either Text VersionRange
-parseVersionRange  = maybe (return anyVersion) (first T.pack . eitherParsec . T.unpack)
+parseVersionRange = maybe (return anyVersion) (first T.pack . eitherParsec . T.unpack)
