Pin ProtonVPN sessions to the plain transport #165

Open
mysticalsoap wants to merge 1 commit from pin-proton-transport into trunk
Owner

Problem

A successful scheduled renewal dumped a full aiohttp traceback and four Task was destroyed but it is pending! errors into the log. proton-core's default AutoTransport races the plain transport against AlternativeRoutingTransport with a 5s head start; the renewal's refresh() ran ~11s, so ART fired its discovery — DoH queries to hardcoded Google (8.8.4.4/8.8.8.8 + v6) and Quad9 resolvers — the v6 probe raised on a v6-less network, and when the primary transport won, the abandoned racer tasks surfaced as ERROR tracebacks. Besides the noise, that's a root service phoning third-party DNS whenever Proton's API is momentarily slow (#164).

Fix

load_proton_core now hands out a session factory that pins session.transport_factory = AiohttpTransport — exactly auto's primary transport, minus the racer. Both the login and renewal paths build sessions through it.

Trade-off, accepted: on a network where Proton's API is blocked, an import fails with the normal network error instead of possibly succeeding via alternative routing's fallback domains. The task leak itself is an upstream python-proton-core bug regardless.

Verification

  • pytest green (370 passed) plus the ruff/compileall gates.
  • New guarded test (skips when python-proton-core isn't installed) builds a real session through the factory and asserts the pinned transport and user agent.
  • Live check after merge: a scheduled renewal that runs long should produce no asyncio/aiohttp tracebacks — and no DNS traffic to 8.8.8.8/Quad9 from the service.

Closes #164

🤖 Generated with Claude Code

## Problem A successful scheduled renewal dumped a full aiohttp traceback and four `Task was destroyed but it is pending!` errors into the log. proton-core's default `AutoTransport` races the plain transport against `AlternativeRoutingTransport` with a 5s head start; the renewal's `refresh()` ran ~11s, so ART fired its discovery — DoH queries to hardcoded Google (8.8.4.4/8.8.8.8 + v6) and Quad9 resolvers — the v6 probe raised on a v6-less network, and when the primary transport won, the abandoned racer tasks surfaced as ERROR tracebacks. Besides the noise, that's a root service phoning third-party DNS whenever Proton's API is momentarily slow (#164). ## Fix `load_proton_core` now hands out a session factory that pins `session.transport_factory = AiohttpTransport` — exactly auto's primary transport, minus the racer. Both the login and renewal paths build sessions through it. Trade-off, accepted: on a network where Proton's API is blocked, an import fails with the normal network error instead of possibly succeeding via alternative routing's fallback domains. The task leak itself is an upstream python-proton-core bug regardless. ## Verification - `pytest` green (370 passed) plus the ruff/compileall gates. - New guarded test (skips when python-proton-core isn't installed) builds a real session through the factory and asserts the pinned transport and user agent. - Live check after merge: a scheduled renewal that runs long should produce no asyncio/aiohttp tracebacks — and no DNS traffic to 8.8.8.8/Quad9 from the service. Closes #164 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix: pin ProtonVPN sessions to the plain transport
All checks were successful
ci / test (pull_request) Successful in 27s
ef9fd3be01
proton-core's default AutoTransport races AiohttpTransport against
AlternativeRoutingTransport with a 5-second head start, so any API
call that runs long fires ART's discovery: DoH queries to hardcoded
Google and Quad9 resolvers -- third-party traffic nothing in aqomui
asked a root service to send. When the primary transport then wins,
the abandoned racer tasks surface through asyncio's exception handler
as ERROR tracebacks, which is how a successful scheduled renewal
still managed to dump a page of aiohttp errors into the log.

Pinning AiohttpTransport keeps exactly auto's primary path and drops
the racer. The cost is alternative routing's censorship rescue: on a
network where Proton's API is blocked, an import now fails with the
normal network error instead of possibly succeeding through a
fallback domain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All checks were successful
ci / test (pull_request) Successful in 27s
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin pin-proton-transport:pin-proton-transport
git switch pin-proton-transport

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch trunk
git merge --no-ff pin-proton-transport
git switch pin-proton-transport
git rebase trunk
git switch trunk
git merge --ff-only pin-proton-transport
git switch pin-proton-transport
git rebase trunk
git switch trunk
git merge --no-ff pin-proton-transport
git switch trunk
git merge --squash pin-proton-transport
git switch trunk
git merge --ff-only pin-proton-transport
git switch trunk
git merge pin-proton-transport
git push origin trunk
Sign in to join this conversation.
No description provided.