Completes tasks 10-15 and fixes what was outstanding:
- vulndb.Pull implemented with oras-go, streaming the ~50MB layer and
staging both files before replacing either, so a failed pull leaves the
previous database intact rather than a half-written one.
- db.go: Vulnerability.Severity is a string, not trivy Severity, so the
int conversion did not compile. Severity now resolves vendor (highest
when vendors disagree) then NVD then unknown, and CVSS is read too.
- findings.go: added sweepFixedFindings plus the fleet query, severity
counts, rescan flag and accept/unaccept the API needs.
- vulnrules.go: added rule CRUD and the digest builder. ResolveTargets
returns []models.Server, not []string, so filterByServers was wrong.
- api/vulnerabilities.go was an empty file while handlers.go registered
twelve routes against it; written, grouped by CVE.
- shared/mail: added the missing sender. The templates were orphaned and
the HTML one was a copy of the text one, defining "subject" (which
html/template would escape) and emitting no markup. render.go parses
every template in init(), so a bad one panics server, admin and sitesvc
at boot — go build never runs init(), which is why nothing complained.
- notify: digests dispatch through their own path so SMTP gets the digest
template rather than arriving dressed as a monitor alert.
Adds migration 0004_org_to_instance, the ScopedCollections list, the
AssertNoScopedCollectionMissed boot check, and moves EnsureAuthIndexes into
its own file.
Two ordering constraints the rename exposed, both now enforced and commented:
- 0004 must run BEFORE EnsureAuthIndexes. The index builder creates
instances.slug, which would create an empty instances collection and make
0004 refuse to rename orgs onto an existing target.
- Migrations 0001 to 0003 run BEFORE 0004 and still read and write org_id, so
they use a private legacyOrg struct rather than shared/models.