ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Osv.Schema

Description

The compiled advisory artifact's schema contract.

Écluse Pilot compiles OSV advisory data into a read-only SQLite artifact (osv.db) and publishes it to object storage; the proxy downloads it and queries it locally on the request path. This module is the one place the writer and the reader agree on what that artifact looks like: the table-schema epoch that names and stamps it, the tables' canonical DDL and the column requirements the reader verifies at acceptance, and the keys of its meta table.

The artifact is immutable and rebuilt from scratch on every compilation, so there are no migrations, only a read-compatibility contract between whoever wrote a file and whoever reads it. The epoch expresses exactly that contract: it moves only when the shape of the data breaks, so the key stays findable and the stamp stays checkable across releases of either side.

Synopsis

The table-schema epoch

osvSchemaEpoch :: Int Source #

The table-schema epoch: the version of the artifact's shape, shared by the Pilot writer and the proxy reader.

Bump it only for a breaking change to the existing shape (a column rename, a semantic change, a key change). Additive changes (a new column, a new table) must not bump it: readers select explicit columns, so additions are invisible to them. A column exists exactly when the build populates it, so a reader learns what data an artifact offers from the schema itself.

The epoch names the published artifact (osvDbFileName) and is stamped into it as SQLite's user_version; a reader must reject an artifact whose stamp does not match its own compiled-in epoch and keep its last known-good database.

Epoch 2 widened the affected-set model: the ranges table gained a last_affected_version column (an inclusive upper bound, distinct from the exclusive fixed_version), exact enumerated versions are stored as points, and severity became a numeric REAL CVSS base score. A reader compiled for epoch 2 requires those columns, so an epoch-1 artifact is rejected rather than read.

Epoch 3 made the stored value types part of the contract: both tables are declared STRICT, so SQLite enforces each column's declared type at write time and PRAGMA quick_check verifies the stored values against it, and the reader accepts an artifact only after confirming that declaration (osvTableSpecs). Every value the reader decodes is therefore type-sound by construction. The ranges table's composite primary key became an equivalent unique index, since STRICT makes primary-key columns implicitly NOT NULL and the bound columns are legitimately absent.

osvDbFileName :: Text -> FilePath Source #

The artifact's file name, and object-storage key, for an ecosystem.

The key is stable per ecosystem, so a reader can poll one known key by ETag, and embeds only the epoch, so the key changes exactly when a reader could no longer use the file.

>>> osvDbFileName "npm"
"npm-osv-schema3.db"

The tables

rangesTableDdl :: Text Source #

The ranges table's canonical DDL. STRICT turns the declared column types from affinity hints into enforced storage types, which is what lets the reader decode rows without defending against type-confused values. The dedup guard (the unique index over all five identity columns) is the writer's concern, not part of the read contract, so it lives with the writer.

metaTableDdl :: Text Source #

The meta provenance table's canonical DDL; STRICT as rangesTableDdl.

data ColumnSpec Source #

One column the reader requires of an artifact table: its name, its declared type (which STRICT makes the enforced storage type), and whether the reader's decode relies on the column being NOT NULL.

Constructors

ColumnSpec 

Instances

Instances details
Show ColumnSpec Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

Eq ColumnSpec Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

data TableSpec Source #

A table the reader requires, with the columns its queries decode.

Constructors

TableSpec 

Instances

Instances details
Show TableSpec Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

Eq TableSpec Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

osvTableSpecs :: [TableSpec] Source #

What the reader verifies before trusting an artifact: each listed table must be a real STRICT table carrying at least these columns with these declared types. Columns beyond these are tolerated, which is what keeps additive schema changes epoch-neutral; the specs mirror rangesTableDdl and metaTableDdl column for column.

The meta table

data MetaKey Source #

A key of the artifact's meta table (one TEXT key/value row per key).

The table carries the artifact's provenance: which build produced it, from what source, and when.

Constructors

MetaPilotVersion

The Pilot application version that produced the artifact.

MetaEcosystem

The ecosystem the artifact was compiled for (e.g. npm).

MetaBuiltAt

When the compilation finished, as an ISO-8601 UTC timestamp.

MetaSourceUrl

The advisory-dump URL the artifact was compiled from.

MetaRowCount

The number of advisory ranges the artifact holds.

Instances

Instances details
Generic MetaKey Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

Associated Types

type Rep MetaKey 
Instance details

Defined in Ecluse.Core.Osv.Schema

type Rep MetaKey = D1 ('MetaData "MetaKey" "Ecluse.Core.Osv.Schema" "ecluse-0.1.0-inplace-ecluse-core" 'False) ((C1 ('MetaCons "MetaPilotVersion" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MetaEcosystem" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "MetaBuiltAt" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "MetaSourceUrl" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MetaRowCount" 'PrefixI 'False) (U1 :: Type -> Type))))

Methods

from :: MetaKey -> Rep MetaKey x #

to :: Rep MetaKey x -> MetaKey #

Show MetaKey Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

Eq MetaKey Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

Methods

(==) :: MetaKey -> MetaKey -> Bool #

(/=) :: MetaKey -> MetaKey -> Bool #

Universe MetaKey Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

Methods

universe :: [MetaKey] Source #

type Rep MetaKey Source # 
Instance details

Defined in Ecluse.Core.Osv.Schema

type Rep MetaKey = D1 ('MetaData "MetaKey" "Ecluse.Core.Osv.Schema" "ecluse-0.1.0-inplace-ecluse-core" 'False) ((C1 ('MetaCons "MetaPilotVersion" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MetaEcosystem" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "MetaBuiltAt" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "MetaSourceUrl" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MetaRowCount" 'PrefixI 'False) (U1 :: Type -> Type))))

renderMetaKey :: MetaKey -> Text Source #

The key's stored form in the meta table.