fix: XSS в debug-title (#13) + order-independent тест-сьют (#17) #20

Merged
agent_vscode merged 1 commits from fix/issues-13-17 into main 2026-07-05 17:22:02 +03:00
Collaborator

Closes #13, closes #17.

#13 — reflected XSS в debug-выводе /post/html

data["html"]["title"] вставлялся в debug-HTML без экранирования (title никогда не проходит bleach). Теперь html.escape, единообразно с соседним raw_message. Аудит debug-ветки: других сырых вставок нет (body/footer санитайзятся в process_message). Регрессионный тест: poll с <script> в вопросе → в выводе только экранированная форма (проверено, что тест падает на старом коде).

#17 — «голый» pytest давал 22 падения

Причины: tests/pytest.ini не подхватывался при запуске из корня (терялся asyncio_mode=auto, коллектились файлы из .venv), плюс каждый тест-модуль на импорте загрязнял sys.modules['config']. Фикс:

  • корневой pytest.ini с testpaths = tests (старый tests/pytest.ini удалён — конфиг один);
  • tests/conftest.py централизованно ставит sys.path и мок config до импорта тест-модулей;
  • преамбулы удалены из всех 10 тест-модулей.

Проверено

Все три способа запуска дают одинаковый результат — 261 passed (260 + новый XSS-тест):

pytest                (из корня)  → 261 passed
pytest tests/         (из корня)  → 261 passed
cd tests && pytest                → 261 passed

Ревью пройдено: проблем не найдено (в т.ч. проверены двойное экранирование, идемпотентность conftest, эквивалентность ini, отсутствие лишних удалений).

🤖 Generated with Claude Code

Closes #13, closes #17. ## #13 — reflected XSS в debug-выводе `/post/html` `data["html"]["title"]` вставлялся в debug-HTML без экранирования (title никогда не проходит bleach). Теперь `html.escape`, единообразно с соседним `raw_message`. Аудит debug-ветки: других сырых вставок нет (body/footer санитайзятся в `process_message`). Регрессионный тест: poll с `<script>` в вопросе → в выводе только экранированная форма (проверено, что тест падает на старом коде). ## #17 — «голый» pytest давал 22 падения Причины: `tests/pytest.ini` не подхватывался при запуске из корня (терялся `asyncio_mode=auto`, коллектились файлы из `.venv`), плюс каждый тест-модуль на импорте загрязнял `sys.modules['config']`. Фикс: - корневой `pytest.ini` с `testpaths = tests` (старый `tests/pytest.ini` удалён — конфиг один); - `tests/conftest.py` централизованно ставит sys.path и мок config **до** импорта тест-модулей; - преамбулы удалены из всех 10 тест-модулей. ## Проверено Все три способа запуска дают одинаковый результат — **261 passed** (260 + новый XSS-тест): ``` pytest (из корня) → 261 passed pytest tests/ (из корня) → 261 passed cd tests && pytest → 261 passed ``` Ревью пройдено: проблем не найдено (в т.ч. проверены двойное экранирование, идемпотентность conftest, эквивалентность ini, отсутствие лишних удалений). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
agent_vscode added 1 commit 2026-07-05 17:20:34 +03:00
fix: escape debug title (XSS) and make test suite order-independent
Docker Image CI / build (pull_request) Has been cancelled
f13d1507ad
Issue #13: data["html"]["title"] was embedded into the debug HTML of
/post/html without escaping; title never passes through bleach, so a post
whose generated title carries markup (e.g. a poll question) was a reflected
XSS under ?debug=true. Escape it with html.escape, same as raw_message.
Add a regression test with a <script> payload in a poll question.

Issue #17: a bare 'pytest' from the repo root failed 22 tests because the
config in tests/pytest.ini was not picked up (asyncio_mode lost, .venv
collected) and every test module polluted sys.modules['config'] at import
time. Move the config to a root pytest.ini with testpaths=tests, and
centralize the sys.path bootstrap + config mock in tests/conftest.py, which
pytest imports before any test module. Drop the per-module preambles.

Closes #13, closes #17

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
agent_vscode merged commit 4fc8ebbd03 into main 2026-07-05 17:22:02 +03:00
agent_vscode deleted branch fix/issues-13-17 2026-07-05 17:22:03 +03:00
Sign in to join this conversation.