packages feed

hsec-tools-0.2.0.2: src/Security/Advisories/Convert/OSV.hs

{-# LANGUAGE OverloadedStrings #-}

module Security.Advisories.Convert.OSV
  ( convert
  )
  where

import qualified Data.Text as T
import Data.Void
import Distribution.Pretty (prettyShow)

import Security.Advisories
import qualified Security.OSV as OSV

convert :: Advisory -> OSV.Model Void Void Void Void
convert adv =
  ( OSV.newModel'
    (T.pack . printHsecId $ advisoryId adv)
    (advisoryModified adv)
  )
  { OSV.modelPublished = Just $ advisoryPublished adv
  , OSV.modelAliases = advisoryAliases adv
  , OSV.modelRelated = advisoryRelated adv
  , OSV.modelSummary = Just $ advisorySummary adv
  , OSV.modelDetails = Just $ advisoryDetails adv
  , OSV.modelReferences = advisoryReferences adv
  , OSV.modelAffected = fmap mkAffected (advisoryAffected adv)
  }

mkAffected :: Affected -> OSV.Affected Void Void Void
mkAffected aff =
  OSV.Affected
    { OSV.affectedPackage = mkPackage (affectedComponentIdentifier aff)
    , OSV.affectedRanges = pure $ mkRange (affectedVersions aff)
    , OSV.affectedSeverity = [OSV.Severity (affectedCVSS aff)]
    , OSV.affectedEcosystemSpecific = Nothing
    , OSV.affectedDatabaseSpecific = Nothing
    }

mkPackage :: ComponentIdentifier -> OSV.Package
mkPackage ecosystem = OSV.Package
  { OSV.packageName = packageName
  , OSV.packageEcosystem = ecosystemName
  , OSV.packagePurl = Nothing
  }
  where
    (ecosystemName, packageName) = case ecosystem of
        Hackage n -> ("Hackage", n)
        GHC c -> ("GHC", ghcComponentToText c)

mkRange :: [AffectedVersionRange] -> OSV.Range Void
mkRange ranges =
    OSV.RangeEcosystem (foldMap mkEvs ranges) Nothing
  where
    mkEvs :: AffectedVersionRange -> [OSV.Event T.Text]
    mkEvs range =
      OSV.EventIntroduced (T.pack $ prettyShow $ affectedVersionRangeIntroduced range)
      : maybe [] (pure . OSV.EventFixed . T.pack . prettyShow) (affectedVersionRangeFixed range)