Files
DECNET/tests/prober/test_prober_rotation.py
anti f2b3393669 chore: relicense to AGPL-3.0-or-later and add SPDX headers
Replaces LICENSE (GPLv3 -> AGPLv3) and prepends
`SPDX-License-Identifier: AGPL-3.0-or-later` to every source file
across decnet/, decnet_web/, tests/, scripts/, and tools/.

Rationale: closes the GPLv3 ASP loophole so any party operating a
modified DECNET as a network service must offer their modified
source. Personal copyright (Samuel Paschuan) + inbound=outbound
contributions make a future unilateral relicense infeasible.

- LICENSE: full AGPL-3.0 text (gnu.org/licenses/agpl-3.0.txt)
- COPYRIGHT: project copyright notice
- tools/add_spdx_headers.py: idempotent header injector
  (shebang- and PEP 263-aware)

Touches 1565 source files (.py, .ts, .tsx, .js, .jsx, .css, .sh).
No behavior change; comments only.
2026-05-22 21:04:16 -04:00

125 lines
4.9 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""Integration test: _run_probe threads the rotation recorder through to probes.
The prober worker constructs the recorder closure at startup; here we
verify that _run_probe calls record_rotation with (ip, port, probe_type,
hash) for JARM / HASSH / TCPFP on a successful probe, and that omitting
record_rotation is a safe no-op.
"""
from __future__ import annotations
from pathlib import Path
from unittest.mock import MagicMock, patch
from decnet.prober.worker import _run_probe
# ─── Helpers ─────────────────────────────────────────────────────────────────
def _recorder():
calls: list[tuple] = []
return calls, lambda ip, port, ptype, h: calls.append((ip, port, ptype, h))
# ─── JARM ────────────────────────────────────────────────────────────────────
def test_jarm_phase_calls_recorder(tmp_path: Path) -> None:
from decnet.prober.probes.jarm import JarmProbe
rec_calls, recorder = _recorder()
probe = JarmProbe()
probe._ports = [443]
with patch("decnet.prober.probes.jarm.jarm_hash", return_value="c0c" * 10 + "a" * 32):
_run_probe(
probe, "10.0.0.5", {},
tmp_path / "decnet.log", tmp_path / "decnet.json",
timeout=1.0, publish_fn=None, record_rotation=recorder,
)
assert rec_calls == [("10.0.0.5", 443, "jarm", "c0c" * 10 + "a" * 32)]
def test_jarm_phase_no_recorder_call_on_empty_hash(tmp_path: Path) -> None:
from decnet.prober.probes.jarm import JarmProbe
from decnet.prober.jarm import JARM_EMPTY_HASH
rec_calls, recorder = _recorder()
probe = JarmProbe()
probe._ports = [443]
with patch("decnet.prober.probes.jarm.jarm_hash", return_value=JARM_EMPTY_HASH):
_run_probe(
probe, "10.0.0.5", {},
tmp_path / "decnet.log", tmp_path / "decnet.json",
timeout=1.0, publish_fn=None, record_rotation=recorder,
)
assert rec_calls == []
# ─── HASSH ───────────────────────────────────────────────────────────────────
def test_hassh_phase_calls_recorder(tmp_path: Path) -> None:
from decnet.prober.probes.hassh import HasshProbe
rec_calls, recorder = _recorder()
probe = HasshProbe()
probe._ports = [22]
stub = {
"hassh_server": "deadbeef",
"banner": "SSH-2.0-OpenSSH_9.2",
"kex_algorithms": "x",
"encryption_s2c": "x",
"mac_s2c": "x",
"compression_s2c": "x",
}
with patch("decnet.prober.probes.hassh.hassh_server", return_value=stub):
_run_probe(
probe, "10.0.0.5", {},
tmp_path / "decnet.log", tmp_path / "decnet.json",
timeout=1.0, publish_fn=None, record_rotation=recorder,
)
assert rec_calls == [("10.0.0.5", 22, "hassh", "deadbeef")]
# ─── TCPFP ───────────────────────────────────────────────────────────────────
def test_tcpfp_phase_calls_recorder(tmp_path: Path) -> None:
from decnet.prober.probes.tcpfp import TcpfpProbe
rec_calls, recorder = _recorder()
probe = TcpfpProbe()
probe._ports = [22]
stub = {
"tcpfp_hash": "tcpfp-hash-1",
"tcpfp_raw": "raw",
"ttl": 64, "window_size": 65535, "df_bit": True,
"mss": 1460, "window_scale": 7, "sack_ok": True,
"timestamp": True, "options_order": "MSS,SACK,TS,NOP,WS",
"tos": 0, "dscp": 0, "ecn": 0, "server_isn": 0,
}
with patch("decnet.prober.probes.tcpfp.tcp_fingerprint", return_value=stub):
_run_probe(
probe, "10.0.0.5", {},
tmp_path / "decnet.log", tmp_path / "decnet.json",
timeout=1.0, publish_fn=None, record_rotation=recorder,
)
assert rec_calls == [("10.0.0.5", 22, "tcpfp", "tcpfp-hash-1")]
# ─── Safety ──────────────────────────────────────────────────────────────────
def test_recorder_optional_no_crash_when_none(tmp_path: Path) -> None:
"""record_rotation=None must keep pre-DEBT-032 behavior — no crash."""
from decnet.prober.probes.jarm import JarmProbe
probe = JarmProbe()
probe._ports = [443]
with patch("decnet.prober.probes.jarm.jarm_hash", return_value="c0c" * 10 + "a" * 32):
_run_probe(
probe, "10.0.0.5", {},
tmp_path / "decnet.log", tmp_path / "decnet.json",
timeout=1.0, publish_fn=None, record_rotation=None,
)