airom ships its rule packs embedded in the binary, so a scan always works with no network. But a new AI framework shouldn’t require a new airom release to detect. airom rules update fetches a newer, signed rule bundle from the airom-rules channel into the cache; scans then prefer it — while the embedded packs remain the offline floor.
Update, then scan

The model

1

Embedded packs are the floor

airom always has a complete rule set compiled in. With no bundle fetched (or with --no-cached-rules), that’s what every scan uses. Nothing here requires a network or a second install.
2

`rules update` fetches a bundle — explicitly

It resolves the release, verifies it, and caches it under <cache-dir>/rules/<version>. This is the deliberate, unthrottled path: it fetches every time you ask, and can pin a version.
3

Scans also check once a day, unless told not to

With --auto-update-rules (on by default) a scan checks for a newer bundle before it resolves its rules — at most once every 24 hours, and never under --offline, --no-cached-rules, or in CI. Verification is identical to rules update, and a failed check keeps whatever you already have.
4

Scans prefer the cached bundle

Once cached, the bundle replaces the embedded packs as the base rule layer, and any lifecycle catalogs it carries overlay the embedded ones per provider. Your --rules overlays still layer on top. Every AIBOM records which ruleset produced it (see Provenance).

Pinning and reproducibility

rules update with no argument installs the latest release; pass a version to pin. In CI, pin both airom and the rules for a byte-reproducible AIBOM:
Pin the tool and the rules
Auto-update stands down whenever a CI environment variable is set (CI, GITHUB_ACTIONS, GITLAB_CI, JENKINS_URL, and friends), so pipelines keep the property that matters to them: the same cached bundle yields the same output every time.
That standdown is not a nicety. airom diff refuses to compare two AIBOMs produced by different rulesets — it will not blame a pull request for a rule change — so a base scan and a head scan that straddle a bundle release would fail the gate with nothing wrong in the code. A --fail-on threshold has the same exposure: a stricter rule turns a green build red with no commit behind it. Pin explicitly (airom rules update v1.2.0) or pass --auto-update-rules=false anywhere the CI detection does not fire.

Offline and air-gapped

--offline is an assertion, not a preference: it disables the auto-update check before anything is dialed, and makes rules update refuse outright. A scan then uses the cached bundle, or the embedded packs.
For an air-gapped environment, run rules update where there is network, then copy the cache directory (<cache-dir>/rules) to the isolated host, or point --rules-source at an internal mirror that serves the release assets.

Trust

A bundle is a gzipped tar of the packs (and, when published, the model lifecycle catalogs under eol/) plus a manifest.json (version, tarball SHA-256, counts) and a detached ed25519 signature over the manifest. airom verifies, in order:
  1. the signature against the public key embedded in the binary, then
  2. the tarball’s SHA-256 against the signed manifest, then
  3. extracts (path-traversal-guarded, size-bounded).
Any failure is fatal and leaves the previously active bundle untouched. The signing key’s private half lives only in the airom-rules CI secret; rotating it means a new airom release with the new public key.
--insecure-skip-signature bypasses signature verification (the checksum is still enforced). Use it only against a source you fully control — never the public channel.

Falling back and cleaning up

A cached bundle that fails to load never bricks a scan — airom falls back to the embedded packs with a warning.

Provenance

Every AIBOM records the active ruleset, so a document is traceable to the rules that produced it:
rulesVersion is builtin or the fetched bundle version; rulesHash is the SHA-256 of the effective ruleset. eolCatalog names the lifecycle catalog behind the document’s EOL claims — builtin, or builtin+<version> when a bundle overlaid it, since the merge is per provider and both layers can be answering. It is absent when --no-eol turned the overlay off: a claim nobody made needs no provenance. A retirement date is only as trustworthy as the catalog and verification date behind it, and a reader holding just the artifact cannot tell an eight-month-old embedded record from yesterday’s publish unless the document says so. All three project into CycloneDX (airom:rules.version, airom:rules.hash, airom:eol.catalog) and SARIF.

Authoring rules

Rules live in airom-rules; stable ones are promoted into airom’s embedded packs over time. To write one, see Writing rules — the schema and fixtures are identical to the built-in packs.