mirror of
https://github.com/Horizontal42/netsleuth.git
synced 2026-11-10 19:12:03 +03:00
docs: sync readme, architecture and tasks with the russian report feature
This commit is contained in:
parent
2e84c434c0
commit
b4c541aecf
5 changed files with 18 additions and 13 deletions
|
|
@ -32,8 +32,8 @@ src/netcheck/
|
||||||
|
|
||||||
**File-size exceptions.** The ~200-line guideline (Global Constraints) held for most modules, but these grew past it during implementation and were kept as single files rather than split, because each one is a single cohesive responsibility that splitting would only scatter across more files with a thinner reason to draw the line anywhere in particular:
|
**File-size exceptions.** The ~200-line guideline (Global Constraints) held for most modules, but these grew past it during implementation and were kept as single files rather than split, because each one is a single cohesive responsibility that splitting would only scatter across more files with a thinner reason to draw the line anywhere in particular:
|
||||||
|
|
||||||
- `exporter.py` (~475 lines) — JSON and Markdown are two renderers of the same report shape; keeping them together is what guarantees they can never drift on which sections exist.
|
- `exporter.py` (~680 lines) — JSON and both Markdown languages are renderers of the same report shape; keeping them together is what guarantees the English and Russian reports can never drift on which sections or rows exist. `render_markdown(report, lang="en"|"ru")` and a handful of inline `_t(lang, en, ru)` calls at each string site render both languages from one code path, deliberately, instead of a second renderer file that could silently fall out of sync.
|
||||||
- `cli.py` (~465 lines) — the Typer app, every flag, and the full `diagnose()` phase pipeline; splitting flag parsing from what the flags toggle would just add an import hop.
|
- `cli.py` (~475 lines) — the Typer app, every flag, and the full `diagnose()` phase pipeline; splitting flag parsing from what the flags toggle would just add an import hop.
|
||||||
- `models.py` (~330 lines) — every shared dataclass plus `to_jsonable()`; this is deliberately the one place that defines the report's vocabulary.
|
- `models.py` (~330 lines) — every shared dataclass plus `to_jsonable()`; this is deliberately the one place that defines the report's vocabulary.
|
||||||
- `interpret.py` (~320 lines) — threshold bands, the latency/path/speed finding generators, VPN scoring and bufferbloat grading all reason over the same `Finding[]` shape.
|
- `interpret.py` (~320 lines) — threshold bands, the latency/path/speed finding generators, VPN scoring and bufferbloat grading all reason over the same `Finding[]` shape.
|
||||||
- `bgp.py` (~305 lines) — four independent providers (RIPEstat, CAIDA ASRank, Team Cymru, PeeringDB) plus the disk cache they share.
|
- `bgp.py` (~305 lines) — four independent providers (RIPEstat, CAIDA ASRank, Team Cymru, PeeringDB) plus the disk cache they share.
|
||||||
|
|
@ -57,7 +57,7 @@ src/netcheck/
|
||||||
|
|
|
|
||||||
+-- interpret ---> Finding[] + overall verdict
|
+-- interpret ---> Finding[] + overall verdict
|
||||||
|
|
|
|
||||||
+-- exporter ---> logs/report_<ASN>_<ts>.md + .json
|
+-- exporter ---> logs/report_<ASN>_<ts>.{md,ru.md,json}
|
||||||
```
|
```
|
||||||
|
|
||||||
Two hard concurrency constraints:
|
Two hard concurrency constraints:
|
||||||
|
|
@ -89,7 +89,7 @@ Two hard concurrency constraints:
|
||||||
|
|
||||||
## Storage
|
## Storage
|
||||||
|
|
||||||
- `./logs/report_<ASN>_<YYYYMMDDTHHMMSSZ>.{md,json}` — one pair per run. `<ASN>` is the target's subject in target mode (an ASN, IP or domain) and the local egress ASN in auto mode. Compact ISO timestamps because Windows forbids `:` in filenames. Falls back to `report_unknown_…` when the ASN lookup fails entirely. Written temp-file-plus-`os.replace()`, always atomic. Gitignored: reports contain the external IP, city, coordinates and ISP name.
|
- `./logs/report_<ASN>_<YYYYMMDDTHHMMSSZ>.{md,ru.md,json}` — one triple per run: English Markdown, a full Russian translation with identical structure, and the JSON dump (English only — no `.ru.json`). The two Markdown files cross-link each other at the top, the same way `README.md`/`README.ru.md` do. `<ASN>` is the target's subject in target mode (an ASN, IP or domain) and the local egress ASN in auto mode. Compact ISO timestamps because Windows forbids `:` in filenames. Falls back to `report_unknown_…` when the ASN lookup fails entirely. Written temp-file-plus-`os.replace()`, always atomic. Gitignored: reports contain the external IP, city, coordinates and ISP name.
|
||||||
- `./logs/watch_<ASN>_<YYYYMMDDTHHMMSSZ>.json` — one time-series artifact per `--watch` session, not one report per tick.
|
- `./logs/watch_<ASN>_<YYYYMMDDTHHMMSSZ>.json` — one time-series artifact per `--watch` session, not one report per tick.
|
||||||
- `./.cache/firehol/*.netset` — downloaded blocklists, refreshed per `providers.firehol_refresh_hours`.
|
- `./.cache/firehol/*.netset` — downloaded blocklists, refreshed per `providers.firehol_refresh_hours`.
|
||||||
- `./.cache/pdb-net-<asn>.json`, `./.cache/pdb-netixlan-<net_id>.json` — PeeringDB responses, valid for `providers.peeringdb_cache_hours`.
|
- `./.cache/pdb-net-<asn>.json`, `./.cache/pdb-netixlan-<net_id>.json` — PeeringDB responses, valid for `providers.peeringdb_cache_hours`.
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ src/netcheck/
|
||||||
|
|
||||||
**Исключения по размеру файла.** Лимит ~200 строк (Общие ограничения) выдержан для большинства модулей, но эти выросли за него в процессе реализации и остались одним файлом, а не были разбиты, потому что каждый — единая цельная ответственность, и разбиение только раскидало бы её по файлам без чёткой причины проводить границу где-то конкретно:
|
**Исключения по размеру файла.** Лимит ~200 строк (Общие ограничения) выдержан для большинства модулей, но эти выросли за него в процессе реализации и остались одним файлом, а не были разбиты, потому что каждый — единая цельная ответственность, и разбиение только раскидало бы её по файлам без чёткой причины проводить границу где-то конкретно:
|
||||||
|
|
||||||
- `exporter.py` (~475 строк) — JSON и Markdown — два рендера одной и той же формы отчёта; то, что они вместе, гарантирует, что они никогда не разойдутся в том, какие разделы существуют.
|
- `exporter.py` (~680 строк) — JSON и оба языка Markdown — рендеры одной и той же формы отчёта; то, что они вместе, гарантирует, что английский и русский отчёты никогда не разойдутся в том, какие разделы или строки существуют. `render_markdown(report, lang="en"|"ru")` и точечные вызовы `_t(lang, en, ru)` в местах со строками рендерят оба языка из одного пути кода — намеренно, вместо отдельного файла-рендера, который мог бы незаметно разойтись.
|
||||||
- `cli.py` (~465 строк) — приложение Typer, все флаги и весь конвейер фаз `diagnose()`; разделение разбора флагов и того, что они переключают, добавило бы только лишний импорт.
|
- `cli.py` (~475 строк) — приложение Typer, все флаги и весь конвейер фаз `diagnose()`; разделение разбора флагов и того, что они переключают, добавило бы только лишний импорт.
|
||||||
- `models.py` (~330 строк) — все общие датаклассы плюс `to_jsonable()`; это намеренно единственное место, определяющее словарь отчёта.
|
- `models.py` (~330 строк) — все общие датаклассы плюс `to_jsonable()`; это намеренно единственное место, определяющее словарь отчёта.
|
||||||
- `interpret.py` (~320 строк) — пороговые полосы, генераторы находок по задержке/маршруту/скорости, скоринг VPN и оценка bufferbloat — всё рассуждает над одной формой `Finding[]`.
|
- `interpret.py` (~320 строк) — пороговые полосы, генераторы находок по задержке/маршруту/скорости, скоринг VPN и оценка bufferbloat — всё рассуждает над одной формой `Finding[]`.
|
||||||
- `bgp.py` (~305 строк) — четыре независимых источника (RIPEstat, CAIDA ASRank, Team Cymru, PeeringDB) плюс общий для них дисковый кэш.
|
- `bgp.py` (~305 строк) — четыре независимых источника (RIPEstat, CAIDA ASRank, Team Cymru, PeeringDB) плюс общий для них дисковый кэш.
|
||||||
|
|
@ -57,7 +57,7 @@ src/netcheck/
|
||||||
|
|
|
|
||||||
+-- interpret ---> Finding[] + общий вердикт
|
+-- interpret ---> Finding[] + общий вердикт
|
||||||
|
|
|
|
||||||
+-- exporter ---> logs/report_<ASN>_<ts>.md + .json
|
+-- exporter ---> logs/report_<ASN>_<ts>.{md,ru.md,json}
|
||||||
```
|
```
|
||||||
|
|
||||||
Два жёстких ограничения по конкурентности:
|
Два жёстких ограничения по конкурентности:
|
||||||
|
|
@ -89,7 +89,7 @@ src/netcheck/
|
||||||
|
|
||||||
## Хранение
|
## Хранение
|
||||||
|
|
||||||
- `./logs/report_<ASN>_<YYYYMMDDTHHMMSSZ>.{md,json}` — пара файлов на прогон. `<ASN>` — это цель в режиме target (ASN, IP или домен) и локальный ASN исходящего адреса в авто-режиме. Компактный ISO-таймстамп, потому что Windows запрещает `:` в именах файлов. При полном провале определения ASN — `report_unknown_…`. Запись через временный файл и `os.replace()`, всегда атомарно. В gitignore: отчёты содержат внешний IP, город, координаты и название провайдера.
|
- `./logs/report_<ASN>_<YYYYMMDDTHHMMSSZ>.{md,ru.md,json}` — тройка файлов на прогон: английский Markdown, его полный перевод на русский с идентичной структурой и JSON-дамп (только английский, `.ru.json` нет). Оба Markdown-файла ссылаются друг на друга вверху, так же как `README.md`/`README.ru.md`. `<ASN>` — это цель в режиме target (ASN, IP или домен) и локальный ASN исходящего адреса в авто-режиме. Компактный ISO-таймстамп, потому что Windows запрещает `:` в именах файлов. При полном провале определения ASN — `report_unknown_…`. Запись через временный файл и `os.replace()`, всегда атомарно. В gitignore: отчёты содержат внешний IP, город, координаты и название провайдера.
|
||||||
- `./logs/watch_<ASN>_<YYYYMMDDTHHMMSSZ>.json` — один тайм-ряд на сессию `--watch`, а не отдельный отчёт на каждый тик.
|
- `./logs/watch_<ASN>_<YYYYMMDDTHHMMSSZ>.json` — один тайм-ряд на сессию `--watch`, а не отдельный отчёт на каждый тик.
|
||||||
- `./.cache/firehol/*.netset` — скачанные блоклисты, обновляются по `providers.firehol_refresh_hours`.
|
- `./.cache/firehol/*.netset` — скачанные блоклисты, обновляются по `providers.firehol_refresh_hours`.
|
||||||
- `./.cache/pdb-net-<asn>.json`, `./.cache/pdb-netixlan-<net_id>.json` — ответы PeeringDB, действительны `providers.peeringdb_cache_hours`.
|
- `./.cache/pdb-net-<asn>.json`, `./.cache/pdb-netixlan-<net_id>.json` — ответы PeeringDB, действительны `providers.peeringdb_cache_hours`.
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@ $ netcheck --quick
|
||||||
netcheck 0.1.0 · auto mode · Windows
|
netcheck 0.1.0 · auto mode · Windows
|
||||||
Verdict: ok (100/100) — No problems found on this connection.
|
Verdict: ok (100/100) — No problems found on this connection.
|
||||||
Report written to logs/report_AS64500_20260808T191200Z.md
|
Report written to logs/report_AS64500_20260808T191200Z.md
|
||||||
|
logs/report_AS64500_20260808T191200Z.ru.md
|
||||||
logs/report_AS64500_20260808T191200Z.json
|
logs/report_AS64500_20260808T191200Z.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Everything else — egress ASN, VPN verdict, latency, path, speed — lives in the two files it just wrote, not on the console; the terminal only tells you the headline and where to look.
|
Everything else — egress ASN, VPN verdict, latency, path, speed — lives in the three files it just wrote, not on the console; the terminal only tells you the headline and where to look.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|
@ -72,7 +73,7 @@ No configuration is required. Copy `.env.example` to `.env` only if you have opt
|
||||||
| `--ndt7` | Opt in to M-Lab NDT7 (publishes your measurement, including your IP, as CC0 open data). On an interactive terminal it prints the consent notice and asks first; on a non-interactive one it proceeds without asking |
|
| `--ndt7` | Opt in to M-Lab NDT7 (publishes your measurement, including your IP, as CC0 open data). On an interactive terminal it prints the consent notice and asks first; on a non-interactive one it proceeds without asking |
|
||||||
| `--tcp-trace` | Opt in to a scapy TCP-SYN traceroute through ICMP-filtering middleboxes (needs the `tcptrace` extra plus Npcap on Windows or root on Unix). Falls through to the normal cascade when it cannot run |
|
| `--tcp-trace` | Opt in to a scapy TCP-SYN traceroute through ICMP-filtering middleboxes (needs the `tcptrace` extra plus Npcap on Windows or root on Unix). Falls through to the normal cascade when it cannot run |
|
||||||
|
|
||||||
Every run writes two files into `./logs/`: a Markdown report to read and a JSON dump containing every raw provider response, untruncated. `./logs/` is gitignored — reports contain your external IP, city, coordinates and ISP name.
|
Every run writes three files into `./logs/`: an English Markdown report, a full Russian translation of the same report (`.ru.md`, same sections, same tables, same numbers — cross-linked with the English one), and a JSON dump containing every raw provider response, untruncated. `./logs/` is gitignored — reports contain your external IP, city, coordinates and ISP name.
|
||||||
|
|
||||||
netcheck never requires administrator or root. Where privileges would give better data, it degrades to an unprivileged method and says so in the report.
|
netcheck never requires administrator or root. Where privileges would give better data, it degrades to an unprivileged method and says so in the report.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@ $ netcheck --quick
|
||||||
netcheck 0.1.0 · auto mode · Windows
|
netcheck 0.1.0 · auto mode · Windows
|
||||||
Verdict: ok (100/100) — No problems found on this connection.
|
Verdict: ok (100/100) — No problems found on this connection.
|
||||||
Report written to logs/report_AS64500_20260808T191200Z.md
|
Report written to logs/report_AS64500_20260808T191200Z.md
|
||||||
|
logs/report_AS64500_20260808T191200Z.ru.md
|
||||||
logs/report_AS64500_20260808T191200Z.json
|
logs/report_AS64500_20260808T191200Z.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Всё остальное — ASN, вердикт по VPN, задержки, маршрут, скорость — попадает в два только что записанных файла, а не в консоль; терминал показывает только заголовок и куда смотреть дальше.
|
Всё остальное — ASN, вердикт по VPN, задержки, маршрут, скорость — попадает в три только что записанных файла, а не в консоль; терминал показывает только заголовок и куда смотреть дальше.
|
||||||
|
|
||||||
## Установка
|
## Установка
|
||||||
|
|
||||||
|
|
@ -72,7 +73,7 @@ netcheck
|
||||||
| `--ndt7` | Включить M-Lab NDT7 (замер публикуется как открытые данные CC0, включая ваш IP). В интерактивном терминале сначала печатает уведомление о согласии и спрашивает подтверждение; в неинтерактивном — продолжает без вопроса |
|
| `--ndt7` | Включить M-Lab NDT7 (замер публикуется как открытые данные CC0, включая ваш IP). В интерактивном терминале сначала печатает уведомление о согласии и спрашивает подтверждение; в неинтерактивном — продолжает без вопроса |
|
||||||
| `--tcp-trace` | Включить TCP-SYN-трассировку через scapy сквозь middlebox'ы, режущие ICMP (нужны extras `tcptrace` и Npcap на Windows или root на Unix). Если не может запуститься — откатывается на обычный каскад |
|
| `--tcp-trace` | Включить TCP-SYN-трассировку через scapy сквозь middlebox'ы, режущие ICMP (нужны extras `tcptrace` и Npcap на Windows или root на Unix). Если не может запуститься — откатывается на обычный каскад |
|
||||||
|
|
||||||
Каждый прогон пишет в `./logs/` два файла: Markdown-отчёт для чтения и JSON-дамп со всеми сырыми ответами провайдеров без усечения. `./logs/` в gitignore — отчёты содержат ваш внешний IP, город, координаты и название провайдера.
|
Каждый прогон пишет в `./logs/` три файла: Markdown-отчёт на английском, его полный перевод на русский (`.ru.md` — те же разделы, те же таблицы, те же числа, со взаимными ссылками) и JSON-дамп со всеми сырыми ответами провайдеров без усечения. `./logs/` в gitignore — отчёты содержат ваш внешний IP, город, координаты и название провайдера.
|
||||||
|
|
||||||
netcheck никогда не требует администратора или root. Там, где привилегии дали бы данные лучше, он деградирует до непривилегированного метода и пишет об этом в отчёте.
|
netcheck никогда не требует администратора или root. Там, где привилегии дали бы данные лучше, он деградирует до непривилегированного метода и пишет об этом в отчёте.
|
||||||
|
|
||||||
|
|
|
||||||
5
TASKS.md
5
TASKS.md
|
|
@ -24,6 +24,8 @@
|
||||||
- `watch.py` — monitoring loop with one time-series artifact per session
|
- `watch.py` — monitoring loop with one time-series artifact per session
|
||||||
- End-to-end smoke test across `--quick`, `--full` and `--target` modes — caught and fixed five live-network defects (egress_v4 mislabeled on a dual-stack host, the same for asn-target identity lookups, target-mode report filenames using the local ASN instead of the target, cf-trace's own IP leaking into a target lookup, a skipped module's warning not reaching its Markdown placeholder) plus one flaky test (Windows mtime clock skew in the PeeringDB cache)
|
- End-to-end smoke test across `--quick`, `--full` and `--target` modes — caught and fixed five live-network defects (egress_v4 mislabeled on a dual-stack host, the same for asn-target identity lookups, target-mode report filenames using the local ASN instead of the target, cf-trace's own IP leaking into a target lookup, a skipped module's warning not reaching its Markdown placeholder) plus one flaky test (Windows mtime clock skew in the PeeringDB cache)
|
||||||
- Documentation freshness pass against the final module and flag set
|
- Documentation freshness pass against the final module and flag set
|
||||||
|
- License finalized as PolyForm Noncommercial 1.0.0 — Shodan InternetDB and the free Spamhaus mirrors are non-commercial-use-only, and this license keeps every downstream fork inside those same terms. Real license text landed in `LICENSE`, README/README.ru.md updated, `pyproject.toml` carries the SPDX identifier
|
||||||
|
- Russian Markdown report (`report_<ASN>_<ts>.ru.md`), written alongside the English one on every run, same structure, same tables, same numbers, cross-linked with its English sibling. `Finding`/`Reputation`/`DnsLeak` carry optional `_ru` sibling fields set alongside the English ones at each construction site; `exporter.py` renders both languages from one code path via `render_markdown(report, lang=...)` and inline `_t(lang, en, ru)` calls, so the two reports cannot structurally drift. Module skip/warning reasons are translated too (small exact-match dict in `exporter.py`)
|
||||||
|
|
||||||
## In Progress
|
## In Progress
|
||||||
|
|
||||||
|
|
@ -31,9 +33,10 @@
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
- Finalize the license: MIT vs Polyform Noncommercial (spec §18). Polyform is the recommendation, because Shodan InternetDB and the free Spamhaus mirrors are non-commercial-use-only and MIT would let a downstream commercial fork violate those terms. If MIT wins, add the caveat to both READMEs. Replace the placeholder `LICENSE` before the first public push.
|
|
||||||
- Consider publishing to PyPI: decide on the distribution name, add a release workflow, and confirm the `tcptrace`/`ndt7` extras install cleanly from a wheel rather than from the repo.
|
- Consider publishing to PyPI: decide on the distribution name, add a release workflow, and confirm the `tcptrace`/`ndt7` extras install cleanly from a wheel rather than from the repo.
|
||||||
- Revisit the opt-in extras' UX. `--ndt7` currently prints its consent notice and prompts on every interactive run, and `--tcp-trace` prints its privilege warning unconditionally. Decide whether consent should be remembered (a flag in `config.yaml`, or a marker in `.cache/`) so a repeat user is not re-prompted, and what the right behaviour is when stdin is not a TTY.
|
- Revisit the opt-in extras' UX. `--ndt7` currently prints its consent notice and prompts on every interactive run, and `--tcp-trace` prints its privilege warning unconditionally. Decide whether consent should be remembered (a flag in `config.yaml`, or a marker in `.cache/`) so a repeat user is not re-prompted, and what the right behaviour is when stdin is not a TTY.
|
||||||
|
- Fix adapter-name mojibake in the DNS-leak table: a non-ASCII Windows adapter name (seen on this dev machine: a Bluetooth virtual adapter) renders as cp1251/cp866-corrupted garbage in both the English and Russian reports. Pre-existing bug in `netinfo.py`'s per-adapter resolver enumeration, not introduced by the Russian-report work — needs its own investigation into what encoding Windows actually hands back for adapter friendly names.
|
||||||
|
- `dual_stack_note` and other free-text notes generated outside `interpret.py`/`reputation.py`/`probes/dns_leak.py` still render in English inside the Russian report (only `Finding`, `Reputation`, `DnsLeak` carry `_ru` fields today). Low-traffic edge case; extend the same inline-sibling pattern if it turns out to matter.
|
||||||
|
|
||||||
## Blocked
|
## Blocked
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue