v0.5.8
16
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c0d17fa9ca |
v0.5.6: advertise the HTTP port in client-facing boot URLs
The base URL handed to PXE clients was built as `http://{ip}` with no port, ignoring OPENPXE_HTTP_PORT. Every client-facing URL derives from it — the DHCP-proxy iPXE filename, UEFI HTTP boot, and the boot menu's kernel/initrd/ISO links — so any non-80 deployment told clients to fetch :80 (the wrong service). On Unraid that's the webGUI, which 301s to https; iPXE (no TLS) then fails the chain with "Operation not supported". This broke the exact configuration the Unraid template recommends (HTTP port 4200, to avoid the webGUI on :80). Fix: build_public_base_url(ip, port) includes the port unless it's 80, so http://10.0.0.5 stays clean while http://10.0.0.5:4200 is reachable. One source of truth, so the whole URL surface is corrected at once. Regression-tested (port included for 4200/8080, omitted for 80). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |
||
|
|
44a2212abe |
v0.5.5: SFTP-over-SSH remote shares (russh, pure-Rust, ring backend)
Adds SFTP as a third remote ISO-library protocol alongside SMB and NFS. Pure-Rust russh + russh-sftp on the ring crypto backend — no kernel mount, no subprocess, no OpenSSL, no new C deps. Like NFS (and unlike SMB), SFTP-sourced ISOs support HTTP Range requests because SFTP opens a seekable file handle. - iso-store: SftpShareManager (connect/auth/READDIR/seekable stream), IsoSource::Sftp, password OR SSH-key auth, trust-on-first-use host-key pinning, 0600 credential sidecar with a restart-safe derived path. - http-api: /api/sftp-shares routes, Range-aware ISO dispatch arm, status/metrics counts, /api/docs entry, `sftp` terminal commands. - webui: "SFTP (SSH)" protocol option with a password/key auth toggle, host-key fingerprint display, dashboard tile, updated copy. SCP was deliberately rejected: sequential-only (no Range) and its crates wrap libssh2 (C + OpenSSL), which would break the static-musl build. russh is pinned to =0.55.0: russh 0.61 needs the stable RustCrypto generation (pkcs8 0.11), which is API-incompatible with the release- candidate crates bergshamra-crypto pins (pkcs8 =0.11.0-rc.11). 0.55 is the newest russh on the prior generation (pkcs8 0.7) that coexists. Do not bump past 0.55 until bergshamra adopts stable RustCrypto. 252 tests pass, clippy clean, static musl x86_64 binary (ring already present via rustls + bergshamra, so no new crypto/C deps). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |
||
|
|
674a69f93b |
v0.5.4: code-cleanup pass (AppError, figment config, encoding dedup, typed status, deps)
Final cleanup before hardware testing. No behaviour changes; 248 tests green, clippy clean. #1 AppError newtype (http-api/src/error.rs) with one IntoResponse mapping (NotFound→404, Invalid→400, _→500) + From<core::Error>/From<io::Error>. Converted the clearly-safe handlers (sso_put, unattended_upload, branding_clear) to `?`; intentionally left handlers with bespoke status semantics (Invalid→404 on category, 409 on duplicate share / open upload) explicit so no asserted status changes. #2 figment-based Config::load (defaults → TOML → env). Keeps the historical flat OPENPXE_* names (Unraid/entrypoint compatible) AND adds the nested OPENPXE_SECTION__FIELD form; now covers every field (apply_env had silently skipped unattended_dir + bind addrs). 6 Jail tests prove backward-compat. Removed the hand-rolled apply_env. #3 thiserror 1→2; dropped unused mime/mime_guess/once_cell deps. #4 Re-evaluated: Duration::from_hours/from_mins are stable on the pinned 1.95 toolchain and clippy prefers them — kept the readable form (the "unstable" premise didn't hold; MSRV is intentionally 1.95). #5 insta snapshot of the rendered iPXE menu (version-filtered) + wiremock coverage of the SAML metadata-URL fetch (200 + non-2xx). #6 api_status → typed StatusResponse struct (was a 25-key json! blob) with a full_flow guard test asserting every UI key + the started_at string shape. Deferred the /api/docs typed conversion (lowest value, highest churn, zero functional benefit). #7 pct_encode/xml_escape de-duplicated into openpxe_core::encoding (were copied across app.rs + the SAML modules). No new crates. #8 UploadSessions registry → parking_lot::RwLock (sync, never held across .await); per-session lock stays tokio::Mutex. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |
||
|
|
7adf5e2918 |
v0.5.2: FleetDM login split, 3-slot branding, unattended installs
Authentication / login:
- Separate the local username/password form from the SSO "Sign in with …"
button (FleetDM-style divider + optional IdP logo); credential fields no
longer double as the SSO trigger. Settings → SSO copy now says SAML is live.
Branding — three slots (light / dark / client) on one row:
- Light/Dark feed the top-left mark + sign-in page by active theme (with
cross-theme fallback; theme toggle swaps the logo live). Client feeds the
PXE boot-menu background. Favicon pinned to the bundled mark via a new
/assets/favicon.svg endpoint. Legacy single logo migrates to dark + client.
- BrandingStore refactored to per-slot storage; /api/branding/logo/:slot.
Unattended installs (Storage → Advanced):
- New UnattendedStore (iso-store) + /api/unattended upload/list/delete and a
public templated serve at /unattended/:id (+ NoCloud seed dir for
autoinstall). Accepts .ks/.cfg/.seed/.yaml/.yml/.xml/user-data; classified
on upload; stored in its own unattended/ dir, never the ISO listing/menu.
- {{HOSTNAME}}/{{IP}}/{{MAC}} substituted per host at serve time.
Host pins + Queue profiles:
- HostBinding + QueueEntry carry an optional DeployProfile (auto_hostname /
auto_ip / unattended_file). Hosts pin form + a per-device Queue "Profile"
button collect them. On boot, a matched MAC has the right kernel arg
injected (inst.ks= / preseed url= / autoinstall ds=nocloud-net) and the
hostname/IP templated into the served answer file. DHCP stays proxy-only.
Storage:
- Remote shares default protocol is now NFS; updated descriptive copy.
235 tests green, clippy clean. Still a single static musl binary, pure Rust.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
||
|
|
cbcd63bb14 |
feat(saml): wire SAML 2.0 SSO end-to-end (pure-Rust) + Settings/Storage UI consolidation (v0.5.1)
SAML SSO (the config was storage-only since v0.4.5; now it logs you in):
- New openpxe-core::saml — pure-Rust SP built on bergshamra (XML-DSig +
exclusive c14n via RustCrypto, no OpenSSL/xmlsec/libxml2). The static
musl binary stays C-free; samael was rejected for hard-requiring OpenSSL.
* metadata.rs — parse IdP EntityDescriptor (SSO URLs + signing certs),
build our SP metadata.
* authn_request.rs — build + HTTP-Redirect-encode AuthnRequests.
* response.rs — verify the signature against the pinned IdP cert
(trusted_keys_only + strict_verification for XSW),
then enforce Status/Destination/Audience/time-bounds/
signature-scope. Stateless; returns the IDs the HTTP
layer needs.
- http-api saml_routes: GET /api/sso/login (302 to IdP), POST /api/sso/acs
(verify -> InResponseTo correlation / IdP-initiated gating / assertion
replay guard -> mint operator session -> 302), GET /api/sso/metadata.
Added to the pre-auth allowlist; /api/sso config stays gated.
- SsoConfig gains entity_id (SP Entity ID, defaults to public base URL)
and allow_idp_initiated (default off), mirroring FleetDM.
- Access model: any IdP-authenticated, cryptographically-verified user gets
an operator session (single-tier; local admin remains the fallback owner).
- Login page: the "Sign in with <IdP>" button now drives the real flow and
surfaces sso_error redirects.
UI consolidation:
- Removed the Advanced sidebar tab; folded its webhook-notifications +
API-reference cards into a collapsible "Advanced" disclosure at the
bottom of Settings.
- Merged the Storage tab's separate SMB and NFS cards into one "Remote
shares" card with a protocol dropdown and a unified, protocol-badged
table. No backend changes — same /api/smb-shares + /api/nfs-shares.
Tests: 17 SAML core tests (accept + reject tampered/unsigned/wrong-key/
wrong-audience/expired/future/wrong-issuer/non-success) and 6 ACS
integration tests (happy path, IdP-initiated gating, SP correlation,
replay, garbage). Full workspace: 206 tests green, clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
||
|
|
fc99973ac3 |
v0.5.0: Wake-on-LAN, webhook notifications, Advanced tab, login logo, update check
Closes the v0.4.x chapter — NFS works end to end. Five additions: ## Wake-on-LAN (Hosts → Bound hosts) - New core::wol module: parse any MAC form, build the 102-byte magic packet, broadcast it. No special capability needed (ephemeral source port; SO_BROADCAST). Sends to the limited broadcast (255.255.255.255) AND the server's own subnet broadcast (computed from advertised IP + detected mask) so it reaches the right VLAN. - POST /api/hosts/:mac/wol — only fires for *bound* MACs (404 otherwise) so it's not an open packet sprayer. - Bound-hosts table grows a "Wake" button with inline Waking…/Sent ✓ state. ## Webhook notifications (Advanced tab) - core::notify: NotifyConfig + NotifyStore (notify.json), one provider at a time — Slack / Discord / Teams (incoming-webhook JSON) or SMTP. SMTP password is persisted but redacted on GET behind a __keep__ sentinel the UI round-trips so the secret never leaves the box. - http-api::notify: delivery — reqwest POST for chat (provider-shaped bodies), lettre for SMTP (rustls, STARTTLS/implicit TLS, no plaintext). 10s timeout; every send is best-effort. - GET/PUT /api/notify, POST /api/notify/test. - Fired fire-and-forget on the canonical "machine is imaging" boot event and on WoL — never blocks the boot path. ## UI: Advanced tab - New nav item. Holds the webhook config card and the API reference block (relocated from the bottom of Settings). ## UI: login/setup logo (FleetDM treatment) - /api/me now returns has_custom_logo + logo_rev (public bootstrap). The login, setup, and connection-error cards render the uploaded logo full-width with the "OpenPXE" wordmark dropped — matching the sidebar. ## About: update check + licenses - "Check for updates" button → GET /api/updates/check queries the Gitea releases API (derived from CARGO_PKG_REPOSITORY) and compares to the running version. Strictly on-demand — no background polling, keeps the air-gapped promise. - License card documents the MIT OR Apache-2.0 dual license with links, plus a note on bundled components (iPXE GPLv2/UBDL, samba, wimtools). Deps: lettre (SMTP, rustls) + reqwest gains the json feature. Both rustls so the static musl binary stays OpenSSL-free. Tests: 179 passing (+notify round-trip/redaction, webhook validation, WoL-unbound-404, WoL packet loopback, version-compare). clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |
||
|
|
3f9d8568f0 |
v0.4.67: NFSv3 alongside SMB (in-process via nfs3_client crate)
NFS is back — done right this time. v0.4.67 ships a pure-Rust NFSv3
client (`nfs3_client` 0.9 from the xetdata/Vaiz crate family) running
in-process inside the openpxe binary. No `mount.nfs`, no kernel
modules, no `CAP_SYS_ADMIN`, no subprocess. Works in every container
that the v0.4.65 SMB path works in (Unraid included).
The v0.4.65 SMB path stays as-is. Operators get both protocols
side-by-side and pick whichever their NAS prefers — or use both
together. NFSv3 has one architectural advantage over the SMB
userspace path: HTTP Range requests work for NFS-sourced ISOs
because NFSv3 READ3 takes an explicit offset. SMB-sourced ISOs still
return 416 for ranges (smbclient CLI can't seek mid-stream).
## What's new
- `crates/iso-store/src/nfs_share.rs` — `NfsShareManager` mirroring
`SmbShareManager` structurally. Lists ISOs via READDIR3+LOOKUP3+
GETATTR3, streams files via READ3 in 64 KiB chunks piped to axum
body streams. Uses `connect_from_privileged_port(false)` because
the openpxe binary runs as uid 10001 — most modern NFS servers
allow that; a server that demands privileged ports needs
`insecure` in /etc/exports, and the hint translation calls that
out specifically.
- `IsoSource::Nfs { share_id, relative_path }` variant alongside the
existing `Smb`. `IsoStore::iso_path_for` returns None for both;
the HTTP handler dispatches to the right share manager.
- `/api/nfs-shares` CRUD + scan endpoints, parallel to
`/api/smb-shares`. `POST` body: `{ server, export, port? }`.
- `nfs` terminal command back (this time as in-process, not kernel
mount): `list | add <srv>:<export> [port] | remove | scan`. The
v0.4.64 `nfs` command name pointing at kernel mount is moot
history — same name, completely different mechanism.
- Storage tab: a new NFS shares card sits directly below the SMB
shares card. The form is simpler (no auth fields) since NFSv3
uses AUTH_SYS and access is gated server-side by client IP.
- Dashboard "Images available" tile sums SMB + NFS reachable shares
into a generic "N remote shares" line.
## What's the same
- The structured `{error, stderr, hint}` JSON shape on failures
matches the SMB API exactly, so the UI's error banner renders
identically.
- Hint translation: NFS3ERR_ACCES → "exports list", NFS3ERR_NOENT →
"export path doesn't exist", `mount denied` → "/etc/exports may
need `insecure`", timeouts → "check IP/port/firewall".
- Persistence: `<work_dir>/nfs_shares.json`. No conflict with the
long-dead v0.4.64 `nfs.json`.
## Why nfs3_client
User picked it: pure-Rust matches the architecture, NFSv3 covers the
real-world cases, AUTH_SYS keeps the UI simple. The crate is at
0.9.0, MIT/Unlicense, rust-version 1.88 (we're on 1.95). Tokio
feature flag enabled. Image size unchanged at compile time — single
musl static binary, no extra OS packages.
## Tests
160 passing (was 150 in v0.4.66, +10):
- nfs_share parser: stable share ids, server normalization (smb://,
cifs://, \\, // all stripped).
- hint_for(): NFS3ERR_ACCES, NFS3ERR_NOENT, mount denied, unknown.
- status_label() covers the common nfsstat3 codes.
- HTTP integration: nfs-shares list starts empty, missing server
rejected, export without leading slash rejected.
`cargo clippy --workspace --all-targets -- -D warnings` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
||
|
|
900b65b3ec |
v0.4.65: swap kernel-mount NFS for userspace SMB (smbclient)
v0.4.64's NFS path didn't work on Unraid even with --privileged
because Unraid's base kernel ships without the nfs/nfsv4 client
modules — and no container-side configuration can load a host kernel
module. SMB has the same kernel-mount problem (`mount -t cifs` needs
the cifs module) but it also has a usable *userspace* client: Samba's
`smbclient` CLI, which speaks the SMB protocol over a plain TCP socket
with no kernel involvement. This is the same approach Bootimus uses,
and works in every container regardless of host kernel modules or
container capabilities.
What's gone:
* `crates/iso-store/src/nfs.rs` (in entirety)
* `NfsManager`, `NfsMount`, `NfsAddRequest`, `NfsVersion` types
* `IsoSource::Nfs` variant
* `IsoStore::nfs_root` / `IsoStore::set_nfs_root`
* `/api/nfs`, `/api/nfs/:id`, `/api/nfs/:id/scan` routes
* `nfs` terminal command
* Storage tab's NFS shares card and the v0.4.64 fstab-options
diagnostics work (the whole error path is moot now)
What's new:
* `crates/iso-store/src/smb_share.rs` — `SmbShareManager` that drives
`smbclient` as a subprocess. Indexes shares via `smbclient -c "ls
*.iso"` and streams files via `smbclient -c "get file -"` piped
straight into HTTP response bodies. No local cache, no double disk
usage.
* `IsoSource::Smb { share_id, relative_path }` variant.
* `IsoStore::iso_path_for` returns None for SMB sources — the HTTP
ISO download handler dispatches on the source kind and streams via
the SmbShareManager when it's SMB.
* `/api/smb-shares` + `/api/smb-shares/:id` + `/api/smb-shares/:id/scan`
routes.
* `share` terminal command (`list | add //srv/share [auth] | remove |
scan`). Auth spec is `guest` or `user:password`.
* Storage tab: SMB shares card replaces the NFS one. Two-column form
for server + share name, three-column form for guest checkbox /
username / password. Username and password fields auto-disable when
Guest is checked.
* Credentials live under <work_dir>/smb_creds/<id>.cred at 0600
permissions so they don't leak through `ps`. Persisted state at
<work_dir>/smb_shares.json (sans password — re-entered on add /
re-scan).
Why subprocess and not a Rust crate:
* The Debian runtime image already ships the `samba` package
(Dockerfile line 84) — `smbclient` is right there.
* Library options (pavao, etc.) wrap libsmbclient so they still pull
in the same C library at runtime.
* Subprocess gives operators a verifiable mental model — anything
OpenPXE can do over SMB, they can reproduce by running `smbclient`
manually at a shell.
Range-request limitation, called out in the smb_share.rs module docs
and the UI explainer: `smbclient -c 'get file -'` is a sequential
whole-file stream. HTTP range requests on SMB-sourced ISOs return
416. PXE workloads (iPXE chain, casper sanboot, wimboot) do
whole-file sequential reads, so this works in practice. A follow-up
release can add libsmbclient-based seek if a real workload needs it.
Stderr-to-hint translation patterns mirror v0.4.64's NFS work:
NT_STATUS_LOGON_FAILURE → "check credentials", BAD_NETWORK_NAME →
"check share name", connection refused / timeout → "verify
reachability + firewall", etc. UI renders the raw smbclient error
plus the hint as two lines.
Tests (149 total, was 142 in v0.4.64):
* smb_share parser tests covering ISO + skipped directory, filenames
with spaces, non-ISO filtering.
* hint_for() translation tests for the dominant NT_STATUS codes.
* Server normalization (smb://, cifs://, \\, // prefixes all stripped).
* HTTP integration: shares list starts empty, invalid server / missing
username / path in share name all rejected with actionable hints.
`cargo clippy --workspace --all-targets -- -D warnings` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
||
|
|
07e7c18698 |
Revert "v0.4.65: Local directory ISO source (bind-mount workaround for Unraid)"
This reverts commit
|
||
|
|
761489761c |
v0.4.65: Local directory ISO source (bind-mount workaround for Unraid)
Field report: even with CAP_SYS_ADMIN and full --privileged, NFS mounts
inside the OpenPXE container fail on Unraid with the same
"failed to apply fstab options" error v0.4.64 added diagnostics for.
The root cause is the host kernel: Unraid's base kernel ships without
the nfs/nfsv4 client modules loaded. Capabilities are necessary but
not sufficient; the modules have to be present on the host kernel for
in-container mount(2) to do anything. No container-side change can
fix that.
This is exactly the case every other PXE/imaging tool sidesteps
(Bootimus uses SMB; iVentoy, FOG, MAAS, Cobbler all rely on the host
to mount network storage and bind-mount the path into the imaging
service). v0.4.65 brings OpenPXE in line with that pattern.
What's new:
* `IsoSource::LocalDir { dir_id, relative_path }` — third source kind
alongside `Local` (uploaded) and `Nfs` (in-container mount).
* `LocalDirManager` (crates/iso-store/src/local_dir.rs) — registers
bind-mounted directories, validates them (absolute path, exists, is
a directory, readable), scans for *.iso files, registers them with
IsoStore. Persisted to <work_dir>/local_dirs.json so the relationship
survives restarts.
* `NfsHostCaps::detect()` — pure read of /proc/filesystems on startup.
Surfaced via GET /api/nfs/capabilities and used by the Storage tab to
show a prominent red banner above the NFS form when in-container
mounts cannot possibly work, pointing the operator at the Local
Directories card as the recommended path.
* Four new API routes:
GET /api/nfs/capabilities
GET /api/local-dirs
POST /api/local-dirs { path, label? }
DELETE /api/local-dirs/:id
POST /api/local-dirs/:id/scan
UI changes (crates/webui/src/app.js):
* Storage tab: new "Local directories" card under the NFS card with
the bind-mount form, an explainer paragraph (with the Docker
`-v /mnt/user/isos:/mnt/external-isos` command), and the list of
registered directories with rescan + remove actions.
* When NFS host caps are unavailable, the NFS card sprouts a red
banner explaining what's wrong and pointing at the local-dir
workaround. The card sub-header also flips to "N registered ·
recommended on this host".
* ISO table: new "dir:<id>" source badge; on-disk ISOs show "on disk"
in the actions column instead of a delete button (same pattern as
NFS — OpenPXE doesn't own those bytes).
* API reference table picks up the four new endpoints + a hint about
the new `port` field on NFS add.
Tests (+12, total 162):
* iso-store: 7 local_dir unit tests covering relative-path rejection,
missing path, non-directory file, empty-directory success, default
label, idempotent re-add, remove + iso-path-resolution clear.
* iso-store: 1 nfs unit test confirming NfsHostCaps::detect() never
panics and the boolean accessors are consistent.
* http-api: 4 integration tests covering /api/nfs/capabilities,
/api/local-dirs list/add/remove + relative-path 400.
`cargo clippy --workspace --all-targets -- -D warnings` clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
||
|
|
a1518110ed |
v0.4.5: VMware UEFI fix, static musl binary, Forms auth + SSO config
VMware UEFI / Casper boot fix:
- Linux cmdline for Debian/Ubuntu/Mint/Pop!_OS/elementary now uses the
canonical Casper `iso-url=` option and `ds=nocloud`, matching the
fix Bootimus shipped in v0.1.67. The previous
`boot=casper netboot=url url=… ip=dhcp ---` form booted fine on
bare-metal UEFI but hung at "cloud-init running" on VMware guests
because subiquity / cloud-init can't reach a metadata datasource
through PXE.
Static binary (matches Bootimus v0.1.70):
- Dockerfile build stage now compiles against
x86_64-unknown-linux-musl. The resulting /openpxe has no glibc
dependency at all; the runtime stage still ships Debian slim for the
samba/wimtools/nfs-common shellouts, but a future scratch/distroless
variant is now a one-line swap. Cuts a class of "GLIBC_2.39 not
found" surprises on older RHEL/Rocky hosts.
Forms auth (Sonarr/Radarr-style):
- New AdminStore in openpxe-core: single admin record persisted to
<work_dir>/auth.json, bcrypt-hashed credentials, rotation requires
current password.
- New SessionStore in openpxe-http-api: in-memory UUID-keyed sessions
with 24h sliding TTL, openpxe_session HttpOnly cookie.
- Endpoints: POST /api/setup (first-run), POST /api/login, POST
/api/logout, GET /api/me, PUT /api/me/credentials (rotates and
revokes every other session).
- Auth middleware gates /api/* once the admin is configured;
passes through entirely until then (tests + fresh installs ride this
path). Allowlists PXE-essential paths (/boot.ipxe, /iso/*, /ipxe/*,
/api/queue/join, /api/queue/poll/*) so iPXE clients still work
without a cookie they can't send.
- WebUI: first-run setup card, login card, logout chip in the sidebar
footer, Account card in Settings for rotating creds. Auth screen is
fully styled (centered narrow card, matches Sonarr layout).
SSO config (FleetDM-shaped, storage-only):
- New SsoStore in openpxe-core: { enabled, idp_name, metadata,
metadata_url } persisted to <work_dir>/sso.json with size caps and
URL-scheme validation.
- Endpoints: GET /api/sso, PUT /api/sso. Validation: enabling SSO
without either metadata or metadata_url returns 400.
- WebUI: SSO card in Settings with a URL-vs-XML mode switch and an
inert "Sign in with X" button on the login screen while runtime
flow is pending. Per the brief: no Entity ID field (defaults to the
advertised public_base_url internally when SAML wiring lands).
Quality:
- 132 tests passing (was 106 in v0.4.4): +5 auth unit tests, +5 SSO
unit tests, +7 auth integration tests, +1 SSO integration test, +1
regression guard pinning the new Casper cmdline.
- cargo clippy --workspace --all-targets clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
||
|
|
7b972dc049 |
v0.4.4: Settings tab, API reference, ISO category, branding, disk space
Settings:
- New top-level Settings tab. Carries a placeholder for the planned
LDAP / OIDC / user-management work, the new branding controls, and
the API reference at the bottom.
- Custom logo upload (PNG/SVG/JPEG/WebP/GIF up to 2 MB) replaces the
bundled brand mark via /assets/logo.svg; bytes live at
<work_dir>/branding/ and survive restart. The original "OpenPXE
v<x.y.z>" pins to the sidebar footer for support.
- API reference rendered from a new GET /api/docs into a per-method
coloured pill list grouped by area.
ISO category (Storage):
- New IsoCategory { Os, Tools } on IsoMeta with PUT
/api/isos/:id/category. Storage table's Type cell becomes a
dropdown; selecting Tools moves the ISO into the Tools submenu next
to memtest / shell / NIC info and removes it from the OS Installers
family submenu. Family detection still drives BIOS/UEFI / kernel
args; only the menu placement changes.
Storage telemetry:
- New IsoStore::disk_usage (libc::statvfs, lives in iso-store so the
http-api crate stays #![forbid(unsafe_code)]) and GET
/api/storage/disk. The Storage tab now shows free/used/total for
the volume hosting the ISO directory with an 80%/95% colour ramp.
UI polish:
- Brand block in the sidebar now matches the topbar height exactly,
so the divider runs straight across the top of the app rather than
stepping; version label moved out of the brand and pinned to the
sidebar footer ("OpenPXE v0.4.4").
- Light-mode terminal: --terminal-bg + per-level text colours track
the active theme rather than being hard-coded dark.
- About: lead paragraph spans the full content width; new Docs row
links to https://openpxe.com/.
106 tests passing (was 89 in v0.4.1, +17 across branding unit tests
and new integration coverage for category / disk / docs / branding).
cargo clippy --workspace --all-targets clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
||
|
|
2c1c80a7ca |
v0.4.1: harden ISO uploads and beta UI polish
Add browser-safe chunked ISO uploads with progress, partial-file visibility, offset validation, and abort cleanup while keeping the legacy multipart endpoint for API clients. Record host-log validation coverage, keep the queue/status UI copy clean, move release docs to 0.4.1, and tighten the dark theme to a near-black Netbox-style palette. |
||
|
|
ec171ede47 |
v0.4.0: upload telemetry, host log, jet-black UI
- Upload reliability + diagnostics:
- api_upload_iso now distinguishes clean EOF from mid-stream errors;
a truncated multipart body (proxy buffer cap, network drop) returns
400 with the cause and a "try the LAN IP" hint instead of silently
finalising a partial file.
- Per-stage tracing (begin/MB-watermark/finish/abort) so a stuck
upload is debuggable from the Terminal tab.
- Web upload UI surfaces bytes/total, percent, throughput, ETA, and
maps 413/502/504/network-drop to actionable hints.
- New BootLog feature under Hosts:
- openpxe-core::BootLog — bounded in-memory ring (500) + append-only
JSONL on disk, recording (timestamp, mac, ip, target_id,
target_title) every time a boot entry script is served.
- iPXE per-entry chain URLs grow ?mac=${mac}; password prompt
submission carries it through; host-binding short-circuit uses the
bound MAC. ConnectInfo<SocketAddr> wired for peer IP capture (with
optional fallback so tower::oneshot in tests still works).
- GET /api/boot-log endpoint + Host log table under the Hosts tab.
- UI changes:
- Queue card header "Forge" → "Status".
- Removed Tinkerbell attribution sentence from Hosts tab.
- Topbar readiness chip moved into the sidebar footer as
"Service status: Ready / Advertised to clients / <url>", grouping
advertised PXE URL with operator-relevant status.
- Jet-black dark palette (#000 / #0a0a0a / #141414 / #1c1c1c)
replacing the blue-tinted ramp; terminal toolbar/input recoloured
to match.
- 89 tests passing (was 85 in v0.3.2); cargo clippy --workspace
--all-targets clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
||
|
|
115ba779da | Name update | ||
|
|
20c585e3ed | Name update |