Ревью: тесты-регрессии на найденные дефекты

Четыре теста закрывают то, что чинил предыдущий коммит: обход каталога
ачивок через slug, неподвижная версия партии при правке участников,
удаление группы с партиями (409 вместо 500) и разжалование последнего
владельца.

#8

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186Fk74jkkszahEHSjBzTjD
This commit is contained in:
2026-09-09 15:26:42 +03:00
co-authored by Claude Opus 5
parent 9d9e4a345a
commit 62d75ea176
3 changed files with 98 additions and 0 deletions
+16
View File
@@ -111,3 +111,19 @@ def test_update_and_delete(client: TestClient, make_admin, monkeypatch, tmp_path
f"/api/admin/achievements/{slug}", headers=csrf_headers(client)
).status_code == 200
assert all(a["slug"] != slug for a in client.get("/api/admin/achievements").json())
def test_delete_rejects_traversal_slug(client: TestClient, make_admin, monkeypatch, tmp_path):
"""Slug из URL не должен уводить файловые операции за каталог ачивок.
Регрессия: `DELETE /api/admin/achievements/%2E%2E` снимал rmtree'ом родительскую
папку каталога (в проде это /data — БД, uploads и ачивки разом)."""
root = _use_tmp_achievements(monkeypatch, tmp_path / "achievements")
root.mkdir(parents=True, exist_ok=True)
sibling = tmp_path / "db.sqlite3"
sibling.write_bytes(b"data")
_admin(client, make_admin)
r = client.delete("/api/admin/achievements/..", headers=csrf_headers(client))
assert r.status_code == 404, r.text
assert sibling.exists() and root.is_dir()