ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Rules

Description

The policy engine denies by default and decides in boot order. One advisory read per package serves every advisory rule an evaluator reaches, so a request's decisions read one generation.

Synopsis

The boot-bound rule capabilities

data RuleDeps Source #

One ecosystem's boot-bound rule capabilities: its advisory database and the rules' observers.

Constructors

RuleDeps 

Fields

data AdvisoryDatabase Source #

An ecosystem's advisory database, as configuration fixes it at boot.

Constructors

NoAdvisoryDatabase 
AdvisoryDatabase (forall a. (Maybe (DbEtag, CveLookup) -> IO a) -> IO a)

Bracketed access to the lookup and ETag acquired together, Nothing until a generation loads.

withCveLookup :: RuleDeps -> (Maybe (DbEtag, CveLookup) -> IO a) -> IO a Source #

Borrow the loaded generation, or Nothing when none is configured or none has loaded yet.

The built-in rule dispatch

data VerdictSource Source #

Where a built-in rule's verdict comes from.

Constructors

FromEvidence (EvalContext -> RuleEvidence -> RuleVerdict)

One version's evidence and the request context.

FromAdvisories AdvisoryAlignment (AdvisoryRows -> RuleEvidence -> RuleVerdict)

The package's advisory rows, with how the rule resolves when it cannot read them.

data AdvisoryAlignment Source #

How an advisory rule resolves when it cannot read: on an expired push, and on a faulted read.

Constructors

AdvisoryAlignment 

Fields

verdictSource :: Rule -> VerdictSource Source #

The single dispatch over the closed vocabulary. A rule that reads a fact nothing supplied refuses rather than abstaining, so the fold stops at it.

type AdvisoryRows = Maybe (DbEtag, PackageAdvisories) Source #

One package's advisory rows and the generation that served them, or Nothing while none is loaded.

readAdvisories :: RuleDeps -> PackageName -> IO AdvisoryRows Source #

Pin a generation and read one package's rows through it, their bounds parsed once for all its versions. A query fault escapes to the caller.

The engine's prepared rule

data PreparedRule Source #

Config obtains evaluators only through prepare, never from arbitrary code.

Constructors

PreparedRule 

Fields

  • prepName :: Text

    The stable, human-facing name: the boot-order tiebreak and the credited identity.

  • prepPrecedence :: Int

    The precedence at which this rule competes. Higher wins in the boot order.

  • prepEval :: RuleEval

    How the rule reaches the versions an evaluator decides.

data RuleEval Source #

How a prepared rule reaches the versions an evaluator decides.

Constructors

PerVersion (EvalContext -> RuleEvidence -> IO RuleVerdict)

Each version's verdict on its own. A throw refuses admission.

PerPackage PackageRead

A verdict for each version from the evaluator's one advisory read of the package.

data PackageRead Source #

An advisory rule: how to make the evaluator's shared read when this rule reaches it first, and how the rule decides from that read.

Constructors

PackageRead 

Fields

data Resilience Source #

The resilience policy around one advisory rule's reads. Each rule holds its own breaker state.

Constructors

Resilience 

Fields

prepare :: RuleDeps -> [PrecededRule] -> IO [PreparedRule] Source #

Allocate each advisory rule's breaker once. With no advisory database configured, an advisory rule's read does no IO and returns the rule's fixed verdict, so it runs without resilience.

prepResilience :: PreparedRule -> Maybe Resilience Source #

The resilience policy a prepared rule's package read runs under, if any.

Boot-time ordering

bootOrder :: [PreparedRule] -> [PreparedRule] Source #

Sort by descending precedence, then ascending rule name, independently of configuration order.

renderBootOrder :: [PreparedRule] -> [Text] Source #

Render the boot order as one line per rule, in evaluation order, so an operator sees at boot how their policy will resolve.

Evaluation

newEvaluator :: EvalContext -> [PreparedRule] -> IO (RuleEvidence -> IO Decision) Source #

An evaluator for one request's versions, in boot order. Its advisory rules must come from one prepare, since the first reached reads the package once for them all. A throw refuses.

evalRules :: EvalContext -> [PreparedRule] -> RuleEvidence -> IO Decision Source #

Decide one version through a fresh newEvaluator.

renderDecision :: RuleEvidence -> Decision -> Text Source #

A human-readable summary of a decision, suitable for logs and the denial response body.

renderDuration :: NominalDiffTime -> Text Source #

Keep two non-zero units to distinguish near-threshold durations. Negative values render as zero.

renderIneligible :: AdvisoryFreshness -> Maybe Text Source #

Why a push is not eligible evidence, or Nothing while it is. A serving generation the store gave no publication time for reads as unverified, because its age cannot be established.

cveIdsInReason :: Text -> [Text] Source #

Read the advisory identifiers from a scored denial reason, or return none.

Observing the advisory source

data SourceHealth Source #

What one rule's evaluation established about the source it reads.

Constructors

SourceAnswered Text

The named rule consulted its source, whatever it decided.

SourceUnavailable Text Reason

The named rule could not consult its source, for the given cause.

data SourceReporter Source #

The observer every advisory-reading evaluation reports to. The composition root installs the live one.

Constructors

SourceReporter 

Fields

noSourceReporter :: SourceReporter Source #

The inert reporter, for an ecosystem with no advisory source to observe. It logs every admission.