| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
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
- osvSchemaEpoch :: Int
- osvDbFileName :: Text -> FilePath
- rangesTableDdl :: Text
- metaTableDdl :: Text
- data ColumnSpec = ColumnSpec {
- colName :: Text
- colDeclaredType :: Text
- colNotNull :: Bool
- data TableSpec = TableSpec {
- tableName :: Text
- tableColumns :: [ColumnSpec]
- osvTableSpecs :: [TableSpec]
- data MetaKey
- renderMetaKey :: MetaKey -> Text
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 | |
Fields
| |
Instances
| Show ColumnSpec Source # | |
Defined in Ecluse.Core.Osv.Schema Methods showsPrec :: Int -> ColumnSpec -> ShowS # show :: ColumnSpec -> String # showList :: [ColumnSpec] -> ShowS # | |
| Eq ColumnSpec Source # | |
Defined in Ecluse.Core.Osv.Schema | |
A table the reader requires, with the columns its queries decode.
Constructors
| TableSpec | |
Fields
| |
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
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. |
| 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
| Generic MetaKey Source # | |||||
Defined in Ecluse.Core.Osv.Schema Associated Types
| |||||
| Show MetaKey Source # | |||||
| Eq MetaKey Source # | |||||
| Universe MetaKey Source # | |||||
Defined in Ecluse.Core.Osv.Schema | |||||
| type Rep MetaKey Source # | |||||
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.