Skip to content

fix(server): allow LAN/private hosts in asset reachability probe - #3103

Merged
vpetersson merged 4 commits into
masterfrom
fix/lan-asset-revalidation-3101
Jul 1, 2026
Merged

fix(server): allow LAN/private hosts in asset reachability probe#3103
vpetersson merged 4 commits into
masterfrom
fix/lan-asset-revalidation-3101

Conversation

@vpetersson

@vpetersson vpetersson commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Issues Fixed

Fixes #3101

Description

Assets served from a LAN host were incorrectly failing the reachability check and going dark, even though the host returned HTTP 200 from inside every container.

The probe url_fails() short-circuited on _is_private_address(): any URL whose host resolved into a private / loopback / link-local range was marked un-reachable without ever being fetched. A sibling Docker container (which resolves to a 172.16.0.0/12 bridge address, e.g. the reporter's menu-webserver), a NAS on 192.168.x.x, or any intranet host was therefore flagged dead. The periodic revalidate_asset_urls sweep then set is_reachable=False, the viewer logged "is not available, skipping" and fired a recheck loop that re-failed for the same reason.

Serving signage from the LAN is a first-class Anthias use case, so this removes the private-address guard entirely — the only place its SSRF concern applied was the public demo node, which has been retired. url_fails() now probes private hosts exactly like any public host, fixing both the periodic sweep and the create-time reachability check.

  • Removed _is_private_address() and the private-address branch in url_fails() (src/anthias_common/utils.py); dropped the now-unused ipaddress / socket imports and the ANTHIAS_ALLOW_PRIVATE_FETCH env var.
  • Replaced the SSRF-guard unit tests with a regression test asserting a reachable private host comes back url_fails() is False and that the probe actually runs (tests/test_utils.py).

Checklist

  • I have performed a self-review of my own code.
  • New and existing unit tests pass locally and on CI with my changes.
  • I have done an end-to-end test for Raspberry Pi devices.
  • I have tested my changes for x86 devices. (Full integrated-stack E2E on an x86 testbed — see the validation comment below. The changed code is board-independent Python, so behaviour is identical on Pi.)
  • I added a documentation for the changes I have made (when necessary).

The reachability probe `url_fails()` short-circuited on
`_is_private_address()`: any URL whose host resolved into a
private / loopback / link-local range was marked un-reachable
without ever being fetched. A sibling Docker container (resolving
to a 172.16.0.0/12 bridge address), a NAS on 192.168.x.x, or any
intranet host was therefore flagged dead even though it served
HTTP 200 fine.

Serving signage from the LAN is a first-class Anthias use case, so
remove the guard entirely (the public demo node it protected has
been retired). `url_fails()` now probes private hosts exactly like
any public host, fixing both the periodic `revalidate_asset_urls`
sweep and the create-time reachability check.

Fixes #3101

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes asset reachability checks for LAN/private-hosted content by removing the private-address short-circuit in url_fails(), so HTTP(S) assets served from intranet/Docker/NAS hosts are actually probed and no longer incorrectly marked unreachable (Fixes #3101).

Changes:

  • Removed the private-address SSRF guard (_is_private_address) and related imports/env var handling from url_fails() so LAN/private hosts are fetched like public hosts.
  • Replaced the SSRF-guard unit tests with a regression test asserting url_fails() probes (calls requests.head) and returns False for a reachable LAN host.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/anthias_common/utils.py Removes private-host short-circuit from url_fails() so LAN/private assets are probed normally.
tests/test_utils.py Updates tests to validate LAN/private host probing behavior instead of SSRF blocking behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_utils.py Outdated
Comment thread tests/test_utils.py Outdated
Comment thread src/anthias_common/utils.py
vpetersson and others added 3 commits July 1, 2026 13:10
Collapse the private-host reachability test onto the existing
requests.head-mocking pattern. The reachable-verdict case is already
covered by test_url_fails_returns_false_on_2xx_response; this test now
only guards the distinct behaviour (no private-address short-circuit)
by asserting the probe actually fires. Drops the misleading
urlunparse/_FAKE_PRIVATE_HTTP scaffolding that implied a private-only
code path.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Avoid a hardcoded CIDR literal in the comment, matching this file's
convention of keeping static analyzers' hardcoded-IP rules quiet.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Annotate the clear-text http:// test literal with NOSONAR(S5332),
matching the repo convention (see tests/test_youtube_helper.py). The
URL is mocked and never fetched, so the clear-text-transport hotspot
is a false positive; this clears the SonarCloud new-hotspots gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@vpetersson

Copy link
Copy Markdown
Contributor Author

On-device validation (x86 testbed)

Reproduced the reporter's exact topology and verified the fix end-to-end through the integrated stack (server API → Celery reachability → viewer), not a unit harness.

Setup — a sibling nginx:alpine container named menu-webserver on the anthias_default network, serving iceCreamMenu/index.html. It landed on 172.18.0.6 — the same private bridge IP that appears in the reporter's logs — and curl from inside the server container returned HTTP 200.

Before the fix (guard present, stock image):

  • _is_private_address('menu-webserver')True, url_fails(url)True despite the 200.
  • Creating the asset via POST /api/v2/assets failed: HTTP 500 {"error":"Could not retrieve file. Check the asset URL."} — the create-time reachability check rejects the LAN URL.

After the fix (patched anthias_common/utils.py deployed to anthias-server + anthias-celery, restarted):

  • The identical POST /api/v2/assetsHTTP 201, asset created with is_reachable: true.
  • Ran the real revalidate_asset_urls Celery sweep → asset stayed is_reachable: true with a fresh last_reachability_check (the periodic path that was flipping it to false).
  • Viewer log (unpatched — it only reads the flag): Showing asset iceCreamMenu (webpage) / Current url is http://menu-webserver/iceCreamMenu/index.html — no more ... is not available, skipping.

Note: a headless grim screenshot of the rendered page came back as a solid-black frame on this particular x86 build — a pre-existing webview first-paint/presentation quirk on the testbed, unrelated to this change (the viewer isn't touched and the fix is pure reachability logic). The reachability/is not available loop that #3101 is about is fully resolved.

Validated on x86; the changed code is board-independent Python (no board-specific branches), so behaviour is identical on the reporter's Pi 5. Testbed restored to its prior state afterwards.

@vpetersson
vpetersson merged commit 7aa52b2 into master Jul 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Assets Incorrectly Failing Revalidation Check

2 participants