test: no test throws a response away; the stream session is narrowed, not baselined

The 7 baselined Optional accesses in plex/stream.py were one fact the type did not carry: the
initial spawn (replace_only=None) always supersedes, so only the fallback respawn can get None.
An assert at the call site says so; the pyright baseline drops 195 -> 188.

test_abuse_limits: the public-URL and YouTube enqueue tests stopped at the profile lookup
(400 no_profile) and passed on that unrelated refusal. They now send an inline spec and assert
the job is queued. The same shape — a request whose response is discarded — sat at 53 more
places across the suite (all returned what they should, measured with a TestClient probe);
each now asserts its status, and test_response_checked keeps it that way (seen red).
This commit is contained in:
2026-10-03 19:06:47 +02:00
parent 614d728561
commit ca9ca85b18
19 changed files with 246 additions and 129 deletions
-58
View File
@@ -548,64 +548,6 @@
}
}
],
"./app/plex/stream.py": [
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 51,
"endColumn": 55,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 23,
"endColumn": 25,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 18,
"endColumn": 31,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 75,
"endColumn": 79,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 10,
"endColumn": 23,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 10,
"endColumn": 12,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 10,
"endColumn": 17,
"lineCount": 1
}
}
],
"./app/plex/sync.py": [
{
"code": "reportArgumentType",
+2 -2
View File
@@ -745,8 +745,7 @@ def start_session(
# check-and-replace happens under ONE _lock, so a newer same-key session (a concurrent
# seek-restart) installed between the fallback's decision and here is never clobbered. When the
# registered session is no longer `replace_only`, we abort and return None (the caller yields to
# whoever is registered now). The INITIAL spawn passes replace_only=None and always supersedes —
# that is the seek-restart's intended last-writer-wins.
# whoever is registered now). The INITIAL spawn never gets None — see its call site.
# Software-fallback encode tuning — read only on the SW transcode path (the VAAPI path and
# remux ignore preset/crf/max_height, and remux must not touch the DB for them).
preset, crf, max_height = "veryfast", 20, 0
@@ -823,6 +822,7 @@ def start_session(
return s
s = _spawn(*_select_encode(db, item, transcode, src))
assert s is not None # replace_only=None always supersedes: a seek-restart's last-writer-wins
# Wait for the first video segment outside the lock (this blocks on ffmpeg, and we must not hold up
# other sessions). Pass the proc so a HW session that dies at VAAPI init fails fast (not after 25s).
ready = wait_for(_seg(0), timeout=25.0, proc=s.proc)
+21 -6
View File
@@ -36,9 +36,14 @@ def test_a_public_url_gets_past_the_guard(db, as_user, make_user, monkeypatch):
"getaddrinfo",
lambda *a, **kw: [(None, None, None, "", ("93.184.216.34", 0))],
)
r = as_user(user).post("/api/downloads", json={"source": "https://example.com/v"})
detail = r.json().get("detail") if r.status_code >= 400 else None
assert not (isinstance(detail, dict) and detail.get("code") == "url_blocked")
# An inline spec, so nothing ELSE refuses it: without one the request stopped at the
# profile lookup (400 no_profile) and "not url_blocked" held for a request the guard never
# had to wave through (E32 S2).
r = as_user(user).post(
"/api/downloads", json={"source": "https://example.com/v", "spec": {"format": "best"}}
)
assert r.status_code == 200, r.text
assert r.json()["status"] == "queued"
def test_youtube_sources_never_consult_the_guard(db, as_user, make_user, monkeypatch):
@@ -50,7 +55,13 @@ def test_youtube_sources_never_consult_the_guard(db, as_user, make_user, monkeyp
user = make_user()
db.commit()
monkeypatch.setattr(urlguard.socket, "getaddrinfo", boom)
as_user(user).post("/api/downloads", json={"source": "dQw4w9WgXcQ"})
# The job must actually be created: a request refused for any other reason would never reach
# the guard either, and the test would pass without proving anything (E32 S2).
r = as_user(user).post(
"/api/downloads", json={"source": "dQw4w9WgXcQ", "spec": {"format": "best"}}
)
assert r.status_code == 200, r.text
assert r.json()["source_kind"] == "youtube"
def test_manual_subscription_sync_goes_on_cooldown(db, as_user, make_user, monkeypatch):
@@ -81,8 +92,12 @@ def test_the_cooldown_is_per_user_not_global(db, as_user, make_user, monkeypatch
monkeypatch.setattr(syncroutes, "import_subscriptions", lambda d, u: {"imported": 0})
ca = as_user(a)
for _ in range(4):
ca.post("/api/sync/subscriptions")
assert [ca.post("/api/sync/subscriptions").status_code for _ in range(4)] == [
200,
200,
200,
429,
]
assert ca.post("/api/sync/subscriptions").status_code == 429
assert as_user(b).post("/api/sync/subscriptions").status_code == 200
+24 -14
View File
@@ -151,7 +151,7 @@ def test_nobody_reaches_another_users_session(db, make_user, as_user):
def test_the_list_is_the_users_own_newest_first(db, make_user, as_user):
client = as_user(make_user())
first = _start(client)["id"]
client.post(f"/api/debug-sessions/{first}/stop")
assert client.post(f"/api/debug-sessions/{first}/stop").status_code == 200
second = _start(client)["id"]
assert [s["id"] for s in client.get("/api/debug-sessions").json()["items"]] == [second, first]
@@ -199,10 +199,13 @@ def test_an_erased_account_takes_its_sessions_with_it(db, make_user, as_user):
user = make_user()
client = as_user(user)
sid = _start(client)["id"]
client.post(
f"/api/debug-sessions/{sid}/screenshots",
content=_PNG,
headers={"content-type": "image/png"},
assert (
client.post(
f"/api/debug-sessions/{sid}/screenshots",
content=_PNG,
headers={"content-type": "image/png"},
).status_code
== 200
)
purge_user(db, user, BackgroundTasks())
assert db.get(DebugSession, sid) is None
@@ -250,7 +253,7 @@ def test_a_request_naming_the_own_open_session_is_tagged_and_raised(gated, db, c
_signed_in(client, make_user)
sid = _start(client, "DEBUG")["id"]
gated.records.clear()
client.get("/api/debug-sessions", headers={"x-debug-session": sid})
assert client.get("/api/debug-sessions", headers={"x-debug-session": sid}).status_code == 200
(line,) = _request_lines(gated)
assert getattr(line, "debug_session_id", None) == sid
# Raised to the session's level: the line is kept for storage though the user's own is Alap.
@@ -263,7 +266,7 @@ def test_a_header_naming_anything_else_is_ignored_not_refused(gated, db, client,
db.commit()
_signed_in(client, make_user)
own = _start(client)["id"]
client.post(f"/api/debug-sessions/{own}/stop")
assert client.post(f"/api/debug-sessions/{own}/stop").status_code == 200
for value in (foreign, own, "not-a-session", "f" * 16, "A" * 16):
gated.records.clear()
# Not `/api/me`: a polled route logs at DEBUG, and an un-raised request would drop the very
@@ -280,7 +283,7 @@ def test_a_header_naming_the_own_session_past_its_cap_is_ignored(gated, db, clie
sid = _start(client)["id"]
_expire(db, sid) # past its cap, not yet swept: still open in the table
gated.records.clear()
client.get("/api/debug-sessions", headers={"x-debug-session": sid})
assert client.get("/api/debug-sessions", headers={"x-debug-session": sid}).status_code == 200
(line,) = _request_lines(gated)
assert getattr(line, "debug_session_id", None) is None
assert getattr(line, "elevated", False) is False
@@ -616,7 +619,7 @@ def test_a_users_screenshots_are_capped_across_their_sessions(recording, monkeyp
client, sid = recording
monkeypatch.setattr(debugsession, "SCREENSHOT_USER_MAX_BYTES", len(_PNG) * 2)
assert _upload(client, sid, _PNG).status_code == 200
client.post(f"/api/debug-sessions/{sid}/stop")
assert client.post(f"/api/debug-sessions/{sid}/stop").status_code == 200
other = _start(client)["id"]
assert _upload(client, other, _PNG).status_code == 200
r = _upload(client, other, _PNG)
@@ -631,7 +634,7 @@ def test_new_sessions_are_paced_but_joining_one_is_not(db, make_user, as_user, m
client = as_user(make_user())
sid = _start(client)["id"]
assert _start(client)["id"] == sid # another tab joining
client.post(f"/api/debug-sessions/{sid}/stop")
assert client.post(f"/api/debug-sessions/{sid}/stop").status_code == 200
r = client.post("/api/debug-sessions", json={"level": "DEBUG"})
assert r.status_code == 429 and r.json()["detail"]["reason"] == "debug_session_rate_limited"
@@ -745,9 +748,16 @@ def test_the_export_is_the_saved_draft_the_evidence_and_the_screenshots(db, make
db.commit()
_upload(client, sid, _PNG)
_upload(client, sid, _JPEG)
client.put(
f"/api/debug-sessions/{sid}/draft",
json={"title": "Spinner stays", "body": "It spins.", "excluded": [dropped_web.id, 999999]},
assert (
client.put(
f"/api/debug-sessions/{sid}/draft",
json={
"title": "Spinner stays",
"body": "It spins.",
"excluded": [dropped_web.id, 999999],
},
).status_code
== 200
)
r = client.get(f"/api/debug-sessions/{sid}/export")
@@ -1144,7 +1154,7 @@ def test_new_issues_are_paced_per_user(gitea_fake, db, make_user, as_user, monke
first = _start(client)["id"]
_ready(client, first)
assert client.post(f"/api/debug-sessions/{first}/issue").status_code == 200
client.post(f"/api/debug-sessions/{first}/stop")
assert client.post(f"/api/debug-sessions/{first}/stop").status_code == 200
second = _start(client)["id"]
_ready(client, second)
r = client.post(f"/api/debug-sessions/{second}/issue")
+26 -11
View File
@@ -212,7 +212,12 @@ def test_a_timestamp_outside_the_consent_window_is_clamped(elevated):
now = datetime.now(timezone.utc)
future = (now + timedelta(days=365)).isoformat()
past = (now - timedelta(days=30)).isoformat()
client.post("/api/diagnostics/events", json={"events": [_event(ts=future), _event(ts=past)]})
assert (
client.post(
"/api/diagnostics/events", json={"events": [_event(ts=future), _event(ts=past)]}
).status_code
== 200
)
late, early = rows()
assert late.ts <= datetime.now(timezone.utc)
assert early.ts >= now - timedelta(hours=diagnostics.ELEVATION_HOURS, minutes=1)
@@ -342,15 +347,15 @@ def _app() -> TestClient:
def test_the_account_reaches_the_handlers_own_lines(gated):
_app().get("/api/thing/41")
assert _app().get("/api/thing/41").status_code == 200
line = next(r for r in gated.records if r.getMessage() == "an ordinary line")
assert getattr(line, "user_id", None) == 41
def test_one_users_elevation_logs_their_requests_in_detail_and_nobody_elses(gated):
client = _app()
client.get("/api/thing/7", params={"level": "DEBUG"})
client.get("/api/thing/8")
assert client.get("/api/thing/7", params={"level": "DEBUG"}).status_code == 200
assert client.get("/api/thing/8").status_code == 200
detail = [r for r in gated.records if r.getMessage().startswith("detail only")]
assert [r.user_id for r in detail] == [7]
assert getattr(detail[0], "elevated", False) is True
@@ -363,9 +368,9 @@ def test_one_users_elevation_logs_their_requests_in_detail_and_nobody_elses(gate
def test_the_root_level_returns_to_the_base_when_the_elevation_ends(gated):
client = _app()
client.get("/api/thing/7", params={"level": "TRACE"})
assert client.get("/api/thing/7", params={"level": "TRACE"}).status_code == 200
assert logging.getLogger().level == logs.TRACE
client.get("/api/thing/7") # the same user, back at the base
assert client.get("/api/thing/7").status_code == 200 # the same user, back at the base
assert logging.getLogger().level == logging.INFO
logs._track_elevation(9, logging.DEBUG, datetime.now(timezone.utc) - timedelta(seconds=1))
assert logging.getLogger().level == logging.INFO # an already-expired one is pruned at once
@@ -373,15 +378,25 @@ def test_the_root_level_returns_to_the_base_when_the_elevation_ends(gated):
def test_the_query_string_is_logged_only_for_a_traced_request_and_redacted(gated):
client = _app()
client.get("/api/thing/7", params={"level": "DEBUG", "q": "lofi"})
client.get("/api/thing/7", params={"level": "TRACE", "q": "lofi", "token": "SECRET"})
assert client.get("/api/thing/7", params={"level": "DEBUG", "q": "lofi"}).status_code == 200
assert (
client.get(
"/api/thing/7", params={"level": "TRACE", "q": "lofi", "token": "SECRET"}
).status_code
== 200
)
lines = [r for r in gated.records if getattr(r, "event", None) == "http.request"]
assert "query" not in lines[0].attrs
assert "q=lofi" in lines[1].attrs["query"] and "SECRET" not in lines[1].attrs["query"]
def test_an_address_typed_into_a_search_is_redacted_though_the_browser_encodes_it(gated):
_app().get("/api/thing/7?level=TRACE&q=someone%40example.com&new_password=hunter2")
assert (
_app()
.get("/api/thing/7?level=TRACE&q=someone%40example.com&new_password=hunter2")
.status_code
== 200
)
(line,) = [r for r in gated.records if getattr(r, "event", None) == "http.request"]
assert line.attrs["query"] == "level=TRACE&q=[email]&new_password=[redacted]"
@@ -400,7 +415,7 @@ def test_a_credential_param_goes_whole_however_its_value_decodes(raw):
def test_an_admin_level_of_trace_does_not_log_other_users_query_strings(gated):
logs.set_level("TRACE")
_app().get("/api/thing/7", params={"q": "something private"})
assert _app().get("/api/thing/7", params={"q": "something private"}).status_code == 200
(line,) = [r for r in gated.records if getattr(r, "event", None) == "http.request"]
assert "query" not in line.attrs
@@ -488,7 +503,7 @@ def test_a_real_sign_in_carries_the_consented_level_into_the_process(gated, clie
user = _signed_in(client, make_user)
assert client.put("/api/me/diagnostics", json={"level": "DEBUG"}).status_code == 200
logs._elevations.clear() # only a request resolving the account through auth may put it back
client.get("/api/me")
assert client.get("/api/me").status_code == 200
assert logs._elevations[user.id][0] == logging.DEBUG
assert client.put("/api/me/diagnostics", json={"level": "INFO"}).status_code == 200
assert user.id not in logs._elevations
+1 -1
View File
@@ -334,7 +334,7 @@ def test_me_reports_the_google_address_only_when_it_differs(client, db, make_use
)
assert client.get("/api/me").json()["google_email"] is None
client.post("/auth/logout")
assert client.post("/auth/logout").status_code == 200
tagged = make_user(email="me+siftlode@gmail.com", password=_UAT_PW)
tagged.google_email = "me@gmail.com"
db.commit()
+6 -1
View File
@@ -100,7 +100,12 @@ def test_the_admin_user_list_carries_last_login(as_user, db, make_user):
def test_the_account_sees_its_own_last_sign_in(client, db, make_user):
# Settings → Account shows it (prod UAT 2026-09-19: only the admin's user list did).
make_user(email="me@example.com", password=_PW)
client.post("/auth/password-login", json={"email": "me@example.com", "password": _PW})
assert (
client.post(
"/auth/password-login", json={"email": "me@example.com", "password": _PW}
).status_code
== 200
)
stamp = client.get("/api/me").json()["last_login_at"]
+5 -5
View File
@@ -277,7 +277,7 @@ def test_a_signed_in_request_is_never_capped_and_names_its_account(sink):
client = TestClient(app)
for _ in range(logs.ANONYMOUS_LINES_PER_MINUTE + 3):
client.get("/api/me")
assert client.get("/api/me").status_code == 200
records = sink.records[-(logs.ANONYMOUS_LINES_PER_MINUTE + 3) :]
assert all(getattr(r, logs.PERSIST, True) for r in records)
assert sink.objects()[-1]["user_id"] == 42 and "user_id" not in sink.objects()[-1]["attrs"]
@@ -325,9 +325,9 @@ def test_the_log_consoles_own_reads_are_debug_but_its_failures_are_not(sink):
http = logging.getLogger("siftlode.http")
http.setLevel(logs.TRACE)
client = _client()
client.get("/api/admin/logs/facets")
assert client.get("/api/admin/logs/facets").status_code == 200
assert sink.objects()[-1]["level"] == "DEBUG"
client.get("/api/admin/logs/facets?fail=1")
assert client.get("/api/admin/logs/facets?fail=1").status_code == 400
assert sink.objects()[-1]["level"] == "WARNING"
@@ -344,7 +344,7 @@ def test_a_polled_read_is_debug_a_write_to_the_same_route_is_not(sink):
r = client.post("/api/messages/unread_count")
assert sink.objects()[-1]["level"] == "INFO"
assert "X-Log-Quiet" not in r.headers
client.get("/api/videos/abc")
assert client.get("/api/videos/abc").status_code == 200
assert sink.objects()[-1]["level"] == "INFO"
@@ -360,7 +360,7 @@ def test_every_polled_route_is_a_route_the_app_has():
def test_a_failing_request_is_logged_by_status_and_an_unhandled_error_is_logged_at_all(sink):
client = _client()
client.get("/api/videos/missing/deeper") # 404 from the router
assert client.get("/api/videos/missing/deeper").status_code == 404 # 404 from the router
assert sink.objects()[-1]["level"] == "WARNING"
client.get("/boom")
payload = sink.objects()[-1]
+37 -7
View File
@@ -154,8 +154,18 @@ def test_an_access_request_records_the_language_it_was_made_in(db, client):
def test_asking_again_from_another_language_updates_the_row(db, client):
client.post("/auth/request-access", json={"email": "asking@example.com", "lang": "en"})
client.post("/auth/request-access", json={"email": "asking@example.com", "lang": "hu"})
assert (
client.post(
"/auth/request-access", json={"email": "asking@example.com", "lang": "en"}
).status_code
== 200
)
assert (
client.post(
"/auth/request-access", json={"email": "asking@example.com", "lang": "hu"}
).status_code
== 200
)
db.expire_all()
inv = db.execute(select(Invite).where(Invite.email == "asking@example.com")).scalar_one()
@@ -165,7 +175,12 @@ def test_asking_again_from_another_language_updates_the_row(db, client):
def test_an_unsupported_language_is_ignored_rather_than_stored(db, client):
client.post("/auth/request-access", json={"email": "asking@example.com", "lang": "../../etc"})
assert (
client.post(
"/auth/request-access", json={"email": "asking@example.com", "lang": "../../etc"}
).status_code
== 200
)
inv = db.execute(select(Invite).where(Invite.email == "asking@example.com")).scalar_one()
assert inv.lang is None
@@ -194,7 +209,12 @@ def test_the_confirmation_mail_is_written_in_the_accounts_language(db, client, m
monkeypatch.setattr(email_mod, "email_enabled", lambda db=None: True)
sent = _bodies(monkeypatch)
client.post("/auth/register", json={"email": "hu@example.com", "password": _PW, "lang": "hu"})
assert (
client.post(
"/auth/register", json={"email": "hu@example.com", "password": _PW, "lang": "hu"}
).status_code
== 200
)
(_, subject, body) = sent[0]
assert subject == mailtext.MAIL_TEXT["verify_email.subject"]["hu"]
@@ -209,7 +229,12 @@ def test_the_approval_mail_answers_in_the_language_the_request_was_made_in(
monkeypatch.setattr(email_mod, "email_enabled", lambda db=None: True)
sent = _bodies(monkeypatch)
admin = make_user(email="admin@example.com", role="admin")
client.post("/auth/request-access", json={"email": "asking@example.com", "lang": "hu"})
assert (
client.post(
"/auth/request-access", json={"email": "asking@example.com", "lang": "hu"}
).status_code
== 200
)
inv = db.execute(select(Invite).where(Invite.email == "asking@example.com")).scalar_one()
sent.clear() # drop the admin notification; this test is about the reply to the requester
@@ -227,11 +252,16 @@ def test_a_denial_answers_in_that_language_too(db, client, make_user, as_user, m
monkeypatch.setattr(email_mod, "email_enabled", lambda db=None: True)
sent = _bodies(monkeypatch)
admin = make_user(email="admin@example.com", role="admin")
client.post("/auth/request-access", json={"email": "asking@example.com", "lang": "hu"})
assert (
client.post(
"/auth/request-access", json={"email": "asking@example.com", "lang": "hu"}
).status_code
== 200
)
inv = db.execute(select(Invite).where(Invite.email == "asking@example.com")).scalar_one()
sent.clear()
as_user(admin).post(f"/api/admin/invites/{inv.id}/deny")
assert as_user(admin).post(f"/api/admin/invites/{inv.id}/deny").status_code == 200
assert sent[0][1] == mailtext.MAIL_TEXT["access_denied.subject"]["hu"]
+1 -1
View File
@@ -97,7 +97,7 @@ def test_putting_a_removed_video_back_leaves_a_linked_list_clean(db, make_user,
pl.synced_fingerprint = current_fingerprint(db, pl)
pl.dirty = False
db.commit()
client.delete(f"/api/playlists/{pl.id}/items/b")
assert client.delete(f"/api/playlists/{pl.id}/items/b").status_code == 200
db.expire_all()
assert db.get(Playlist, pl.id).dirty is True
_add(client, pl.id, {"video_id": "b", "position": 1})
+1 -1
View File
@@ -67,7 +67,7 @@ def test_each_variant_is_cut_at_its_own_size(db, make_user, monkeypatch, tmp_pat
]
# Each cut is cached under its own name: asking again reaches Plex no more.
for variant in ("thumb", "thumb_sm", "art", "art_sm"):
client.get(f"/api/plex/image/pm1?variant={variant}")
assert client.get(f"/api/plex/image/pm1?variant={variant}").status_code == 200
assert len(_FakePlex.calls) == 4
@@ -105,8 +105,11 @@ def test_remove_then_put_back_is_no_change(db, make_user, as_user):
user = make_user()
pl = _seed(db, user, ["a", "b", "c", "d"], extra=())
client = as_user(user)
client.post(
f"/api/plex/playlists/{pl.id}/items/remove-bulk", json={"item_rating_keys": ["b", "d"]}
assert (
client.post(
f"/api/plex/playlists/{pl.id}/items/remove-bulk", json={"item_rating_keys": ["b", "d"]}
).status_code
== 200
)
assert _order(db, pl.id)[0] == ["a", "c"]
_add(client, pl.id, ["b", "d"], [1, 3])
+1 -1
View File
@@ -208,7 +208,7 @@ def test_an_unshowable_track_says_why_and_maps_to_a_status(client, monkeypatch):
raise subtitles.SubtitleUnavailable("bitmap")
monkeypatch.setattr(subtitles, "_extract_and_publish", _bitmap)
client.get("/api/plex/subtitle/98614/0/status")
assert client.get("/api/plex/subtitle/98614/0/status").status_code == 200
pool.run_all()
st = client.get("/api/plex/subtitle/98614/0/status").json()
assert st["state"] == "failed" and st["code"] == "bitmap"
+6 -1
View File
@@ -51,7 +51,12 @@ def test_a_link_whose_account_was_deleted_is_reported_dead(client, db, make_user
def test_a_spent_link_is_reported_dead(client, db, make_user):
raw = _issue(db, make_user(email="spent@example.com", password=_PW))
client.post("/auth/password-reset/confirm", json={"token": raw, "password": _NEW})
assert (
client.post(
"/auth/password-reset/confirm", json={"token": raw, "password": _NEW}
).status_code
== 200
)
assert client.post("/auth/password-reset/check", json={"token": raw}).json() == {"ok": False}
+58
View File
@@ -0,0 +1,58 @@
"""No test sends a request and throws the response away (E32 S2).
A discarded `client.post(...)` passes whatever it got back. As a SETUP step, a failure leaves the
test asserting on a state it never reached; as the step UNDER test, the test proves nothing. E32
found `test_youtube_sources_never_consult_the_guard` passing on a 400 that stopped the request
before the code it meant to exercise, and 53 more discarded responses across the suite. Each one
now states the status it expects; this keeps it that way.
"""
import ast
from pathlib import Path
TESTS = Path(__file__).resolve().parent
VERBS = {"get", "post", "put", "patch", "delete", "head", "options", "request"}
def discarded_requests(source: str) -> list[int]:
"""Line numbers of the statements that are a bare request call on an app path."""
hits = []
for node in ast.walk(ast.parse(source)):
if not (isinstance(node, ast.Expr) and isinstance(node.value, ast.Call)):
continue
func = node.value.func
if not (isinstance(func, ast.Attribute) and func.attr in VERBS):
continue
path = node.value.args[0] if node.value.args else None
literal = path.value if isinstance(path, ast.Constant) else None
if isinstance(path, ast.JoinedStr):
first = path.values[0] if path.values else None
literal = first.value if isinstance(first, ast.Constant) else None
if isinstance(literal, str) and literal.startswith(("/api", "/auth")):
hits.append(node.lineno)
return hits
def test_the_detector_sees_a_discarded_request_and_passes_a_checked_one():
src = (
"client.post('/api/x')\n"
"client.get(f'/auth/{u}')\n"
"assert client.post('/api/x').status_code == 200\n"
"r = client.get('/api/y')\n"
"items.get('/api/not-a-request-but-a-key')\n"
)
# The last line is a false positive by design: a dict keyed by an app path is not a thing the
# suite does, and a narrower match would miss a client held under any other name.
assert discarded_requests(src) == [1, 2, 5]
def test_no_test_discards_a_response():
offenders = [
f"{p.name}:{line}"
for p in sorted(TESTS.rglob("test_*.py"))
for line in discarded_requests(p.read_text(encoding="utf-8"))
]
assert offenders == [], (
"assert the status these requests expect (`assert client.post(...).status_code == 200`), "
f"or keep the response and check it: {offenders}"
)
+38 -13
View File
@@ -100,15 +100,22 @@ def test_a_later_registration_never_touches_an_existing_password(db, client, smt
have installed a password where the whole point is that there is none. Reverted; the owner's
recourse is password-reset, which proves the mailbox. Residual logged as SEC-16.
"""
client.post(
"/auth/register", json={"email": "victim@example.com", "password": "the first password"}
assert (
client.post(
"/auth/register", json={"email": "victim@example.com", "password": "the first password"}
).status_code
== 200
)
db.expire_all()
user = db.execute(select(User).where(User.email == "victim@example.com")).scalar_one()
before = user.password_hash
client.post(
"/auth/register", json={"email": "victim@example.com", "password": "the second password"}
assert (
client.post(
"/auth/register",
json={"email": "victim@example.com", "password": "the second password"},
).status_code
== 200
)
db.expire_all()
@@ -116,8 +123,11 @@ def test_a_later_registration_never_touches_an_existing_password(db, client, smt
def test_a_later_registration_leaves_a_link_already_in_flight_alive(db, client, smtp_on, wire):
client.post(
"/auth/register", json={"email": "victim@example.com", "password": "the first password"}
assert (
client.post(
"/auth/register", json={"email": "victim@example.com", "password": "the first password"}
).status_code
== 200
)
db.expire_all()
user = db.execute(select(User).where(User.email == "victim@example.com")).scalar_one()
@@ -126,8 +136,12 @@ def test_a_later_registration_leaves_a_link_already_in_flight_alive(db, client,
# would go green while asserting nothing the day registration stops issuing a token.
assert len(first) == 1
client.post(
"/auth/register", json={"email": "victim@example.com", "password": "the second password"}
assert (
client.post(
"/auth/register",
json={"email": "victim@example.com", "password": "the second password"},
).status_code
== 200
)
db.expire_all()
@@ -148,8 +162,12 @@ def test_a_stripped_account_keeps_its_recovery_stamp(db, client, smtp_on, make_u
password_revoked_at=datetime.now(timezone.utc),
)
client.post(
"/auth/register", json={"email": "stripped@example.com", "password": "an attacker password"}
assert (
client.post(
"/auth/register",
json={"email": "stripped@example.com", "password": "an attacker password"},
).status_code
== 200
)
db.expire_all()
@@ -169,7 +187,9 @@ def test_a_denied_sibling_is_not_reopened_while_a_pending_row_exists(db, client)
)
db.commit()
client.post("/auth/request-access", json={"email": "pairone@gmail.com"})
assert (
client.post("/auth/request-access", json={"email": "pairone@gmail.com"}).status_code == 200
)
db.expire_all()
rows = {i.email: i.status for i in db.execute(select(Invite)).scalars().all()}
@@ -195,7 +215,7 @@ def test_an_env_granted_address_cannot_be_shadowed_by_a_stranger(db, client, mon
# env grant. With the env list matched canonically the request never opens a row.
monkeypatch.setattr(settings, "allowed_emails", "bob@gmail.com")
client.post("/auth/request-access", json={"email": "b.ob@gmail.com"})
assert client.post("/auth/request-access", json={"email": "b.ob@gmail.com"}).status_code == 200
assert db.execute(select(Invite)).scalars().all() == []
assert auth_core.is_allowed(db, "bob@gmail.com") is True
@@ -331,7 +351,12 @@ def test_two_admins_two_languages_two_mails(db, client, make_user, smtp_on, wire
make_user(email="hu.admin@example.com", role="admin", preferences={"language": "hu"})
make_user(email="en.admin@example.com", role="admin", preferences={"language": "en"})
client.post("/auth/request-access", json={"email": "asking@example.com", "lang": "en"})
assert (
client.post(
"/auth/request-access", json={"email": "asking@example.com", "lang": "en"}
).status_code
== 200
)
notices = [w for w in wire if "asking@example.com" in w[1]]
assert len(notices) == 2
+2 -2
View File
@@ -53,8 +53,8 @@ def test_default_is_per_source(db, monkeypatch, override_dep):
pid = c.post("/api/saved-views", json={"name": "P", "filters": {}, "source": "plex"}).json()[
"id"
]
c.patch(f"/api/saved-views/{fid}", json={"is_default": True})
c.patch(f"/api/saved-views/{pid}", json={"is_default": True})
assert c.patch(f"/api/saved-views/{fid}", json={"is_default": True}).status_code == 200
assert c.patch(f"/api/saved-views/{pid}", json={"is_default": True}).status_code == 200
# Making the Plex view default must NOT clear the feed view's default (different source).
assert c.get("/api/saved-views?source=feed").json()[0]["is_default"] is True
assert c.get("/api/saved-views?source=plex").json()[0]["is_default"] is True
+6 -2
View File
@@ -68,8 +68,12 @@ def test_using_the_link_evicts_whoever_held_the_old_password(db, as_user, make_u
admin = make_user(role="admin")
db.commit()
token = _link(as_user(admin), target.id)
client.post(
"/auth/password-reset/confirm", json={"token": token, "password": "the owner's own choice"}
assert (
client.post(
"/auth/password-reset/confirm",
json={"token": token, "password": "the owner's own choice"},
).status_code
== 200
)
db.refresh(target)
+6 -1
View File
@@ -229,7 +229,12 @@ def test_registering_again_does_not_create_a_second_account(db, client, monkeypa
_smtp_on(monkeypatch)
_capture(monkeypatch, "send_verify_email")
for _ in range(2):
client.post("/auth/register", json={"email": "twice@example.com", "password": _PW})
assert (
client.post(
"/auth/register", json={"email": "twice@example.com", "password": _PW}
).status_code
== 200
)
db.expire_all()
rows = db.execute(select(User).where(User.email == "twice@example.com")).scalars().all()