The published image can't run jobs or push: prometheus-client, defusedxml and zeroconf aren't installed #173
Labels
No labels
area/ai
area/backend
area/frontend
area/infra
area/scheduler
area/wled
good-first-issue
priority/high
priority/low
priority/medium
security
type/bug
type/chore
type/ci-cd
type/docs
type/feature
type/qa
v1.0.0
v1.1.0
v1.2.0
v2.0.0
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Iris-WLED#173
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug (critical)
Verified against the published
git.rhoving.com/rbrooks/iris-wled:1.1.1image:schedule_service.log_run(so every scheduler job) andwled_push._try_push(every WLED push) importapp.services.metricswithout a guard. A container from this image starts and passes its health check, but can't run the on/off jobs or push to the lights. Off-site S3 backup (defusedxml) and controller discovery (zeroconf) are broken too. This affects 1.1.0 and 1.1.1; the production deploy (Rhoving/iac-repo#527) is on hold.Found by the delegate building #154, and then confirmed against the registry image.
Cause
The Dockerfile installs from
backend/requirements.txt, a hand-kept copy ofpyproject.toml's dependencies. It was not updated when #15 (metrics), #18 (off-site backup) and #50 (discovery) added dependencies topyproject.toml. It also installspytestandrespxinto the production image. Andaudit.ymlrunspip-audit -r requirements.txt, so the weekly dependency audit has been auditing the wrong set as well.It's the same class of bug as #147: two lists that nothing keeps in step.
Why CI didn't catch it
Tests run from
uv sync(so everything is installed), and the E2E container never runs a scheduler job or pushes to a controller. The image's health endpoint doesn't import metrics.Fix
uv.lock, viauv export --frozen --no-devwith hashes, so the image is byte-for-byte the locked set.requirements.txtis deleted, so there's no second list left to drift.audit.ymlaudits the same exported set.app.*module inside the built image, so any runtime import that the image can't satisfy fails the build.release/1.1.xbranch cut atv1.1.1, becausemainalready has unreleased v1.2.0 features. The same fix goes tomain.Fixed and released.
release/1.1.x, cut fromv1.1.1) is published assha256:6a5c1fb5….:1.1.2,:1.1and:latestall point to it.app.*module imports, andprometheus_client,defusedxmlandzeroconfare present.pytestandrespxare gone.schedule_service.log_runsucceeds in a read-only, cap-dropped container. On 1.1.1 it raisesModuleNotFoundError.main: #174 (squash-merged, CI green). The build installs the locked set exported fromuv.lockwith hashes,requirements.txtis deleted,audit.ymlaudits the same export, and the new CI step imports every app module inside the built image.Known limit:
zeroconfis imported inside a function, so the import sweep can't detect its absence. It's installed from the lock now regardless.Note: CI doesn't run on
release/*branches, so the 1.1.2 image was verified by hand. A follow-up could extendci.yml's triggers torelease/**.claude-bot referenced this issue2026-09-26 11:48:16 +00:00