Кратко
- Тест задаёт порог в один байт, переводит непустые элементы на диск и точно сравнивает результат
FileUpload.getBytes()с исходными данными. - За именами
organizations.xlsxиcarta-ce.pdfскрываются короткие синтетические строки, а не настоящая книга OOXML и полный PDF-документ. - Такой быстрый тест следует сохранить, но его утверждение нужно связать с отдельными свидетельствами формата, предметных правил, полномочий и ресурсных ограничений.
Что именно стало зелёным
11 сентября 2026 года в публичном репозитории выборной системы LACNIC появился метод wicketFileUploadGetBytesWorksForDiskBackedExcelAndPdf. В его имени соединены механизм хранения и два знакомых пользователю формата. Код действительно испытывает механизм хранения. Форматы присутствуют только как имена файлов и назначение синтетических массивов.
Тест создаёт DiskFileItemFactory, указывает временный каталог JUnit и устанавливает размер буфера равным 1. При таком пороге любой из двух непустых примеров должен перейти с хранения в памяти на временный файл. Вспомогательная функция записывает байты в multipart-элемент, оборачивает его в Wicket FileUpload, вызывает getBytes(), а затем сравнивает массив с оригиналом. Удаление временного элемента выполняется в finally.
Проверка отвечает на важный вопрос обновления зависимостей. Commons FileUpload может держать малые элементы в памяти, а более крупные — на диске. Обёртка фреймворка должна одинаково прочитать оба состояния. Ошибка на границе временного файла способна не проявиться в обычном тесте с короткой строкой, если её оставить в памяти. Принудительный порог делает выбранную ветку наблюдаемой.
Но переменная spreadsheet содержит только ORGID, перевод строки и ALFA-001. У настоящей .xlsx есть ZIP-контейнер OOXML, части, отношения и XML. Переменная pdf содержит %PDF-1.1, перевод строки, %carta и ещё один перевод строки. У неё есть начальная сигнатура, но отсутствует структура завершённого PDF. Ни XSSFWorkbook, ни PDF-парсер в методе не вызываются.
Поэтому точное утверждение выглядит так: Wicket вернул те же байты, которые были записаны в дисковый multipart-элемент. Тест не утверждает, что файл открывается, содержит требуемые поля, отправлен уполномоченным человеком или приводит к ожидаемому изменению. Такая формулировка не обесценивает результат. Наоборот, она позволяет использовать его как надёжный диагностический чек именно для адаптера.
Другие гарантии находятся в других местах
Соседние тесты показывают, что разработчики умеют пересекать границу от имени к содержимому. Текст с названием photo.jpg передаётся валидатору фотографии кандидата и должен получить отказ «неверный формат». Другой случай создаёт реальный PNG, прогоняет его через обработчик, ждёт JPEG и заново декодирует результат, проверяя размеры не более 400 на 400 пикселей. Изображение обязано быть изображением, а не просто набором байтов с подходящим суффиксом.
Маршрут книг организаций также не заканчивается расширением. OrganizationExcelFileValidator сначала продолжает обработку, если имя завершается на .xlsx либо заявленный MIME соответствует таблице OOXML. Оба сигнала задаются клиентом, поэтому это предварительный фильтр. Для должников и удалений байты направляются на удалённую проверку. Для добавлений и обновлений детальная проверка запускается при отправке формы.
В ExcelUtils данные записываются во временный файл. Код требует MIME OOXML, создаёт Apache POI XSSFWorkbook, выбирает первый лист, ищет обязательные заголовки и обходит строки. Список должников должен иметь ORGID; массовое обновление требует более широкого набора столбцов. Пустые и повторяющиеся идентификаторы, отсутствующие столбцы и недопустимые значения получают предметные ошибки. Панель до постановки задачи проверяет применимость операции к выборам. Если обработка уже идёт, второй запрос не ставится.
Таким образом, строка ORGID\nALFA-001 закономерно проходит новый тест и закономерно не проходит реальный XSSFWorkbook. Первый результат говорит о сохранности байтов. Второй — о структуре документа. Их нельзя сводить к одной галочке.
Загрузка списка избирателей устроена похожим образом. Панель получает FileUpload, проверяет возможность применить обновление к указанным выборам и лишь затем пытается поставить работу в очередь. Новый тест повторяет способ чтения байтов, но не запускает разбор книги, проверку колонок или выборное решение.
Для писем о результатах действует иной набор. Multipart-форма ограничена 10 МБ. При сохранении страница заново загружает выборы, обеспечивает контроль доступа и прекращает действие, если выборы закрыты. Необязательные испанское, английское и португальское письма проверяются до записи выбранных байтов с контекстом администратора и клиентского адреса.
При этом ElectionResultLetterSupport.isPdf смотрит только на первые четыре байта %PDF. Короткая тестовая строка удовлетворяет такому условию. Она не доказывает, что файл откроется в PDF-программе или имеет целостную структуру. Лимит, полномочия и статус выборов остаются реальными контролями, но не становятся от этого проверкой документа.
Пять независимых квитанций
Удобнее говорить не «загрузка работает», а хранить несколько квитанций приёмки.
Транспортная квитанция проверяет режим памяти и режим диска, явно утверждает isInMemory() == false, сравнивает байты, закрывает потоки и следит за очисткой. Новый метод LACNIC уже составляет её основу. Название о сохранении байтов через FileUpload.getBytes() не было бы скромнее по существу — оно точнее указывало бы защищённое свойство.
Форматная квитанция использует настоящие документы. Для OOXML нужна минимальная книга, созданная POI или совместимым инструментом, с требуемым листом и заголовками. Рядом нужны ZIP, который не является OOXML, оборванный пакет и зашифрованный случай в соответствии с политикой. Для PDF нужен полный минимальный файл, принимаемый выбранным парсером, а также один заголовок, обрыв и уместные обманные образцы. Расширение, MIME и сигнатура полезны, но не заменяют структуру.
Предметная квитанция ведёт настоящую книгу через правила организаций или списка избирателей. Она различает невозможность открыть файл, отсутствие колонки, пустую строку, повторный ORGID, неправильную страну или число голосов. Она проверяет отчёт об ошибках и отсутствие поставленной работы после отказа. Для условий выборов нужен известный начальный набор данных и заранее определённый результат.
Процедурная квитанция проверяет право и эффект. Уполномоченный администратор работает с открытыми выборами; неподходящая сессия и закрытые выборы получают отказ. Валидный файл создаёт ровно одну задачу с правильным контекстом, а параллельная отправка встречает защиту «обработка уже выполняется». Для трёх писем отказ одного файла должен произойти до применения какой-либо части обновления.
Ресурсная квитанция измеряет размер запроса, память, временное расположение, очистку, время разбора и распакованный объём. Commons FileUpload описывает порог хранения и ограничения размера. Apache POI предупреждает, что парсинг чужих документов требует дополнительных барьеров: библиотека не может полностью исключить вредные эффекты. ZipSecureFile задаёт минимальное отношение сжатия и максимальный распакованный размер записи. OWASP рекомендует совмещать полномочия, разрешённые расширения, MIME, сигнатуру и ограничения после распаковки.
Эти рекомендации не доказывают уязвимость LACNIC. Источник — снимок открытого репозитория, а не производственная среда. В закреплённом POM административного модуля указан Wicket 10.9.0; модуль WildFly ссылается на POI OOXML 5.0.0. Это сведения о дереве кода. Близость изменения зависимостей и нового теста по времени также не означает, что обновление вызвало сбой или что такой сбой вообще происходил.
Узкое свидетельство служит дольше
Маленький тест выигрывает скоростью и локальностью. Если после обновления Commons FileUpload чтение с диска ломается, он указывает на стык библиотек раньше, чем к расследованию добавятся парсер, данные выборов и очередь. Если он проходит, результат можно трактовать без догадок: байты пережили эту границу.
Риск создаёт не код, а сокращённый пересказ. Названия тестов попадают в проверки релиза и институциональную память. Фраза «Excel и PDF на диске работают» легко вытесняет более точное описание. Позже она может быть предъявлена как гарантия документа или процедуры. Переименование и ссылка на отдельные квитанции стоят дёшево до инцидента и дорого после него.
Разделение помогает и самим фикстурам. Синтетические массивы должны оставаться маленькими для транспортной проверки. Настоящие документы должны версионироваться отдельно и иметь понятное происхождение. Предметные книги должны содержать известные строки и ожидаемые результаты. Один большой образец для всего ухудшает диагностику; несколько минимальных образцов сообщают, какая именно гарантия перестала выполняться.
Полезен и отдельный журнал отрицательных примеров. Он должен объяснять, почему каждый файл отвергается: потому что это обычный ZIP, оборванный OOXML, книга без обязательного листа, повторный идентификатор или PDF только с заголовком. Тогда изменение сообщения или поведения можно оценить без угадывания. Если же все повреждённые файлы свести к одному непрозрачному бинарному образцу, зелёный результат не покажет, какие ветви действительно сработали. Версионированный набор минимальных случаев позволяет связывать каждую ошибку с правилом, а каждое правило — с пользовательским последствием.
При обновлении POI, Wicket или Commons изменившийся слой станет виден сразу. Такой журнал также удерживает границу между общей защитной рекомендацией и фактом о приложении: он показывает только те пределы, которые тест действительно вызвал и измерил, не приписывая производственной среде непроверенные настройки.
Для администраторского интерфейса важна точность обратной связи. Невалидный документ, конфликт уже выполняющейся задачи и закрытые выборы требуют разных действий. Первый нужно исправить, второй — дождаться, третий — нельзя обходить. Тесты должны сохранять это различие и убеждаться, что отказ не оставляет частичного изменения. Тогда техническая классификация становится частью управляемого процесса, а не скрытой деталью исключения.
Источники
- Описание выборной системы LACNIC
- Закреплённый commit LACNIC
- Тест multipart-совместимости
- Валидатор Excel для организаций
- Панель результатов выборов
- Поддержка писем о результатах
- Утилиты обработки книг
- Панель загрузки организаций
- Панель загрузки списка избирателей
- Исходный код FileUpload в Wicket 10.9.0
- Документация Commons DiskFileItem
- Руководство Commons FileUpload
- Рекомендации по безопасности Apache POI
- Документация Apache POI ZipSecureFile
- Рекомендации OWASP по загрузке файлов
- POM административного модуля LACNIC
- Модуль POI OOXML в LACNIC
Обзор для участников
Подробный контекст профиля
Войдите с подходящим уровнем подписки, чтобы открыть полный обзор и примечания к источникам.
Только для Стратегического сообщества
Стратегическое сообщество
Открыто всем читателям. Вступите и войдите, чтобы открыть обзоры профилей.
Вступить в Стратегическое сообществоТолько для Альянса лидеров
Альянс лидеров
Для проверенных владельцев IP-активов и руководителей. Войдите, чтобы открыть обзоры Альянса.
Вступить в Альянс лидеров
