Every result TRUSTIVAN produces depends on the advisory data behind it. This page covers where that data comes from, how it is cached, and the freshness policy that decides whether a scan is allowed to succeed at all.

Freshness is a correctness problem

A vulnerability scanner’s most dangerous failure is not an error. It is a scan that succeeds, exits zero, and reports a clean image — because the advisory data behind it predates the vulnerabilities it was supposed to find. Nothing in the result, the timestamp or the status distinguishes that from a correct clean scan. Every other failure in TRUSTIVAN announces itself. A scan that cannot reach a registry fails. A worker that dies has its lease reaped. A stale database announces nothing, so it has to be made to.

Two thresholds: degrade, then fail closed

The honest answer to “is this data too old” is not binary. A database two days old is missing a handful of advisories and is still enormously more useful than no scan. A database three months old will confidently report a clean image with dozens of known criticals. 48 hours is chosen because a deployment with working egress is never near it — the upstream database rebuilds several times a day — so reaching it means something is wrong: blocked egress, a stale mirror, or a cache directory that is not actually persisted. Exactly the conditions that otherwise go unnoticed for months. An operator who sets the hard limit below the soft one has made a mistake that would refuse every stale database instantly. The policy widens it rather than rejecting it at startup: refusing to boot over an ordering slip in two optional settings is worse than applying the stricter of the two sensibly.

Why the hard limit fails the scan rather than flagging it

Because reconciliation resolves findings a scan did not observe. A scan against a three-month-old database does not merely under-report. It reads its own silence as evidence that everything is fixed, and closes the tenant’s existing backlog — the accepted risks, the triage decisions, the regression history.
A stale database is not a reporting problem. It is a data-destruction problem.
This is why freshness is assessed before anything is persisted. The check runs against the result’s own metadata and, if the data is unusable, the scan returns an error and writes nothing. A test establishes a real critical, runs a scan against 120-day-old data that finds nothing, and asserts the critical is still open. Freshness is assessed after the scan rather than before it, for a related reason: the engine refreshes its database as part of scanning, so a pre-scan check would refuse the very run that would have fixed the staleness, and would be asserting something about a database other than the one actually used.

Where staleness surfaces

database_state is serialised while the engine identity and database version are not. Those name internal machinery and are stripped at the API boundary; database_state names nothing internal and answers a question the user genuinely has — was this scan looking at current data? — which a green result cannot otherwise be challenged on. unusable never appears on a succeeded scan, because such a scan never succeeds.

Providers

upstream — the default, and its honest limits

upstream pulls the database from the scanning engine’s own public infrastructure, published as OCI artifacts on ghcr.io and mirror.gcr.io. Integrity comes from OCI content digests, verified by the registry client during the pull. It is convenient, and the configuration comments in this repository say plainly that it is not an acceptable production configuration. Two reasons, both operational:
  • It makes TRUSTIVAN’s core data path depend on free public infrastructure whose own documentation warns it “could be rate limited”.
  • That infrastructure is operated by a company selling a competing product, and a commercial product cannot depend on a competitor’s goodwill for its core data path.
It is the default only in development (ENV=development). In any deployed environment there is no default: the backend refuses to start until VULN_DB_PROVIDER is set, and choosing upstream there also requires VULN_DB_ACKNOWLEDGE_UPSTREAM=true. That refuses inaction, not upstream: a deployment can still choose it, deliberately.

mirror — the intended answer, with an unresolved question

A mirror provider exists in internal/vulndb and works: it pulls from an OCI registry you operate.
Selecting mirror with no repositories is a startup error, not a silent fallback. Falling back quietly would mean an operator who configured a mirror for a perimeter deployment discovers the mistake as a scan reaching for the public internet — which either fails confusingly or, worse, succeeds and defeats the isolation they were configuring. A mirror must be populated by copying artifacts by digest, never by rebuilding them, so the digest a customer verifies is the digest the upstream publisher produced. Two things must be said about this rather than left implied:
  • Configuring a mirror is a technical capability, not a licence. Whether TRUSTIVAN may mirror this data for commercial redistribution is an unresolved legal question. A customer mirroring for their own internal use is a materially different position from TRUSTIVAN mirroring for redistribution, and the code distinguishes neither and grants neither. The open questions are logged as warnings at startup, so an operator running a commercial deployment has seen them at least once.
  • Air-gapped operation is a design goal, not a shipping feature. The provider interface exists so that a source inside a perimeter is a configuration change rather than a code change, and the 14-day hard limit was chosen partly to leave a site refreshing monthly room to notice before an auditor does. But the default provider still reaches the public internet, and the question of how an isolated site lawfully obtains the data is open.

Caching

Set it to a persistent path — /cache, backed by a volume, in the shipped compose file. Without persistence every worker restart re-downloads roughly 50 MB, which is the difference between a scan taking seconds and taking minutes. A cache directory that is silently not persisted is one of the conditions the 48-hour soft threshold exists to catch: nothing else about the deployment looks wrong, and the age creeps up. The cache is safely disposable. Discarding the volume costs one slow scan, not any data. See Upgrades.

Next