Рефакторинг рендера [этап 1/6]: единый модуль sanitizer.py, санитайз per-post внутри _render_pipeline #22
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Часть эпика «Рефакторинг пайплайна рендера» (см. эпик-ишью, этап 1 из 6, выполняется первым).
Цель
Один конфиг bleach на весь проект, один санитайз на пост, ноль thread-hop'ов в циклах. Сейчас конфиг скопирован в трёх местах и уже разъехался, а RSS-путь делает отдельный
asyncio.to_threadна каждый пост.Намеренные изменения поведения (фиксируются этим этапом)
s,delразрешены и в фидах (сейчас зачёркивание выживает только в одиночном посте:post_parser._sanitize_htmlих разрешает, обе копии вrss_generator— нет).PostParser._sanitize_htmlпри исключении bleach возвращал сырой HTML (fail-open) → теперьhtml.escape(fail-closed).<hr class="post-divider">в HTML-фиде теперь реально виден — сейчас он добавляется ДО финального санитайза, аhrнет в whitelist, и bleach соstrip=Trueмолча вырезает все разделители.Новый файл
sanitizer.pyПравки
post_parser.py_sanitize_html(~строки 702–737) → однострочный делегат вsanitizer.sanitize_html. Метод оставить — его зовётprocess_message. Веткаreturn html_rawпри исключении исчезает (фикс №2).rss_generator.py_render_pipeline(~строка 344): после_render_messages_groupsдобавитьfor p in posts: p['html'] = sanitize_html(p['html']). Комментарий: sanitize runs here because the whole pipeline already executes in a worker thread.rss_generator.pyцикл RSS-entries (~строки 458–497): удалить вложенный_sanitize_sync,try/exceptиto_thread—fe.content(content=post['html'], type='CDATA')напрямую.rss_generator.pyHTML-путь (~строки 671–705): удалить_concat_html+to_threadи_sanitize_sync+to_thread; остаётсяhtml = '\n<hr class="post-divider">\n'.join(p['html'] for p in final_posts)— join ПОСЛЕ санитайза (фикс №3).rss_generator.py._render_pipelineдля фидов;process_message(sanitize=True)для одиночного поста — путьget_postНЕ трогать).Крайние случаи
fe.description(post['text']...)не трогать — feedgen сам XML-эскейпит.Тесты
Новый
tests/test_sanitizer.py:s/delвыживают после sanitize_html;script/onerrorвырезаются;generate_channel_htmlприсутствует<hr class="post-divider">.Прогнать
tests/test_stage4_eventloop.py— он закрепляет старые границы санитайза; при конфликте обновить тест с комментарием-ссылкой на номер фикса из списка выше.DoD
rss_generator.pyнет прямых вызовов bleach;pytestполностью зелёный.Общие правила эпика
Ветка
refactor/render-pipeline(отfeat/kurigram-2.2.23после коммита её текущих правок), один этап = один коммит, комментарии в коде только на английском, точечные правки без переписывания файлов целиком.Устарело: ишью создавалось по v1 спеки. Спека прошла пять раундов адверсариального ревью и дошла до v5 (
plans/2026-07-05-render-pipeline-refactor.md) — состав этапа 1 существенно изменился (protocols/strip в sanitizer, §3.16 единое имя санитайз-лога, log_context, зависимость от нового этапа 0 с golden-эталонами). Закрыто как superseded; замена — новый набор ишью по этапам 0–6 спеки v5.