Documentation
¶
Overview ¶
Package rulesync fetches, verifies, and caches a signed rule-pack bundle from the airomhq/airom-rules release channel, so rules can move faster than the airom binary without the user installing a second tool (Model B).
Trust model. A bundle is a gzipped tar of the YAML packs plus a manifest.json (version, tarball SHA-256, counts) and a detached ed25519 signature over the manifest bytes. airom verifies the signature against a public key embedded in the binary, then checks the tarball's SHA-256 against the manifest, then extracts. Any failure is fatal — a bundle is never partially trusted. The only escape hatch is an explicit InsecureSkipSignature.
Determinism and offline. Fetching happens on an explicit `airom rules update`, and — when the caller enables it — through AutoUpdate before a scan resolves its rules. AutoUpdate is throttled to at most one check a day, is skipped entirely under Offline or in a CI environment, and treats every network failure as "keep what we have", so a scan can never fail because a rules server was unreachable. Update refuses before dialing when Offline is set, mirroring the git source. The embedded packs remain the offline floor; a cached bundle is an override, and `--rules` overlays still layer on top of whichever wins.
Auto-update trades reproducibility for freshness, which is why it stands down in CI: two scans of one commit must agree, `airom diff` refuses across a ruleset change by design, and a --fail-on gate that flips with no commit behind it is a broken build rather than a finding. When it does install something, the scan says so in the document, not only on stderr.
This package holds airom's only outbound fetch besides the OSV overlay and its first crypto verification; it lives in internal/ so pkg/airom stays stdlib-only.
Index ¶
Constants ¶
const DefaultAutoInterval = 24 * time.Hour
DefaultAutoInterval is the minimum time between automatic checks.
Rule releases land on a human's schedule, so checking more often than daily buys nothing and costs a network round-trip on every scan — plus, from a CI fleet behind one NAT, GitHub's unauthenticated rate limit.
Variables ¶
var ( // ErrOffline is returned before any network call when Offline is set. ErrOffline = errors.New("rulesync: offline — refusing to fetch a rule bundle over the network") // ErrNoSigningKey means this airom build embeds no rules-signing public key // (verification impossible). Bypass with InsecureSkipSignature at your risk. ErrNoSigningKey = errors.New("rulesync: this airom build has no rules-signing public key embedded") // ErrSignature means the manifest's ed25519 signature did not verify. ErrSignature = errors.New("rulesync: bundle signature verification failed") // ErrIntegrity means the downloaded tarball's SHA-256 did not match the // (signed) manifest — corruption or tampering after signing. ErrIntegrity = errors.New("rulesync: bundle checksum mismatch") // ErrVersionMismatch means a pinned version was requested but the fetched // manifest declared a different one. ErrVersionMismatch = errors.New("rulesync: fetched bundle version does not match the requested version") )
Sentinel errors — callers match with errors.Is to map to exit codes and messages. Every one is fail-closed: on any of them, the cache is left untouched and the previously active bundle (or the embedded packs) stands.
Functions ¶
func Active ¶
Active returns the currently installed rule bundle as a filesystem plus its version, or ok=false when no valid bundle is cached (so the caller falls back to the embedded packs). It never touches the network and never errors: a missing, unreadable, or dangling pointer is simply "no bundle", because a scan must degrade to the embedded floor, never fail on a bad cache.
Types ¶
type AutoOptions ¶ added in v0.3.2
AutoOptions configures one throttled check. Interval ≤ 0 uses DefaultAutoInterval; the embedded Options are passed through to Update.
type AutoResult ¶ added in v0.3.2
type AutoResult struct {
Checked bool // a version check actually reached the network
From string // the version that was active before ("" = none, embedded packs)
To string // the version installed by this call ("" = nothing installed)
Updated bool // a newer bundle was fetched and made active
}
AutoResult reports what a check did. All three states are distinguishable so a caller can say something truthful without guessing: Checked=false means the network was never touched.
func AutoUpdate ¶ added in v0.3.2
func AutoUpdate(ctx context.Context, o AutoOptions) (*AutoResult, error)
AutoUpdate checks for a newer rule bundle and installs it, at most once per Interval. It is deliberately forgiving: every failure short of a corrupt install returns a nil error with Updated=false, because a scan must not fail because a rules server was unreachable. The signed-bundle guarantees are NOT relaxed — installation still runs through Update, so signature and checksum verification are identical to an explicit `airom rules update`.
Only a strictly NEWER version is installed. An older or equal remote version is left alone, so a rollback on the server never silently downgrades a machine that already fetched the newer one.
type Doer ¶
Doer is the minimal HTTP surface Update needs, so tests can inject a server-free transport (mirrors internal/osv).
type Manifest ¶
type Manifest struct {
Version string `json:"version"` // e.g. "v1.2.0"
Tarball string `json:"tarball"` // asset filename of the gzipped tar
SHA256 string `json:"sha256"` // lowercase hex of the tarball
RuleCount int `json:"ruleCount"` // informational
PackCount int `json:"packCount"` // informational
}
Manifest is the signed description of a bundle. The ed25519 signature covers the exact bytes of the manifest.json that carries these fields.
type Options ¶
type Options struct {
CacheDir string // where bundles live; the caller resolves the default
Version string // "" or "latest" → the newest release; otherwise pinned (e.g. "v1.2.0")
Source string // base URL override (mirror/testing); "" → the GitHub release channel
Offline bool // refuse to touch the network (fail before dialing)
InsecureSkipSignature bool // skip ed25519 verification — integrity check still runs
HTTP Doer // nil → a default 30s http.Client
PublicKey ed25519.PublicKey // nil → the key embedded in this build (tests inject their own)
Now func() time.Time // nil → time.Now; injectable for deterministic tests
}
Options configures a single Update. Zero values pick safe defaults.
type Result ¶
type Result struct {
Version string // the manifest version now active
SHA256 string // the tarball hash
Path string // the extracted bundle directory
RuleCount int
PackCount int
}
Result reports what Update installed.