Files
upload-platform/HISTORY/2026-09-05-gemini-review-qa.md

5.5 KiB

Вопросы и ответы по ревью Gemini 3.8 Flash — 2026-09-05

Контекст

После критического разбора ревью Gemini 3.8 Flash были заданы уточняющие вопросы по версии исходников, дублированию API, семантике File.name, legacy XSS, build.mjs, ZIP-фильтрации и приоритетам исправлений.

Зафиксированные ответы

Версия кода и номера строк

Ревью выполнялось по исходникам upload-platform; dist/ отдельно не исследовался. Номера строк в первой сводке были смещены из-за объединения отчётов субагента. Фактические участки находятся в текущих исходниках on_files_change.js и list_zip_files.js.

init_upload_table.js

Буквального совпадения интерфейса с initFilePicker нет: один entry point принимает готовые DOM-узлы, другой создаёт DOM внутри mount. Однако внутренняя логика жизненного цикла таблицы параллельна: состояние nodes/fileKeys/busy, удаление узлов, делегирование кликов и похожий API. Файл не входит в граф сборки build.mjs, поэтому это legacy-альтернатива, создающая риск рассинхронизации.

File.name и логический путь

flattenFiles() возвращает name, path и file раздельно, но при rebaseTree вложенный browser File получает полный путь в file.name. При прямом FormData.append('files', file) сервер получает filename с разделителями пути. Это может конфликтовать с серверными basename/secure_filename и нарушает обычный контракт browser File, где name является базовым именем. При явной передаче третьего аргумента FormData.append('files', file, path) проблема не возникает.

XSS в set_status.js

Замечание относится только к legacy-файлу. set_status.js не входит в активный граф сборки и не используется боевым рендерером. В активном render.js значения статуса экранируются через esc(). Реальная уязвимость в текущем активном рендеринге не подтверждена; пункт относится к гигиене мёртвого кода.

build.mjs

Для top-level await необработанная ошибка сборки сама приводит Node.js к завершению с ненулевым кодом. Явные try/catch и process.exit(1) технически избыточны. Реальное возможное улучшение этого пункта — определить поведение каталога dist/ перед сборкой, например его предварительную очистку.

Проверка фильтра fflate

Проверка исходника fflate подтвердила, что filter вызывается после чтения метаданных ZIP entry, но до копирования или декомпрессии данных. Если фильтр возвращает false, inflateSync для этой записи не вызывается и буфер для распакованных данных не создаётся. Поэтому добавление проверки расширения в filter является корректным способом не распаковывать тяжёлые неразрешённые entries.

Приоритет до прода

Согласован обязательный приоритет:

  1. №2: отбрасывать неразрешённые расширения внутри ZIP filter до декомпрессии, чтобы снизить риск OOM и лишнего расхода бюджета.
  2. №1: сбрасывать elements.fileInputEl.value, чтобы повторный выбор того же файла после удаления снова генерировал change.
  3. №5: объединять корневые папки с одинаковыми путями, чтобы избежать дублирующихся деревьев при последовательном выборе.

Пункты File.name, onError, fallback-конфигурация, legacy-код и очистка служебных каталогов отнесены ко второй очереди.

Итог

Уточнение подтвердило, что главным техническим finding является ZIP-фильтрация до декомпрессии. Пункты про set_status.js и явный process.exit(1) не являются активными production-дефектами. Исправления кода в рамках этой записи не выполнялись.