ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Cve.Internal

Description

The advisory lookup's internals: the hardened SQLite open and the raw queries Ecluse.Core.Cve curates into the public handle.

Importing this module opts out of the public surface's stability promises; it exists so tests can pin the hardening properties (the connection refuses writes, schema-borne SQL is distrusted) directly against the connection the handle actually uses.

Synopsis

Documentation

data AdvisoryRange Source #

One advisory segment recorded against a package: the advisory's identifier, its CVSS base score (0 to 10, Nothing when unscored), and the affected interval's bounds as the artifact stores them (verbatim version text). The lower bound arIntroduced is inclusive (Nothing == from the beginning); the upper bound is arFixed (exclusive) or arLastAffected (inclusive) or neither (open-ended). An exactly-enumerated affected version is a point segment (introduced == last_affected).

Instances

Instances details
Show AdvisoryRange Source # 
Instance details

Defined in Ecluse.Core.Cve.Internal

Eq AdvisoryRange Source # 
Instance details

Defined in Ecluse.Core.Cve.Internal

data CveDbRejected Source #

Why a downloaded artifact was refused before a handle was built over it.

A rejection is a value, not an exception: the caller (the sync task, once it exists) has a real decision to make, keep the last known-good database and alarm, rather than a fault to unwind from.

Constructors

CveDbWrongEpoch Int

The artifact's user_version stamp (carried) does not match this binary's osvSchemaEpoch.

CveDbIntegrityFailed [Text]

The artifact is not a usable SQLite database: either it is not a database at all (absent or wrong header magic, which SQLite reports as SQLITE_NOTADB on the first header read), or PRAGMA quick_check found it structurally corrupt (a malformed, truncated, or crafted b-tree). The carried lines are the thrown error or the integrity report (which SQLite caps at 100 problems).

CveDbSchemaNonConformant Text

A required relation (carried) does not conform to the epoch's schema contract: absent, not a real STRICT table, or missing a required column with its declared type. A view here is attacker-authored SQL wearing the table's name; a lax (non-STRICT) table would leave the reader's decodes exposed to type-confused values.

CveDbEcosystemMismatch (Maybe Text)

The artifact's meta table names a different ecosystem (carried) than the one this handle was asked to serve, or carries no ecosystem row at all so the ecosystem cannot be confirmed (Nothing). An absent meta table is caught earlier, as CveDbSchemaNonConformant.

Instances

Instances details
Show CveDbRejected Source # 
Instance details

Defined in Ecluse.Core.Cve.Internal

Eq CveDbRejected Source # 
Instance details

Defined in Ecluse.Core.Cve.Internal

openHardenedConnection :: Ecosystem -> FilePath -> IO (Either CveDbRejected Connection) Source #

Open an artifact read-only-in-effect and accept or reject it.

Hardening order matters, and every pragma is applied before the first query. trusted_schema = OFF distrusts schema-defined functions, views feeding triggers, and virtual tables in the file; query_only = ON refuses every write, so no trigger can ever fire through the connection; cell_size_check = ON validates each b-tree cell against its page as pages are read, so a crafted oversized cell becomes a clean error rather than an out-of-bounds access; and mmap_size = 0 keeps reads on the bounds-checked pager instead of mapping hostile file pages straight into the address space.

Acceptance then checks, cheapest and least trusting first: the osvSchemaEpoch stamp (a header field, so a stale, substituted, or non-SQLite artifact is refused before the file's interior is walked at all), a PRAGMA quick_check integrity walk (a malformed or truncated b-tree is rejected before any lookup dereferences it, and stored values are verified against each STRICT table's declared column types), the required tables conforming to the epoch's schema contract (osvTableSpecs: real STRICT tables carrying the required columns with their declared types, which is what makes every later row decode total), and the meta ecosystem matching the one asked for. A rejected artifact's connection is closed before returning, and so is a connection whose hardening or acceptance throws before it can return a rejection value: the whole phase runs under a close-on-exception guard, so the just-opened connection is never leaked (the "an exception never leaks it" contract openCveDb promises).

Read-only is enforced at the connection level: sqlite-simple's public API has no way to pass SQLITE_OPEN_READONLY at open time, and query_only yields the same guarantee for every statement this connection will run.

probeQuery :: Connection -> Text -> Text -> IO Bool Source #

Does any advisory for this package name this exact version string as a fixed bound? One indexed probe (package_name, fixed_version); deliberately string equality, per the artifact contract's canonical-semver expectation.

advisoriesQuery :: Connection -> Text -> IO [AdvisoryRange] Source #

Every advisory segment recorded against a package name.

provenanceQuery :: Connection -> IO [(Text, Text)] Source #

The artifact's meta provenance rows, key-sorted for a deterministic snapshot. This only ever runs on an accepted connection, and acceptance has confirmed meta is a STRICT table of NOT NULL TEXT whose stored values the integrity walk verified, so the (Text, Text) decode is total here: no artifact content can make it throw.