Files
vulncheck/tests/test_asb_negative_cache.py
T
vulncheck 7b006411ff fix(android): read a newly published ASB month the next night
A month the ASB fetch found missing (Google had not published it yet)
was cached as empty for three days. The November 2026 bulletin went live
on 2026-11-02, after the sync of 2026-11-01 had asked, so non-Samsung
Android devices would have got its CVEs on 2026-11-04 at the earliest,
two nightly syncs late. The empty answer now expires after 12 hours:
still long enough that the devices of one sync do not each re-fetch it,
short enough that the next nightly sync reads the published page.

Samsung devices were not affected: their months come from the SMR page,
and ASB is read for a month only when SMR has no section for it. That is
also why their findings show samsung-smr and never android-asb.
2026-11-04 10:36:32 +01:00

74 lines
2.6 KiB
Python

"""A month Google publishes after we first asked is read on the next nightly sync — run: python tests/test_asb_negative_cache.py
Field case 2026-11-03: the November ASB went live on 2026-11-02, but the
sync of 2026-11-01 had already found the page missing and cached that empty
answer for three days. Non-Samsung Android devices got the month's CVEs on
2026-11-04 at the earliest, two nightly syncs late. Samsung devices were not
hit (their November came from the SMR page, which the ASB cache never sees).
Pinned here: an empty month cached by the previous night is fetched again,
one cached minutes ago (same sync, many devices) is not.
"""
import json
import os
import sys
from datetime import datetime, timedelta
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ.setdefault("JWT_SECRET_KEY", "test-key-test-key-test-key-test-key")
import httpx # noqa: E402
from sqlalchemy import create_engine # noqa: E402
from sqlalchemy.orm import sessionmaker # noqa: E402
import app.models # noqa: F401,E402 (registers every mapper)
from app.models.base import Base # noqa: E402
from app.models.setting import Setting # noqa: E402
from app.services import android_cve_service as asb # noqa: E402
_PAGE = ('<h3>Framework</h3><table><tr><td>CVE-2026-58868</td>'
'<td>RCE</td><td>Critical</td></tr></table>')
def _db_with_empty_month(age: timedelta):
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
db = sessionmaker(bind=engine)()
db.add(Setting(key=asb._CACHE_PREFIX + "2026-11-01", value=json.dumps(
{"ts": (datetime.now() - age).isoformat(), "pairs": []})))
db.commit()
return db
def demo():
calls = []
def handler(request):
calls.append(str(request.url))
return httpx.Response(200, text=_PAGE)
real_client = httpx.Client
httpx.Client = lambda **kw: real_client(transport=httpx.MockTransport(handler), **kw)
try:
# Empty answer from last night's sync: the page is live now.
db = _db_with_empty_month(timedelta(hours=23, minutes=30))
assert asb.fetch_asb_month(db, "2026-11-01") == [("CVE-2026-58868", "critical")]
assert len(calls) == 1, calls
# Empty answer from earlier in this sync: no second request.
calls.clear()
db = _db_with_empty_month(timedelta(minutes=5))
assert asb.fetch_asb_month(db, "2026-11-01") == []
assert calls == [], calls
finally:
httpx.Client = real_client
print("OK")
def test_asb_negative_cache():
demo()
if __name__ == "__main__":
demo()