Files
orchestrator/docs/work-items/ORCH-095/04-test-plan.yaml

96 lines
6.3 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
work_item: ORCH-095
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-09
model_used: claude-opus-4-8
title: "HTML-безопасность динамических полей render_task_tracker (фикс инъекции «<1м»)"
framework: pytest
scope: >
Покрывается: HTML-безопасность всех подставляемых данных в render_task_tracker
(длительности < 1 мин, токены/стоимость, имя модели/эффорт, статус-лейбл, заголовок со
спецсимволами), сохранность намеренной разметки (<a href> номер задачи, _done_link),
возобновление обновлений застрявшей карточки, never-raise. Вне покрытия: реальная сеть к
Telegram Bot API (мокируется httpx), изменения STAGE_TRANSITIONS/QG_CHECKS/схемы БД (не
трогаются).
notes: >
Тесты — изоляция от сети: httpx.post/get мокируются; БД — временная SQLite-фикстура с
задачей и agent_runs (стадия < 60 с). Полный регресс pytest tests/ -q должен оставаться
зелёным, включая существующие test_telegram_tracker.py / test_tracker_*.py /
test_notifications_orphans.py / test_notify_issue_links.py. Регрессом считается: красный
любой существующий тест трекера, заэкранированная намеренная разметка, двойное
экранирование, непойманное исключение в пути рендера.
tests:
- id: TC-01
type: unit
description: "_fmt_minutes для длительности < 60 с (напр. 30) не возвращает сырой '<1м': результат HTML-безопасен (&lt;1м либо переформулированный '~0м'/'< 1 мин' без сырого '<')."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-02
type: unit
description: "_fmt_minutes для граничных входов (0, None, нечисловое, ровно 60, большое значение) — never-raise и HTML-безопасный вывод во всех ветках."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-03
type: unit
description: "render_task_tracker для задачи со стадией < 1 мин: в выходном тексте нет неэкранированного '<' из данных длительности; подстрока длительности безопасна для parse_mode=HTML."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-04
type: unit
description: "render_task_tracker с заголовком, содержащим спецсимволы '<', '>', '&' (напр. 'A <b>x</b> & <1'): спецсимволы данных присутствуют только экранированными (&lt;/&gt;/&amp;), не как сырые теги; двойного экранирования (&amp;lt;) нет."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-05
type: unit
description: "Статус-лейбл (_card_status_label) и имя модели/эффорт, попадающие в текст карточки, экранированы (defence-in-depth): спецсимволы в них не ломают HTML."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-06
type: unit
description: "Метрики токенов/стоимости (fmt_tokens/fmt_cost) в карточке HTML-безопасны: '$' и числовой формат не порождают сырых тегов."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-07
type: unit
description: "Регресс намеренной разметки: кликабельный номер задачи (plane_issue_link -> <a href>) присутствует в выводе как валидный незаэкранированный <a>-тег; href/label не задвоены экранированием."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-08
type: unit
description: "Регресс _done_link: для завершённой задачи строка '🔗 PR #n · 📦 Внедрено' рендерится валидной (ссылочная разметка не экранирована)."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-09
type: integration
description: "update_task_tracker (edit-режим) с замоканным editMessageText: текст карточки со стадией < 1 мин принимается (мок ассертит отсутствие 'can't parse entities'-триггера, т.е. нет сырого '<1м' в payload text)."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-10
type: integration
description: "Возобновление застрявшей карточки (AC-4): после фикса валидный рендер проходит edit-путь без EDIT_FAILED из-за parse-ошибки; защита от дублей сохранена — транзиентный (network) фейл по-прежнему НЕ плодит новую карточку."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-11
type: unit
description: "never-raise: render_task_tracker на 'битых' входах (отсутствует задача, None-заголовок, нечисловые длительности) возвращает fallback-строку, не выбрасывает исключение."
module: tests/test_tracker_html_escape.py
expected: PASS
- id: TC-12
type: integration
description: "Полный регресс существующих тестов трекера (test_telegram_tracker.py, test_tracker_issue_link.py, test_tracker_status_line.py, test_notifications_orphans.py, test_notify_issue_links.py) остаётся зелёным после фикса."
module: tests/test_telegram_tracker.py
expected: PASS