Opening a purged note, or one of its files, is a 404

get_note and get_attachment selected with the ACL inline and skipped the purged
filter, so a tombstone came back 200 (#2128 says a purged note reads as absent).
Both now go through _get_visible, which cannot skip it. Reorder's batch lookup
gains the same filter, so a stale id cannot write a place onto a tombstone.

Fixes #5383.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 14:09:40 -04:00
co-authored by Claude Opus 5.5
parent 8eff5f60a6
commit bfab8746ad
2 changed files with 26 additions and 14 deletions
+16
View File
@@ -891,6 +891,22 @@ async def test_an_offline_attachment_uploads_once_under_its_own_id(app_client, d
assert (await _put(app_client, aid, other, b"%PDF-1")).status_code == 409, "one id, one note"
async def test_a_purged_note_and_its_files_read_as_gone(app_client, db):
"""A purged note reads as absent (#2128). Opening it and its attachment selected
with the ACL inline and skipped that filter, so a tombstone came back 200 (#5383)."""
await _signed_in(app_client, "purged")
nid = await _pushed_note(app_client)
aid = str(uuid.uuid4())
assert (await _put(app_client, aid, nid, b"%PDF-1")).status_code == 201
assert (await app_client.get(f"/api/notes/{nid}/attachments/{aid}")).status_code == 200
assert (await app_client.post(f"/api/notes/{nid}/trash")).status_code == 200
assert (await app_client.delete(f"/api/notes/{nid}")).status_code == 200
assert (await app_client.get(f"/api/notes/{nid}")).status_code == 404
assert (await app_client.get(f"/api/notes/{nid}/attachments/{aid}")).status_code == 404
async def test_an_upload_to_a_note_the_caller_does_not_own_is_not_found(app_client, db):
# Signed in first: registration is open only to the first account.
await _signed_in(app_client, "intruder")