fix(analysis): harden readiness gate and vision-manager per self-review
Some checks failed
deploy / test-backend (push) Failing after 7m32s
deploy / build-and-push (push) Has been cancelled
deploy / deploy (push) Has been cancelled
deploy / test-frontend (push) Has been cancelled

Backend:
- Log on readiness state transitions (ready<->not-ready) so a misconfigured
  ANALYSIS_VISION_HEALTH_URL, which otherwise parks the worker silently
  forever, is diagnosable.
- Add unit tests for HttpVisionReadiness: 2xx->ready, non-2xx->not-ready,
  connection error->not-ready (the production status mapping had no test).

vision-manager:
- Guard the backlog count against non-numeric output before `-gt`, so a stray
  value can't exit-2 and kill the loop under `set -e`.
- Throttle the crawl-mutex "deferring start" log to once per episode.
- Only reset the idle/uptime timers when `docker stop` actually succeeds, so a
  failed stop retries next tick instead of waiting a full debounce window.
- Decouple the per-probe curl timeout (HEALTH_TIMEOUT) from the warm-up poll
  cadence.

Docs:
- Correct the docker-socket-proxy comment: CONTAINERS+POST permits the full
  container lifecycle (not just start/stop); state the real trust boundary.
- Document that the externally-defined mangalord-vision container must share
  the compose network for name resolution.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-14 15:15:40 +02:00
parent 64a9dceb67
commit f441425519
4 changed files with 132 additions and 22 deletions

View File

@@ -126,16 +126,22 @@ services:
# The vision container itself is NOT defined here (it lives elsewhere on the
# host); the manager drives it by name. See VISION-AUTOSCALE.md.
# Scoped Docker access for the manager: exposes ONLY the /containers API and
# write methods (start/stop) over TCP on an internal-only network. The raw
# host socket is mounted HERE and nowhere else — never on the backend.
# Scoped Docker access for the manager. The proxy gates by API *section*
# (not per-method), so CONTAINERS=1 + POST=1 permits the full /containers
# lifecycle — inspect/start/stop, but also create/kill/restart/update/
# rename/remove. It does NOT expose exec, images, volumes, networks, swarm,
# etc. (all default-denied). The trust boundary is therefore: (a) this is an
# internal-only network reachable solely by vision-manager, and (b) the raw
# host socket is mounted HERE and nowhere else — never on the backend. A
# backend RCE still cannot reach the Docker API. If you need true start/stop-
# only granularity, front the socket with an allow-list reverse proxy instead.
docker-socket-proxy:
image: tecnativa/docker-socket-proxy:latest
profiles: ["ai"]
environment:
CONTAINERS: 1 # allow /containers/* (inspect, start, stop)
CONTAINERS: 1 # allow the /containers/* section
POST: 1 # allow write methods (start/stop are POSTs)
# Everything else stays denied (images, exec, networks, volumes, ...).
# Everything else stays at its default-deny (EXEC, IMAGES, NETWORKS, ...).
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks: