-
Notifications
You must be signed in to change notification settings - Fork 0
firmware registry
The device preflight healthcheck (#80) has a firmware currency pillar, but it
was under-built: it reported the running version as INFO and listed known
quirks, yet never checked whether the firmware was current or known-bad, and
carried nothing about a device's capabilities / expected experience. #80 asked
the pillar to "flag known-bad or EOL firmware and available updates." A device
on outdated firmware (often the cause of the other findings) sailed through.
A device is identified by the {vendor, product, version} its driver's
get_firmware_info() normalizes. The only vendor-specific knowledge — how to
read the version off the box — lives in the driver:
| driver | vendor | product | version (the comparable one) |
|---|---|---|---|
glkvm |
gl.inet |
reported board (Rockchip RV1126B-P …) |
kvmd version (4.82) |
pikvm / blikvm
|
pikvm / blikvm
|
reported board | kvmd version |
redfish |
Manufacturer (Dell/HPE/…) |
Manager Model (iDRAC 9, iLO 5) |
Manager FirmwareVersion
|
The registry and the checks stay 100% generic. Adding IPMI or AMT later is just a new driver returning the same three fields — no change to the registry or the checks. (On the PiKVM family a device can't report its product firmware version, so kvmd is the currency proxy; on BMCs the reported version is the upgradeable one.)
The report a user actually wants — what can this do and how good is the
experience — has ~5 axes, but most are detectable live by the healthcheck
(video codec/res/fps from /api/streamer, recovery path, exposed services). We
store only the differentiators a live probe can't safely determine:
- mouse — absolute vs relative decides whether a GUI is usable; can't probe without moving the pointer on a live host.
-
vmedia —
reports-onlyis the #77 trap (API says mounted, host sees an empty drive); can't probe without a reboot. -
power_state_trusted — whether power/LED readings can be believed (the GL
quirk behind the
.18no-recovery incident); a stored fact, not observable. - video — a fallback ceiling for devices whose stream API won't report it.
-
remote_update — whether a driver can flash this model over the network and how
reliable that is (
risk,recovery_required,self_flash_blind). Drives the healthcheck's actionable update offer and thefirmware-updatecommand's risk assessment; see firmware-update.md. A stored judgment, not a live probe.
Everything else on the report is computed live and combined. get_firmware_info()
can auto-populate the observable half, so humans only supply these few facts —
and can enrich them over time (an initial profile on first contact, a follow-up
report adding vmedia once an ISO has actually been booted).
Each entry's versions[].maturity records how proven a (vendor, product, firmware_version) combo is. The levels are derived — never hand-set — by
kvm_pilot.maturity from live runs only (source: "real" in
src/kvm_pilot/data/test_runs.jsonl — shipped in the wheel since #102, so
installed consumers can read the evidence offline); synthetic/mock runs never
promote anything.
| level | rule (per capability, from its live pass history) |
|---|---|
alpha |
0 live passes (mocks only, or live failures only) |
beta |
≥ 1 live pass |
rc |
≥ 3 live passes across ≥ 2 distinct UTC dates (destructive caps use the same ladder; the harness's explicit include gate, #99, guarantees they were deliberate) |
ga |
≥ 5 live passes spanning ≥ 14 days, all after the capability's most recent live failure (a new failure resets the window) |
The overall level is the min() of the exercised capabilities' levels.
Regenerate with:
python -m kvm_pilot.maturity --ledger src/kvm_pilot/data/test_runs.jsonl \
--registry src/kvm_pilot/data/firmware_registry.json --writeCI re-derives the levels from the ledger and fails if the committed registry
disagrees (tests/test_maturity.py::test_committed_registry_matches_ledger),
so a hand-edited level cannot survive a pull request.
-
check_firmware_currency— match(vendor, product); then:- installed version satisfies a
known_bad.affectedrange → that severity; - else
version < latest(ordered_vercmp) →WARNING"update available"; - else nothing — a current device stays quiet (no over-reporting).
- installed version satisfies a
-
check_capability_profile— surfaces the stored profile as the expected-UX line:INFOwhen all-good,WARNINGwhen any axis is degraded (relative/no mouse, non-reliablevmedia, untrusted power).
_vercmp compares each dot/dash segment numerically (correct for 4.82,
7.10.30.00, 2.78, V1.9.1 release1); genuinely non-numeric schemes only ever
compare equal and fall through to exact known_bad matches rather than a bogus
ordering. Version strings in the registry must use the device's own scheme (write
4.90, not 4.9, if you mean build 90).
Some devices report not just their installed version but their vendor's latest
release — GLKVM exposes both at /api/upgrade/compare (local_version vs
server_version). That telemetry lets a device keep the SSoT current:
-
driver.get_available_update()→{current, latest, beta, update_available}(GLKVM via/api/upgrade/compare; other drivers returnNoneuntil they wire their own update check — e.g. RedfishUpdateService). -
firmware_registry.reconcile(vendor, product, latest, registry=…)returns a ready-to-file "Latest known release" submission when the SSoT has nolatestfor that(vendor, product)or itslatestis older than the device-reported one;Nonewhen the SSoT already reflects it. -
kvm-pilot firmware-check --profile <name>runs detection + reconcile and prints the currency verdict plus the contribution to file (or--json). File it through the Issue Form and the ingest workflow folds it in — so a device in the field that sees a newerserver_versionthan the SSoT contributes the bump.
get_firmware_info() reports the product firmware the operator sees (GLKVM
uses /api/upgrade/version → V1.9.1 release1 (RM1PE)), not just the kvmd
component version, so the report and the registry key match the UI.
-
Bundled on PyPI.
data/firmware_registry.jsonships in the wheel, so the check works fully offline — the stdlib-only core never fetches on its own. -
Loader precedence (
load_registry):KVM_PILOT_FIRMWARE_DB(explicit file) → the user cache a refresh writes (~/.cache/kvm-pilot/) → the bundled copy. A missing or invalid override is skipped, so a bad refresh can never take the check offline. -
Opt-in refresh (not the default, never automatic): pull the latest registry
from
DEFAULT_DB_URL(the repo's raw file on GitHub's CDN — the single source of truth), validate it, and write it to the user cache. Explicit only — air-gapped / mgmt-LAN use and privacy mean we don't phone home per run.
-
Issue Form (
.github/ISSUE_TEMPLATE/firmware-report.yml) — a contributor picks a submission type (latest release / known-bad / capability profile) and fills structured fields. -
Action (
.github/workflows/firmware-ingest.yml, gated on thefirmware-reportlabel) runspython -m kvm_pilot.firmware_registry, which parses the issue body as data (never eval'd), validates it, merges it, and the workflow opens a PR automatically viaGITHUB_TOKEN. Invalid submissions comment the errors back on the issue; duplicates are a no-op. - Profiles merge field by field, so partial/enriching reports accumulate.
GitHub-hosted runners are free and unlimited for public repos; each run is seconds. The issue body is untrusted input, so a spam/injection issue just fails validation harmlessly.
The registry ships empty; real (vendor, product) entries are added through the
ingestion pipeline (no fabricated firmware facts — see CLAUDE.md). The mechanism
is verified end-to-end against a live GLKVM.
- Home
- Getting started
- Architecture
- CLI reference
- Configuration
- Design decisions
- Reflexes (RFC)
- Redfish reference
- Firmware registry
- Remote firmware update
- Unattended Linux installs
- Claude skill
- MCP server
- Contributing
- Security policy
- Analysis: 2026-07-01 deep review
- Analysis: 2026-07-03 RM1PE firmware + encoder
- Hardware compatibility
{ "schema_version": 2, "updated": "YYYY-MM-DD", "firmware": [ { "vendor": "dell", // == get_firmware_info().vendor (case-insensitive) "product": "iDRAC9", // substring of get_firmware_info().product "latest": "7.10.30.00", // latest known release (device's own scheme) "source": "https://…", "date": "2026-05-01", "known_bad": [ {"affected": "<=6.10.30.00", "severity": "critical", "issue": "…", "fixed_in": "6.10.80.00", "source": "https://…"} ], "profile": { // capability / expected-UX (all optional, incrementally enriched) "mouse": "absolute", // absolute | relative | none → GUI usability "vmedia": "reports-only", // reliable | reports-only | none → boot-from-ISO fidelity (#77) "power_state_trusted": false, // are ATX/LED readings truthful → safe to automate reboots? "video": "h264/1080p60", // rated transport + ceiling (fallback when unreadable live) "remote_update": { // can a driver flash this model, and how risky? (firmware-update.md) "supported": true, "method": "gl-api", "risk": "high", "recovery_required": true, "self_flash_blind": true, "notes": "…" } }, "versions": [ // DERIVED from src/kvm_pilot/data/test_runs.jsonl (#98) — never hand-edit {"version": "V1.9.1 release1", "maturity": {"level": "beta", "capabilities": {"info": "beta", "snapshot": "beta"}}} ] } ] }