- webapp/requirements.txt pins all eight wheels with sha256, at the fixed
releases (lxml 6.1.3 for GHSA-vfmq-68hx-4jfw / PYSEC-2026-87, werkzeug
3.1.9 for GHSA-g6x2-hccm-hh4m).
- download-packages.sh fetches exactly that set for Python 3.12 / x86_64
into an emptied folder; PIP_DIR is honoured inside the container (own
mount), files are handed back to the calling user, USE_DOCKER=1 forces
the container on a noble host, an unknown package name now prints apt's
error instead of failing silently, and linux-modules-extra-7.0.* is gone
(it does not exist; 7.0 ships those modules in linux-modules).
- Playbook: the wheel installer refuses any wheel whose sha256 is not
pinned, needs exactly one wheel per pin, and removes an older installed
version by its RECORD first. The webapp copy is a full rsync every run
(was cp with creates: app.py, which never updated an install).
- scripts/check-updates.py: offline debs against noble security/updates
and the pins against PyPI + osv.dev; exit 1 when something needs
updating. Run it before building a USB.
Tested: installer in a Python 3.12 venv (clean install, upgrade over lxml
6.0.4 + werkzeug 3.1.8 leaves no old dist-info, re-run is a no-op, a stray
wheel is refused); check-updates.py flags the April bundle (94 security
updates) and passes the pins.
- webapp/: Flask web management app with:
- Dashboard showing image types and service status
- USB import page for WinPE deployment content
- Unattend.xml visual editor (driver paths, specialize commands,
OOBE settings, first logon commands, raw XML view)
- API endpoints for services and image management
- SETUP.md: Complete setup documentation for streamlined process
- build-usb.sh: Now copies webapp and optional WinPE images to USB
- playbook: Added webapp deployment (systemd service, Apache reverse
proxy), offline package verification, WinPE auto-import from USB
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>