Files
camoufox/pythonlib/tests/test_shipped_data.py
T
Jake WriterandClaude Opus 5.5 40edebb925 chore(data): drop the 23 presets whose GPU has no WebGL data
A preset records only its GPU's name. The WebGL parameters, extensions and
shader precision behind it have to come from somewhere, and for these 23
nothing Camoufox has describes the GPU: fpgen has never seen Firefox report it
on that OS. So each launch paired the name with another device's parameters,
a mismatch any WebGL fingerprinter can see. They were:

- Windows on ARM (Adreno 650);
- Direct3D 10-level GPUs (vs_4_0/vs_4_1);
- "Generic Renderer";
- 945GM and GTX 480 on macOS;
- nouveau/Mesa buckets on Linux;
- one Linux preset pairing NVIDIA's proprietary vendor string with the
  nouveau renderer name.

scripts/clean-fingerprint-data.py now applies the rule, via a shared
fingerprints.firefox_gpus(), and test_shipped_data asserts it. 374 presets
remain, and every OS keeps its presets. ROADMAP.md lists capturing WebGL data
for these GPUs, which would bring them back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 21:43:44 -06:00

115 lines
4.5 KiB
Python

"""The data files that ship must not contain an identity we would refuse to use.
`camoufox.coherence` filters at draw time, so an impossible row can never reach
a page either way. This is the second filter, on the data itself: a row that
survives here is one a future refresh could ship, a consumer reading the JSON
directly would get, and a reviewer would take as real. Both filters run the same
rules -- `scripts/clean-fingerprint-data.py --write` is what makes these pass.
Dropped on 2026-09-17: 38 of 435 presets (26 with a GPU their OS cannot report,
7 pairing Apple Silicon with a core count Apple never shipped, 4 with a colour
depth their GPU contradicts, 3 with a phone viewport, 1 claiming 40 touch
points), and 2 impossible macOS weights in webgl_data.db.
"""
import json
import sqlite3
import sys
from os.path import dirname, join
from pathlib import Path
import pytest
sys.path.insert(0, join(dirname(__file__), ".."))
from camoufox import coherence # noqa: E402
from camoufox.fingerprints import from_preset # noqa: E402
from camoufox.webgl.sample import DB_PATH # noqa: E402
DATA = Path(__file__).parent.parent / "camoufox"
PRESET_FILES = ("fingerprint-presets.json", "fingerprint-presets-v150.json")
OS_KEY = {"macos": "mac", "windows": "win", "linux": "lin"}
@pytest.mark.parametrize("filename", PRESET_FILES)
def test_every_bundled_preset_is_coherent_as_stored(filename):
presets = json.loads((DATA / filename).read_text())["presets"]
for os_name, entries in presets.items():
assert entries, f"{filename}/{os_name} has no presets left"
for index, preset in enumerate(entries):
config = from_preset(preset, "152")
violations = coherence.validate(config, OS_KEY[os_name])
assert violations == [], (
f"{filename} {os_name}[{index}]: "
+ "; ".join(v.detail for v in violations)
+ " -- run scripts/clean-fingerprint-data.py --write"
)
def test_no_gpu_is_offered_to_an_os_that_cannot_report_it():
connection = sqlite3.connect(DB_PATH)
try:
rows = connection.execute(
"SELECT vendor, renderer, win, mac, lin FROM webgl_fingerprints"
).fetchall()
finally:
connection.close()
assert rows, "webgl_data.db is empty"
for vendor, renderer, *weights in rows:
for os_key, weight in zip(("win", "mac", "lin"), weights):
if weight and weight > 0:
assert coherence.gpu_fits_os(renderer, os_key), (
f"{renderer!r} is offered to {os_key} at {weight}"
)
def test_each_os_still_has_gpus_to_draw_from():
"""The filter must not empty a pool -- a single GPU per OS is its own tell."""
connection = sqlite3.connect(DB_PATH)
try:
for os_key in ("win", "mac", "lin"):
count = connection.execute(
f"SELECT COUNT(*) FROM webgl_fingerprints WHERE {os_key} > 0" # nosec
).fetchone()[0]
assert count >= 2, f"{os_key} has {count} GPU(s) left"
finally:
connection.close()
def test_every_gpu_row_can_be_drawn_on_some_os():
"""A row no OS can draw is dead weight a reader would take as real data."""
connection = sqlite3.connect(DB_PATH)
try:
rows = connection.execute(
"SELECT vendor, renderer, win, mac, lin FROM webgl_fingerprints"
).fetchall()
finally:
connection.close()
undrawable = [
(vendor, renderer)
for vendor, renderer, *weights in rows
if not any(
weight > 0 and coherence.gpu_fits_os(renderer, os_key)
for os_key, weight in zip(("win", "mac", "lin"), weights)
)
]
assert undrawable == []
@pytest.mark.parametrize("filename", PRESET_FILES)
def test_every_preset_gpu_has_webgl_data(filename):
"""A preset records only its GPU's name; the WebGL parameters behind it come
from fpgen. A GPU fpgen has never seen Firefox report on that OS has none, so
launching it would pair the name with another device's parameters."""
from camoufox.fingerprints import firefox_gpus
presets = json.loads((DATA / filename).read_text())["presets"]
for os_name, entries in presets.items():
known = firefox_gpus(os_name)
for index, preset in enumerate(entries):
gpu = (preset["webgl"]["unmaskedVendor"], preset["webgl"]["unmaskedRenderer"])
assert gpu in known, (
f"{filename} {os_name}[{index}]: {gpu[1]!r} has no WebGL data"
" -- run scripts/clean-fingerprint-data.py --write"
)