| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Server.Pipeline.Internal
Description
Internal guts of the serve pipeline (Ecluse.Core.Server.Pipeline), exposed for
tests without widening that module's two-handler public API -- the .Internal convention,
as Ecluse.Core.Credential.Refresh.Internal uses. Importing it opts out of the public
module's stability promise.
It holds the operator-facing warning helpers for the bad-upstream and misconfiguration
conditions the response-bound guards leave silent -- an upstream whose body does not
decode into a usable packument (logDecodeFailure), one whose packument self-reports a
name for a different package (logNameMismatch), a mount whose configured base URL
cannot be formed into a request (logUpstreamUnformable), and an upstream the transport
could not reach (logUpstreamUnreachable) -- each surfaced at a WarningS through the
ambient katip context before the contribution degrades. The conditions themselves are
classified on the serve path as a typed
MetadataError; this module only renders their warning
lines. Alongside them sit the pure integrity-floor admission and the metric-label
projections the serve path records.
Synopsis
- logDecodeFailure :: KatipContext m => PackageName -> m ()
- logNameMismatch :: KatipContext m => PackageName -> Text -> Text -> m ()
- logUpstreamUnformable :: KatipContext m => PackageName -> Text -> UrlFormationError -> m ()
- logUpstreamUnreachable :: KatipContext m => PackageName -> Text -> TransportFault -> m ()
- admitByIntegrity :: IntegrityFloor floor => floor -> ServeDecision -> ServeDecision -> PackageInfo -> (PackageInfo, [ServeDecision])
- packumentServeDecision :: [ServeDecision] -> Decision
- serveDecisionClass :: ServeDecision -> Decision
- denialLabels :: RejectReason -> (Maybe Text, ReasonClass)
- evalTier :: [PreparedRule] -> Tier
- transienceCause :: Transience -> Cause
- recordDenials :: MetricsPort -> [ServeDecision] -> IO ()
- recordEffectfulFailures :: MetricsPort -> [Decision] -> IO ()
- data VersionVerdict = VersionVerdict {}
- newtype Metadata = Metadata (Map Text Text)
- data DenialAudit = DenialAudit {}
- denialAuditPayload :: DenialAudit -> SimpleLogPayload
- logDenials :: KatipContext m => PackageName -> Maybe DbEtag -> [VersionVerdict] -> m ()
Documentation
logDecodeFailure :: KatipContext m => PackageName -> m () Source #
Log a parse failure at WarningS -- the one bad-upstream condition the
response-bound guards leave silent: the upstream answered, but its body did not decode
into the typed view and raw document the serve path needs. Same fail-closed degrade and
the same module/package payload convention as the breach log in
Ecluse.Core.Server.Pipeline, so an operator sees an undecodable upstream distinctly
rather than as silence. Emitted through the ambient katip context (the request's, so
the line carries its trace-correlation dd).
logNameMismatch :: KatipContext m => PackageName -> Text -> Text -> m () Source #
Log an upstream name mismatch at WarningS before the contribution degrades: the
origin answered, but its packument self-reported a name for a different package than
the one requested, so it is dropped as untrusted for this request. The structured
payload carries both names and the origin (its base URL) -- the high-cardinality
identifiers that belong on the log line -- so an operator can tell a misconfigured or
hostile upstream from an ordinary outage. Same fail-closed degrade and payload
convention as logDecodeFailure.
logUpstreamUnformable :: KatipContext m => PackageName -> Text -> UrlFormationError -> m () Source #
Log an unformable upstream request URL at WarningS before the contribution
degrades: the base URL configured for this origin is empty or could not be parsed into a
request, so no fetch could even be attempted. A configuration fault, surfaced
distinctly from a decode failure or a transient outage (it carries its own
MetadataUrlUnformable) so an operator sees a misconfigured
mount rather than an upstream that merely appears unreachable. The structured payload
carries the origin and the rendered URL fault; same fail-closed degrade and payload
convention as logNameMismatch.
logUpstreamUnreachable :: KatipContext m => PackageName -> Text -> TransportFault -> m () Source #
Log an unreachable upstream at WarningS before the contribution degrades: the
transport failed before a usable body returned (a timeout, a refused connection, a TLS
refusal), so the origin contributes nothing this request. The structured payload
carries the origin, the bounded TransportCause, and the rendered
detail, so an operator can tell an outage apart from a decode failure or a
misconfigured mount; same fail-closed degrade and payload convention as
logUpstreamUnformable.
Integrity-floor admission (pure)
admitByIntegrity :: IntegrityFloor floor => floor -> ServeDecision -> ServeDecision -> PackageInfo -> (PackageInfo, [ServeDecision]) Source #
Apply an integrity-floor admission policy to a PackageInfo, keeping only the versions
whose strongest digest meets the floor and projecting the rest to refusals. A version
whose digests are all weaker than the floor (or absent) cannot be tied to a
floor-strength tamper-evident fingerprint, so it is dropped from the served listing rather
than served a client could never safely verify. Used by both gates: the public gate
(gatePublic) with the hard-floored MinIntegrity, and the
trusted gate (admitTrusted) with the loosenable
MinTrustedIntegrity. Returns the admissible PackageInfo
(with dist-tags pruned to the kept keys, exactly as restrictToSurvivors prunes for the
rules; each kept version carries its own publish time, so restricting the versions carries
the times with it) and the refusals for the dropped versions: BelowIntegrityFloor for a
too-weak digest, MissingIntegrity for none at all, each feeding the no-survivors
status.
Metric-label projections (pure)
packumentServeDecision :: [ServeDecision] -> Decision Source #
Classify a no-survivors packument outcome into the bounded ecluse.serve.decision
value: a forbidden set is a denial, any other non-served status a transient
unavailability. (A served set is recorded as an admit at the call site, not here.)
serveDecisionClass :: ServeDecision -> Decision Source #
Classify a single artifact-path serve decision into the bounded metric decision: a policy or integrity refusal is a denial, an upstream outage or invalid response an unavailability.
denialLabels :: RejectReason -> (Maybe Text, ReasonClass) Source #
Map a reject reason to the ecluse.rule.denials labels: the deciding rule (only a
policy denial names one) and the bounded reason class.
evalTier :: [PreparedRule] -> Tier Source #
The rule-evaluation tier a duration is attributed to, from the mount's rule set: a mount with any resilient (effectful) rule is attributed to the effectful tier; a purely-pure rule set reduces to the structural tier. The resilience policy a prepared rule carries -- not a separate list -- is what distinguishes an effectful rule now that the two tiers are one engine.
transienceCause :: Transience -> Cause Source #
Map an undecidable verdict's transience to the bounded
ecluse.rule.effectful.failures cause: a retryable cause is a connection-class fault (the
source was unreachable now), a permanent one the catch-all other.
Metric emits (off a serve outcome)
recordDenials :: MetricsPort -> [ServeDecision] -> IO () Source #
Record the ecluse.rule.denials counter for each rejected decision, labelled by
the bounded reason class and -- for a policy denial -- the deciding rule name
(denialLabels). An admit records nothing.
recordEffectfulFailures :: MetricsPort -> [Decision] -> IO () Source #
Count each effectful-rule failure among a packument's per-version decisions: an
Undecidable is an effectful rule whose source could not be consulted, so it is the
effectful-failure signal, classified to a bounded cause by its transience
(transienceCause). A decided version (allowed or denied) is not a failure.
Denial audit trail (structured log)
data VersionVerdict Source #
A per-version serve outcome that keeps the version (the decision's subject),
so a denial's audit line can name it. gatePublic
preserves it rather than dropping the version when it projects to ServeDecision.
Constructors
| VersionVerdict | |
Fields
| |
Instances
| Show VersionVerdict Source # | |
Defined in Ecluse.Core.Server.Pipeline.Internal Methods showsPrec :: Int -> VersionVerdict -> ShowS # show :: VersionVerdict -> String # showList :: [VersionVerdict] -> ShowS # | |
| Eq VersionVerdict Source # | |
Defined in Ecluse.Core.Server.Pipeline.Internal Methods (==) :: VersionVerdict -> VersionVerdict -> Bool # (/=) :: VersionVerdict -> VersionVerdict -> Bool # | |
An extensible bag of audit fields folded into a denial line's JSON at emit
time. It lives here, at the audit boundary, deliberately not on the pure
Decision: the rule engine carries no logging concern,
and new audit data (a CVE id, an EPSS score) is added at this layer without
threading a field through the decision path.
data DenialAudit Source #
Everything one denial audit line records: typed and stable. The advisory
DbEtag is the database active when the request was admitted (carried on the
EvalContext); it is named as active at emit, never
claimed as the database the decision was evaluated against, since a shadow-swap
may land mid-request.
Constructors
| DenialAudit | |
Fields
| |
denialAuditPayload :: DenialAudit -> SimpleLogPayload Source #
Render a DenialAudit to the structured payload katip folds into the line's data object.
logDenials :: KatipContext m => PackageName -> Maybe DbEtag -> [VersionVerdict] -> m () Source #
Emit one audit log line per denied version, denials only (an admit logs
nothing). Companion to recordDenials, which counts the same denials as metrics.
The DbEtag is the advisory database active at emit (from the request's
EvalContext), so the line answers "which database was
live when this verdict was logged", not "which database produced it".