• v0.4.5 a1518110ed

    mward4 released this 2026-05-25 22:37:25 -04:00 | 42 commits to main since this release

    OpenPXE v0.4.5

    Maintenance / hardening release. Three meaningful changes:
    a Casper-cmdline fix that makes Ubuntu / Mint / Pop!_OS / elementary
    ISOs reliably PXE-boot under VMware UEFI; a fully static musl binary
    that removes the glibc dependency; and a complete Sonarr/Radarr-style
    Forms admin auth layer with FleetDM-shaped SSO configuration on the
    side.

    VMware UEFI fix

    Borrowed from Bootimus v0.1.67.
    The Debian/Ubuntu kernel command line now reads

    boot=casper initrd=initrd ds=nocloud ip=dhcp iso-url=…
    

    instead of the legacy boot=casper netboot=url url=… ip=dhcp ---.
    Two material changes:

    • iso-url= is the canonical Casper option. Subiquity (the
      live-server installer) consumes it directly; the older netboot=url url=… syntax was a Debian-installer-era artifact that subiquity
      doesn't always honour.
    • ds=nocloud short-circuits cloud-init's metadata probe. On
      VMware-UEFI guests the vmxnet3 driver comes up late enough that
      cloud-init's autoprobe stalls indefinitely; ds=nocloud tells it
      there's no datasource and it should move on.

    Effect: Ubuntu Desktop, Ubuntu Live-Server, Mint, Pop!_OS, and
    elementary OS now boot consistently under ESXi / vSphere / Workstation
    UEFI guests. Bare-metal UEFI was unaffected and continues to work.

    A unit test (casper_cmdline_vmware_uefi_safe) pins the new form so
    this doesn't regress.

    Static musl binary

    The container build stage now compiles against
    x86_64-unknown-linux-musl. The resulting /openpxe binary has zero
    glibc dependency:

    $ ldd /usr/local/bin/openpxe
            statically linked
    

    This matches what Bootimus shipped in v0.1.70 and gives us:

    • No more "GLIBC_2.39 not found" surprises on older RHEL / Rocky
      hosts whose libc trails Debian 12's.
    • A future scratch / distroless variant is now a one-line swap (the
      binary is its own world); v0.4.5 still ships Debian slim runtime so
      we keep the existing samba / wimtools / nfs-common shellouts
      working without behavioural changes.
    • Slightly smaller attack surface — no dynamic-loader, no glibc
      symbol-version skew.

    The choice of Rust pays off here: the entire workspace compiles
    warning-free against musl without touching any code (rustls-via-reqwest,
    tokio, axum, bcrypt all "just work" on the musl target).

    Forms-style admin auth (Sonarr / Radarr layout)

    A complete first-run-bootstrap → login → change-credentials flow,
    deliberately modelled on Sonarr / Radarr. From a fresh install:

    1. The WebUI's /api/me returns setup_required: true and the SPA
      renders a centered "First-run setup" card. The operator picks a
      username + password.
    2. The bootstrap call (POST /api/setup) creates the admin record
      in <work_dir>/auth.json (bcrypt-hashed, cost 10) and sets a
      24-hour openpxe_session HttpOnly cookie.
    3. From that moment on, /api/* requests require the cookie; PXE
      endpoints (/boot.ipxe, /iso/*, /ipxe/*, the iPXE long-poll
      paths) stay public so booting clients don't get gated.
    4. The Settings tab gains an "Administrator account" card for
      rotating username / password. The current password is required
      to make any change; on success every other browser session is
      revoked.

    Endpoints: POST /api/setup, POST /api/login, POST /api/logout,
    GET /api/me, PUT /api/me/credentials.

    Sidebar footer carries a signed in as X chip + Sign out button.
    Forgot-password recovery is the same as Sonarr's: SSH to the host and
    delete <work_dir>/auth.json — the next launch re-enters setup mode.

    SSO config (storage-only this release)

    A FleetDM-shaped SAML configuration surface. Operators teach OpenPXE
    about their IdP today; the actual SAML-response-validation flow lands
    in a future release. Per the brief, the operator-visible fields are
    just:

    • Enable SSO (toggle)
    • IdP display name ("Sign in with X" label)
    • Metadata source — radio between Metadata URL (HTTPS) and
      pasted Metadata XML

    No Entity ID field — that defaults to the advertised public base URL
    internally when the SAML wiring lands, which is what every common IdP
    expects.

    Validation: enabling SSO without either metadata source returns 400;
    metadata XML is capped at 1 MiB; URLs must be http:// or https://
    and ≤2048 chars. Endpoints: GET /api/sso, PUT /api/sso.

    The login screen surfaces a non-functional "Sign in with X" button
    when SSO is configured but the runtime flow isn't live yet — so once
    v0.4.6+ lights it up, no operator config re-entry is needed.

    Container image

    • gitea.milesward.dev/mward4/openpxe:0.4.5
    • gitea.milesward.dev/mward4/openpxe:latest

    linux/amd64; ~97 MB compressed; static-musl binary, Debian 12-slim
    runtime for the shellouts. Non-root UID 10001 with
    setcap NET_BIND_SERVICE.

    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 Casper-cmdline regression guard.
    • cargo clippy --workspace --all-targets clean.

    Compatibility

    • Existing installs keep working. Old meta.json and hosts.json
      files deserialize unchanged. There is no auth file on existing
      deployments, so the first hit to the WebUI lands on the new
      first-run setup page — that's the intended UX for the rollout.
    Downloads