[1] critical Файл: .gitlab-ci.yml Строка: 55-124 Тип: security Описание: `sshpass -p "$SSH_PASSWORD"` хранит пароль в CI-шаблоне и подставляет его в командную строку, что делает его доступным в логах и передаёт его в открытом виде через процесс. Это критический риск компрометации SSH-доступа. Решение: используйте SSH-ключи (deploy keys или GitLab-internal deploy token) и эскалируйте их через `ssh-agent`/`gitlab-ci.yml` с `ssh-add`, либо передавайте защищённый GitLab Secret Variable и избегайте `sshpass -p` вообще. [2] major Файл: .gitlab-ci.yml Строка: 63-129 Тип: security Описание: `ssh -o StrictHostKeyChecking=no` отключает проверку fingerprint удалённого хоста, оставляя CI уязвимым к MITM-атакам, особенно в сочетании с передачей пароля. Нужно зафиксировать ключ хоста в `known_hosts` и избегать `StrictHostKeyChecking=no` (или использовать `ssh-keyscan` один раз при сохранении ключа и затем запускать с настройкой, не принудительно отключающей проверку). [3] major Файл: .gitlab-ci.yml Строка: 67-130 Тип: code-smell Описание: Блок `script` в `deploy` содержит всю логику инициализации, обхода директорий, настройки git, выбора аутентификации и `git pull` — это нарушает принцип единственной ответственности и затрудняет отладку/повторное использование. Вынесите этот сценарий в отдельный `deploy.sh` (или `bash <<<`-скрипт в репозитории), разделите обязанности (поиск пути, настройка аутентификации, деплой) и добавьте явные `set -euo pipefail` и логирование, чтобы поддерживать читаемость и обеспечивать воспроизводимость. [4] major Файл: ai-review.js Строка: 141-186 Тип: code-smell Описание: `loadPromptForDeepSeek` одновременно загружает промпт по URL, обрабатывает ошибки, берет локальный файл и даже строит адаптацию, что делает функцию перегруженной и трудно тестируемой. Поделите на вспомогательные функции: загрузку файла, проверку наличия, генерацию fallback, и оставьте читаемую цепочку возвратов. Это упростит поддержку и даст точные точки отказа. [5] major Файл: ai-review.js Строка: 189-266 Тип: code-smell Описание: `adaptPromptForCodex` собирает текстовый промпт методом конкатенации через множество вложенных веток, повторяя шаблоны для контекста, связанных файлов и др., что порождает высокую сложность и риски ошибок (например, пропущенные переносы). Переформатируйте генерацию в последовательность вспомогательных функций/шаблонов, собирая блоки через массивы и `join`, чтобы уменьшить вложенность и улучшить читабельность. [6] major Файл: ai-review.js Строка: 307-352 Тип: code-smell Описание: `getChangedFiles` пробует три разных диффа и молча игнорирует ошибки, затем падает на `git ls-files`; это делает поведение неявным, и трудно понять, какую ветку он реально использовал. Разделите на явные стадии (`tryCollectFromMergeRequest`, `tryCollectFromPush`, `fallbackAllFiles`) с логами и четкими обработчиками ошибок, а также не игнорируйте исключения, чтобы было видно, что пошло не так. [7] major Файл: ai-review.js Строка: 369-401 Тип: performance Описание: `buildFilesContentPrompt` читает содержание всех изменённых файлов целиком и добавляет его в промпт без лимитов, что может привести к огромным запросам к DeepSeek/OpenAI и переполнению квот. Добавьте ограничения на общий размер/количество файлов, пропускайте бинарные и большие файлы или используйте `head`/`tail`, а также собирайте контент порционно, чтобы не отправлять десятки мегабайт. [8] major Файл: ai-review.js Строка: 431-612 Тип: code-smell Описание: `parseTextReport` содержит десятки регулярных выражений и ручных состояний, объединённых в одну функцию, и обрабатывает несколько форматов (маркерные блоки, фразы «проблем не найдено», fallback). Это тяжело поддерживать и расширять; выносите каждый парсер в отдельный метод, используйте структуру для метаданных (паттерн-обработчик) и делайте обработку фраз «no issues» и fallback отдельными этапами, чтобы упростить тестируемость. [9] major Файл: ai-review.js Строка: 650-689 Тип: code-smell Описание: `extractCodeWithContext` смешивает чтение файла, расширение контекста, поиск границ блока, и вычисление `actualStartLine`, делая функцию громоздкой, а также модифицирует `endLine` внутрь (побочный эффект). Разделите логику: валидируйте линии, выделите чтение/шаблон в отдельную функцию, а heuristics (`findCodeBlockEnd`) вызывайте до построения объекта, чтобы легче отслеживать состояние и избежать случайных модификаций входных параметров. [10] major Файл: ai-review.js Строка: 692-770 Тип: code-smell Описание: `extractCodeSnippetsFromDeepSeekResults` обрабатывает множество кейсов (код в описании, чтение из файла, контекст, связанные файлы) в одной функции, в которой циклы и вложенные ветки делают управление сложным и шумным. Разбейте её на этапы: сначала извлечь код/описание (вспомогательная функция), затем собрать связанный контекст, а затем построить DTO; это поможет избежать дублирования логики и упростит юнит-тестирование. [11] major Файл: ai-review.js Строка: 803-839 Тип: code-smell Описание: `getOpenAIApiKey` жёстко смешивает проверку существования файла, чтение JSON, валидацию структуры и установку глобального состояния, и в случае ошибки выбрасывает `error`. Такая монолитная функция трудно отлаживать. Выделите парсинг/валидатор JSON (с чёткими сообщениями об ошибках) и установку глобального `globalAuthData` отдельно, чтобы было проще проверить корректность входных данных. [12] major Файл: ai-review.js Строка: 870-930 Тип: code-smell Описание: `callCodexCLI` вручную создаёт процесс, навешивает прослушки stdout/stderr, резюмирует ошибки и обрабатывает stdin; повторяемая логика делает функцию длинной. Используйте более компактную обёртку (`spawnSync`/`execFile`) или вынесите код чтения stdout/stderr в отдельную утилиту, чтобы избежать дублирования менеджмента потоков, и добавьте явную таймаут-обработку и логирование ошибок. [13] major Файл: ai-review.js Строка: 961-1075 Тип: code-smell Описание: `callDeepSeekAPI` построена как одна громоздкая функция с ручным созданием HTTPS-запроса, логами и детальными проверками содержимого (включая `log`-превью). Такое количество обязанностей затрудняет поддержку, а повторное логирование/JSON-парсинг можно вынести. Рекомендуется использовать модуль вроде `fetch`/`axios` или вынести подготовку `options`/обработку ответа в отдельные методы, чтобы сократить цикломатическую сложность и упростить тесты. [14] major Файл: ai-review.js Строка: 1390-1464 Тип: code-smell Описание: `runAnalysis` координирует сбор файлов, построение промпта, вызов DeepSeek, очистку ответа, распарсивание, извлечение сниппетов и вызов Codex — всё в одной функции. Это делает поток управления сложно читаемым и трудно тестируемым. Разбейте `runAnalysis` на последовательные шаги (`preparePrompt`, `callDeepSeek`, `processDeepSeekResponse`, `runCodexOnSnippets`) и передавайте состояния в виде DTO, чтобы каждая часть была независимой. [15] major Файл: ai-review.js Строка: 1129-1197 Тип: code-smell Описание: `saveReportToServer` готовит отчёт, пишет временный файл, запускает `sshpass`/`scp` с `StrictHostKeyChecking=no` и удаляет файл. Эта функция объединяет подготовку содержимого, файловые операции и небезопасную передачу, что усложняет аудит и повторное использование. Поделите на этапы: подготовка содержимого, безопасный перенос (SSH-ключи/SFTP или GitLab artifact push) и логику удалённого пути, избегая `sshpass`/`StrictHostKeyChecking=no` в пользу заранее проверенных ключей. [16] major Файл: ai-review.js Строка: 1264-1328 Тип: code-smell Описание: `sendToPachka` как монолитная функция собирает сообщение, форматирует summary, формирует payload и делает HTTPS-запрос, не разделяя генерацию текста и отправку. Это повышает циклока. Вынесите генерацию текста (включая `generateSummaryReport`) и создание опций/обработку ответа в отдельные функции, чтобы можно было протестировать каждую часть и обработать ошибки сетевого вызова отдельно. [17] major Файл: ai-review.js Строка: 1466-1518 Тип: code-smell Описание: `mergeIssues` строит `Map` по пути+строке и затем в одной петле проверяет подтверждение/отклонение/копию, одновременно обрабатывая строки в нескольких местах. Это усложняет логику, особенно при наличии проблем без `.location`. Упростите, вынеся комбинацию ключа и проверку `false positive` в отдельные функции, и добавьте проверки на отсутствие `location`, чтобы избежать крашей при неожиданных данных. [18] major Файл: ai-review.js Строка: 1525-1567 Тип: code-smell Описание: `generateReport` записывает пару файлов, собирает финальный текст, печатает, сохраняет report URL и отправляет уведомления — всё в одной функции. Так утверждается масштаб сложности и риски пропуска шагов в случае ошибки. Разделите на «формирование отчёта», «сохранение на сервер», «отправка уведомлений» и «логгинг», чтобы каждая ответственность могла быть протестирована и легко изменена. [19] major Файл: src/components/ui/Dropdown.tsx Строка: 1-220 Тип: code-smell Описание: `Dropdown` содержит большое количество `useRef`, `useEffect`, логов и логики позиционирования/слушателей, из-за чего компонент трудно читать и тестировать. Разделите на кастомные хуки (например, `useDropdownPosition`, `useClickAway`, `useEscapeKey`) и/или вынесите логирование в отдельный утилитный слой, чтобы сократить количество состояний в компоненте и улучшить читаемость. [20] major Файл: src/components/ui/Dropdown.tsx Строка: 103-144 Тип: code-smell Описание: Второй `useEffect`, который следит за позиционированием, объединяет расчёт позиции, таймауты, ручной `requestAnimationFrame` и подписки на события в один блок, из-за чего сложно предсказать, когда и как обновляется `menuPosition`. Вынесите `updatePosition` и подписки на события в отдельный хук, и используйте чистые эффекты (одна подписка на события, отдельный эффект для резайза/скрола) с контролем таймаута, чтобы сделать поведение предсказуемым.