Repository navigation
refactor: share loopback IP checks across URL and RPC policies - #945
Conversation
Move canonical loopback IP classification into security.hosts and reuse it from the browser origin and URL plaintext policies. Keep each caller's local-name rules and the browser Origin/Host check in place. Cover canonical addresses, legacy spellings, local aliases and forwarded sign-ins so sharing the IP predicate preserves both policies.
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Reviewed the full diff plus the surrounding URL/RPC policy code, callers, the originating port-forward history, backward compatibility, test changes, AGENTS.md/CLAUDE.md, CONTEXT-MAP.md and the security/layer-seat architecture rules. The shared predicate preserves the URL policy's rejection of legacy numeric spellings, keeps each caller's distinct local-name rules, and introduces only the documented surface-to-security dependency. I found no weakened tests.
Verification: uv run --no-sync pytest tests/test_security_hosts.py tests/test_security_urls.py tests/test_rpc_transport.py -x passed (168 tests); targeted Ruff check and format checks passed; git diff --check and the source-language check passed. The initial test run could not start because the declared dev plugin was absent, so I synced the repository's dev extra with uv and reran unchanged. CI's unit shards are still pending; all currently completed checks pass.
ZuyiZhou
left a comment
There was a problem hiding this comment.
The shared is_loopback_ip is equivalent to both old predicates: the legacy-form guard in the URL check was redundant because as_ip already returns None for those spellings, and I found no origin differences on bracket edge cases for the RPC check. Each caller keeps its own name policy. The new tests pin the accepted and refused hosts through the real sign-in handler. CI green at 554705d.
Summary
RPC browser-origin checks and URL plaintext checks each implemented the same loopback IP classification. Both now use
security.hosts.is_loopback_ip, which reuses the existingas_ipparser.The callers retain their name policies: RPC accepts
localhostalongside loopback IPs; URL plaintext checks also allowlocalhost.localdomainand trailing-dot aliases. Origin/Host matching and malformed-origin refusals remain in the RPC layer. Regression cases exercise both accepted and refused hosts through the real sign-in handler.Type
Verification
Linux, Python 3.12.13, with existing dependencies matching the lockfile for the affected modules and check tools:
726 passed; one supervisor test timed out waiting for its child to write the state file. Its isolated rerun passed:
The expanded URL/RPC boundary cases passed before the production refactor (60 passed). A separate comparison of the original and shared predicates found no differences across 6,535 host strings and 39,214 origins, including legacy addresses, aliases, mapped IPv6 and malformed brackets.
These checks passed:
No user-facing documentation change is needed for this refactor. The full repository suite and native Windows/macOS runs were not performed. The supervisor timeout was not compared against an unmodified main checkout.
Risk
The change touches authentication and URL trust predicates. It retains each caller's local-name rules and the standard library's IP classification, including acceptance of IPv4-mapped loopback on Python 3.12.13. No DNS resolution, listeners, credentials or configuration are added. Reverting this refactor restores the previous separate checks without a data migration.
Related Issues
#939