feeds

package
v0.136.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

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

View Source
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

View Source
var ErrNoLocalGoVulnDB = errors.New("no local Go vulnerability database")

ErrNoLocalGoVulnDB means no local copy of the Go vulnerability database has been fetched.

Functions

func CheckGoVulnDB added in v0.133.0

func CheckGoVulnDB(path string) error

CheckGoVulnDB reports whether path holds a Go vulnerability database govulncheck can answer from: an index that parses, and at least one module in it.

The shape is the documented offline form (`index/db.json`, `index/modules.json`, `ID/*.json`). Both checks exist because govulncheck reports "No vulnerabilities found" against a database that is empty or unreadable, and a scan must never read that as a clean result.

func Describe

func Describe(n Name) string

Describe returns a human-readable name for a feed, or "" if it is not a known one.

func Dir

func Dir() (string, error)

Dir is the feed cache, ~/.draugr/feeds.

func HumanAge added in v0.135.0

func HumanAge(d time.Duration) string

HumanAge renders a duration the way someone reads a staleness report: the largest unit that still says something useful, and never more precision than the answer deserves.

func HumanBytes added in v0.135.0

func HumanBytes(n int64) string

HumanBytes renders a size in the largest unit that keeps it under four digits.

func Load

func Load(dir string) map[Name]Record

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.

func Path

func Path(dir string, n Name) string

Path is where a feed's data lives inside dir, decompressed and ready to parse.

func URL

func URL(n Name) string

URL returns the upstream a feed is fetched from, or "" if it is not a known one.

Types

type LocalGoVulnDB added in v0.133.0

type LocalGoVulnDB struct {
	Path   string
	Record Record
}

LocalGoVulnDB is a local copy of the Go vulnerability database that passed its checks.

func FindGoVulnDB added in v0.133.0

func FindGoVulnDB(dir string, now time.Time, maxAge time.Duration) (LocalGoVulnDB, error)

FindGoVulnDB returns the cached Go vulnerability database if it is usable as of now: fetched, no older than maxAge, and structurally sound. The error names the check that failed.

Age is measured from when Draugr fetched the copy, not from the database's own modified date, which moves only when an advisory changes and so can lag a copy fetched this morning by days.

type Name

type Name string

Name identifies a feed.

const (
	KEV  Name = "kev"
	EPSS Name = "epss"
	// GoVulnDB is the Go vulnerability database govulncheck reads, kept as a local copy for a
	// runner that cannot reach vuln.go.dev.
	GoVulnDB Name = "govulndb"
)

The feeds Draugr knows how to fetch.

func Names

func Names() []Name

Names lists every known feed, in the order commands should present them.

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

func Fetch(ctx context.Context, dir string, n Name, client *http.Client) (Record, error)

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 catalog behind for the next scan to parse as though it were complete.

func (Record) Age

func (r Record) Age(now time.Time) time.Duration

Age reports how long ago the feed was fetched, as of now.

func (Record) Stale

func (r Record) Stale(now time.Time, maxAge time.Duration) bool

Stale reports whether the feed is older than maxAge. A maxAge of zero or less means never stale. The caller has said it does not care, which is a legitimate thing to say on a runner that is deliberately pinned to a known copy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL