Two real issues v0.4.6 left on the table:
Asset caching:
- index.html now interpolates the running OpenPXE version into every
asset URL as `?v=<version>` (app.css, app.js, logo.svg). Combined
with `Cache-Control: no-cache, must-revalidate` on the asset
handlers, browsers and intermediary proxies are forced to fetch
fresh on every upgrade. Without this, last release's bundled JS
kept serving the old UI even after the operator pulled the new
image — invisible to anyone who only checks the version chip in
the footer (which is dynamic).
- The Cache-Control header is also applied to logo.svg and loader.svg
so a logo upload reflects immediately rather than after a hard
refresh.
Real-image PXE menu logo (matches iVentoy now):
- New Dockerfile stage `ipxe-build` clones the iPXE source and
compiles all four binaries (undionly.kpxe, snponly.efi for
x86_64/i386, snponly.efi for arm64 via gcc-aarch64-linux-gnu) with
IMAGE_PNG + CONSOLE_FRAMEBUFFER + CONSOLE_VESAFB enabled. Replaces
the boot.ipxe.org fetch — those binaries are built without PNG
support, which is why v0.4.6's `console --picture` line silently
no-op'd.
- `iso-store::pxe_logo::compose_pxe_logo` decodes any operator upload
(PNG / JPEG / WebP / GIF), downscales-to-fit if larger than
600×200, and pastes it onto a transparent 1024×768 canvas
centered horizontally with a 64-pixel top margin. iPXE paints the
result at 1:1 on the typical VESA framebuffer, giving the
iVentoy-style centered-logo look regardless of the operator's
source dimensions.
- GET /branding/pxe-logo now returns the composed PNG. wimboot still
fetches from ipxe/wimboot's GitHub release (separately signed).
- Dropped the ASCII OpenPXE wordmark from render_menu — once the
real image paints, the banner would duplicate it visually. iPXE
builds without PNG (none of ours after this release, but a third-
party undionly might) simply show the menu without a logo, which
is the right graceful-degradation outcome.
Quality:
- 142 tests passing (was 138 in v0.4.6): +4 pxe_logo unit tests
covering canvas dimensions, centered-top placement, oversize
downscale, and unsupported-bytes error handling; existing
integration tests updated to verify the 1024×768 IHDR header from
the composed PNG instead of round-tripping the raw upload.
- cargo clippy --workspace --all-targets clean.
- Image dependency: `image = "0.25"` with only `png/jpeg/webp/gif`
features enabled. No new transitive C deps.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This is the bulk pre-beta cleanup pass. Bumps the workspace to 0.2.0.
Test count is 56 -> 66 (+10), clippy is fully clean across the
workspace (was several dozen warnings).
## New features
**Per-MAC host bindings** (Tinkerbell smee pattern). New
`HostBindings` registry maps a MAC -> preferred boot target, persisted
to <work_dir>/hosts.json. The DHCP reply now embeds `?mac=${mac}` in
the boot.ipxe URL; iPXE substitutes the literal MAC client-side, so
the HTTP layer can short-circuit straight to the bound target instead
of rendering the menu. Reserved menu shortcuts (`_local`, `_gate`,
`_tools_menu`) are valid targets too. New /api/hosts CRUD + a Hosts
tab in the sidebar.
**Prometheus `/metrics`** endpoint. Tiny lock-free implementation —
just AtomicU64s and a Display impl, no `prometheus` / `metrics-rs`
dep. Counters: DHCP replies (per arch label), DHCP declined, TFTP
transfers (per status), TFTP bytes, HTTP requests (per route).
Gauges: ISO count, client count, gate count, gate-imaging, NFS active
mounts, uptime, build info. Plain text exposition format,
text/plain;version=0.0.4 content-type, no auth (all metric values are
non-sensitive counts).
**Light + dark themes**. CSS tokens on `:root` and
`:root[data-theme=light]`, swap by toggle button (top-right) or `T`
hotkey. Persisted in localStorage; pre-paint inline script avoids
dark<->light flash. Light palette designed against the Netbox Labs
reference screenshot — near-white surfaces, soft grey dividers,
accent unchanged for brand consistency. Terminal pane stays dark in
both themes (it's a console, that's the right read).
**Animated SVG logo + forge widget**. New `logo.svg` is a refined
silver/grey anvil. New `anvil-forge.svg` adds rising sparks and a
pulsing underglow via SMIL — pure SVG, no GIF, no JS animation loop.
Used:
- in the **forge progress** widget on Dashboard + Forge Gate, paired
with a `linear-gradient(warn -> accent)` bar with a moving sheen;
goes idle (greyscale, no sheen) at zero imaging load
- in the page-load `<div class=loader>` that replaces the old
"Loading..." text
## Code cleanup pass
`cargo clippy --workspace --all-targets` is now warning-free. Spot
fixes across the tree:
- `format!()`-into-`String` -> `std::fmt::Write::write!`
- manual reverse comparators -> `Reverse`
- `map_or(false, ...)` -> `is_some_and`
- redundant closures -> method references
- `r#"..."#` raw strings without `"` -> `r"..."`
- `std::io::Error::new(Other, ...)` -> `Error::other`
- `as i32` on `c.id()` -> `cast_signed()`
- merged identical match arms
## Windows workflow validation
New integration test synthesizes an ISO9660 with the SOURCES\\BOOT.WIM
sentinel, uploads it, asserts:
1. introspection labels it `windows_pe` with has_boot_wim=true,
2. the boot entry is `BootKind::Wimboot` with all five canonical
files (bootmgr, bootmgr.efi, bcd, boot.sdi, boot.wim),
3. the rendered iPXE script chains wimboot with `initrd --name`
entries for each file, and
4. NO trust-store strings appear in the rendered output: bcdedit,
testsigning, certutil, httpdisk, and test-signed are all
explicitly forbidden as a hard guarantee.
WinPE bootstrap (startnet.cmd) picks up the Bootimus v0.1.58 lessons:
explicit `net start Workstation` before `net use` to avoid the SMB
client lazy-init race, and surfaces errors instead of blind retries.
## Docs
architecture.md gains a "Phase 5" section explaining the host-bindings
+ metrics + theming + Windows-test work, plus a refreshed "deferred
to Phase 6" list (real-hardware integration, autounattend library,
distro profile manifest, WoL trigger, syslog receiver, IPv6).
README updates the status line, the "what it does" list, and adds
the new Hosts/Terminal tab names.