asyncio.open_connection hangs indefinitely when backend port is silently
dropped. Add wait_for(timeout=3.0) so the WS close frame is always sent
within the test's 5s window.
- Start real pylsp process in fixture (retry-loop until port accepts)
- Fake client sends LSP initialize via WebSocket proxy
- Verify real pylsp capabilities + completionProvider in response
- Fix LSP frame parser to handle multi-header responses (Content-Length + Content-Type)
- Test graceful close when backend unreachable
- Remove static ports 2087/2088/2089 from Nomad; use one dynamic port
- pylsp and Bicep LS stay on localhost inside container (not exposed)
- aiohttp adds /python and /bicep WebSocket routes bridging to localhost LSPs
- Nomad env: HTTP_PORT=$NOMAD_PORT_http, internal ports fixed at 2087/2088
- Editors connect via ws://ilsp.i80.dk/python and ws://ilsp.i80.dk/bicep
- Traefik routes ilsp.i80.dk → single dynamic HTTP port
- Remove all DevOpsMCP/aiohttp runtime deps from BicepModuleCatalog
- BicepModuleCatalog.load() reads bicep_modules_catalog.json from disk at startup (sync)
- Fix _load_catalog: catalog uses dict {path: {versions, schema}} not a list
- server.py: call BicepModuleCatalog.load() synchronously, not via asyncio.gather
- Dockerfile: COPY bicep_modules_catalog.json into both builder + runtime stages
- Health endpoint now reports bicep_modules: 27
Verified locally: make run-quick → health returns pypi_packages:40 bicep_modules:27
catalog.py: Fix HTML parsing regex — pypi-server.i80.dk uses relative hrefs
like href="pkg-name/" not /simple/pkg-name/. Use simpler <a> text extractor.
modules.py: Replace /call-tool POST (wrong) with GET /api/bicep-modules (new REST
endpoint added to DevOpsMCP). Simpler, no MCP protocol overhead.
Dockerfile:
- Final stage now FROM mcr.microsoft.com/dotnet/runtime:8.0 instead of python:3.12-slim
+ MS apt repo. Reason: packages.microsoft.com GPG key uses SHA1 which Debian trixie
rejects since 2026-02-01. The official MS container image has no signing issue.
- Add python3 + pip3 + wget on top of dotnet base (bookworm)
- pip3 install --break-system-packages for debian bookworm compatibility
Makefile targets:
make build - build image locally
make rebuild - force no-cache build
make run - build + start container with port mappings
make run-quick - start without rebuilding
make stop/restart - container lifecycle
make logs - follow logs
make shell - bash into running container
make health - curl health endpoint
make smoke - end-to-end TCP + health test (scripts/smoke_test.sh)
make test - unit tests (pytest, no Docker)
make ps/ports - status helpers
make clean - stop + remove image