3ce45a8911
- tests/integration/conftest.py: get_live_service_vips() now reads from the config API's service_ips field instead of docker exec. The docker exec approach spawns a fresh Python process that imports firewall_manager with its hardcoded initial SERVICE_IPS, ignoring any update_service_ips() calls made at runtime. The config API always computes VIPs from the current ip_range, so it matches what the running app actually uses when writing iptables rules. - api/app.py: reject ip_range values without a CIDR prefix (e.g. '10.0.0.1') with a 400. Bare IPs are parsed as /32 by ipaddress.ip_network(strict=False), which shifts all VIP offsets and produces unusable Docker subnet configs. - tests/integration/test_config_api.py: update bare-ip test to expect 400 now that the API enforces the prefix requirement. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>