Documentation
¶
Overview ¶
Package feeds fetches and caches the exploitability datasets Draugr can enrich findings with: CISA's Known Exploited Vulnerabilities catalog and FIRST's EPSS scores.
Fetching is never implicit. A scan that silently reaches the internet is not reproducible, and the gate has to be — so the network is touched when someone asks for it, by running `draugr feeds update` or by passing `auto`, and a scan otherwise reads a local cache with no network access at all. That keeps the air-gapped path and the connected path the same code.
The cache records where each feed came from and when, because "we escalated this to critical because it was on KEV as of 2026-08-01" is an auditable statement and "KEV said so" is not.
Index ¶
Constants ¶
const DefaultMaxAge = 24 * time.Hour
DefaultMaxAge is how old a cached feed may be before `auto` refetches it and a scan warns.
One day, because EPSS is republished daily: a score is a 30-day probability recomputed every morning, so a week-old copy silently mis-ranks. KEV changes far less often and is held to the same bar deliberately — two staleness rules to explain is worse than one that is slightly strict for one feed.
Variables ¶
This section is empty.
Functions ¶
func Load ¶
Load reads the manifest. A missing or unreadable manifest is an empty one: the feeds it described are then treated as absent, which is the safe direction — worst case a refetch.
Types ¶
type Record ¶
type Record struct {
URL string `json:"url"`
FetchedAt time.Time `json:"fetchedAt"`
SHA256 string `json:"sha256"` // of the decompressed bytes on disk
Bytes int64 `json:"bytes"`
}
Record is what the cache knows about one fetched feed.
func Fetch ¶
Fetch downloads one feed into dir, decompressing it if the upstream is gzipped, and records what it fetched. It returns the resulting cache entry.
The write is atomic: a temporary file in the same directory, renamed into place. A fetch interrupted halfway must not leave a half a catalogue behind for the next scan to parse as though it were complete.