Commit graph

12 commits

Author SHA1 Message Date
google-labs-jules[bot]
09c3317bcf test: add unit test for setup_dir in netsleuth.reputation
Added a test case `test_refresh_netsets_setup_dir` to `tests/test_reputation.py` to ensure that the `setup_dir` nested function in `refresh_netsets` creates the required cache directory.

The test utilizes `unittest.mock.patch` to spy on `pathlib.Path.mkdir`, verifying that the function is called with `parents=True, exist_ok=True`. By setting the mock's `side_effect` to the original `mkdir` function, we ensure side-effects still execute securely, without causing issues if the test suite is run concurrently. All tests pass successfully and test coverage is extended.

Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com>
2026-08-19 11:32:31 +00:00
Andrew Pimenov
10846e3017 measure IPv6 reference-host latency alongside IPv4
Scoped down from the original plan: traceroute and --path-diversity's v6
legs are deferred as a documented follow-up, since extending the trace
cascade to a second address family is real additional work that doesn't
share the trick that made latency cheap. Latency alone captures the core
value (a tunneled or poorly-peered IPv6 path is otherwise invisible to
tools that only report whichever stack the OS picked) at a fraction of
the risk.

Turns out no family-detection code was needed at all. icmp_win's
ping_samples_win() calls the IPv4-only socket.gethostbyname(), which
raises on a v6 literal - already caught by ping_host()'s existing bare
except-fallback to TCP, which handles v6 fine via asyncio.open_connection.
icmplib handles v6 natively on Linux/macOS. So v6 hosts ride the existing
ping_fanout() completely unmodified, tagged with a "<label>-v6" PingResult
label instead of a parallel report section - exporter, metrics.py and
compare.py needed zero changes since they already key everything off
label.

New probing.reference_hosts_v6/probing.ipv6 (auto/on/off) config,
--ipv6/--no-ipv6 override, interpret.dual_family_findings() for
net.ipv6_unreachable and latency.v6_much_slower.

Live-tested with --ipv6 forced on a v6-unreachable host: every row fell
back to method=tcp with 100% loss as expected. Caught and fixed a wording
bug in the same pass - the unreachable finding said "on this dual-stack
connection" unconditionally, which is wrong when --ipv6 forces the check
on a host that isn't actually dual-stack.

Part of plans/zesty-zooming-wilkinson.md (gitignored).
2026-08-12 22:55:51 +03:00
Andrew Pimenov
84c3dffbce detect captive portals up front, flag off-country speedtest servers
New Phase 0 in diagnose(): three generate_204-style probes run before every
other module, using detect-and-tag rather than short-circuit — a portal is
rarely total (DNS/ICMP often pass while only HTTP is intercepted), and an
aborted run would look identical to a dead link. On detection every later
phase still runs, tagged with a crit finding and a banner at the top of the
report.

Caught live before it shipped: detectportal.firefox.com/success.txt (one of
the original three default check URLs) returns 200 "success" on a genuinely
clean connection, which the generate_204-shaped classifier misread as a
portal redirect. Swapped for a second real generate_204 endpoint instead of
teaching the classifier a second success shape.

Also redesigned the speedtest server geo-sanity check after checking the
bundled Ookla CLI's actual JSON output: its server object never carries
lat/lon (documented schema, not a version gap), so speed.server_other_country
compares server_country against the client's own country instead of a
haversine distance that no tier can actually supply.

Part of plans/zesty-zooming-wilkinson.md (gitignored).
2026-08-12 21:36:54 +03:00
Andrew Pimenov
fb3c6ca77f optimize overall_verdict by combining severity iterations 2026-08-09 16:10:45 +03:00
Andrew Pimenov
d2ab0caafd refactor gather_vpn_signals to use VpnContext dataclass 2026-08-09 16:07:27 +03:00
Andrew Pimenov
4888862305 fix false-positive sustained-loss verdict on long runs of silent hops
path_findings() flagged ICMP rate limiting as real loss whenever two
consecutive traceroute hops both went silent, but real transit paths
routinely have long runs of silent hops (10 in a row, confirmed on a live
--full run) while the destination itself answers cleanly. Only flag loss
that persists all the way to the last hop in the trace; a run that clears
before the end is now ignored regardless of how many hops it spans.
2026-08-09 13:00:19 +03:00
Andrew Pimenov
483989c1bc rename package netcheck to netsleuth (name taken on pypi) 2026-08-09 11:43:00 +03:00
Andrew Pimenov
db407595d6 interpret: russian title/detail/advice alongside english findings 2026-08-09 04:09:01 +03:00
Andrew Pimenov
3425e87dbf interpret: label a non-responding hop instead of printing None
a hop with no icmp reply has ip=None; the sustained-loss finding
formatted it straight into the report text as the literal string
'(None)'. seen live in a --quick smoke test report.
2026-08-09 03:43:57 +03:00
Andrew Pimenov
925bf1b910 interpret: bufferbloat grading and overall verdict scoring 2026-08-08 22:10:26 +03:00
Andrew Pimenov
7533f7e5bd interpret: weighted vpn confidence scoring 2026-08-08 22:08:20 +03:00
Andrew Pimenov
f99de6b7dc interpret: threshold bands, latency and path findings 2026-08-08 22:07:07 +03:00