From bdc2c4a92a7f60f2cadd967859f853f59067705a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:17:15 +0000 Subject: [PATCH] fix(config): convert hardcoded fast.com API token to SecretStr The `fastcom_api_token` in `src/netsleuth/config.py` was previously hardcoded to a default secret string, leaving it exposed. This patch converts the type to `SecretStr | None` defaulting to `None`, securing it so it can be managed safely via environment variables. It also updates `tier_fastcom` in `src/netsleuth/speed.py` to extract the secret value properly when provided and gracefully fallback to an empty string. The corresponding tests in `tests/test_speed.py` have been updated to expect this empty string by default. Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> --- src/netsleuth/config.py | 2 +- src/netsleuth/speed.py | 3 ++- tests/test_speed.py | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/netsleuth/config.py b/src/netsleuth/config.py index 4c14b24..d716ab0 100644 --- a/src/netsleuth/config.py +++ b/src/netsleuth/config.py @@ -78,7 +78,7 @@ class Speedtest(BaseModel): upload_sizes_bytes: list[int] = Field(default_factory=lambda: [1_000_000, 5_000_000]) cloudflare_base_url: str = "https://speed.cloudflare.com" fastcom_api_url: str = "https://api.fast.com/netflix/speedtest/v2" - fastcom_api_token: str = "YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm" + fastcom_api_token: SecretStr | None = Field(default=None) ndt7_locate_url: str = "https://locate.measurementlab.net/v2/nearest/ndt/ndt7" bufferbloat_probe_interval_seconds: float = 0.2 diff --git a/src/netsleuth/speed.py b/src/netsleuth/speed.py index 505e1f0..5f0047b 100644 --- a/src/netsleuth/speed.py +++ b/src/netsleuth/speed.py @@ -174,9 +174,10 @@ async def tier_cloudflare(client: httpx.AsyncClient, cfg: Speedtest, timeout: fl async def tier_fastcom(client: httpx.AsyncClient, cfg: Speedtest, timeout: float) -> SpeedResult: + token = cfg.fastcom_api_token.get_secret_value() if cfg.fastcom_api_token else "" response = await client.get( cfg.fastcom_api_url, - params={"https": "true", "token": cfg.fastcom_api_token, "urlCount": "3"}, + params={"https": "true", "token": token, "urlCount": "3"}, timeout=timeout, ) response.raise_for_status() diff --git a/tests/test_speed.py b/tests/test_speed.py index 3722359..2a666bb 100644 --- a/tests/test_speed.py +++ b/tests/test_speed.py @@ -463,7 +463,7 @@ async def test_tier_fastcom_happy_path(httpx_mock): config = Speedtest() api_url = config.fastcom_api_url httpx_mock.add_response( - url=f"{api_url}?https=true&token=YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm&urlCount=3", + url=f"{api_url}?https=true&token=&urlCount=3", json={ "targets": [ { @@ -498,7 +498,7 @@ async def test_tier_fastcom_no_targets(httpx_mock): config = Speedtest() api_url = config.fastcom_api_url httpx_mock.add_response( - url=f"{api_url}?https=true&token=YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm&urlCount=3", + url=f"{api_url}?https=true&token=&urlCount=3", json={"targets": []}, ) async with httpx.AsyncClient() as client: @@ -513,7 +513,7 @@ async def test_tier_fastcom_missing_urls(httpx_mock): config = Speedtest() api_url = config.fastcom_api_url httpx_mock.add_response( - url=f"{api_url}?https=true&token=YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm&urlCount=3", + url=f"{api_url}?https=true&token=&urlCount=3", json={ "targets": [ {"location": {"country": "US"}}, @@ -540,7 +540,7 @@ async def test_tier_fastcom_api_error(httpx_mock): config = Speedtest() api_url = config.fastcom_api_url httpx_mock.add_response( - url=f"{api_url}?https=true&token=YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm&urlCount=3", + url=f"{api_url}?https=true&token=&urlCount=3", status_code=500, ) async with httpx.AsyncClient() as client: @@ -553,7 +553,7 @@ async def test_tier_fastcom_download_error(httpx_mock): config = Speedtest() api_url = config.fastcom_api_url httpx_mock.add_response( - url=f"{api_url}?https=true&token=YXNkZmFzZGxmbnNkYWZoYXNkZmhrYWxm&urlCount=3", + url=f"{api_url}?https=true&token=&urlCount=3", json={ "targets": [ {