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.
67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""Stealth-egress HTTP client must NOT advertise DECNET.
|
|
|
|
Captures the request that the client emits (using httpx's MockTransport)
|
|
and asserts the User-Agent never contains a DECNET marker. This is the
|
|
most important contract on the file — every threat-intel egress path
|
|
inherits it.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from decnet.net.http import DEFAULT_STEALTH_USER_AGENT, stealth_client
|
|
|
|
|
|
_FORBIDDEN_TOKENS = ("decnet", "honeypot", "decoy", "deck")
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_default_user_agent_is_curl_shaped():
|
|
captured: list[httpx.Request] = []
|
|
|
|
async def _handler(request: httpx.Request) -> httpx.Response:
|
|
captured.append(request)
|
|
return httpx.Response(200, json={"ok": True})
|
|
|
|
transport = httpx.MockTransport(_handler)
|
|
async with stealth_client() as base:
|
|
# Swap transport to keep test offline.
|
|
base._transport = transport # noqa: SLF001 — internal field, deliberate
|
|
await base.get("https://api.example.test/check")
|
|
|
|
ua = captured[0].headers.get("user-agent", "")
|
|
assert ua == DEFAULT_STEALTH_USER_AGENT
|
|
lower = ua.lower()
|
|
for token in _FORBIDDEN_TOKENS:
|
|
assert token not in lower, f"stealth UA leaked {token!r}: {ua!r}"
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_custom_user_agent_override_takes_effect():
|
|
captured: list[httpx.Request] = []
|
|
|
|
async def _handler(request: httpx.Request) -> httpx.Response:
|
|
captured.append(request)
|
|
return httpx.Response(200)
|
|
|
|
transport = httpx.MockTransport(_handler)
|
|
async with stealth_client(user_agent="Mozilla/5.0 (test)") as base:
|
|
base._transport = transport # noqa: SLF001
|
|
await base.get("https://api.example.test/")
|
|
|
|
assert captured[0].headers["user-agent"] == "Mozilla/5.0 (test)"
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_redirects_do_not_follow_by_default():
|
|
async def _handler(request: httpx.Request) -> httpx.Response:
|
|
return httpx.Response(302, headers={"Location": "https://elsewhere/"})
|
|
|
|
transport = httpx.MockTransport(_handler)
|
|
async with stealth_client() as base:
|
|
base._transport = transport # noqa: SLF001
|
|
resp = await base.get("https://api.example.test/")
|
|
assert resp.status_code == 302
|