module Ecluse.Core.Server.Pipeline.Internal (
logDecodeFailure,
logNameMismatch,
logUpstreamUnformable,
logUpstreamUnreachable,
admitByIntegrity,
packumentServeDecision,
serveDecisionClass,
denialLabels,
evalTier,
transienceCause,
recordDenials,
recordEffectfulFailures,
VersionVerdict (..),
Metadata (..),
DenialAudit (..),
denialAuditPayload,
logDenials,
) where
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Data.Text qualified as T
import Katip (KatipContext, Severity (WarningS), SimpleLogPayload, katipAddContext, logFM, ls, sl)
import Ecluse.Core.Cve (DbEtag (..))
import Ecluse.Core.Fault (TransportFault (tfCause, tfDetail))
import Ecluse.Core.Package (
PackageDetails (pkgArtifacts),
PackageInfo (infoDistTags, infoVersions),
PackageName,
renderPackageName,
)
import Ecluse.Core.Package.Integrity (
IntegrityFloor,
VersionIntegrity (BelowFloor, MeetsFloor, NoIntegrity),
classifyArtifacts,
)
import Ecluse.Core.Registry (UrlFormationError)
import Ecluse.Core.Rules (PreparedRule (prepResilience), cveIdsInReason)
import Ecluse.Core.Rules.Types (Decision (Undecidable))
import Ecluse.Core.Server.Response (
PackumentStatus (PackumentForbidden, PackumentOk),
RejectReason (BelowIntegrityFloor, ByPolicy, MissingIntegrity, Unavailable, UpstreamInvalid),
Rejection (Rejection),
RuleName (RuleName),
ServeDecision (Admit, Reject),
Transience (WillResolve, WontResolve),
packumentStatus,
)
import Ecluse.Core.Telemetry.Metrics qualified as Metric
import Ecluse.Core.Telemetry.Record (MetricsPort, mpRuleDenial, mpRuleEffectfulFailure)
import Ecluse.Core.Version (renderVersion)
pipelineInternalModule :: Text
pipelineInternalModule :: Text
pipelineInternalModule = Text
"Ecluse.Server.Pipeline.Internal"
logDecodeFailure :: (KatipContext m) => PackageName -> m ()
logDecodeFailure :: forall (m :: * -> *). KatipContext m => PackageName -> m ()
logDecodeFailure PackageName
name =
SimpleLogPayload -> m () -> m ()
forall i (m :: * -> *) a.
(LogItem i, KatipContext m) =>
i -> m a -> m a
katipAddContext SimpleLogPayload
payload (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> LogStr -> m ()
forall (m :: * -> *).
(Applicative m, KatipContext m) =>
Severity -> LogStr -> m ()
logFM Severity
WarningS (Text -> LogStr
forall a. StringConv a Text => a -> LogStr
ls Text
message)
where
payload :: SimpleLogPayload
payload = Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"module" Text
pipelineInternalModule SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"package" (PackageName -> Text
renderPackageName PackageName
name)
message :: Text
message :: Text
message = Text
"refused an upstream metadata document: it did not decode into a usable packument"
logNameMismatch :: (KatipContext m) => PackageName -> Text -> Text -> m ()
logNameMismatch :: forall (m :: * -> *).
KatipContext m =>
PackageName -> Text -> Text -> m ()
logNameMismatch PackageName
requested Text
origin Text
reported =
SimpleLogPayload -> m () -> m ()
forall i (m :: * -> *) a.
(LogItem i, KatipContext m) =>
i -> m a -> m a
katipAddContext SimpleLogPayload
payload (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> LogStr -> m ()
forall (m :: * -> *).
(Applicative m, KatipContext m) =>
Severity -> LogStr -> m ()
logFM Severity
WarningS (Text -> LogStr
forall a. StringConv a Text => a -> LogStr
ls Text
message)
where
payload :: SimpleLogPayload
payload =
Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"module" Text
pipelineInternalModule
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"package" (PackageName -> Text
renderPackageName PackageName
requested)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"origin" Text
origin
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"upstreamName" Text
reported
message :: Text
message :: Text
message = Text
"dropped an upstream contribution: its packument self-reported a name for a different package"
logUpstreamUnformable :: (KatipContext m) => PackageName -> Text -> UrlFormationError -> m ()
logUpstreamUnformable :: forall (m :: * -> *).
KatipContext m =>
PackageName -> Text -> UrlFormationError -> m ()
logUpstreamUnformable PackageName
name Text
origin UrlFormationError
urlErr =
SimpleLogPayload -> m () -> m ()
forall i (m :: * -> *) a.
(LogItem i, KatipContext m) =>
i -> m a -> m a
katipAddContext SimpleLogPayload
payload (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> LogStr -> m ()
forall (m :: * -> *).
(Applicative m, KatipContext m) =>
Severity -> LogStr -> m ()
logFM Severity
WarningS (Text -> LogStr
forall a. StringConv a Text => a -> LogStr
ls Text
message)
where
payload :: SimpleLogPayload
payload =
Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"module" Text
pipelineInternalModule
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"package" (PackageName -> Text
renderPackageName PackageName
name)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"origin" Text
origin
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"urlError" (UrlFormationError -> Text
forall b a. (Show a, IsString b) => a -> b
show UrlFormationError
urlErr :: Text)
message :: Text
message :: Text
message = Text
"refused an upstream metadata fetch: the configured base URL could not be formed into a request"
logUpstreamUnreachable :: (KatipContext m) => PackageName -> Text -> TransportFault -> m ()
logUpstreamUnreachable :: forall (m :: * -> *).
KatipContext m =>
PackageName -> Text -> TransportFault -> m ()
logUpstreamUnreachable PackageName
name Text
origin TransportFault
fault =
SimpleLogPayload -> m () -> m ()
forall i (m :: * -> *) a.
(LogItem i, KatipContext m) =>
i -> m a -> m a
katipAddContext SimpleLogPayload
payload (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> LogStr -> m ()
forall (m :: * -> *).
(Applicative m, KatipContext m) =>
Severity -> LogStr -> m ()
logFM Severity
WarningS (Text -> LogStr
forall a. StringConv a Text => a -> LogStr
ls Text
message)
where
payload :: SimpleLogPayload
payload =
Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"module" Text
pipelineInternalModule
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"package" (PackageName -> Text
renderPackageName PackageName
name)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"origin" Text
origin
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"transportCause" (TransportCause -> Text
forall b a. (Show a, IsString b) => a -> b
show (TransportFault -> TransportCause
tfCause TransportFault
fault) :: Text)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"transportDetail" (TransportFault -> Text
tfDetail TransportFault
fault)
message :: Text
message :: Text
message = Text
"an upstream metadata fetch could not reach the origin; its contribution degrades this request"
admitByIntegrity ::
(IntegrityFloor floor) =>
floor ->
ServeDecision ->
ServeDecision ->
PackageInfo ->
(PackageInfo, [ServeDecision])
admitByIntegrity :: forall floor.
IntegrityFloor floor =>
floor
-> ServeDecision
-> ServeDecision
-> PackageInfo
-> (PackageInfo, [ServeDecision])
admitByIntegrity floor
floorSpec ServeDecision
belowFloorRefusal ServeDecision
missingRefusal PackageInfo
info =
( PackageInfo
info
{ infoVersions = Map.restrictKeys (infoVersions info) admissibleKeys
, infoDistTags = Map.filter ((`Set.member` admissibleKeys) . renderVersion) (infoDistTags info)
}
, [ServeDecision]
refusals
)
where
classified :: Map Text VersionIntegrity
classified :: Map Text VersionIntegrity
classified = (PackageDetails -> VersionIntegrity)
-> Map Text PackageDetails -> Map Text VersionIntegrity
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map (floor -> NonEmpty Artifact -> VersionIntegrity
forall floor.
IntegrityFloor floor =>
floor -> NonEmpty Artifact -> VersionIntegrity
classifyArtifacts floor
floorSpec (NonEmpty Artifact -> VersionIntegrity)
-> (PackageDetails -> NonEmpty Artifact)
-> PackageDetails
-> VersionIntegrity
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageDetails -> NonEmpty Artifact
pkgArtifacts) (PackageInfo -> Map Text PackageDetails
infoVersions PackageInfo
info)
admissibleKeys :: Set Text
admissibleKeys :: Set Text
admissibleKeys = Map Text VersionIntegrity -> Set Text
forall k a. Map k a -> Set k
Map.keysSet ((VersionIntegrity -> Bool)
-> Map Text VersionIntegrity -> Map Text VersionIntegrity
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (VersionIntegrity -> VersionIntegrity -> Bool
forall a. Eq a => a -> a -> Bool
== VersionIntegrity
MeetsFloor) Map Text VersionIntegrity
classified)
refusals :: [ServeDecision]
refusals :: [ServeDecision]
refusals = [ServeDecision]
below [ServeDecision] -> [ServeDecision] -> [ServeDecision]
forall a. Semigroup a => a -> a -> a
<> [ServeDecision]
missing
where
([ServeDecision]
below, [ServeDecision]
missing) = (VersionIntegrity
-> ([ServeDecision], [ServeDecision])
-> ([ServeDecision], [ServeDecision]))
-> ([ServeDecision], [ServeDecision])
-> Map Text VersionIntegrity
-> ([ServeDecision], [ServeDecision])
forall a b k. (a -> b -> b) -> b -> Map k a -> b
Map.foldr VersionIntegrity
-> ([ServeDecision], [ServeDecision])
-> ([ServeDecision], [ServeDecision])
bucket ([], []) Map Text VersionIntegrity
classified
bucket :: VersionIntegrity
-> ([ServeDecision], [ServeDecision])
-> ([ServeDecision], [ServeDecision])
bucket VersionIntegrity
BelowFloor ([ServeDecision]
b, [ServeDecision]
m) = (ServeDecision
belowFloorRefusal ServeDecision -> [ServeDecision] -> [ServeDecision]
forall a. a -> [a] -> [a]
: [ServeDecision]
b, [ServeDecision]
m)
bucket VersionIntegrity
NoIntegrity ([ServeDecision]
b, [ServeDecision]
m) = ([ServeDecision]
b, ServeDecision
missingRefusal ServeDecision -> [ServeDecision] -> [ServeDecision]
forall a. a -> [a] -> [a]
: [ServeDecision]
m)
bucket VersionIntegrity
MeetsFloor ([ServeDecision], [ServeDecision])
acc = ([ServeDecision], [ServeDecision])
acc
packumentServeDecision :: [ServeDecision] -> Metric.Decision
packumentServeDecision :: [ServeDecision] -> Decision
packumentServeDecision [ServeDecision]
decisions = case [ServeDecision] -> PackumentStatus
packumentStatus [ServeDecision]
decisions of
PackumentStatus
PackumentForbidden -> Decision
Metric.Deny
PackumentStatus
PackumentOk -> Decision
Metric.Admit
PackumentStatus
_ -> Decision
Metric.Unavailable
serveDecisionClass :: ServeDecision -> Metric.Decision
serveDecisionClass :: ServeDecision -> Decision
serveDecisionClass = \case
ServeDecision
Admit -> Decision
Metric.Admit
Reject (Rejection RejectReason
reason Text
_) -> case RejectReason
reason of
ByPolicy{} -> Decision
Metric.Deny
RejectReason
MissingIntegrity -> Decision
Metric.Deny
RejectReason
BelowIntegrityFloor -> Decision
Metric.Deny
Unavailable{} -> Decision
Metric.Unavailable
RejectReason
UpstreamInvalid -> Decision
Metric.Unavailable
denialLabels :: RejectReason -> (Maybe Text, Metric.ReasonClass)
denialLabels :: RejectReason -> (Maybe Text, ReasonClass)
denialLabels = \case
ByPolicy (RuleName Text
name) -> (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
name, ReasonClass
Metric.ReasonPolicy)
RejectReason
MissingIntegrity -> (Maybe Text
forall a. Maybe a
Nothing, ReasonClass
Metric.ReasonMissingIntegrity)
RejectReason
BelowIntegrityFloor -> (Maybe Text
forall a. Maybe a
Nothing, ReasonClass
Metric.ReasonMissingIntegrity)
Unavailable Transience
_ -> (Maybe Text
forall a. Maybe a
Nothing, ReasonClass
Metric.ReasonUnavailable)
RejectReason
UpstreamInvalid -> (Maybe Text
forall a. Maybe a
Nothing, ReasonClass
Metric.ReasonUnavailable)
evalTier :: [PreparedRule] -> Metric.Tier
evalTier :: [PreparedRule] -> Tier
evalTier [PreparedRule]
rules = if (PreparedRule -> Bool) -> [PreparedRule] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Maybe Resilience -> Bool
forall a. Maybe a -> Bool
isJust (Maybe Resilience -> Bool)
-> (PreparedRule -> Maybe Resilience) -> PreparedRule -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PreparedRule -> Maybe Resilience
prepResilience) [PreparedRule]
rules then Tier
Metric.Effectful else Tier
Metric.Structural
transienceCause :: Transience -> Metric.Cause
transienceCause :: Transience -> Cause
transienceCause = \case
WillResolve Maybe RetryAfter
_ -> Cause
Metric.Connection
Transience
WontResolve -> Cause
Metric.OtherCause
recordDenials :: MetricsPort -> [ServeDecision] -> IO ()
recordDenials :: MetricsPort -> [ServeDecision] -> IO ()
recordDenials MetricsPort
metrics = (ServeDecision -> IO ()) -> [ServeDecision] -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ ServeDecision -> IO ()
recordOne
where
recordOne :: ServeDecision -> IO ()
recordOne :: ServeDecision -> IO ()
recordOne = \case
ServeDecision
Admit -> IO ()
forall (f :: * -> *). Applicative f => f ()
pass
Reject (Rejection RejectReason
reason Text
_) ->
let (Maybe Text
rule, ReasonClass
reasonClass) = RejectReason -> (Maybe Text, ReasonClass)
denialLabels RejectReason
reason
in MetricsPort -> Maybe Text -> ReasonClass -> IO ()
mpRuleDenial MetricsPort
metrics Maybe Text
rule ReasonClass
reasonClass
recordEffectfulFailures :: MetricsPort -> [Decision] -> IO ()
recordEffectfulFailures :: MetricsPort -> [Decision] -> IO ()
recordEffectfulFailures MetricsPort
metrics = (Decision -> IO ()) -> [Decision] -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ Decision -> IO ()
recordOne
where
recordOne :: Decision -> IO ()
recordOne :: Decision -> IO ()
recordOne = \case
Undecidable Transience
transience Text
_ -> MetricsPort -> Cause -> IO ()
mpRuleEffectfulFailure MetricsPort
metrics (Transience -> Cause
transienceCause Transience
transience)
Decision
_ -> IO ()
forall (f :: * -> *). Applicative f => f ()
pass
data VersionVerdict = VersionVerdict
{ VersionVerdict -> Text
vvVersion :: Text
, VersionVerdict -> ServeDecision
vvDecision :: ServeDecision
}
deriving stock (VersionVerdict -> VersionVerdict -> Bool
(VersionVerdict -> VersionVerdict -> Bool)
-> (VersionVerdict -> VersionVerdict -> Bool) -> Eq VersionVerdict
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: VersionVerdict -> VersionVerdict -> Bool
== :: VersionVerdict -> VersionVerdict -> Bool
$c/= :: VersionVerdict -> VersionVerdict -> Bool
/= :: VersionVerdict -> VersionVerdict -> Bool
Eq, Int -> VersionVerdict -> ShowS
[VersionVerdict] -> ShowS
VersionVerdict -> String
(Int -> VersionVerdict -> ShowS)
-> (VersionVerdict -> String)
-> ([VersionVerdict] -> ShowS)
-> Show VersionVerdict
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> VersionVerdict -> ShowS
showsPrec :: Int -> VersionVerdict -> ShowS
$cshow :: VersionVerdict -> String
show :: VersionVerdict -> String
$cshowList :: [VersionVerdict] -> ShowS
showList :: [VersionVerdict] -> ShowS
Show)
newtype Metadata = Metadata (Map Text Text)
deriving stock (Metadata -> Metadata -> Bool
(Metadata -> Metadata -> Bool)
-> (Metadata -> Metadata -> Bool) -> Eq Metadata
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Metadata -> Metadata -> Bool
== :: Metadata -> Metadata -> Bool
$c/= :: Metadata -> Metadata -> Bool
/= :: Metadata -> Metadata -> Bool
Eq, Int -> Metadata -> ShowS
[Metadata] -> ShowS
Metadata -> String
(Int -> Metadata -> ShowS)
-> (Metadata -> String) -> ([Metadata] -> ShowS) -> Show Metadata
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Metadata -> ShowS
showsPrec :: Int -> Metadata -> ShowS
$cshow :: Metadata -> String
show :: Metadata -> String
$cshowList :: [Metadata] -> ShowS
showList :: [Metadata] -> ShowS
Show)
instance Semigroup Metadata where
Metadata Map Text Text
a <> :: Metadata -> Metadata -> Metadata
<> Metadata Map Text Text
b = Map Text Text -> Metadata
Metadata (Map Text Text
a Map Text Text -> Map Text Text -> Map Text Text
forall a. Semigroup a => a -> a -> a
<> Map Text Text
b)
instance Monoid Metadata where
mempty :: Metadata
mempty = Map Text Text -> Metadata
Metadata Map Text Text
forall k a. Map k a
Map.empty
data DenialAudit = DenialAudit
{ DenialAudit -> PackageName
daPackage :: PackageName
, DenialAudit -> Text
daVersion :: Text
, DenialAudit -> Maybe Text
daRule :: Maybe Text
, DenialAudit -> ReasonClass
daReasonClass :: Metric.ReasonClass
, DenialAudit -> Maybe DbEtag
daAdvisoryEtag :: Maybe DbEtag
, :: Metadata
}
denialAuditPayload :: DenialAudit -> SimpleLogPayload
denialAuditPayload :: DenialAudit -> SimpleLogPayload
denialAuditPayload DenialAudit
da =
Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"module" Text
pipelineInternalModule
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"package" (PackageName -> Text
renderPackageName (DenialAudit -> PackageName
daPackage DenialAudit
da))
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"version" (DenialAudit -> Text
daVersion DenialAudit
da)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> SimpleLogPayload
-> (Text -> SimpleLogPayload) -> Maybe Text -> SimpleLogPayload
forall b a. b -> (a -> b) -> Maybe a -> b
maybe SimpleLogPayload
forall a. Monoid a => a
mempty (Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"rule") (DenialAudit -> Maybe Text
daRule DenialAudit
da)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"reason_class" (ReasonClass -> Text
forall b a. (Show a, IsString b) => a -> b
show (DenialAudit -> ReasonClass
daReasonClass DenialAudit
da) :: Text)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> SimpleLogPayload
-> (DbEtag -> SimpleLogPayload) -> Maybe DbEtag -> SimpleLogPayload
forall b a. b -> (a -> b) -> Maybe a -> b
maybe SimpleLogPayload
forall a. Monoid a => a
mempty (\(DbEtag Text
e) -> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
"active_advisory_db_etag" Text
e) (DenialAudit -> Maybe DbEtag
daAdvisoryEtag DenialAudit
da)
SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> Metadata -> SimpleLogPayload
metadataPayload (DenialAudit -> Metadata
daExtra DenialAudit
da)
where
metadataPayload :: Metadata -> SimpleLogPayload
metadataPayload (Metadata Map Text Text
m) = (Text -> Text -> SimpleLogPayload -> SimpleLogPayload)
-> SimpleLogPayload -> Map Text Text -> SimpleLogPayload
forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
Map.foldrWithKey (\Text
k Text
v SimpleLogPayload
acc -> Text -> Text -> SimpleLogPayload
forall a. ToJSON a => Text -> a -> SimpleLogPayload
sl Text
k Text
v SimpleLogPayload -> SimpleLogPayload -> SimpleLogPayload
forall a. Semigroup a => a -> a -> a
<> SimpleLogPayload
acc) SimpleLogPayload
forall a. Monoid a => a
mempty Map Text Text
m
cveMetadata :: Text -> Metadata
cveMetadata :: Text -> Metadata
cveMetadata Text
message = case Text -> [Text]
cveIdsInReason Text
message of
[] -> Metadata
forall a. Monoid a => a
mempty
[Text]
ids -> Map Text Text -> Metadata
Metadata (Text -> Text -> Map Text Text
forall k a. k -> a -> Map k a
Map.singleton Text
"cve" (Text -> [Text] -> Text
T.intercalate Text
", " [Text]
ids))
logDenials :: (KatipContext m) => PackageName -> Maybe DbEtag -> [VersionVerdict] -> m ()
logDenials :: forall (m :: * -> *).
KatipContext m =>
PackageName -> Maybe DbEtag -> [VersionVerdict] -> m ()
logDenials PackageName
pkg Maybe DbEtag
etag = (VersionVerdict -> m ()) -> [VersionVerdict] -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ VersionVerdict -> m ()
forall {f :: * -> *}. KatipContext f => VersionVerdict -> f ()
logOne
where
logOne :: VersionVerdict -> f ()
logOne VersionVerdict
vv = case VersionVerdict -> ServeDecision
vvDecision VersionVerdict
vv of
ServeDecision
Admit -> f ()
forall (f :: * -> *). Applicative f => f ()
pass
Reject (Rejection RejectReason
reason Text
message) ->
let (Maybe Text
rule, ReasonClass
reasonClass) = RejectReason -> (Maybe Text, ReasonClass)
denialLabels RejectReason
reason
audit :: DenialAudit
audit = PackageName
-> Text
-> Maybe Text
-> ReasonClass
-> Maybe DbEtag
-> Metadata
-> DenialAudit
DenialAudit PackageName
pkg (VersionVerdict -> Text
vvVersion VersionVerdict
vv) Maybe Text
rule ReasonClass
reasonClass Maybe DbEtag
etag (Text -> Metadata
cveMetadata Text
message)
in SimpleLogPayload -> f () -> f ()
forall i (m :: * -> *) a.
(LogItem i, KatipContext m) =>
i -> m a -> m a
katipAddContext (DenialAudit -> SimpleLogPayload
denialAuditPayload DenialAudit
audit) (f () -> f ()) -> f () -> f ()
forall a b. (a -> b) -> a -> b
$
Severity -> LogStr -> f ()
forall (m :: * -> *).
(Applicative m, KatipContext m) =>
Severity -> LogStr -> m ()
logFM Severity
WarningS (Text -> LogStr
forall a. StringConv a Text => a -> LogStr
ls (Text
"denied" :: Text))