v0.8.1: add ISO by URL, zero-touch admin bootstrap

Ease-of-use pass inspired by Bootimus (Dnsmasq-PXE is a manual dnsmasq
setup guide — nothing to adopt; OpenPXE already replaces that stack).

Add ISO by URL:
- New http-api `fetch` module: a small FetchJobs registry + a background
  streaming download (reqwest) that pipes a remote .iso through the same
  UploadHandle + introspection path as an upload, so a URL-fetched image
  classifies and gains boot entries identically. Progress is polled by the
  Storage view and rendered as rows, mirroring uploads.
- Routes POST/GET/DELETE /api/isos/fetch. http/https only; .iso-only
  filename derived from Content-Disposition / URL basename with path
  traversal stripped; 16 GiB cap; cancel; credential-stripped URL display.
  Operator-gated, no boot-time outbound — offline boot is untouched.
- Storage upload card gains an "Or add by URL" field with progress + cancel.

Zero-touch admin bootstrap:
- OPENPXE_ADMIN_USERNAME + OPENPXE_ADMIN_PASSWORD (or _PASSWORD_FILE for
  Docker/K8s secrets) auto-create the admin on first run, so a fresh
  container is usable with no setup wizard. Seeds the first run only — a
  lingering env var can't reset a rotated password.

Tests: URL parse / filename / Content-Disposition unit tests + a wiremock
end-to-end fetch-into-store integration test. clippy/fmt/node clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Miles Ward
2026-07-16 15:56:27 -04:00
co-authored by Claude Opus 4.8
parent 1c262a6d61
commit 5f98e6e03f
10 changed files with 684 additions and 12 deletions
Generated
+8 -8
View File
@@ -2758,7 +2758,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openpxe"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"axum",
@@ -2778,7 +2778,7 @@ dependencies = [
[[package]]
name = "openpxe-core"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"base64",
@@ -2803,7 +2803,7 @@ dependencies = [
[[package]]
name = "openpxe-dhcp-proxy"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"dhcproto",
@@ -2818,7 +2818,7 @@ dependencies = [
[[package]]
name = "openpxe-http-api"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"axum",
@@ -2852,7 +2852,7 @@ dependencies = [
[[package]]
name = "openpxe-ipxe-assets"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"openpxe-core",
"rust-embed",
@@ -2861,7 +2861,7 @@ dependencies = [
[[package]]
name = "openpxe-iso-store"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"bcrypt",
@@ -2887,7 +2887,7 @@ dependencies = [
[[package]]
name = "openpxe-tftp"
version = "0.8.0"
version = "0.8.1"
dependencies = [
"anyhow",
"openpxe-core",
@@ -2899,7 +2899,7 @@ dependencies = [
[[package]]
name = "openpxe-webui"
version = "0.8.0"
version = "0.8.1"
[[package]]
name = "p256"