The vulnerability database across the air gap
An isolated zone cannot reach the upstream vulnerability database, and a
side channel to update it would defeat the point of a tool whose job is
to be the channel (ADR-0008). So the database — and, on a Linux or
Windows host, the scanner binary itself — travel as ordinary
ingredients of a signed recipe, tobby-system, through the same
synchronization, the same medium and the same verification as everything
else (FR-032).
The tobby-system recipe
Section titled “The tobby-system recipe”The site’s qualification chain cooks and signs it, like any other recipe — the destination’s trust roots ignore any key but the site’s:
apiVersion: recipe.tobby.dev/v1alpha1kind: Recipemetadata: name: tobby-system version: 2026.11.11 # one version per database refreshspec: ingredients: - name: trivy-db # the vulnerability database, schema 2 kind: OCIArtifact ref: ghcr.io/aquasecurity/trivy-db version: "2" digest: sha256:… # pinned at cooking time artifactType: application/vnd.aquasec.trivy.config.v1+json - name: trivy # the scanner, for Linux and Windows hosts kind: FileSet ref: ghcr.io/aquasecurity/trivy version: "0.76.2" digest: sha256:… # the multi-platform indexThe container image already bundles the pinned scanner, so an instance
deployed from it only needs the database. A Windows host needs a FileSet
holding trivy.exe at its root (packed with tobby fileset pack from the
upstream release archive, checked against its checksum) referenced through
scan.trivy.ref: upstream publishes no Windows image. macOS takes trivy
from the PATH and needs only the database.
Only this recipe delivers: the one named tobby-system, admitted with
its signature verified. The scanner and its database decide what else
crosses, so a recipe admitted under a relaxed trust scope — even one named
tobby-system — or any other recipe never supplies them, whatever
repository it names; and the repository is matched exactly (the relocated
ref under the base prefix of the instance that wrote the record), never
by its ending. Such a recipe still synchronizes like any other; the
scanner simply does not see it, and stays in the degraded mode until the
signed one is recorded.
Bootstrap, in order
Section titled “Bootstrap, in order”- Connected zone. List
tobby-systemfirst in the Retriever: once it is recorded, the scanner re-reads its deliveries, so the recipes after it are scanned in the same run. Before that, every image is reported not scanned — and refused under a blocking policy. - Synchronize (mirror:
tobby sync --wait). Check the Retriever screen’s scanning indicator, or the metrics:tobby_scan_scanner_available 1,tobby_scan_db_present 1,tobby_scan_db_age_secondsa few hours. - Carry the medium and import it on the isolated side. Media verification and import (FR-052, FR-054) do not need the database: a destination instance without one still verifies and pushes a medium.
- Inside the zone, every instance that retrieves from the zone
registry lists
tobby-systemfirst in its own Retriever, and finds the very database that crossed — same digest, same build timestamp, its age in every report.
Until a database is present, the degraded mode is stated on every surface
(TBY-SCN-003): banner, startup log, tobby_scan_db_present 0.
Keeping it fresh
Section titled “Keeping it fresh”The database is only as good as its last transfer. Its age is measured
from the build timestamp it records, not from the transfer, and
scan.maxDbAge (default 168 h) bounds it: beyond, warn reports
staleness on the report, the UI and tobby_scan_db_stale, while block
refuses items scanned with it (TBY-SCN-004). Cook a new tobby-system
version on the cadence the bound implies — weekly by default — and let it
ride the next medium.
A database whose recorded build time lies in the future of this
instance’s clock — beyond one hour of tolerated skew — has no age that can
be stated: it is treated as stale, with its own code (TBY-SCN-008), on
the report, the banner and tobby_scan_db_stale, and refused under
block. Check the host’s clock.
Tobby keeps only the current database unpacked, in its state directory
(<state.root>/scanner, never on the transportable store); a new
delivery replaces it at the next synchronization. That directory must be
the instance’s own: owned by the user Tobby runs as and writable by
nobody else, or the scanner refuses it and stays in the degraded mode
(TBY-SCN-001 names why). An instance without a state directory unpacks
into a fresh private directory under the temporary directory, removed at
shutdown.