| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Osv.Epss
Description
The FIRST.org EPSS feed, the exploitability score Pilot joins onto each advisory.
Pilot joins the scores through advisory aliases (Ecluse.Core.Osv.Advisory). Every compile
attempts the feed. A failed fetch is an EpssFeedFailure, and the ecosystem's EpssRequirement
decides whether it stops publication. Individual missing scores remain absent.
Synopsis
- maxEpssFeedBytes :: Int
- maxEpssLineBytes :: Int
- data EpssFeed = EpssFeed {}
- fetchEpssScores :: (MonadResource m, MonadThrow m, KatipContext m) => Int -> String -> m EpssFeed
- data EpssFeedTooLarge
- data EpssFeedEmpty = EpssFeedEmpty
- data EpssFeedTruncated = EpssFeedTruncated
- data EpssFeedFailure
- renderEpssFeedFailure :: EpssFeedFailure -> Text
- classifyEpssFailure :: SomeException -> Maybe EpssFeedFailure
- acquireEpssFeed :: (MonadResource m, MonadMask m, MonadUnliftIO m, KatipContext m) => Int -> String -> m (Either EpssFeedFailure EpssFeed)
- data EpssEnrichment
- resolveEnrichment :: EpssRequirement -> Either EpssFeedFailure EpssFeed -> Either EpssFeedFailure EpssEnrichment
- enrichedFeed :: EpssEnrichment -> Maybe EpssFeed
- enrichmentStatus :: EpssEnrichment -> EpssStatus
- data EpssScores
- mkEpssScores :: [(Text, Double)] -> EpssScores
- epssForIds :: EpssScores -> [Text] -> Maybe Double
- epssScoreCount :: EpssScores -> Int
- parseEpssLine :: ByteString -> Maybe (Text, Double)
- data EpssPreamble = EpssPreamble {}
- parseEpssPreamble :: ByteString -> EpssPreamble
The feed
maxEpssFeedBytes :: Int Source #
The byte ceiling Pilot fetches under, 64 MiB, applied to the served stream and again to its expansion. The feed is one short row per scored CVE, so the headroom is several times over.
maxEpssLineBytes :: Int Source #
The longest feed line Pilot holds, 4 KiB. A scored row is under 100 bytes, so a longer line is no row, and bytes that never reach a newline cannot pile up.
One fetch of the feed: the scores it carries, and what it says about itself. The feed declares its own score date, so a stalled feed is visible without a second source of truth.
Constructors
| EpssFeed | |
Fields
| |
Instances
fetchEpssScores :: (MonadResource m, MonadThrow m, KatipContext m) => Int -> String -> m EpssFeed Source #
Fetch the feed and decode it into a score table, bounded by cap bytes on each side of
decompression. A non-2xx, undecodable, over-large, or scoreless feed throws.
data EpssFeedTooLarge Source #
The feed passed a byte ceiling, so the fetch refused it whole. Each carries that ceiling and the bytes seen when it tripped, which is the ceiling plus at most one chunk.
Constructors
| CompressedTooLarge Int Int | The compressed stream the host served, so an endless one cannot hang the pass. |
| DecompressedTooLarge Int Int | Its expansion under gzip, which is what a compression bomb inflates. |
| LineTooLarge Int Int | One line of the expansion ( |
Instances
| Exception EpssFeedTooLarge Source # | |
Defined in Ecluse.Core.Osv.Epss Methods toException :: EpssFeedTooLarge -> SomeException # fromException :: SomeException -> Maybe EpssFeedTooLarge # | |
| Show EpssFeedTooLarge Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssFeedTooLarge -> ShowS # show :: EpssFeedTooLarge -> String # showList :: [EpssFeedTooLarge] -> ShowS # | |
| Eq EpssFeedTooLarge Source # | |
Defined in Ecluse.Core.Osv.Epss Methods (==) :: EpssFeedTooLarge -> EpssFeedTooLarge -> Bool # (/=) :: EpssFeedTooLarge -> EpssFeedTooLarge -> Bool # | |
data EpssFeedEmpty Source #
The feed decoded to no scores at all: an error page served as 200, or a column order the row decode no longer reads. Whole-feed failure remains distinct from an individual missing score.
Constructors
| EpssFeedEmpty |
Instances
| Exception EpssFeedEmpty Source # | |
Defined in Ecluse.Core.Osv.Epss Methods toException :: EpssFeedEmpty -> SomeException # fromException :: SomeException -> Maybe EpssFeedEmpty # displayException :: EpssFeedEmpty -> String # backtraceDesired :: EpssFeedEmpty -> Bool # | |
| Show EpssFeedEmpty Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssFeedEmpty -> ShowS # show :: EpssFeedEmpty -> String # showList :: [EpssFeedEmpty] -> ShowS # | |
| Eq EpssFeedEmpty Source # | |
Defined in Ecluse.Core.Osv.Epss Methods (==) :: EpssFeedEmpty -> EpssFeedEmpty -> Bool # (/=) :: EpssFeedEmpty -> EpssFeedEmpty -> Bool # | |
data EpssFeedTruncated Source #
A gzip member ended before its end-of-stream marker, so the rows it carried may be a fraction.
Constructors
| EpssFeedTruncated |
Instances
| Exception EpssFeedTruncated Source # | |
Defined in Ecluse.Core.Osv.Epss Methods toException :: EpssFeedTruncated -> SomeException # fromException :: SomeException -> Maybe EpssFeedTruncated # | |
| Show EpssFeedTruncated Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssFeedTruncated -> ShowS # show :: EpssFeedTruncated -> String # showList :: [EpssFeedTruncated] -> ShowS # | |
| Eq EpssFeedTruncated Source # | |
Defined in Ecluse.Core.Osv.Epss Methods (==) :: EpssFeedTruncated -> EpssFeedTruncated -> Bool # (/=) :: EpssFeedTruncated -> EpssFeedTruncated -> Bool # | |
One compile's attempt
data EpssFeedFailure Source #
Why one attempt at the feed produced no scores.
Constructors
| EpssFeedStatus Int | The feed host answered with this non-2xx status. |
| EpssFeedTransport TransportCause | The transport could not deliver the feed. |
| EpssFeedOversize EpssFeedTooLarge | The feed passed a byte ceiling. |
| EpssFeedUndecodable | The feed is not valid gzip, or its stream ended early. |
| EpssFeedNoScores | The feed decoded to no scores. |
Instances
| Show EpssFeedFailure Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssFeedFailure -> ShowS # show :: EpssFeedFailure -> String # showList :: [EpssFeedFailure] -> ShowS # | |
| Eq EpssFeedFailure Source # | |
Defined in Ecluse.Core.Osv.Epss Methods (==) :: EpssFeedFailure -> EpssFeedFailure -> Bool # (/=) :: EpssFeedFailure -> EpssFeedFailure -> Bool # | |
renderEpssFeedFailure :: EpssFeedFailure -> Text Source #
The failure as an operator reads it. It never names the feed URL, which can carry a credential.
classifyEpssFailure :: SomeException -> Maybe EpssFeedFailure Source #
The feed failures a compile can continue past. An invalid URL is a configuration fault, and anything unnamed here may be a bug, so both stay exceptions rather than read as an outage.
acquireEpssFeed :: (MonadResource m, MonadMask m, MonadUnliftIO m, KatipContext m) => Int -> String -> m (Either EpssFeedFailure EpssFeed) Source #
Fetch the feed under the advisory retry policy. A failure classifyEpssFailure names returns
as a value, and every other exception, a cancellation included, propagates.
data EpssEnrichment Source #
What one compile joins onto its advisories.
Constructors
| EpssEnriched EpssFeed | The feed arrived, so its scores join and its provenance is recorded. |
| EpssUnavailable EpssFeedFailure | The feed failed where the ecosystem does not require it, so no score joins. |
Instances
| Show EpssEnrichment Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssEnrichment -> ShowS # show :: EpssEnrichment -> String # showList :: [EpssEnrichment] -> ShowS # | |
| Eq EpssEnrichment Source # | |
Defined in Ecluse.Core.Osv.Epss Methods (==) :: EpssEnrichment -> EpssEnrichment -> Bool # (/=) :: EpssEnrichment -> EpssEnrichment -> Bool # | |
resolveEnrichment :: EpssRequirement -> Either EpssFeedFailure EpssFeed -> Either EpssFeedFailure EpssEnrichment Source #
Settle one attempt under the ecosystem's requirement. A failure stays Left where the
ecosystem requires enrichment, so an unavailable feed never stands in for a required one.
enrichedFeed :: EpssEnrichment -> Maybe EpssFeed Source #
The feed an enrichment joined, if one arrived.
enrichmentStatus :: EpssEnrichment -> EpssStatus Source #
The status the artifact records for this enrichment.
The score table
data EpssScores Source #
The scores from one fetch of the feed. Keys are upper-cased CVE ids, so a case difference between the feed and an advisory's aliases cannot silently miss the join.
Instances
| Show EpssScores Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssScores -> ShowS # show :: EpssScores -> String # showList :: [EpssScores] -> ShowS # | |
| Eq EpssScores Source # | |
Defined in Ecluse.Core.Osv.Epss | |
mkEpssScores :: [(Text, Double)] -> EpssScores Source #
Build a score table from (CVE id, probability) rows. A duplicate id keeps the higher
score, the fail-closed direction for a rule that denies above a threshold.
epssForIds :: EpssScores -> [Text] -> Maybe Double Source #
The highest score the feed carries for any of these identifiers, or Nothing when it
scores none of them.
epssScoreCount :: EpssScores -> Int Source #
How many CVEs the table scores.
One feed row
parseEpssLine :: ByteString -> Maybe (Text, Double) Source #
One feed row as (CVE id, probability). A comment, the header, an unreadable row, and a
score outside [0, 1] all yield Nothing, so one bad row drops out instead of failing the pass.
The feed's preamble
data EpssPreamble Source #
What the feed's leading comment line declares. FIRST.org writes it as
#model_version:v2026.08.01,score_date:2026-08-29T00:00:00+0000.
Constructors
| EpssPreamble | |
Fields | |
Instances
| Show EpssPreamble Source # | |
Defined in Ecluse.Core.Osv.Epss Methods showsPrec :: Int -> EpssPreamble -> ShowS # show :: EpssPreamble -> String # showList :: [EpssPreamble] -> ShowS # | |
| Eq EpssPreamble Source # | |
Defined in Ecluse.Core.Osv.Epss | |
parseEpssPreamble :: ByteString -> EpssPreamble Source #
Read the feed's leading comment line. A line that is not a comment, a comment naming neither field, and a date the grammar cannot read all yield absence, never a substitute value.