13 Commits
Author SHA1 Message Date
catarrh 5a41de092c start/sniff-start: refuse to run in Windows-hosted shells
A Windows user could run the bash launchers from WSL or Git Bash / MSYS2 /
MinGW / Cygwin, where the Linux USB assumptions do not hold: WSL cannot reach
the Windows SIMtrace2 device, and those shells have no Linux /sys + /dev/bus/usb
view for the udev pre-flight.  Both launchers now detect a Windows host up
front (WSL via /proc/version, the rest via uname -s) and exit 2 with a pointer
at the matching .bat launcher, which drives the Windows Python/PyUSB stack.
The message goes to stderr; a deliberate WSL/Cygwin flow can still run the
Python module directly (noted in the source comment).

Tests: tests/test_launchers.py runs each script with a fake mingw uname and
asserts exit 2 plus the start.bat/sniff-start.bat pointer, pins the WSL
detection, and checks bash -n syntax (skipped when bash is absent).

Bumps 2.7.14 (version.py, pyproject, PWA_VERSION), SW cache v96, the README
download examples and the release-notes preamble.  561 Python + 80 Node tests.
2026-11-04 19:30:41 +03:00
catarrh 8a7bfe87d1 Merge the Gitea manual deploy workflow
Gitea main carried five commits adding .gitea/workflows/deploy.yml while
GitHub main carried the README description refresh.  Merging keeps both
remotes' histories (no force-push) and makes their trees identical; the
workflow is manual (workflow_dispatch) and does not run automatically.
2026-11-02 23:02:47 +03:00
catarrh 4a973a791a README: refresh the project description in both languages
The Russian title and lead now say APDU trace analyser (APDU-трейсы)
and describe the full input scope: a UDP GSMTAP stream, Osmocom
SIMtrace2 hardware, PCAP/PCAPNG files and the COMPRION text format,
decoded in the web UI (PWA).  The bundled simtrace2-pysniff is described
as the Python replacement for simtrace2-sniff that captures SIMtrace2
traffic and relays GSMTAP/UDP without analysing it.

The English lead mirrors the same structure, the Russian related-tools
line uses the same term, and the pyproject summary now names the same
sources.  Docs-only; 558 Python + 80 Node tests.
2026-11-02 23:00:41 +03:00
catarrh dd48798495 ci: add manual deploy workflow 2026-11-02 21:36:00 +03:00
catarrh 02fe1b5189 ci: add manual deploy workflow 2026-11-02 21:27:34 +03:00
catarrh 6a6a4671dd ci: add manual deploy workflow 2026-11-02 21:25:12 +03:00
catarrh 4d4852463a ci: add manual deploy workflow 2026-11-02 21:23:19 +03:00
catarrh c63bac45eb ci: add manual deploy workflow 2026-11-02 21:11:43 +03:00
catarrh ebe7dc82d1 README: point the hosted UI and news links at the new project domains
The hosted UI moved off the shared news domain to a dedicated one:

- hosted UI: https://simtrace.atroshin.ru -> https://simtrace.ru
- project news: https://atroshin.ru -> https://sim-tools.ru

Both old addresses redirect, so no link breaks; the READMEs now name the
canonical destinations (the Related tools paragraph included).
2026-10-30 02:59:50 +03:00
catarrh 50dba20f04 README: add SIMple as a GSMTAP-SIM source to the diagram
SIMple can stream its own ISO 7816 APDUs as GSMTAP-SIM packets (its --gsmtap
option), so it belongs beside the sniffers and the sigrok decoder.  The
diagrams get a compact SIMple block between the SIMtrace2 sniffers and the
sigrok_iso7816_stream boxes (they do not move): title SIMple, subtitle
"APDU -> GSMTAP", and its own arrow into the UDP :4729 listener.  It is
deliberately smaller than the primary sniffers, matching its role as a
secondary source.

The README alt text and the gsmtap capture-mode bullet/comment now list SIMple
as a source too (linked to its repository in the bullet).

Both languages; 558 Python + 80 Node tests; runtime zip rebuilt with the
updated diagrams.
2026-10-28 12:36:38 +03:00
catarrh f492f29ea6 README: correct the architecture diagram's capture paths
The diagrams conflated the SIMtrace2 hardware with the sniffer that reads it
and omitted the original Osmocom simtrace2-sniff: they showed
simtrace2-pysniff feeding the GSMTAP listener with the hardware only as its
subtitle, and a second, unexplained "SIMtrace2 hardware / direct USB" box.

The diagrams now show the device -> sniffer -> GSMTAP relationship explicitly:
SIMtrace2 hardware is read either by simtrace2-pysniff or by the original
simtrace2-sniff, and FX2 hardware by the sigrok_iso7816_stream decoder; the
sniffers/decoder stream GSMTAP-SIM to the UDP :4729 listener.  The direct USB
path is drawn separately from the device to the server and is labelled
"pysniff code in-process": --capture direct uses the bundled
simtrace2_pysniff package (DirectSniffer -> SniffSession) inside the server
process, not the simtrace2-pysniff CLI, and bypasses GSMTAP.  PCAP/COMPRION
import, SQLite and the browser UI keep their places.

The READMEs' alt text, the first-run capture-mode notes and the Usage command
comments now name the original simtrace2-sniff as a GSMTAP source and say the
direct mode runs the bundled sniffer code inside the server.

Both languages; 558 Python + 80 Node tests; runtime zip still carries both
diagrams and the README image guard passes.
2026-10-28 01:46:13 +03:00
catarrh 2b83d21e64 README: add architecture diagrams (EN/RU)
Both READMEs gain a capture-and-analysis diagram right under the screenshot:
simtrace2-pysniff and sigrok_iso7816_stream feed the GSMTAP UDP :4729
listener, SIMtrace2 hardware can be read directly over USB, PCAP/COMPRION
traces come from files, and simtrace-analyser-server decodes/stores into
SQLite and serves the web UI.  The SVGs carry title/desc and role=img, use
only inline presentation attributes (no scripts, no external refs) and render
without clipped text; the RU text matches the EN layout.

The runtime zip includes both diagrams so the embedded READMEs keep working,
and a new drift guard checks that every image a README references is present
in the archive.  RU wording: "устанавливаемое PWA" (neuter agreement).

558 Python + 80 Node tests.
2026-10-28 00:36:26 +03:00
catarrh 9a661f5ab2 README: expand the title, move the news line up, update Related tools
The heading now names the tool and what it analyses instead of just the
product name, and the news/website line sits right under the language switch
so it is visible before the description.

The Related section became "Related tools" with the same family block the
sibling projects use (SIMple, SIMtrace Analyser, sigrok_iso7816_stream on one
website and news channel), and simtrace2 is mentioned as the upstream
hardware/firmware the bundled capture utility sniffs from.  One wording tweak:
the capture-liveness paragraph states the current behaviour ("does not
pollute") instead of describing it as a change ("no longer pollutes").

Both languages; docs only, 557 Python + 80 Node tests.
2026-10-27 23:38:43 +03:00
16 changed files with 402 additions and 53 deletions

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
name: deploy
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Show toolchain
run: node -v && npm -v
- name: Configure SSH
env:
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
MX_HOST_KEY: ${{ secrets.MX_HOST_KEY }}
run: |
install -m 700 -d ~/.ssh
printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519
printf '%s\n' "$MX_HOST_KEY" > ~/.ssh/known_hosts
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/known_hosts
- name: Deploy
run: |
set -euo pipefail
REL="$(date -u +%Y%m%dT%H%M%SZ)-$(printf %s "$GITHUB_SHA" | cut -c1-7)"
rsync -a --exclude=.git --exclude=tests \
--link-dest=/var/www/simtrace/current \
frontend/ deploy@10.8.0.1:/var/www/simtrace/releases/"$REL"/
ssh deploy@10.8.0.1 "deploy-site simtrace $REL"
+4
View File
@@ -13,6 +13,10 @@ The source archive is the same tree a clone would have: unzip it and run
`./start.sh` (Linux/macOS) or `start.bat` (Windows). Direct SIMtrace2 capture `./start.sh` (Linux/macOS) or `start.bat` (Windows). Direct SIMtrace2 capture
on Linux additionally needs the attached `70-simtrace2-pysniff.rules` udev rule. on Linux additionally needs the attached `70-simtrace2-pysniff.rules` udev rule.
The `.sh` launchers are for Linux/macOS only: on Windows use `start.bat` /
`sniff-start.bat` from `cmd.exe` or PowerShell (WSL, Git Bash, MSYS2, MinGW and
Cygwin are refused).
**Runtime zip (no installer)** — `simtrace-analyser-*.zip` **Runtime zip (no installer)** — `simtrace-analyser-*.zip`
is the runtime tree only (packages, PWA, launchers, docs — no tests, no git): is the runtime tree only (packages, PWA, launchers, docs — no tests, no git):
extract it anywhere and run `start.bat` (Windows) or `./start.sh` extract it anywhere and run `start.bat` (Windows) or `./start.sh`
+45 -23
View File
@@ -1,18 +1,21 @@
# SIMtrace Analyser # SIMtrace Analyser — an APDU trace analyser
English | [Русский](README_RUS.md) English | [Русский](README_RUS.md)
APDU trace analyser for the GSMTAP-SIM format — captures SIM/UICC 📢 Project news and updates: [website](https://sim-tools.ru) · [Telegram channel](https://t.me/youeyeseesee)
communication from a UDP GSMTAP stream (or imports PCAP/PCAPNG files),
decodes it, and serves an installable web app for browsing. The repository
also bundles **simtrace2-pysniff**, a Python replacement for
`simtrace2-sniff` that captures from Osmocom SIMtrace2 hardware and can feed
GSMTAP into this analyser.
📢 Project news and updates: [atroshin.ru](https://atroshin.ru) | [Telegram channel](https://t.me/youeyeseesee) An APDU trace analyser for the GSMTAP format (from Osmocom) — captures
SIM/UICC traffic from a UDP GSMTAP stream or directly from Osmocom SIMtrace2
hardware, imports PCAP/PCAPNG files or the COMPRION text format, decodes it,
and displays it in a convenient web interface (PWA). The repository also
bundles **simtrace2-pysniff**, a Python replacement for `simtrace2-sniff`
that captures traffic from Osmocom SIMtrace2 and relays it as GSMTAP/UDP
without analysing it.
![SIMtrace Analyser UI](frontend.png) ![SIMtrace Analyser UI](frontend.png)
![Capture and analysis: SIMtrace2 hardware is read by simtrace2-pysniff or the original simtrace2-sniff, and FX2 hardware by the sigrok_iso7816_stream decoder; the sniffers, the decoder and SIMple stream GSMTAP-SIM to the UDP :4729 listener. The server can also read SIMtrace2 hardware directly over USB with the bundled pysniff code in-process, and imports PCAP/COMPRION traces from files. simtrace-analyser-server decodes and stores the traffic in SQLite and serves the web UI](architecture_en.svg)
## Prerequisites ## Prerequisites
**Required** **Required**
@@ -44,7 +47,7 @@ http://127.0.0.1:8081/.
The wheel includes the UI, so the server serves it by itself: The wheel includes the UI, so the server serves it by itself:
```sh ```sh
pip install ./simtrace_analyser-2.7.13-py3-none-any.whl pip install ./simtrace_analyser-2.7.14-py3-none-any.whl
simtrace-analyser-server --capture gsmtap simtrace-analyser-server --capture gsmtap
``` ```
@@ -58,7 +61,7 @@ Every artifact is on the
CLI can pick the latest one: CLI can pick the latest one:
```sh ```sh
pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.13/simtrace_analyser-2.7.13-py3-none-any.whl pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.14/simtrace_analyser-2.7.14-py3-none-any.whl
# or: # or:
gh release download --pattern '*.whl' gh release download --pattern '*.whl'
pip install ./simtrace_analyser-*.whl pip install ./simtrace_analyser-*.whl
@@ -66,7 +69,7 @@ pip install ./simtrace_analyser-*.whl
### 2. Zip (no installer) ### 2. Zip (no installer)
Download `simtrace-analyser-2.7.13.zip` from the release page and extract it Download `simtrace-analyser-2.7.14.zip` from the release page and extract it
anywhere: it is the runtime tree (the Python packages, the web UI, the launchers anywhere: it is the runtime tree (the Python packages, the web UI, the launchers
and the docs — no tests, no git). The archive works on any OS; then run: and the docs — no tests, no git). The archive works on any OS; then run:
@@ -113,9 +116,11 @@ simtrace-analyser-server --capture gsmtap
Open **http://127.0.0.1:8081/** in a browser. `Ctrl+C` stops the server. Open **http://127.0.0.1:8081/** in a browser. `Ctrl+C` stops the server.
- `--capture gsmtap` (default) — listen for GSMTAP-SIM on UDP 4729, e.g. from - `--capture gsmtap` (default) — listen for GSMTAP-SIM on UDP 4729, e.g. from
`simtrace2-pysniff` or `sigrok_iso7816_stream`; `simtrace2-pysniff`, the original `simtrace2-sniff`,
- `--capture direct` — read SIMtrace2 hardware directly (needs PyUSB; Windows `sigrok_iso7816_stream` or [SIMple](https://github.com/anttro/simple);
also needs the driver swap, see [USB Device Access](#usb-device-access)); - `--capture direct` — read SIMtrace2 hardware directly (the bundled sniffer
code runs inside the server and talks to the device over USB; needs PyUSB;
Windows also needs the driver swap, see [USB Device Access](#usb-device-access));
- `--capture disabled` — only browse stored captures. - `--capture disabled` — only browse stored captures.
The full runtime guide (server options, the UI views, the capture utility) is The full runtime guide (server options, the UI views, the capture utility) is
@@ -131,10 +136,12 @@ bundled into the package on install) on the same origin. Three capture
modes: modes:
```sh ```sh
# Listen for GSMTAP from simtrace2-pysniff (or original simtrace2-sniff): # Listen for GSMTAP from simtrace2-pysniff, the original simtrace2-sniff,
# sigrok_iso7816_stream or SIMple:
simtrace-analyser-server --capture gsmtap simtrace-analyser-server --capture gsmtap
# Capture directly from SIMtrace2 hardware (no external tool needed): # Capture directly from SIMtrace2 hardware (the bundled sniffer code reads the
# device; no external tool, no GSMTAP):
simtrace-analyser-server --capture direct simtrace-analyser-server --capture direct
# Browse/analyse existing captures without a capture backend: # Browse/analyse existing captures without a capture backend:
@@ -160,6 +167,11 @@ start.bat --capture direct
start.bat --capture disabled start.bat --capture disabled
``` ```
On Windows use `start.bat` / `sniff-start.bat` from `cmd.exe` or PowerShell:
the `.sh` launchers refuse to run in WSL (the Linux guest cannot reach the
Windows SIMtrace2 USB device) and in Git Bash / MSYS2 / MinGW / Cygwin (no
Linux `/sys` + `/dev/bus/usb` view for the udev checks).
Options pass through unchanged (`./start.sh --capture direct --port 8080`). Options pass through unchanged (`./start.sh --capture direct --port 8080`).
The server logs its capture liveness to stderr (each line timestamped The server logs its capture liveness to stderr (each line timestamped
@@ -171,7 +183,7 @@ datagram is dropped and counted (`dropped`) rather than silently
killing the capture; a `tpdu` packet that is not APDU-shaped at all killing the capture; a `tpdu` packet that is not APDU-shaped at all
(shorter than the header, the invalid CLA `FF` or an ISO-reserved class) (shorter than the header, the invalid CLA `FF` or an ISO-reserved class)
is skipped and counted (`skipped`) — a character-level or mis-sampled is skipped and counted (`skipped`) — a character-level or mis-sampled
stream no longer pollutes the decode. The heartbeat interval defaults to 60 s and is stream does not pollute the decode. The heartbeat interval defaults to 60 s and is
tunable via `--log-interval SECONDS`. tunable via `--log-interval SECONDS`.
The GSMTAP listener also accepts the **sigrok-iso7816-stream** decoder The GSMTAP listener also accepts the **sigrok-iso7816-stream** decoder
@@ -331,7 +343,7 @@ serve a different UI directory (default: the bundled frontend, or
### Hosted UI (landing page) ### Hosted UI (landing page)
A standalone copy of the UI is hosted at **https://simtrace.atroshin.ru**. A standalone copy of the UI is hosted at **https://simtrace.ru**.
It is a pure frontend: point it (Settings → Server URL) at a locally running It is a pure frontend: point it (Settings → Server URL) at a locally running
`simtrace-analyser-server`. `simtrace-analyser-server`.
@@ -553,13 +565,23 @@ prompt).
- Installable **PWA** (progressive web app: installs to the desktop or home - Installable **PWA** (progressive web app: installs to the desktop or home
screen and works offline), dark theme, English/Russian UI screen and works offline), dark theme, English/Russian UI
## Related ## Related tools
- **[simtrace2](https://gitea.osmocom.org/sim-card/simtrace2)** — the upstream SIMple, SIMtrace Analyser and sigrok_iso7816_stream are three standalone
SIMtrace2 hardware/firmware project that the capture utility sniffs from. tools for working with SIM/UICC cards, published together on the same
[website](https://sim-tools.ru) and [news channel](https://t.me/youeyeseesee).
Each one is fully independent — install only the tools you need:
- **[SIMple](https://github.com/anttro/simple)** — a UICC workbench: APDU
construction, SCP80/SCP81 OTA, SIM Toolkit simulation and card profiling.
- **[SIMtrace Analyser](https://github.com/anttro/simtrace-analyser)** — an
APDU trace analyser for GSMTAP-SIM captures.
- **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** — - **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** —
FX2LP-based passive ISO 7816 sniffer that emits the same GSMTAP-SIM stream a passive ISO 7816 sniffer built on a cheap FX2 logic analyser.
on UDP 4729 (accepted by this project's GSMTAP listener).
The bundled capture utility also sniffs from the upstream
[simtrace2](https://gitea.osmocom.org/sim-card/simtrace2) hardware/firmware
project.
## License ## License
+44 -24
View File
@@ -1,18 +1,20 @@
# SIMtrace Analyser # SIMtrace Analyser — анализатор APDU-трейсов
[English](README.md) | Русский [English](README.md) | Русский
Анализатор APDU-трассировок в формате GSMTAP-SIM — захватывает обмен с 📢 Новости и обновления проекта: [сайт](https://sim-tools.ru) · [Telegram-канал](https://t.me/youeyeseesee)
SIM/UICC из UDP-потока GSMTAP (или импортирует файлы PCAP/PCAPNG),
декодирует его и отдаёт устанавливаемое веб-приложение для просмотра.
В репозиторий также включён **simtrace2-pysniff** — замена `simtrace2-sniff`
на Python, которая захватывает трафик с оборудования Osmocom SIMtrace2
и может передавать GSMTAP этому анализатору.
📢 Новости и обновления проекта: [atroshin.ru](https://atroshin.ru) | [Telegram-канал](https://t.me/youeyeseesee) Анализатор APDU-трейсов в формате GSMTAP (от Osmocom) — захватывает обмен с
SIM/UICC из UDP-потока GSMTAP или напрямую с оборудования Osmocom
SIMtrace2, импортирует файлы PCAP/PCAPNG или текстовый формат COMPRION,
декодирует его и отображает в удобном веб-интерфейсе (PWA). В репозиторий
также включён **simtrace2-pysniff** — замена `simtrace2-sniff` на Python
для захвата трафика с Osmocom SIMtrace2 и трансляции GSMTAP/UDP без анализа.
![Интерфейс SIMtrace Analyser](frontend.png) ![Интерфейс SIMtrace Analyser](frontend.png)
![Захват и анализ: оборудование SIMtrace2 читает simtrace2-pysniff или оригинальный simtrace2-sniff, а оборудование FX2 — декодер sigrok_iso7816_stream; они и SIMple передают GSMTAP-SIM слушателю UDP :4729. Сервер также может читать оборудование SIMtrace2 напрямую по USB встроенным кодом pysniff внутри сервера и импортирует трассы PCAP/COMPRION из файлов. simtrace-analyser-server декодирует и сохраняет трафик в SQLite и раздаёт веб-интерфейс](architecture_ru.svg)
## Требования ## Требования
**Обязательно** **Обязательно**
@@ -45,7 +47,7 @@ http://127.0.0.1:8081/.
Wheel содержит интерфейс внутри пакета, поэтому сервер отдаёт его сам: Wheel содержит интерфейс внутри пакета, поэтому сервер отдаёт его сам:
```sh ```sh
pip install ./simtrace_analyser-2.7.13-py3-none-any.whl pip install ./simtrace_analyser-2.7.14-py3-none-any.whl
simtrace-analyser-server --capture gsmtap simtrace-analyser-server --capture gsmtap
``` ```
@@ -59,7 +61,7 @@ Fedora), сначала создайте виртуальное окружени
CLI — выбрать последнюю: CLI — выбрать последнюю:
```sh ```sh
pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.13/simtrace_analyser-2.7.13-py3-none-any.whl pip install https://github.com/anttro/simtrace-analyser/releases/download/v2.7.14/simtrace_analyser-2.7.14-py3-none-any.whl
# или: # или:
gh release download --pattern '*.whl' gh release download --pattern '*.whl'
pip install ./simtrace_analyser-*.whl pip install ./simtrace_analyser-*.whl
@@ -67,7 +69,7 @@ pip install ./simtrace_analyser-*.whl
### 2. Zip (без установки) ### 2. Zip (без установки)
Скачайте `simtrace-analyser-2.7.13.zip` со страницы релиза и распакуйте в любое Скачайте `simtrace-analyser-2.7.14.zip` со страницы релиза и распакуйте в любое
место: это рабочее дерево (пакеты Python, интерфейс, скрипты запуска и документация — место: это рабочее дерево (пакеты Python, интерфейс, скрипты запуска и документация —
без тестов и git). Архив подходит для любой ОС. Затем запустите. без тестов и git). Архив подходит для любой ОС. Затем запустите.
@@ -115,9 +117,11 @@ simtrace-analyser-server --capture gsmtap
сервер. сервер.
- `--capture gsmtap` (по умолчанию) — слушать GSMTAP-SIM на UDP 4729, - `--capture gsmtap` (по умолчанию) — слушать GSMTAP-SIM на UDP 4729,
например от `simtrace2-pysniff` или `sigrok_iso7816_stream`; например от `simtrace2-pysniff`, оригинального `simtrace2-sniff`,
- `--capture direct` — читать оборудование SIMtrace2 напрямую (нужен PyUSB; в `sigrok_iso7816_stream` или [SIMple](https://github.com/anttro/simple);
Windows также нужна замена драйвера, см. - `--capture direct` — читать оборудование SIMtrace2 напрямую (встроенный код
сниффера работает внутри сервера и обращается к устройству по USB; нужен
PyUSB; в Windows также нужна замена драйвера, см.
[Доступ к USB-устройству](#доступ-к-usb-устройству)); [Доступ к USB-устройству](#доступ-к-usb-устройству));
- `--capture disabled` — только просмотр сохранённых захватов. - `--capture disabled` — только просмотр сохранённых захватов.
@@ -134,10 +138,12 @@ simtrace-analyser-server --capture gsmtap
Три режима захвата: Три режима захвата:
```sh ```sh
# Слушать GSMTAP от simtrace2-pysniff (или оригинального simtrace2-sniff): # Слушать GSMTAP от simtrace2-pysniff, оригинального simtrace2-sniff,
# sigrok_iso7816_stream или SIMple:
simtrace-analyser-server --capture gsmtap simtrace-analyser-server --capture gsmtap
# Захват напрямую с оборудования SIMtrace2 (внешний инструмент не нужен): # Захват напрямую с оборудования SIMtrace2 (встроенный код сниффера читает
# устройство; внешний инструмент и GSMTAP не нужны):
simtrace-analyser-server --capture direct simtrace-analyser-server --capture direct
# Просмотр/анализ существующих записей без бэкенда захвата: # Просмотр/анализ существующих записей без бэкенда захвата:
@@ -163,6 +169,11 @@ start.bat --capture direct
start.bat --capture disabled start.bat --capture disabled
``` ```
В Windows запускайте `start.bat` / `sniff-start.bat` из `cmd.exe` или
PowerShell: `.sh`-скрипты отказываются работать в WSL (гостевая Linux-система
не видит USB-устройство SIMtrace2) и в Git Bash / MSYS2 / MinGW / Cygwin (нет
Linux-представления `/sys` + `/dev/bus/usb` для проверок udev).
Параметры передаются как есть (`./start.sh --capture direct --port 8080`). Параметры передаются как есть (`./start.sh --capture direct --port 8080`).
Сервер пишет в stderr информацию о жизненном цикле захвата (каждая строка Сервер пишет в stderr информацию о жизненном цикле захвата (каждая строка
@@ -174,7 +185,7 @@ heartbeat `Capture alive: session=N messages=M bytes=B dropped=D skipped=S`
убивают захват; `tpdu`-пакет, вовсе не похожий на APDU (короче заголовка, убивают захват; `tpdu`-пакет, вовсе не похожий на APDU (короче заголовка,
недопустимый CLA `FF` или зарезервированный ISO класс `001x`), недопустимый CLA `FF` или зарезервированный ISO класс `001x`),
пропускается и считается (`skipped`) — посимвольный или миссемплированный пропускается и считается (`skipped`) — посимвольный или миссемплированный
поток больше не засоряет декодирование. Интервал heartbeat по умолчанию поток не засоряет декодирование. Интервал heartbeat по умолчанию
60 с, настраивается через `--log-interval SECONDS`. 60 с, настраивается через `--log-interval SECONDS`.
GSMTAP-листенер также принимает декодер **sigrok-iso7816-stream** GSMTAP-листенер также принимает декодер **sigrok-iso7816-stream**
@@ -335,7 +346,7 @@ TS 51.011), поэтому FID, повторно используемый в р
### Размещённый интерфейс (лендинг) ### Размещённый интерфейс (лендинг)
Автономная копия интерфейса размещена на **https://simtrace.atroshin.ru**. Автономная копия интерфейса размещена на **https://simtrace.ru**.
Это только интерфейс: укажите в нём (Settings → Server URL) адрес Это только интерфейс: укажите в нём (Settings → Server URL) адрес
локально запущенного `simtrace-analyser-server`. локально запущенного `simtrace-analyser-server`.
@@ -568,14 +579,23 @@ Python 3 должен быть в `PATH` (проверьте `python --version`
- **PWA** (progressive web app): устанавливается на рабочий стол или домашний - **PWA** (progressive web app): устанавливается на рабочий стол или домашний
экран и работает офлайн; тёмная тема, интерфейс на английском/русском экран и работает офлайн; тёмная тема, интерфейс на английском/русском
## Связанные проекты ## Связанные инструменты
- **[simtrace2](https://gitea.osmocom.org/sim-card/simtrace2)** — вышестоящий SIMple, SIMtrace Analyser и sigrok_iso7816_stream — три автономных
проект оборудования/прошивки SIMtrace2, с которого утилита захвата инструмента для работы с SIM/UICC-картами, представленные на одном
снимает трафик. [сайте](https://sim-tools.ru) и в одном [Telegram-канале](https://t.me/youeyeseesee).
Каждый полностью независим — устанавливайте только нужные вам:
- **[SIMple](https://github.com/anttro/simple)** — мастерская для UICC/SIM:
конструкторы APDU, OTA SCP80/SCP81, симуляция SIM Toolkit и профилирование
карт.
- **[SIMtrace Analyser](https://github.com/anttro/simtrace-analyser)** —
анализатор APDU-трейсов GSMTAP-SIM.
- **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** — - **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** —
пассивный ISO 7816 сниффер на базе FX2LP, выдающий такой же поток пассивный ISO 7816-сниффер на дешёвом логическом анализаторе FX2.
GSMTAP-SIM на UDP 4729 (принимается GSMTAP-листенером этого проекта).
Встроенная утилита захвата также снимает трафик с вышестоящего проекта
оборудования/прошивки [simtrace2](https://gitea.osmocom.org/sim-card/simtrace2).
## Лицензия ## Лицензия
+78
View File
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="640" viewBox="0 0 960 640" role="img" aria-labelledby="diagram-title diagram-desc" font-family="'Segoe UI', 'Helvetica Neue', Arial, 'DejaVu Sans', sans-serif">
<title id="diagram-title">SIMtrace Analyser: capture and analysis</title>
<desc id="diagram-desc">SIMtrace2 hardware is read by simtrace2-pysniff (bundled) or the original simtrace2-sniff, and FX2 hardware by the sigrok_iso7816_stream decoder; the sniffers, the decoder and SIMple stream GSMTAP-SIM to the listener on UDP :4729. The server can also read SIMtrace2 hardware directly over USB with the bundled sniffer code, and imports PCAP/COMPRION traces from files. simtrace-analyser-server decodes and stores the traffic in SQLite and serves the web UI.</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 Z" fill="#64748b"/>
</marker>
</defs>
<rect x="1" y="1" width="958" height="638" rx="18" fill="#ffffff" stroke="#e2e8f0" stroke-width="1.5"/>
<text x="480" y="30" text-anchor="middle" font-size="14" fill="#475569">capture → analyse</text>
<!-- capture devices -->
<rect x="100" y="48" width="250" height="64" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="225" y="74" text-anchor="middle" font-size="15" font-weight="600" fill="#0f172a">SIMtrace2 hardware</text>
<text x="225" y="94" text-anchor="middle" font-size="12" fill="#475569">Osmocom USB sniffer</text>
<rect x="610" y="48" width="250" height="64" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="735" y="74" text-anchor="middle" font-size="15" font-weight="600" fill="#0f172a">FX2 logic analyzer</text>
<text x="735" y="94" text-anchor="middle" font-size="12" fill="#475569">Saleae clone</text>
<line x1="225" y1="112" x2="225" y2="148" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="735" y1="112" x2="735" y2="148" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- sniffers -->
<rect x="100" y="150" width="250" height="96" rx="12" fill="#eff6ff" stroke="#93c5fd" stroke-width="1.5"/>
<text x="225" y="176" text-anchor="middle" font-size="14" font-weight="600" fill="#0f172a">SIMtrace2 sniffers</text>
<text x="225" y="202" text-anchor="middle" font-size="13" fill="#334155" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">simtrace2-pysniff</text>
<text x="225" y="224" text-anchor="middle" font-size="13" fill="#334155" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">simtrace2-sniff (Osmocom)</text>
<rect x="610" y="150" width="250" height="96" rx="12" fill="#f5f3ff" stroke="#c4b5fd" stroke-width="1.5"/>
<text x="735" y="190" text-anchor="middle" font-size="14" font-weight="600" fill="#0f172a" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">sigrok_iso7816_stream</text>
<text x="735" y="212" text-anchor="middle" font-size="13" fill="#475569">decoder</text>
<!-- a secondary GSMTAP-SIM source: SIMple can stream its APDUs -->
<rect x="395" y="166" width="170" height="64" rx="12" fill="#ecfeff" stroke="#a5f3fc" stroke-width="1.5"/>
<text x="480" y="192" text-anchor="middle" font-size="16" font-weight="600" fill="#0f172a">SIMple</text>
<text x="480" y="212" text-anchor="middle" font-size="12" fill="#475569">APDU → GSMTAP</text>
<line x1="225" y1="246" x2="425" y2="278" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="480" y1="230" x2="480" y2="278" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="735" y1="246" x2="535" y2="278" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- GSMTAP listener -->
<rect x="350" y="280" width="260" height="72" rx="12" fill="#fffbeb" stroke="#fcd34d" stroke-width="1.5"/>
<text x="480" y="310" text-anchor="middle" font-size="16" font-weight="600" fill="#0f172a" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">GSMTAP UDP :4729</text>
<text x="480" y="332" text-anchor="middle" font-size="13" fill="#475569">listener</text>
<!-- file import -->
<rect x="650" y="280" width="240" height="72" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="770" y="310" text-anchor="middle" font-size="14" font-weight="600" fill="#0f172a">PCAP / COMPRION</text>
<text x="770" y="332" text-anchor="middle" font-size="13" fill="#475569">import from files</text>
<line x1="480" y1="352" x2="480" y2="390" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="770" y1="352" x2="635" y2="390" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- the direct USB path bypasses the sniffers and GSMTAP -->
<path d="M100 84 H52 V448 H258" fill="none" stroke="#64748b" stroke-width="2" stroke-linejoin="round" marker-end="url(#arrow)"/>
<text x="64" y="418" font-size="12" font-weight="600" fill="#475569">direct USB</text>
<text x="64" y="436" font-size="12" fill="#475569">pysniff code in-process</text>
<!-- analysis server -->
<rect x="260" y="392" width="440" height="84" rx="12" fill="#ecfdf5" stroke="#6ee7b7" stroke-width="1.5"/>
<text x="480" y="427" text-anchor="middle" font-size="18" font-weight="600" fill="#0f172a" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">simtrace-analyser-server</text>
<text x="480" y="451" text-anchor="middle" font-size="13" fill="#475569">decodes · stores</text>
<line x1="400" y1="476" x2="250" y2="514" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="560" y1="476" x2="710" y2="514" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- storage and UI -->
<rect x="110" y="516" width="280" height="76" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="250" y="548" text-anchor="middle" font-size="18" font-weight="600" fill="#0f172a">SQLite</text>
<text x="250" y="570" text-anchor="middle" font-size="13" fill="#475569">sessions.db</text>
<rect x="570" y="516" width="280" height="76" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="710" y="548" text-anchor="middle" font-size="18" font-weight="600" fill="#0f172a">Browser (web UI)</text>
<text x="710" y="570" text-anchor="middle" font-size="13" fill="#475569">installable PWA</text>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

+78
View File
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="640" viewBox="0 0 960 640" role="img" aria-labelledby="diagram-title diagram-desc" font-family="'Segoe UI', 'Helvetica Neue', Arial, 'DejaVu Sans', sans-serif">
<title id="diagram-title">SIMtrace Analyser: захват и анализ</title>
<desc id="diagram-desc">Оборудование SIMtrace2 читает simtrace2-pysniff (входит в комплект) или оригинальный simtrace2-sniff, а оборудование FX2 — декодер sigrok_iso7816_stream; они и SIMple передают GSMTAP-SIM слушателю UDP :4729. Сервер также может читать оборудование SIMtrace2 напрямую по USB встроенным кодом сниффера и импортирует трассы PCAP/COMPRION из файлов. simtrace-analyser-server декодирует и сохраняет трафик в SQLite и раздаёт веб-интерфейс.</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 Z" fill="#64748b"/>
</marker>
</defs>
<rect x="1" y="1" width="958" height="638" rx="18" fill="#ffffff" stroke="#e2e8f0" stroke-width="1.5"/>
<text x="480" y="30" text-anchor="middle" font-size="14" fill="#475569">захват → анализ</text>
<!-- устройства захвата -->
<rect x="100" y="48" width="250" height="64" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="225" y="74" text-anchor="middle" font-size="15" font-weight="600" fill="#0f172a">Оборудование SIMtrace2</text>
<text x="225" y="94" text-anchor="middle" font-size="12" fill="#475569">USB-сниффер Osmocom</text>
<rect x="610" y="48" width="250" height="64" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="735" y="74" text-anchor="middle" font-size="15" font-weight="600" fill="#0f172a">Логический анализатор FX2</text>
<text x="735" y="94" text-anchor="middle" font-size="12" fill="#475569">клон Saleae</text>
<line x1="225" y1="112" x2="225" y2="148" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="735" y1="112" x2="735" y2="148" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- снифферы -->
<rect x="100" y="150" width="250" height="96" rx="12" fill="#eff6ff" stroke="#93c5fd" stroke-width="1.5"/>
<text x="225" y="176" text-anchor="middle" font-size="14" font-weight="600" fill="#0f172a">Снифферы SIMtrace2</text>
<text x="225" y="202" text-anchor="middle" font-size="13" fill="#334155" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">simtrace2-pysniff</text>
<text x="225" y="224" text-anchor="middle" font-size="13" fill="#334155" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">simtrace2-sniff (Osmocom)</text>
<rect x="610" y="150" width="250" height="96" rx="12" fill="#f5f3ff" stroke="#c4b5fd" stroke-width="1.5"/>
<text x="735" y="190" text-anchor="middle" font-size="14" font-weight="600" fill="#0f172a" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">sigrok_iso7816_stream</text>
<text x="735" y="212" text-anchor="middle" font-size="13" fill="#475569">декодер</text>
<!-- второй источник GSMTAP-SIM: SIMple умеет отдавать свои APDU -->
<rect x="395" y="166" width="170" height="64" rx="12" fill="#ecfeff" stroke="#a5f3fc" stroke-width="1.5"/>
<text x="480" y="192" text-anchor="middle" font-size="16" font-weight="600" fill="#0f172a">SIMple</text>
<text x="480" y="212" text-anchor="middle" font-size="12" fill="#475569">APDU → GSMTAP</text>
<line x1="225" y1="246" x2="425" y2="278" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="480" y1="230" x2="480" y2="278" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="735" y1="246" x2="535" y2="278" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- слушатель GSMTAP -->
<rect x="350" y="280" width="260" height="72" rx="12" fill="#fffbeb" stroke="#fcd34d" stroke-width="1.5"/>
<text x="480" y="310" text-anchor="middle" font-size="16" font-weight="600" fill="#0f172a" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">GSMTAP UDP :4729</text>
<text x="480" y="332" text-anchor="middle" font-size="13" fill="#475569">слушатель</text>
<!-- импорт файлов -->
<rect x="650" y="280" width="240" height="72" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="770" y="310" text-anchor="middle" font-size="14" font-weight="600" fill="#0f172a">Импорт PCAP / COMPRION</text>
<text x="770" y="332" text-anchor="middle" font-size="13" fill="#475569">из файлов</text>
<line x1="480" y1="352" x2="480" y2="390" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="770" y1="352" x2="635" y2="390" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- прямой USB-путь минует снифферы и GSMTAP -->
<path d="M100 84 H52 V448 H258" fill="none" stroke="#64748b" stroke-width="2" stroke-linejoin="round" marker-end="url(#arrow)"/>
<text x="64" y="418" font-size="12" font-weight="600" fill="#475569">прямой USB</text>
<text x="64" y="436" font-size="12" fill="#475569">код pysniff внутри сервера</text>
<!-- анализирующий сервер -->
<rect x="260" y="392" width="440" height="84" rx="12" fill="#ecfdf5" stroke="#6ee7b7" stroke-width="1.5"/>
<text x="480" y="427" text-anchor="middle" font-size="18" font-weight="600" fill="#0f172a" font-family="'Cascadia Mono', Consolas, 'DejaVu Sans Mono', monospace">simtrace-analyser-server</text>
<text x="480" y="451" text-anchor="middle" font-size="13" fill="#475569">декодирует · сохраняет</text>
<line x1="400" y1="476" x2="250" y2="514" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<line x1="560" y1="476" x2="710" y2="514" stroke="#64748b" stroke-width="2" marker-end="url(#arrow)"/>
<!-- хранилище и интерфейс -->
<rect x="110" y="516" width="280" height="76" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="250" y="548" text-anchor="middle" font-size="18" font-weight="600" fill="#0f172a">SQLite</text>
<text x="250" y="570" text-anchor="middle" font-size="13" fill="#475569">sessions.db</text>
<rect x="570" y="516" width="280" height="76" rx="12" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>
<text x="710" y="548" text-anchor="middle" font-size="18" font-weight="600" fill="#0f172a">Браузер (веб-интерфейс)</text>
<text x="710" y="570" text-anchor="middle" font-size="13" fill="#475569">устанавливаемое PWA</text>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

+1 -1
View File
@@ -3389,7 +3389,7 @@ function onSearchChange() {
} }
// ──────────────────── Versioning ──────────────────── // ──────────────────── Versioning ────────────────────
const PWA_VERSION = '2.7.13'; const PWA_VERSION = '2.7.14';
const MIN_SERVER_VERSION = '2.3.0'; const MIN_SERVER_VERSION = '2.3.0';
function parseVersion(v) { function parseVersion(v) {
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simtrace-analyser-v95'; const CACHE = 'simtrace-analyser-v96';
const PRECACHE = [ const PRECACHE = [
'index.html', 'index.html',
+2 -2
View File
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "simtrace-analyser" name = "simtrace-analyser"
version = "2.7.13" version = "2.7.14"
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)" description = "SIMtrace Analyser — APDU trace analyser for GSMTAP-SIM, SIMtrace2, PCAP/PCAPNG and COMPRION captures (bundles the simtrace2-pysniff utility)"
readme = {file = "README.md", content-type = "text/markdown"} readme = {file = "README.md", content-type = "text/markdown"}
license = "MIT" license = "MIT"
license-files = ["LICENSE"] license-files = ["LICENSE"]
+2
View File
@@ -40,6 +40,8 @@ ROOT_FILES = (
'README.md', 'README.md',
'README_RUS.md', 'README_RUS.md',
'frontend.png', 'frontend.png',
'architecture_en.svg',
'architecture_ru.svg',
'LICENSE', 'LICENSE',
) )
+1 -1
View File
@@ -1,3 +1,3 @@
"""Single source of truth for the SIMtrace Analyser version.""" """Single source of truth for the SIMtrace Analyser version."""
__version__ = '2.7.13' __version__ = '2.7.14'
+14
View File
@@ -8,6 +8,20 @@
set -euo pipefail set -euo pipefail
shopt -s nullglob shopt -s nullglob
# Windows guard: sniff-start.sh is the native Linux/macOS launcher. Under WSL
# the Linux guest cannot reach the Windows SIMtrace2 USB device, and a Git Bash /
# MSYS2 / MinGW / Cygwin shell has no Linux /sys + /dev/bus/usb view for the
# permission pre-flight below. Use sniff-start.bat from cmd.exe or PowerShell,
# which drives the Windows Python/PyUSB stack. A deliberate WSL/Cygwin flow can
# run `python -m simtrace2_pysniff` directly.
if grep -qi microsoft /proc/version 2>/dev/null || \
uname -s 2>/dev/null | grep -qiE 'MINGW|MSYS|CYGWIN'; then
echo "Error: sniff-start.sh is the Linux/macOS helper and cannot run on Windows" >&2
echo "(WSL / MSYS2 / MinGW / Cygwin detected)." >&2
echo "Use sniff-start.bat from a Windows command prompt (cmd.exe / PowerShell) instead." >&2
exit 2
fi
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
GSMTAP="${GSMTAP:-}" GSMTAP="${GSMTAP:-}"
+14
View File
@@ -8,6 +8,20 @@
set -euo pipefail set -euo pipefail
shopt -s nullglob shopt -s nullglob
# Windows guard: start.sh is the native Linux/macOS launcher. Under WSL the
# Linux guest cannot reach the Windows SIMtrace2 USB device, and a Git Bash /
# MSYS2 / MinGW / Cygwin shell has no Linux /sys + /dev/bus/usb view for the
# udev pre-flight below. Use start.bat from cmd.exe or PowerShell, which drives
# the Windows Python/PyUSB stack. A deliberate WSL/Cygwin flow can run
# `python -m simtrace_analyser` directly.
if grep -qi microsoft /proc/version 2>/dev/null || \
uname -s 2>/dev/null | grep -qiE 'MINGW|MSYS|CYGWIN'; then
echo "Error: start.sh is the Linux/macOS helper and cannot run on Windows" >&2
echo "(WSL / MSYS2 / MinGW / Cygwin detected)." >&2
echo "Use start.bat from a Windows command prompt (cmd.exe / PowerShell) instead." >&2
exit 2
fi
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
CAPTURE="${CAPTURE:-gsmtap}" CAPTURE="${CAPTURE:-gsmtap}"
+71
View File
@@ -0,0 +1,71 @@
"""Tests for the bash launchers' Windows-hosted-shell guard."""
import os
import shutil
import stat
import subprocess
import tempfile
import unittest
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
BASH = shutil.which('bash')
LAUNCHERS = (
('start.sh', 'start.bat'),
('sniff-start.sh', 'sniff-start.bat'),
)
@unittest.skipUnless(BASH, 'bash is not installed')
class TestWindowsGuard(unittest.TestCase):
def _run_as_windows(self, script):
"""Run *script* with a fake `uname -s` naming a mingw host."""
with tempfile.TemporaryDirectory() as tmp:
fake = Path(tmp) / 'uname'
fake.write_text('#!/bin/sh\necho MINGW64_NT-10.0\n')
fake.chmod(0o755)
env = dict(os.environ)
env['PATH'] = tmp + os.pathsep + env.get('PATH', '')
return subprocess.run(
[BASH, str(REPO / script)], cwd=REPO, env=env,
capture_output=True, text=True, timeout=30)
def test_guard_exits_and_names_the_bat_launcher(self):
for script, bat in LAUNCHERS:
with self.subTest(script=script):
res = self._run_as_windows(script)
self.assertEqual(res.returncode, 2, res.stderr)
self.assertIn(
'Error: %s is the Linux/macOS helper and cannot run on '
'Windows' % script, res.stderr)
self.assertIn(
'(WSL / MSYS2 / MinGW / Cygwin detected).', res.stderr)
self.assertIn(
'Use %s from a Windows command prompt (cmd.exe / '
'PowerShell) instead.' % bat, res.stderr)
def test_guard_detects_wsl_and_native_windows_shells(self):
# The mingw/msys/cygwin branch is exercised above; pin the WSL branch
# and the exit code so a refactor cannot drop either detection.
for script, _ in LAUNCHERS:
with self.subTest(script=script):
src = (REPO / script).read_text()
self.assertIn('grep -qi microsoft /proc/version', src)
self.assertIn('MINGW|MSYS|CYGWIN', src)
self.assertIn('exit 2', src)
self.assertLess(src.index('Windows guard'),
src.index('PROJECT_DIR='),
'the guard must run before the launcher setup')
def test_shell_syntax(self):
for script, _ in LAUNCHERS:
with self.subTest(script=script):
res = subprocess.run(
[BASH, '-n', str(REPO / script)],
capture_output=True, text=True)
self.assertEqual(res.returncode, 0, res.stderr)
if __name__ == '__main__':
unittest.main()
+1 -1
View File
@@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase):
class TestVersion(unittest.TestCase): class TestVersion(unittest.TestCase):
def test_package_version(self): def test_package_version(self):
from simtrace2_pysniff import __version__ from simtrace2_pysniff import __version__
self.assertEqual(__version__, '2.7.13') self.assertEqual(__version__, '2.7.14')
def test_status_includes_version(self): def test_status_includes_version(self):
import os import os
+15
View File
@@ -81,6 +81,21 @@ class TestReleaseZip(unittest.TestCase):
self.assertIn('%s/frontend/%s' % (top, asset), self.names, self.assertIn('%s/frontend/%s' % (top, asset), self.names,
'precached %s is missing from the zip' % asset) 'precached %s is missing from the zip' % asset)
def test_readme_images_are_in_the_zip(self):
# Drift guard: the runtime tree's READMEs embed the screenshot and the
# architecture diagrams by relative path, so every referenced image
# must travel with the archive.
top = 'simtrace-analyser-%s' % __version__
for readme in ('README.md', 'README_RUS.md'):
text = (REPO / readme).read_text()
images = re.findall(r'!\[[^\]]*\]\(([^)\s]+)\)', text)
self.assertTrue(images, 'no images referenced by %s' % readme)
for image in images:
self.assertNotIn('://', image, image)
self.assertIn('%s/%s' % (top, image), self.names,
'%s references %s, which is missing from the zip'
% (readme, image))
def test_batch_files_use_crlf(self): def test_batch_files_use_crlf(self):
with zipfile.ZipFile(self.archive) as zf: with zipfile.ZipFile(self.archive) as zf:
bats = [n for n in self.names if n.endswith('.bat')] bats = [n for n in self.names if n.endswith('.bat')]