fix: look up the default interface lazily instead of at import time #77

Merged
mysticalsoap merged 1 commit from fix/lazy-default-interface into trunk 2026-08-19 23:19:29 -04:00
Owner

Closes #66

Problem

aqomui_service.py resolved the default gateway interface with netifaces in the class body, at import time. Two problems stack: any lookup failure prevents the service from starting at all, and netifaces (archived upstream since 2021) returns an empty 'default' dict when a second routing table also holds a default route — exactly the state bypass leaves behind in table 11. Net effect: after any bypass run, systemctl restart aqomui crash-loops (KeyError: 2) until ip route del default table 11 is run by hand.

Fix

  • utils.default_interface() parses ip -j route show default (iproute2 is already a hard dependency). It reads only the main table, so a default parked in another table can't shadow the answer, and it returns "None" on any failure instead of raising.
  • The class attribute becomes a lazy property: the gui-registered interface (via bypass()) still wins when present; otherwise the lookup happens at the point of use. Import no longer touches the routing table.
  • The one remaining netifaces use (interface-name validation in bypass()) checks /sys/class/net/<name> directly. import netifaces is gone, and python-netifaces is dropped from the PKGBUILD and ci.yml.

Verification

  • 4 new tests for default_interface() (route present / no default route / ip failing / ip missing); suite at 93 passing, CI lint + syntax checks clean.
  • Module imported live under an empty routing table (the crash scenario): import succeeds and the property returns "None"; with a real table it resolves enp5s0. Setter round-trip (gui registration) confirmed.
  • Live restart-after-bypass verified 2026-08-19: main + bypass connection up, then systemctl restart aqomui — service came back active (running) with no crash-loop and no manual table-11 cleanup. The same sequence crash-looped reliably on the previous build.

🤖 Generated with Claude Code

Closes #66 **Problem** `aqomui_service.py` resolved the default gateway interface with netifaces in the class body, at import time. Two problems stack: any lookup failure prevents the service from starting at all, and netifaces (archived upstream since 2021) returns an empty `'default'` dict when a second routing table also holds a default route — exactly the state bypass leaves behind in table 11. Net effect: after any bypass run, `systemctl restart aqomui` crash-loops (`KeyError: 2`) until `ip route del default table 11` is run by hand. **Fix** - `utils.default_interface()` parses `ip -j route show default` (iproute2 is already a hard dependency). It reads only the main table, so a default parked in another table can't shadow the answer, and it returns `"None"` on any failure instead of raising. - The class attribute becomes a lazy property: the gui-registered interface (via `bypass()`) still wins when present; otherwise the lookup happens at the point of use. Import no longer touches the routing table. - The one remaining netifaces use (interface-name validation in `bypass()`) checks `/sys/class/net/<name>` directly. `import netifaces` is gone, and `python-netifaces` is dropped from the PKGBUILD and ci.yml. **Verification** - 4 new tests for `default_interface()` (route present / no default route / `ip` failing / `ip` missing); suite at 93 passing, CI lint + syntax checks clean. - Module imported live under an empty routing table (the crash scenario): import succeeds and the property returns `"None"`; with a real table it resolves `enp5s0`. Setter round-trip (gui registration) confirmed. - Live restart-after-bypass verified 2026-08-19: main + bypass connection up, then `systemctl restart aqomui` — service came back `active (running)` with no crash-loop and no manual table-11 cleanup. The same sequence crash-looped reliably on the previous build. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix: look up the default interface lazily instead of at import time
All checks were successful
ci / test (pull_request) Successful in 39s
ci / test (push) Successful in 46s
c557ca649d
netifaces resolved the default gateway interface in the class body, so
importing aqomui_service required a default route to exist -- and
netifaces returns an empty 'default' dict when a second routing table
also holds a default route, which is exactly the state bypass leaves
behind in table 11. The service crash-looped on every restart after a
bypass run until the table-11 route was removed by hand.

Replace it with a property that prefers the gui-registered interface
and otherwise parses `ip -j route show default` at the point of use;
the main-table-only read can't be shadowed by another table, and a
missing default route now yields "None" instead of an exception. The
one remaining netifaces use (interface-name validation) reads
/sys/class/net directly, dropping the archived-upstream dependency
entirely.

Closes #66

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mysticalsoap deleted branch fix/lazy-default-interface 2026-08-19 23:19:29 -04:00
Sign in to join this conversation.
No description provided.