<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>GitHub</title>
    <description>GitHub — популярный сервис для хостинга проектов, основанный на VCS Git. Здесь вы найдёте информацию о том, как устроен и работает Гитхаб.</description>
    <link>https://tproger.ru/tag/github</link>
    <atom:link href="https://tproger.ru/tag/github/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 03 Oct 2026 09:29:36 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>GitHub</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>SDL3 получила поддержку HarmonyOS и OpenHarmony</title>
      <link>https://tproger.ru/news/sdl3-poluchila-podderzhku-harmonyos-i-openharmony</link>
      <comments>https://tproger.ru/news/sdl3-poluchila-podderzhku-harmonyos-i-openharmony?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Тимур Гайнутдинов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/sdl3-poluchila-podderzhku-harmonyos-i-openharmony</guid>
      <description><![CDATA[<p>Кроссплатформенная библиотека SDL3 для игр, эмуляторов и мультимедийных приложений получила официальный порт для HarmonyOS и OpenHarmony.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/sdl3-poluchila-podderzhku-harmonyos-i-openharmony">SDL3 получила поддержку HarmonyOS и OpenHarmony</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 16 Sep 2026 10:40:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>15 сентября разработчики объединили в основную ветку SDL порт для HarmonyOS и OpenHarmony. SDL упрощает создание кроссплатформенных игр и мультимедийных приложений, поэтому обновление в первую очередь касается разработчиков на C и C++, которым нужен ещё один целевой набор платформ.</p><p>Автор порта протестировал его на реальном устройстве Huawei. По его словам, возможностей уже достаточно для выпуска полноценных игр и приложений, а коммерческие проекты на базе порта готовятся к релизу. В репозитории также появилась подробная инструкция по настройке среды, сборке проекта и отладке.</p><p>Порт пока закрывает не все сценарии. Самый заметный пробел связан с поддержкой джойстиков; также остаётся добавить поддержку пера и диалоговых окон.</p><p>Для инди-разработчиков и небольших команд это означает, что HarmonyOS и OpenHarmony становятся официальной целью сборки SDL3, а не отдельной веткой, которую приходится поддерживать самостоятельно. Работа над портом была профинансирована Outfit7.</p><h2>Источники</h2><ul><li><a href="https://github.com/libsdl-org/SDL/pull/16281">harmonyos: Port SDL3 to HarmonyOS/OpenHarmony. by icculus · Pull Request #16281 · libsdl-org/SDL · GitHub</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Phoenix 20.11.0 получил заметки для трассировок и навык анализа ошибок</title>
      <link>https://tproger.ru/news/phoenix-20-11-0-poluchil-zametki-dlya-trassirovok-i-navyk-analiza</link>
      <comments>https://tproger.ru/news/phoenix-20-11-0-poluchil-zametki-dlya-trassirovok-i-navyk-analiza?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/phoenix-20-11-0-poluchil-zametki-dlya-trassirovok-i-navyk-analiza</guid>
      <description><![CDATA[<p>Arize AI выпустила Phoenix 20.11.0. В релиз вошли GraphQL-мутации для заметок, новый навык анализа ошибок и исправление MCP.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/phoenix-20-11-0-poluchil-zametki-dlya-trassirovok-i-navyk-analiza">Phoenix 20.11.0 получил заметки для трассировок и навык анализа ошибок</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 13 Sep 2026 15:24:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>12 сентября 2026 года вышел Phoenix 20.11.0. В нём появились GraphQL-мутации для добавления заметок к спанам, трассировкам и сессиям.</p><h2>Что ещё изменилось</h2><p>MCP-сервер теперь раздаёт общий каталог навыков через путь /mcp. В поставку также добавили навык phoenix-error-analysis, а во внутрипроцессной диспетчеризации MCP-инструментов исправили передачу состояния жизненного цикла приложения.</p><p>В примечаниях к релизу нет сравнения с предыдущей версией или конкурентами, а также сведений о ценовых ограничениях и доступности функций из России.</p><h2>Источники</h2><ul><li><a href="https://github.com/Arize-ai/phoenix/releases/tag/arize-phoenix-v20.11.0">Release arize-phoenix: v20.11.0 · Arize-ai/phoenix · GitHub</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Metro 0.87.1 добавил поддержку URI-схем и исправил Fast Refresh</title>
      <link>https://tproger.ru/news/metro-0-87-1-dobavil-podderzhku-uri-shem-i-ispravil-fast-refresh</link>
      <comments>https://tproger.ru/news/metro-0-87-1-dobavil-podderzhku-uri-shem-i-ispravil-fast-refresh?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/metro-0-87-1-dobavil-podderzhku-uri-shem-i-ispravil-fast-refresh</guid>
      <description><![CDATA[<p>Metro 0.87.1, сборщик JavaScript для React Native, получил поддержку собственных резолверов URI-схем, исправления Fast Refresh и более экономный FallbackWatcher.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/metro-0-87-1-dobavil-podderzhku-uri-shem-i-ispravil-fast-refresh">Metro 0.87.1 добавил поддержку URI-схем и исправил Fast Refresh</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 13 Sep 2026 13:59:37 GMT</pubDate>
      <content:encoded><![CDATA[<p>Metro — сборщик JavaScript для разработчиков приложений на React Native. 13 сентября вышел Metro 0.87.1. Разработчики могут подключать собственные обработчики для спецификаторов с URI-схемой, например foo:bar, через настройку resolver.schemeResolvers. Импорты вида metro:babel-runtime/&lt;path&gt; теперь разрешаются во внутреннюю зависимость Metro от @babel/runtime.</p><p>Обновление затрагивает проекты, которые используют Metro для разработки и сборки. В релизе исправили Fast Refresh с ленивыми сегментированными бандлами, пропуск файлов, записанных в каталог во время его обхода FallbackWatcher, ошибки сокета при записи через HttpStore и обработку выражений с Platform.OS и Platform.select.</p><p>FallbackWatcher стал экономнее: потребление RSS при обходе файлов снизилось примерно на 34%, а пиковое использование heap — примерно на 41%. Также Metro отказался от зависимости image-size в пользу встроенных парсеров, чтобы устранить предупреждения CVE.</p><p>Перед обновлением стоит отдельно проверить экспериментальные настройки сериализатора и файловой карты. Авторы предупреждают, что такие возможности не покрываются правилами семантического версионирования и могут измениться без сохранения совместимости.</p><h2>Источники</h2><ul><li><a href="https://github.com/react/metro/releases/tag/v0.87.1">Release v0.87.1 · react/metro · GitHub</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Вышел flatpak-builder 1.4.11 с исправлениями безопасности</title>
      <link>https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti</link>
      <comments>https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti</guid>
      <description><![CDATA[<p>Сборщик Linux-приложений Flatpak Builder обновился до версии 1.4.11. Обновление отключает Git-хуки при применении патчей и устраняет выход источников за пределы base_dir в режиме песочницы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/vywel-flatpak-builder-1-4-11-s-ispravleniyami-bezopasnosti">Вышел flatpak-builder 1.4.11 с исправлениями безопасности</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 13 Sep 2026 13:25:04 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Что произошло</h2><p>Flatpak Builder — инструмент для разработчиков и сопровождающих Linux-приложений: он собирает их в пакеты формата Flatpak. Версия flatpak-builder 1.4.11 вышла 12 сентября. В ней полностью отключили Git-хуки при применении патчей. Изменение связано с уязвимостью CVE-2026-86320. Также разработчики исправили проблему GHSA-484h-v688-jq5j, из-за которой источник мог выйти за пределы base_dir в режиме песочницы.</p><p>Кроме того, flatpak-builder теперь раньше прерывает обработку некорректных контрольных сумм для архивов и файлов, проверяет наличие URL при разборе источников bzr и svn и пропускает уже перенесённые записи при миграции локалей.</p><h2>Что делать</h2><p>Если используется более ранний выпуск, стоит перейти на 1.4.11. В заметках к релизу не указаны затронутые диапазоны версий или дополнительные меры защиты, поэтому ориентиром остаётся установка исправленного выпуска.</p><h2>Источники</h2><ul><li><a href="https://github.com/flatpak/flatpak-builder/releases/tag/1.4.11">Release 1.4.11 · flatpak/flatpak-builder · GitHub</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Crush 0.94.1 получил вход через ChatGPT и ускоренный интерфейс</title>
      <link>https://tproger.ru/news/crush-0-94-1-poluchil-vhod-cherez-chatgpt-i-uskorennyj-interfejs</link>
      <comments>https://tproger.ru/news/crush-0-94-1-poluchil-vhod-cherez-chatgpt-i-uskorennyj-interfejs?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/crush-0-94-1-poluchil-vhod-cherez-chatgpt-i-uskorennyj-interfejs</guid>
      <description><![CDATA[<p>Терминальный ИИ-помощник для программистов Crush 0.94.1 получил поддержку подписки ChatGPT и настройку reasoning effort для запуска без интерфейса. Разработчики также ускорили прокрутку и уменьшили размер программы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/crush-0-94-1-poluchil-vhod-cherez-chatgpt-i-uskorennyj-interfejs">Crush 0.94.1 получил вход через ChatGPT и ускоренный интерфейс</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 13 Sep 2026 13:23:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Crush — ИИ-помощник для программирования, работающий в терминале. Пользователи Crush теперь могут авторизоваться через ChatGPT и работать со своей подпиской. Для тех, кто запускает инструмент в автоматизации или без интерактивного интерфейса, команда crush run получила флаг --reasoning-effort с проверкой допустимых значений.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-09-13/3c10cc34-ac98-43fd-9aa1-5ccf458df321.webp" alt="Непод интерактивный режим с допустимыми значениями усилий рассуждения" /><figcaption>Непод интерактивный режим: параметры рассуждений</figcaption></figure><p>Под капотом разработчики сократили лишнюю работу интерфейса: события прокрутки мышью объединяются, готовые кадры чата переиспользуются, а все индикаторы загрузки работают от общих часов. Это похоже на один таймер для нескольких анимаций вместо отдельного таймера для каждой.</p><p>Также команда отказалась от Swagger-компонентов в клиент-серверном режиме и заменила их реестром конечных точек на Go с поддержкой OpenAPI 3.2.1. В результате размер исполняемого файла уменьшился примерно на 4 МБ.</p><p>Релиз ориентирован на пользователей подписки ChatGPT и тех, кто запускает Crush в автоматизированных сценариях. Обновление также улучшает прокрутку и работу индикаторов загрузки в интерфейсе.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-09-13/6744610c-0297-4dd9-8168-2c95b83fe224.webp" alt="Раздел Crush для использования подписки ChatGPT" /><figcaption>Использование подписки ChatGPT в Crush</figcaption></figure><p>Релиз <a href="https://github.com/charmbracelet/crush/releases/tag/v0.94.1">Crush 0.94.1 опубликован на GitHub</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Spec Kit 1.0 от GitHub заменяет переписку с ИИ-агентом спекой, плюс десять инструментов для агентов</title>
      <link>https://tproger.ru/news/spec-kit-1-0-i-eshhyo-desyat-ii-repozitoriev-sobravwih-zvyozdy-za-n</link>
      <comments>https://tproger.ru/news/spec-kit-1-0-i-eshhyo-desyat-ii-repozitoriev-sobravwih-zvyozdy-za-n?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/spec-kit-1-0-i-eshhyo-desyat-ii-repozitoriev-sobravwih-zvyozdy-za-n</guid>
      <description><![CDATA[<p>GitHub довёл Spec Kit до 1.0: 135 тысяч звёзд, 30+ агентов, converge, расширения bug и assess. Рядом ponytail, ECC, humanizer, archify, MiniMind, Magnitude и blender-mcp.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/spec-kit-1-0-i-eshhyo-desyat-ii-repozitoriev-sobravwih-zvyozdy-za-n">Spec Kit 1.0 от GitHub заменяет переписку с ИИ-агентом спекой, плюс десять инструментов для агентов</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Методологии разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 10 Sep 2026 18:42:37 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub выпустил <a href="https://github.com/github/spec-kit/releases/tag/v1.0.0">версию 1.0.0</a> набора Spec Kit ровно через год после первого коммита, 21 августа, а к 10 сентября довёл его до 1.0.6. Это открытый инструмент, который заставляет ИИ-агента сначала написать спецификацию и план, а уже потом код, и работает с любым агентом: Copilot, Claude Code, Codex, Cursor, Gemini CLI и ещё больше чем с двадцатью другими. У <a href="https://github.com/github/spec-kit">репозитория</a> 135 тысяч звёзд и 12 тысяч форков, лицензия MIT.</p><p>Для программиста, который уже работает с агентами, это готовая замена самодельным файлам с инструкциями и длинным описаниям задачи в чате. Вместо «сделай мне функцию экспорта» агент получает конституцию проекта, спеку с пользовательскими историями, технический план и список задач в репозитории, и каждый шаг можно прочитать и поправить до того, как появится код. За год к базовой цепочке добавились команда сверки кода со спекой, расширения для багфикса и оценки идей, пресеты под стандарты команды и бандлы под роли. Spec Kit при этом не единственный репозиторий такого рода в топе GitHub: за ту же неделю звёзды собирали ещё десять проектов про агентов, от скиллов и надстроек над Claude Code и Codex до локального инференса и управления Blender; они разобраны во второй части.</p><ul><li>Spec Kit 1.0.0 вышел 21 августа 2026 года, текущий релиз 1.0.6 от 10 сентября; между ними шесть патч-релизов.</li><li>Ставится через uv или с PyPI, командой specify init подключается к проекту под любой из более чем 30 агентов.</li><li>Цепочка из шести слэш-команд: constitution, specify, plan, tasks, implement, converge; последняя сверяет код со спекой и дописывает недостающие задачи.</li><li>Расширение bug ведёт исправление по шагам «оценить, починить, проверить», assess разбирает идею до решения «делать» или «не делать».</li><li>Мейнтейнер пишет, что 1.0 больше не обещает стабильности API: ломающие изменения агент теперь переносит сам.</li><li>Среди набравших звёзды за неделю: ponytail (135 тысяч, режет объём кода агента на 54% в замере автора), ECC (256 тысяч), skills (259 тысяч), humanizer (46 тысяч), archify (57 тысяч), HyperFrames, MiniMind, Magnitude, SGLang и blender-mcp.</li></ul><h2>Что такое Spec Kit и как он работает?</h2><p>Spec Kit это утилита specify на Python плюс набор markdown-шаблонов и скриптов, которые она раскладывает в проект. После specify init в каталоге агента (например, .claude/ или .github/) появляются слэш-команды или скиллы с префиксом speckit, а в .specify/ лежат шаблоны документов. Дальше вся работа идёт внутри привычного агента.</p><p>Базовая цепочка описана в README репозитория и состоит из шести шагов. /speckit.constitution один раз на проект фиксирует принципы: стек, стиль, что запрещено. /speckit.specify превращает описание задачи в спеку с требованиями и пользовательскими историями, /speckit.plan пишет технический план под выбранный стек, /speckit.tasks режет план на задачи, /speckit.implement их выполняет. Замыкает цикл /speckit.converge: команда сравнивает кодовую базу со спекой, планом и задачами и дописывает в список то, что ещё не сделано. Шаги implement и converge повторяются, пока converge не сообщит, что всё сошлось.</p><p>Есть три необязательные команды. /speckit.clarify вытаскивает недосказанное из спеки вопросами, её рекомендуют запускать до плана. /speckit.analyze ищет расхождения между спекой, планом и задачами после tasks и до implement. /speckit.checklist генерирует чек-листы качества требований, в документации их называют «юнит-тестами для английского языка». Команда /speckit.taskstoissues, которая раскладывает задачи в GitHub Issues, в релизе 1.0.5 помечена как уходящая из ядра в отдельное расширение github-issues; пока она работает.</p><h2>Что изменилось к версии 1.0?</h2><p>Год назад Spec Kit был набором шаблонов под несколько команд и несколько агентов. К 1.0 вокруг ядра выросла система настройки из четырёх слоёв. Внизу ядро с встроенными командами и шаблонами, выше расширения, которые добавляют новые команды, ещё выше пресеты, которые переписывают шаблоны ядра и расширений, а на самом верху локальные правки конкретного проекта в .specify/templates/overrides/. Шаблоны разрешаются во время выполнения сверху вниз, побеждает первое совпадение.</p><p>Два расширения идут в комплекте и включаются по желанию. specify extension add bug добавляет цепочку из трёх команд для исправления ошибок: assess проверяет диагноз по отчёту, fix чинит именно найденную причину, test подтверждает, что исходный симптом исчез. Авторы объясняют это тем, что агент, который прыгает от баг-репорта сразу к патчу, часто чинит не то. Расширение assess работает ещё до спеки: intake, research, define, shape, decide, на выходе документированное решение «делать», «нужны уточнения» или «не делать». Идею с решением «делать» можно передать в /speckit.specify.</p><p>Пресеты ставятся командой specify preset add и меняют форму, а не набор возможностей: например, требуют в спеке трассируемость под регуляторику, добавляют обязательный этап проверки безопасности в план, переставляют задачи так, чтобы тесты шли первыми, или переводят весь процесс на другой язык. Бандлы собирают расширения, пресеты, шаги и рабочие процессы в один версионированный набор под роль: продакт-менеджер, аналитик, исследователь безопасности, разработчик. Ставится бандл одной командой specify bundle install, каталог бандлов у проекта свой, поверх пользовательского и встроенного. В релиз-нотах 1.0.x рядом с исправлениями регулярно идут обновления расширений сообщества, например Jira Mirror в 1.0.2, и правки в загрузчике бандлов.</p><p>Список агентов вырос до <a href="https://github.github.io/spec-kit/reference/integrations.html">более чем 30</a>. Для части из них, включая Claude Code, Codex CLI, Copilot и Devin, команды ставятся как скиллы, а не как файлы промптов, и вызываются как /speckit-specify или $speckit-specify, в зависимости от агента. Для остальных остаётся режим слэш-команд; переключатель --integration-options="--skills" есть у тех, кто поддерживает оба.</p><h2>Почему 1.0 больше ничего не обещает?</h2><p>Ведущий мейнтейнер проекта в <a href="https://www.manorrock.com/blog/2026/08/21/spec_kit_turns_one.html">записи к годовщине</a> прямо говорит, что единица в номере версии здесь только число. Раньше мажорная версия была страховкой от стоимости изменений: ломающее изменение означало ручной обход всех мест вызова по гайду миграции, и семантическое версионирование превращало эту стоимость в сигнал. Теперь, по его словам, адаптация к ломающему изменению это одно предложение агенту, который правит места вызова быстрее, чем автор успевает описать их в changelog. Поэтому 1.0.0 у Spec Kit значит «хорошее место, чтобы начать», а не обещание замороженной формы. Это заявление проекта о себе, и для команд, которые встраивают Spec Kit в CI и внутренние инструменты, оно означает, что пинить версию всё равно придётся: за три недели после 1.0.0 вышло шесть патч-релизов.</p><h2>Как установить и с чего начать?</h2><p>В README рекомендуют менеджер uv, альтернатива pipx. Установка идёт с привязкой к тегу релиза, тег с ведущей буквой v, либо из PyPI, где пакет specify-cli обновлён до 1.0.6. Проверить, не вышла ли новая версия, можно командой specify self check.</p><p>Ключ --integration принимает имя агента из списка интеграций, например copilot, claude, codex, cursor-agent или gemini; полный перечень выдаёт specify integration list. Дальше запускается сам агент в каталоге проекта, и цепочка начинается с /speckit.constitution.</p><h2>Кому это не нужно?</h2><p>Spec Kit не единственный инструмент такого рода. Kiro от AWS делает то же самое внутри собственной IDE на базе VS Code, у Tessl это CLI и MCP-сервер к разным ассистентам, а сам фреймворк на момент разбора был в закрытой бете; в <a href="https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html">разборе трёх подходов</a> на сайте Мартина Фаулера Spec Kit выделяют как самый агентонезависимый: это markdown и скрипты в репозитории, которые легко править. Обратная сторона та же: спека, план и задачи это документы, которые кто-то должен читать, и для правки в одну функцию цепочка из шести команд избыточна. Авторы и сами пишут в README, что не каждое изменение проходит полный цикл: небольшие исправления идут обычным путём через issue, pull request, ревью и тесты.</p><h2>Какие ещё репозитории про ИИ-агентов набирали звёзды на этой неделе?</h2><p>Подборку из десяти репозиториев, которые «за неделю разом собрали звёзды», <a href="https://x.com/so_ainsight/status/2097885286265180398">опубликовал</a> 10 сентября японский аккаунт So AInsight; прирост за неделю там не приведён, поэтому ниже суммарное число звёзд на 11 сентября по данным GitHub. Половина списка про то же, что и Spec Kit: как заставить агента работать по процессу, а не по настроению; остальное про инференс, обучение и управление другими программами.</p><ol><li><a href="https://github.com/mattpocock/skills">skills</a>, 259 тысяч звёзд. Скиллы Мэтта Покока, автора Total TypeScript, из его рабочего каталога .agents: небольшие, составные, под любую модель. В README автор прямо противопоставляет их Spec Kit, GSD и BMAD: те, по его словам, забирают процесс себе и делают ошибки в нём трудноразрешимыми.</li><li><a href="https://github.com/affaan-m/ECC">ECC</a>, 256 тысяч. Надстройка над Claude Code, Codex, OpenCode и Cursor с циклом «план, тест, реализация, ревью из свежего контекста, проверка, память, улучшение». Репозиторий под MIT, у автора есть платная версия ECC Pro как GitHub App для приватных репозиториев от $19 за место в месяц.</li><li><a href="https://github.com/DietrichGebert/ponytail">ponytail</a>, 135 тысяч. Скилл, который заставляет агента думать «как самый ленивый сеньор»: перед кодом пройти лестницу из семи вопросов, от «нужно ли это вообще» до «есть ли это в стандартной библиотеке». Автор замерил на Claude Code и репозитории full-stack-fastapi-template по 12 тикетам: минус 54% строк, минус 22% токенов, минус 20% стоимости против агента без скилла; ранние цифры «на 80–94% меньше кода» он сам признал завышенными из-за некорректной базы.</li><li><a href="https://github.com/tt-a1i/archify">archify</a>, 57 тысяч. Скилл для Cursor, Claude Code, Codex CLI и OpenCode: агент описывает систему типизированным JSON, Node.js-компилятор превращает его в самодостаточный HTML с интерактивной схемой архитектуры, последовательности или потока данных, экспорт в PNG, SVG и WebM. Умеет сравнивать два снимка архитектуры до и после изменения.</li><li><a href="https://github.com/blader/humanizer">humanizer</a>, 46 тысяч. Скилл на чистом markdown, который переписывает текст агента так, чтобы в нём не было характерных следов машинного письма, без изменения смысла; ставится через npx skills add blader/humanizer или как плагин Claude Code.</li><li><a href="https://github.com/heygen-com/hyperframes">HyperFrames</a>, 49 тысяч. Проект HeyGen: пишешь HTML, получаешь видео. Рассчитан на агентов, которым нужно генерировать ролики с диаграммами и озвучкой без съёмки; TypeScript, Apache 2.0, Node 22 и новее.</li><li><a href="https://github.com/jingyaogong/minimind">MiniMind</a>, 61 тысяча. Учебный проект: обучить языковую модель на 64 млн параметров с нуля на чистом PyTorch. Заявленные «2 часа» и «3 юаня» это оценка автора для одного прохода предобучения и дообучения минимальной версии на одной RTX 3090 и аренда GPU на это время; в репозитории полная цепочка от предобучения до DPO, GRPO и агентного RL, плюс версии с картинками и диффузией.</li><li><a href="https://github.com/magnitudedev/magnitude">Magnitude</a>, 4 тысячи. Локальный движок инференса: профилирует машину (Mac, NVIDIA, AMD или только CPU), подбирает подходящие модели, скачивает, настраивает и запускает их. Единственный проект списка с числом звёзд в тысячах, а не десятках тысяч.</li><li><a href="https://github.com/sgl-project/sglang">SGLang</a>, 36 тысяч. Зрелый фреймворк раздачи больших языковых и мультимодальных моделей под нагрузкой, существует с января 2024 года; в список попал, судя по всему, из-за очередного всплеска интереса, а не как новинка.</li><li><a href="https://github.com/ahujasid/blender-mcp">blender-mcp</a>, 28 тысяч. MCP-сервер и аддон, через которые любая модель управляет Blender: создание сцен, моделирование и расстановка объектов по текстовому запросу. Сторонний проект, к Blender Foundation отношения не имеет, о чём README предупреждает отдельно.</li></ol><p>Общий знаменатель списка тот же, что у Spec Kit 1.0: скиллы и надстройки, которые фиксируют процесс работы агента в репозитории, стали отдельной категорией инструментов, и у неё уже есть внутренняя полемика. Spec Kit и ECC предлагают полный цикл, skills и ponytail дают отдельные небольшие правила, которые сочетаются с чем угодно. Что выбирать, зависит от размера задачи: для мелких правок цепочка из шести команд избыточна, для новой функции с несколькими файлами спека и план окупаются тем, что их можно прочитать до кода.</p><p>Что смотреть дальше у Spec Kit: вынос /speckit.taskstoissues в расширение github-issues и следующие патч-релизы: между 1.0.1 и 1.0.6 паузы были от нескольких часов до десяти дней. Раздел экспериментальных целей из README никуда не делся, сроков по 1.1 или 2.0 GitHub не называет.</p><p>Источники: <a href="https://github.com/github/spec-kit">GitHub: репозиторий github/spec-kit</a>, <a href="https://github.com/github/spec-kit/releases/tag/v1.0.0">Релиз Spec Kit v1.0.0</a>, <a href="https://github.com/github/spec-kit/releases/tag/v1.0.6">Релиз Spec Kit v1.0.6</a>, <a href="https://www.manorrock.com/blog/2026/08/21/spec_kit_turns_one.html">Manorrock: Spec Kit Turns One — and Ships 1.0.0</a>, <a href="https://github.github.io/spec-kit/reference/integrations.html">Документация: поддерживаемые агенты</a>, <a href="https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html">Martin Fowler: Understanding Spec-Driven Development: Kiro, Spec-Kit, and Tessl</a>, <a href="https://x.com/so_ainsight/status/2097885286265180398">So AInsight в X: десять ИИ-инструментов, собравших звёзды на GitHub за неделю</a>, <a href="https://github.com/mattpocock/skills">GitHub: mattpocock/skills</a>, <a href="https://github.com/affaan-m/ECC">GitHub: affaan-m/ECC</a>, <a href="https://github.com/DietrichGebert/ponytail">GitHub: DietrichGebert/ponytail</a>, <a href="https://github.com/tt-a1i/archify">GitHub: tt-a1i/archify</a>, <a href="https://github.com/blader/humanizer">GitHub: blader/humanizer</a>, <a href="https://github.com/heygen-com/hyperframes">GitHub: heygen-com/hyperframes</a>, <a href="https://github.com/jingyaogong/minimind">GitHub: jingyaogong/minimind</a>, <a href="https://github.com/magnitudedev/magnitude">GitHub: magnitudedev/magnitude</a>, <a href="https://github.com/sgl-project/sglang">GitHub: sgl-project/sglang</a>, <a href="https://github.com/ahujasid/blender-mcp">GitHub: ahujasid/blender-mcp</a></p><p>Изображение на обложке: Логотип: GitHub</p>]]></content:encoded>
    </item>
    <item>
      <title>Copilot в приложении и CLI перестал читать исключённые файлы</title>
      <link>https://tproger.ru/news/copilot-v-prilozhenii-i-cli-perestal-chitat-isklyuchyonnye-fajly</link>
      <comments>https://tproger.ru/news/copilot-v-prilozhenii-i-cli-perestal-chitat-isklyuchyonnye-fajly?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/copilot-v-prilozhenii-i-cli-perestal-chitat-isklyuchyonnye-fajly</guid>
      <description><![CDATA[<p>Исключение файлов теперь действует в Copilot app и CLI на планах Business и Enterprise. Что покрыто и где возможна утечка: IDE, симлинки, удалённые ФС.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/copilot-v-prilozhenii-i-cli-perestal-chitat-isklyuchyonnye-fajly">Copilot в приложении и CLI перестал читать исключённые файлы</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 05:20:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub 2 сентября <a href="https://github.blog/changelog/2026-09-02-content-exclusions-generally-available-in-copilot-app-and-cli/">объявила</a>, что политики content exclusion, то есть списки файлов, которые Copilot не имеет права читать, теперь в общем доступе для приложения Copilot и для Copilot CLI. Настраивают их администраторы репозитория, владельцы организации или enterprise; доступно на планах Copilot Business и Enterprise. Исключённые файлы не должны использоваться агентом как контекст, попадать в ответы и проверяться Copilot code review.</p><p>Для команд, которые пускают агента в репозиторий с .env, приватными схемами и внутренними документами, это способ формально закрыть ему доступ. Но по документации GitHub у механизма есть заметные дыры: в VS Code режимы Edit и Agent исключения пока не поддерживают, симлинки и репозитории на удалённых файловых системах не покрываются, а семантическая информация из IDE (типы, определения по наведению, свойства сборки) может просочиться в контекст даже для исключённого файла.</p><ul><li>Content exclusions стали GA для Copilot app и Copilot CLI; сайт GitHub и GitHub Mobile остаются в public preview.</li><li>Политику настраивают администраторы репозитория, владельцы организации и enterprise; планы Copilot Business и Enterprise.</li><li>Исключённые файлы не участвуют в inline-подсказках, не влияют на подсказки в других файлах, не попадают в ответы чата и не проверяются Copilot code review.</li><li>Не покрыты: режимы Edit и Agent в VS Code, симлинки, репозитории на удалённых файловых системах; возможна утечка через семантику IDE.</li><li>Клиент передаёт GitHub URL текущего репозитория, чтобы получить политику; GitHub заявляет, что эти URL не логируются.</li></ul><h2>Как работает исключение и что оно гарантирует</h2><p>Механизм описан в <a href="https://docs.github.com/en/copilot/concepts/context/content-exclusion">документации GitHub</a>: администратор задаёт пути и маски файлов на уровне репозитория, организации или enterprise. Клиент Copilot при запуске отправляет на GitHub URL текущего репозитория и получает применимую политику; по заявлению GitHub, эти URL не логируются. Дальше клиент обязан не показывать содержимое исключённых файлов модели: ни для автодополнения внутри них, ни как контекст для подсказок в соседних файлах, ни в ответах чата, ни в автоматическом ревью.</p><p>Слово «обязан» здесь важно. Это политика на стороне клиента, а не криптографическая изоляция: GA-статус означает, что GitHub заявляет поддержку в приложении и CLI и берёт на себя ответственность за её работу. До 2 сентября правила действовали в части IDE-сценариев и в code review, а для app и CLI были в предварительном статусе.</p><h2>Где исключения не срабатывают</h2><ul><li>VS Code: режимы Edit и Agent пока не поддерживают content exclusion. Именно в агентном режиме модель читает файлы активнее всего.</li><li>Симлинки: если исключённый файл доступен по символической ссылке под другим путём, политика его не закроет.</li><li>Удалённые файловые системы: репозитории на сетевых дисках и в remote-окружениях не покрываются.</li><li>Семантика IDE: языковой сервер может отдать типы, hover-определения и свойства сборки из исключённого файла, и они попадут в контекст.</li></ul><p>Практический вывод: исключение файлов снижает риск случайной утечки секрета в подсказку, но не заменяет хранение секретов вне репозитория. Файл .env с ключами в Git был плохой идеей и до Copilot; агент лишь делает цену ошибки заметнее. Как это выглядит на практике, показал недавний <a href="https://tproger.ru/news/metr-rasskazala-kak-u-neyo-ukrali-api-klyuch-k-modelyam-vajb-kodi">инцидент METR</a> с украденным API-ключом.</p><h2>Что настроить сегодня</h2><ol><li>В настройках репозитория, организации или enterprise добавить в исключения .env*, каталоги с ключами и сертификатами, приватные схемы данных и внутренние документы.</li><li>Проверить каждую поверхность отдельно: Copilot app, CLI, IDE, code review. Для VS Code помнить, что Edit и Agent исключения игнорируют.</li><li>Найти симлинки на чувствительные файлы (find . -type l) и репозитории на сетевых дисках: там политика не действует.</li><li>Убедиться, что тариф Business или Enterprise: на индивидуальных планах content exclusion недоступен.</li></ol><p>Доступность оплаты планов Business и Enterprise из России GitHub в changelog не обсуждает. В тот же день GitHub выпустила и другое изменение для администраторов: <a href="https://github.blog/changelog/2026-09-02-enterprise-managed-settings-support-any-default-model/">managed settings</a> теперь позволяют назначать командам любую модель Copilot по умолчанию с возможностью переопределения. Про то, что Copilot научился <a href="https://tproger.ru/news/github-razrewil-copilot-stavit-approve-na-pull-request">ставить approve на pull request</a>, мы писали накануне; в связке с исключениями это означает, что ревьюер-агент может не видеть части файлов, которые одобряет.</p><p>Источники: <a href="https://github.blog/changelog/2026-09-02-content-exclusions-generally-available-in-copilot-app-and-cli/">GitHub Changelog: Content exclusions generally available in Copilot app and CLI</a>, <a href="https://docs.github.com/en/copilot/concepts/context/content-exclusion">GitHub Docs: Content exclusion for GitHub Copilot</a></p><p>Изображение на обложке: GitHub</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub CLI 2.99 прикладывает скриншоты и видео к issue из терминала</title>
      <link>https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin</link>
      <comments>https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin</guid>
      <description><![CDATA[<p>В GitHub CLI 2.99.0 появился флаг --attach: картинки и видео загружаются в issue, pull request и комментарии прямо из терминала. Лимиты, форматы, требования к токену и что не работает на Enterprise Server.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-cli-2-99-prikladyvaet-skrinwoty-i-video-k-issue-iz-termin">GitHub CLI 2.99 прикладывает скриншоты и видео к issue из терминала</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Sep 2026 01:32:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub 1 сентября <a href="https://github.blog/changelog/2026-09-01-github-cli-media-in-issues-pull-requests-and-comments/">объявил</a>, что в GitHub CLI появился флаг --attach: он загружает локальные изображения и видео в issue, pull request или комментарий. Раньше терминальный клиент умел работать только с текстом, а скриншот или запись экрана приходилось тащить через браузер. Функция доступна всем пользователям GitHub на всех тарифах после обновления до версии 2.99.0.</p><p>Для тех, кто пишет багрепорты из скриптов, собирает отчёты в CI или просто не хочет переключаться в браузер ради одной картинки, это закрывает давний разрыв между «вот команда, которая падает» и «вот как это выглядит». Единственное серьёзное исключение: GitHub Enterprise Server в этом релизе не поддерживается.</p><ul><li>Флаг --attach работает в gh issue create, edit, comment и в gh pr create, edit, comment; его можно повторять несколько раз.</li><li>Форматы: PNG, JPEG, GIF, WebP, SVG для картинок и MP4, MOV, WebM для видео.</li><li>Лимит на изображение и GIF 10 МБ; видео до 10 МБ на бесплатном плане и до 100 МБ на платных.</li><li>Нужен OAuth-токен от gh auth login или classic personal access token и право записи в репозиторий.</li><li>GitHub Enterprise Server не поддерживается; нужна версия gh 2.99.0.</li></ul><h2>Как это выглядит в командной строке</h2><p>Минимальный пример из changelog: приложить скриншот к комментарию в issue.</p><p>Флаг повторяемый, поэтому к одному issue можно приложить сразу несколько файлов, указав --attach для каждого. Alt-текст задаётся после пути через решётку: --attach './login.png#The login error state'. Это тот же alt, который потом увидят читатели со скринридером, так что писать его стоит осмысленно.</p><p>Самая полезная деталь спрятана в обработке Markdown. Если в тексте issue или комментария уже стоит локальная ссылка вида ![alt](./login.png), CLI перепишет её на адрес загруженного файла. Вложения, на которые в тексте ссылок нет, добавляются в конец Markdown. Значит, можно писать описание бага в редакторе с относительными путями к картинкам, а потом одной командой отправить и текст, и файлы.</p><h2>Ограничения, о которых стоит знать заранее</h2><p>Для загрузки нужен либо OAuth-токен, полученный через gh auth login, либо classic personal access token; другие типы токенов в changelog не упомянуты, и это стоит учитывать в CI. Кроме того, требуется право записи в репозиторий: приложить файл к чужому issue в проекте, где вы не участник, не получится, даже если оставлять комментарии там можно.</p><p>Лимиты размеров: 10 МБ для изображений и GIF, для видео 10 МБ на Free и 100 МБ на платных планах. GitHub Enterprise Server новую возможность не получил; сроки для самостоятельно развёрнутых инсталляций в публикации не названы.</p><p>Что ещё не сказано: как ведёт себя команда при превышении лимита, поддерживает ли она загрузку по URL вместо локального файла и когда флаг доберётся до gh release. Судя по тексту changelog, речь только об issue, pull request и комментариях.</p><h2>Где это пригодится</h2><ul><li>Тестовые пайплайны: упавший end-to-end тест прикладывает скриншот или запись браузера к автоматически созданному issue.</li><li>Ревью интерфейсов: gh pr comment --attach с записью экрана вместо описания «нажмите сюда, потом сюда».</li><li>Скрипты отчётов: график из matplotlib или диаграмма сборки уходит в комментарий к pull request без промежуточного хостинга.</li></ul><p>Обновиться можно штатным способом: через менеджер пакетов, которым gh ставился, или скачав релиз 2.99.0 с GitHub.</p><p>Редакция проверит, появится ли поддержка Enterprise Server в следующих релизах gh.</p><p>Источник: <a href="https://github.blog/changelog/2026-09-01-github-cli-media-in-issues-pull-requests-and-comments/">Changelog GitHub: GitHub CLI media in issues, pull requests, and comments</a></p><p>Изображение на обложке: GitHub</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub разрешил Copilot ставить approve на pull request</title>
      <link>https://tproger.ru/news/github-razrewil-copilot-stavit-approve-na-pull-request</link>
      <comments>https://tproger.ru/news/github-razrewil-copilot-stavit-approve-na-pull-request?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-razrewil-copilot-stavit-approve-na-pull-request</guid>
      <description><![CDATA[<p>GitHub добавил Copilot возможность ставить настоящий approve, который засчитывается в обязательные одобрения. Функция выключена по умолчанию, в public preview. Разбираем, что проверить в настройках.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-razrewil-copilot-stavit-approve-na-pull-request">GitHub разрешил Copilot ставить approve на pull request</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 02 Sep 2026 01:32:29 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub 1 сентября <a href="https://github.blog/changelog/2026-09-01-copilot-code-review-can-now-approve-pull-requests/">сообщил</a>, что Copilot code review научился ставить на pull request настоящий approve, и такое одобрение может засчитываться в обязательные approvals репозитория. Для команд, у которых merge закрыт правилом «нужно одно одобрение», это означает, что при включённой настройке код сможет доехать до main без единого человека.</p><p>Функция вышла в public preview для тарифов Copilot Pro, Pro+, Max, Business и Enterprise. По умолчанию она выключена: администраторам придётся включить её явно, и сделать это можно на уровне enterprise, организации или отдельного репозитория. GitHub при этом ничего не говорит о региональной доступности, поэтому для аккаунтов из России действуют те же условия, что и у самого Copilot: нужна платная подписка, а вопрос её оплаты публикация не затрагивает.</p><ul><li>Каждый обзор Copilot теперь содержит вердикт «готов к одобрению или нет»; сам по себе вердикт в merge-требования не засчитывается.</li><li>Если администратор включит настройку, Copilot будет ставить настоящий approve, и он считается наравне с одобрением человека.</li><li>Настройка выключена по умолчанию; управляется на уровне enterprise, организации и репозитория.</li><li>В репозитории можно ограничить approve списком путей: за пределами списка Copilot только комментирует.</li><li>Новый коммит после approve автоматически снимает одобрение, как и у обычных ревьюеров.</li></ul><h2>Вердикт и approve теперь разные вещи</h2><p>До этого релиза Copilot code review оставлял замечания и общий комментарий, а решение «можно ли мержить» оставалось за людьми. Теперь в каждом обзоре появился approval assessment: Copilot пишет, считает ли он pull request готовым к одобрению. GitHub прямо оговаривает, что «одна только оценка готовности не засчитывается в merge-требования» (здесь и далее перевод редакции). Это информационный сигнал, и он появляется у всех, кто пользуется Copilot code review, без дополнительных настроек.</p><p>Второй уровень включается отдельно. Если администратор разрешил Copilot одобрять, то при положительной оценке Copilot отправляет обычный approve через штатный механизм ревью. Такой approve участвует в правилах защиты веток: если branch protection требует одно одобрение, оно будет выполнено. По нашей оценке, именно эта деталь и есть новость: Copilot code review теперь формально закрывает требование ревью.</p><p>Механика отзыва одобрения не изменилась. Как и у ревьюера-человека, approve Copilot снимается, когда в ветку приходит новый коммит. Поэтому сценарий «получил одобрение от бота, потом дописал что угодно и смержил» не работает: после каждого пуша Copilot будет пересматривать изменения заново.</p><h2>Три уровня контроля и фильтр по путям</h2><p>GitHub построил включение по каскаду. Администратор enterprise может запретить функцию всем организациям сразу. Администратор организации включает её выборочно для репозиториев. Администратор репозитория включает или выключает approve у себя и, что важнее, может задать список путей, к которым Copilot имеет право применять approve.</p><p>На практике это значит, что разумная конфигурация выглядит не как «Copilot одобряет всё», а как «Copilot одобряет документацию, тесты и локализацию, а к src/auth/ и инфраструктурному коду не прикасается». Если pull request задевает файлы вне списка, Copilot по-прежнему оставит замечания, но approve не поставит.</p><p>Что GitHub не сказал: по каким критериям Copilot принимает решение о готовности, как часто он ошибается и есть ли у компании собственные замеры доли ложных одобрений. Публикация описывает только механику и настройки. Пока функция в public preview, GitHub оставляет за собой право менять её поведение.</p><h2>Что проверить у себя сегодня</h2><ol><li>Убедиться, что в организации функция по-прежнему выключена: она отключена по умолчанию, но проверить настройки Copilot в разделе организации стоит, особенно если администраторов несколько.</li><li>Если approve от Copilot нужен, включать его точечно: сначала в репозиториях без критичного кода и с фильтром по путям, а не на всю организацию.</li><li>Пересмотреть правила защиты веток. Если merge требует ровно одно одобрение и Copilot попадает в число допустимых ревьюеров, стоит поднять требование до двух или добавить в CODEOWNERS обязательного человека для чувствительных каталогов.</li><li>Договориться в команде, что approve Copilot не заменяет ревью человека для изменений в аутентификации, платежах, миграциях и CI-конфигурации.</li></ol><p>Approve от Copilot снимается новым коммитом: как только в ветку приходит изменение, одобрение отзывается, и Copilot пересматривает pull request заново. Про истечение одобрения по времени GitHub ничего не пишет.</p><h2>Почему это шаг дальше, чем автообзор</h2><p>Автоматический обзор Copilot существует давно, и у многих команд он включён на каждый pull request. Но роль у него была совещательная: комментарии можно проигнорировать, а merge всё равно требовал одобрения человека. С 1 сентября GitHub позволяет передать ИИ часть формальной ответственности за merge-gate. Для маленьких команд и соло-проектов это удобно: правило «одно одобрение» перестаёт блокировать работу, когда второго человека просто нет. Для больших организаций это ещё один пункт в аудите доступов.</p><p>Следить стоит за двумя вещами: когда функция выйдет из public preview и появятся ли у GitHub публичные данные о точности вердиктов. Редакция проверит, изменятся ли значения по умолчанию к стабильному релизу.</p><p>Источник: <a href="https://github.blog/changelog/2026-09-01-copilot-code-review-can-now-approve-pull-requests/">Changelog GitHub: Copilot code review can now approve pull requests</a></p><p>Изображение на обложке: GitHub</p>]]></content:encoded>
    </item>
    <item>
      <title>Ваши open source-контрибьюторы теперь ИИ-first. Как не утонуть в потоке агентских пулреквестов</title>
      <link>https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen</link>
      <comments>https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen</guid>
      <description><![CDATA[<p>Агенты генерируют пулреквесты в open source. Разбираем опыт AutoGPT: как ставить ворота, писать AGENTS.md и не тратить команду на ревью слабых PR.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/vawi-kontribyutory-teper-ai-first-kak-ne-utonut-v-potoke-agen">Ваши open source-контрибьюторы теперь ИИ-first. Как не утонуть в потоке агентских пулреквестов</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Организация разработки]]></category>
      <category><![CDATA[Методологии разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Aug 2026 07:01:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если в очереди на ревью вашего open source-проекта всё чаще оказываются пулреквесты, написанные не человеком, а агентом, — вы не одни. Чтобы не утонуть в этом потоке, мейнтенеру нужно перенести правила рядом с кодом и настроить автоматические ворота: шаблон PR, CI, требования к тестам и лицензионное соглашение участника.</p><p>В AutoGPT, где на момент интервью у репозитория было свыше 180 тысяч звёзд и 150 открытых PR, большая часть этих PR создана агентами: Copilot, OpenClaw, собственными инструментами команды и сторонними ботами. Большинство мейнтенеров реагируют просто: закрыть дверь, отключить пулреквесты, не тратить силы на чужой LLM-вывод. Но у Николаса Тиндла, одного из основателей ИИ-инженерии в AutoGPT, другой взгляд: «По сути, кто-то другой платит за ваши вычислительные ресурсы. Если контрибьютор хочет потратить свои токены на улучшение вашего проекта — пусть тратит. Главное, сделать так, чтобы единственный путь внутрь проходил через ваши правила.»</p><p>ИИ-first контрибьютор — это разработчик, который отдаёт написание кода, тестов или документации генеративной модели, либо самоходный агент, который клонирует репозиторий, ищет issue, пишет код и открывает PR. Для мейнтенера результат одинаков: в репозиторий приходит поток кода, который часто не учитывает контекст проекта и требует ревью.</p><p>Агенты не ищут документацию сами — они читают то, что лежит рядом с кодом. AGENTS.md и CLAUDE.md в нужных директориях работают лучше, чем вики.</p><p>Пропускные ворота должны быть автоматическими и однозначными: шаблон PR, тест-план, CI как стена, CLA как детектор человека.</p><p>Не все ворота стоит оставлять включёнными: автоматические комментарии об ошибках CI быстро превращаются в шум.</p><p>Плохой AGENTS.md хуже, чем его отсутствие: избыточные инструкции засоряют контекст и ломают поведение агентов.</p><p>Мейнтенер всё ещё решает, что принимать: закрыть PR и переписать самому — тоже валидный выбор.</p><h2>Проблема не в документации, а в её обнаружении</h2><p>Первое, что пробовала сделать AutoGPT, — улучшить CONTRIBUTING.md, написать подробную вики и обновить гайды. Это не сработало. Дело в том, что агенты не ходят по ссылкам и не ищут документацию в разделах репозитория. Они смотрят на то, что находится в текущей директории и на один-два уровня выше. Если инструкция не лежит там, где агент работает, для него её не существует.</p><p>Сначала команда добавила файлы CLAUDE.md, потому что Claude открывал пулреквесты без достаточного контекста о репозитории. Потом выяснилось, что Copilot и Codex эти файлы игнорируют — они не Claude. Решением стал централизованный AGENTS.md, на который указывают все специфичные для модели файлы.</p><p>Важный нюанс: AGENTS.md действует внутри директории. Если агент работает в backend/, он видит правила для бэкенда. Если динамически загружается навык, связанный с фронтендом, агент может не знать, в какой директории искать инструкции — и навык сам должен ему подсказать путь. Поэтому в AutoGPT файл AGENTS.md лежит рядом с кодом, который он регулирует.</p><p><b>Навык — что это?</b><br />В терминологии агентских инструкций навык — это файл с описанием, по которому агент решает, когда загружать полный набор правил. Агент сканирует описания заранее и подключает нужный навык, когда задача совпадает. Например: «напиши Storybook-тест, если компонент лежит в этих папках».</p><p>Фронтенд-инженер AutoGPT устал от одного и того же класса сломанных PR в open source-проекте и оформил гайд как навык. Теперь каждый агент, который касается репозитория, видит триггер и выполняет правило. Бэкенд делает то же самое: не набрал 80% покрытия — PR не пройдёт.</p><h2>Ворота для ИИ-контрибьюторов в open source</h2><p>AutoGPT выстроила несколько механизмов, которые сдерживают поток низкокачественных пулреквестов и заставляют агентов вести себя предсказуемо.</p><h3>Шаблон пулреквеста как пропускной пункт</h3><p>В шаблоне PR прямо написано: PR, не соответствующий шаблону, закрывается автоматически и без колебаний. Команда даже построила бота, который это делает. Но запускать его не понадобилось — само правило изменило поведение агентов. Агенты стали заполнять шаблон. А вот люди иногда его игнорировали, и это Тиндл считает полезным сигналом: «Если вы не следуете шаблону, вы, скорее всего, человек, и я отнесусь к вам мягче.»</p><h3>Тест-план, который запускает код</h3><p>В шаблоне есть раздел тест-плана, и его формулировка незаметно подсказывает агенту протестировать пулреквест. Эта фраза активирует навык test PR: агент устанавливает браузер, разворачивает приложение и проверяет изменение. Агент пришёл поставить галочку, а в итоге запустил код. После этого сломанные PR стали редкостью. Осталась другая проблема — PR, которые работают, но не вписываются в дорожную карту.</p><h3>CI — стена, а не рекомендация</h3><p>Codecov и другие проверки настроены как required checks. Агент открывает PR, через несколько минут видит, что мёрж заблокирован, загружает навык с тестами и добивается покрытия. Никто не просил — инфраструктура сама направила агента.</p><h3>CLA (Contributor License Agreement) как детектор человека</h3><p>AutoGPT использует двойную лицензию, но Тиндл советует лицензионное соглашение участника (Contributor License Agreement, CLA) любому проекту, даже MIT. Подписание требует браузера и OAuth-потока GitHub на отдельном домене. Сегодня агенты с этим справляются плохо — и это хорошо, потому что большинство мейнтенеров не хотят, чтобы агент ходил в GitHub от их имени. Если CLA не подписан в течение недели, PR закрывается с комментарием «подпишите CLA и переоткройте».</p><h3>SHA коммита перед закрытием замечания</h3><p>Часть агентов закрывает все треды ревью, не исправляя код. В AutoGPT есть навык pr-address, который описывает допустимую последовательность: исправить, закоммитить, запушить, ответить, потом разрешить тред. Ответ должен содержать полный SHA коммита, полученный через git rev-parse HEAD, чтобы агент не подсунул старый хеш. Навык явно называет антипаттерны: «Acknowledged» — не исправление, и ссылка на коммит, который не трогает указанную строку, тоже не считается.</p><h2>Ворота, от которых пришлось отказаться</h2><p>Когда CI падает, AutoGPT изначально запускала агента, который читал лог и писал комментарий, что сломалось. Первая версия использовала Claude Code внутри GitHub Actions с аутентификацией в CI — лишняя широкая учётная запись. Потом перешли на Copilot внутри рабочего процесса: тот же результат, но без лишних кредов.</p><p>А потом выключили именно автоматические комментарии об ошибках CI. Прогоны в AutoGPT падают часто, и бот, который целыми днями описывает каждый падший прогон, создаёт не меньше шума, сколько и сами ошибки. Урок: оставляйте то, что снижает нагрузку на мейнтенера, и выключайте то, что превращается в фоновый шум.</p><h2>Четыре ловушки, которые стоит записать</h2><ul><li><b>Плохой AGENTS.md хуже, чем его отсутствие.</b> В AutoGPT сначала разбросали файлы повсюду и засорили контекст. Если поведение агентов ухудшилось — перечитайте, что вы написали.</li><li><b>GraphQL API GitHub быстро исчерпывает лимит запросов.</b> Если каждый инструмент в команде ходит в CLI как отдельный пользователь, лимит закончится. Создайте GitHub App и аутентифицируйте CLI через неё.</li><li><b>Сложное ревью стоит реальных денег.</b> У AutoGPT PR проходит через клон ветки, восемь агентов с разными ролями, запуск стека и скриншоты. Круто, но дорого. Сейчас эту процедуру запускают только для совсем маленьких или крупных PR.</li><li><b>Проверяйте авторизованные приложения.</b> Каждый протестированный инструмент оставляет OAuth-разрешение. Если перестали использовать приложение — удалите его из настроек GitHub.</li></ul><h2>Не всё в open source решается воротами</h2><p>Тиндл подчёркивает два тезиса, которые не связаны с инструментами. Первый: вы не обязаны принимать каждый пулреквест. Мёржить чужой LLM-вывод — асимметричная сделка: вы будете поддерживать этот код вечно. Закрыть PR и переписать решение самому — валидный выбор.</p><p>GitHub даёт мейнтенерам ручки: можно отключить пулреквесты целиком, ограничить создание issue только участникам с правами collaborator или требовать предварительного обсуждения. Если хотите — вообще закройте приём внешнего кода, как это сделали в SQLite: они принимают только баг-репорты. У вашего проекта тоже может быть своя граница.</p><p>Второй тезис: когда вы закрываете PR, но переписываете его идею сами, добавьте автора как соавтора, если это уместно. В AutoGPT 800 контрибьюторов, и один дополнительный соавтор ничего не стоит. Для большинства людей важно, что их проблему заметили и исправили.</p><h2>Выводы</h2><p>Open source развивался, делая сотрудничество явным: лицензии формализовали разрешения, issue сделали работу видимой, пулреквесты превратили ревью в общую практику. Инструкции для агентов в репозитории — следующий шаг в этом направлении. Правильная форма ещё не устоялась: у AutoGPT уже третья версия AGENTS.md, и она появилась потому, что команда сначала развёртывала плохие версии и смотрела, что с ними делают агенты.</p><p>Тиндл советует мейнтенерам записываться в программу обратной связи GitHub — maintainers.github.com:</p><blockquote>You've got to go there. You've got to sign up. It gets you all the connections you want at GitHub. That's where I learned about all this stuff, and where I share it.</blockquote><p>Мейнтенер всё ещё решает, что принимать, и задаёт планку. Разница лишь в том, что всё больше этого решения можно вынести рядом с кодом — туда, где уже находятся ваши контрибьюторы и их агенты.</p><p>Если тема интересна, загляните в разделы tproger: <a href="https://tproger.ru/tag/open-source">open source</a>, <a href="https://tproger.ru/tag/github">GitHub</a> и <a href="https://tproger.ru/tag/ai">искусственный интеллект</a>.</p><p><b>Источник:</b> <a href="https://github.blog/open-source/maintainers/your-contributors-are-ai-first-now-is-your-project/">GitHub Blog — Your contributors are AI-first now. Is your project?</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Как тестировать ИИ-агентов, если «правильно» не детерминировано</title>
      <link>https://tproger.ru/articles/kak-testirovat-ii-agentov-esli-pravilno-ne-determinirovano</link>
      <comments>https://tproger.ru/articles/kak-testirovat-ii-agentov-esli-pravilno-ne-determinirovano?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-testirovat-ii-agentov-esli-pravilno-ne-determinirovano</guid>
      <description><![CDATA[<p>GitHub построил Trust Layer для Copilot-агентов: валидация по ключевым состояниям вместо жёстких скриптов. Узнайте, как снизить ложные падения CI.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-testirovat-ii-agentov-esli-pravilno-ne-determinirovano">Как тестировать ИИ-агентов, если «правильно» не детерминировано</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Методологии разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[OpenAI]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 30 Jul 2026 09:32:53 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваш CI падает не из-за бага в коде, а потому что ИИ-агент выбрал другой путь к правильному результату — пора менять подход к тестированию. Классические тесты заточены под детерминированное ПО: на входе X, на выходе Y, посередине строго определённая последовательность шагов. Но агенты с функцией Computer Use работают с настоящими интерфейсами, где загрузка может длиться на полсекунды дольше, а кнопка оказаться в другом месте. GitHub недавно предложил способ отличать реальные ошибки от такого «шума» — независимый <b>Trust Layer</b>, который учится на примерах успешных запусков.</p><p>В этой статье разберём, почему стандартные assert-тесты и record-and-replay плохо справляются с автономными агентами, как теория графов помогает выделить обязательные этапы задачи и что из этого следует для российских команд, которые уже пробуют GitHub Copilot или собственных агентов в CI/CD.</p><p>Исследование, опубликованное 6 мая 2026 года в блоге GitHub, описывает метод валидации агентского поведения, который не требует ручного написания скриптов для каждого сценария и не верит агенту на слово. Вместо этого он строит модель «ground truth» из 2–10 успешных выполнений и проверяет новые запуски по структуре, а не по совпадению шагов.</p><ul><li>ИИ-агенты с Computer Use недетерминированы: один и тот же задача может решаться разными путями.</li><li>GitHub предлагает <b>Trust Layer</b> — внешний слой валидации, который учится на успешных запусках и выделяет обязательные этапы.</li><li>В основе — <b>Prefix Tree Acceptor (PTA)</b> и <b>dominator analysis</b> из теории компиляторов.</li><li>В эксперименте метод показал 100% accuracy, precision, recall и F1 против 82,2%, 83,3%, 60,0% и 69,8% у самооценки агента.</li><li>Trust Layer лучше определяет «не баг, а шум»: F1 52,2% против 0% у внутренней самопроверки агента.</li></ul><p>Современная разработка всё чаще сталкивается с ситуацией, когда «правильно» нельзя описать одной последовательностью действий. Агент может открыть поиск в VS Code через горячую клавишу или через меню, подождать загрузки или успеть до неё, кликнуть мышью или использовать клавиатуру. Для человека результат одинаков. Для классического теста — разные выполнения, одно из которых рискует быть отмечено как регрессия.</p><h2>Почему классические тесты сдаются</h2><p>Привычные инструменты тестирования хороши, пока путь выполнения фиксирован. Как только поведение начинает ветвиться, они начинают ломаться не от плохой инженерии, а от неверной посылки: «правильность = точное совпадение последовательности состояний».</p><ul><li><b>Assertion-based testing</b> требует вручную прописывать каждую проверку и не терпит допустимых альтернативных путей.</li><li><b>Record-and-replay</b> чувствителен к задержкам сети, рендерингу и незначительным изменениям интерфейса.</li><li><b>Visual regression</b> сравнивает скриншоты изолированно, не понимая контекста выполнения и семантики состояний.</li><li><b>ML-оракулы</b> — чёрный ящик: нужны тысячи примеров обучения, и невозможно объяснить, почему помечен конкретный прогон как ошибочный.</li></ul><p>В России эта проблема особенно актуальна для команд, которые используют self-hosted runners или зеркала репозиториев. Сетевые лаги, доступ к зарубежным API и особенности локальной инфраструктуры добавляют ещё больше «шума», не связанного с качеством кода. В результате CI начинает «краснеть» по чужой вине, а разработчики привыкают игнорировать падения.</p><h2>Что значит «правильно» для агента</h2><p>GitHub предлагает переформулировать определение корректности: не «агент повторил записанный сценарий», а «агент достиг обязательных результатов». Это разделяет поведение на три категории.</p><ul><li><b>Обязательные состояния (essential states).</b> Этапы, без которых успех невозможен. Например, открытие диалога поиска и появление результатов.</li><li><b>Опциональные вариации (optional variations).</b> Случайный шум: спиннер загрузки, небольшая задержка, временное уведомление.</li><li><b>Сходящиеся пути (convergent paths).</b> Разные последовательности действий, которые приводят к одному и тому же итоговому состоянию.</li></ul><p>Ключевой инсайт: если состояние «спиннер загрузки» можно пропустить в быстром прогоне, оно не может быть обязательным. А вот состояние «диалог поиска открыт» доминирует результат: без него невозможно получить список найденного. Эта идея напрямую заимствована из теории компиляторов — <b>dominator analysis</b>.</p><h2>Как устроен Trust Layer</h2><p>Метод GitHub состоит из трёх шагов: собрать успешные выполнения, построить из них единую модель и выделить в ней обязательные состояния.</p><h3>От трасс к графу</h3><p>Вместо линейного скрипта каждое выполнение представляется как направленный граф. Узлы — наблюдаемые состояния: скриншоты интерфейса, снапшоты кода или структуры DOM. Рёбра — действия агента: клики, нажатия клавиш, вызовы API. Несколько успешных трасс объединяются в <b>Prefix Tree Acceptor (PTA)</b> — дерево, которое сохраняет общие префиксы и разветвляет пути там, где выполнения действительно расходятся.</p><h3>Три уровня эквивалентности</h3><p>Самая сложная часть — понять, когда два разных состояния на самом деле одно и то же. GitHub использует трёхуровневую проверку.</p><ol><li><b>Визуальные метрики.</b> Быстрые perceptual hash и SSIM ловят почти идентичные скриншоты.</li><li><b>Семантический анализ через LLM.</b> Мультимодальная модель решает, значима ли разница: timestamp или декорация окна игнорируются, пропавшая кнопка или другое сообщение об ошибке — фиксируются.</li><li><b>Консервативное слияние.</b> Состояния объединяются только при высокой уверенности, чтобы не потерять реальное расхождение.</li></ol><h3>Доминаторы выделяют суть</h3><p>После слияния к графу применяется <b>dominator analysis</b>. Состояние A доминирует состояние B, если любой путь от начала к B проходит через A. Те состояния, которые доминируют успешное завершение задачи, становятся обязательными. Всё остальное автоматически классифицируется как опциональный шум.</p><p>При проверке нового прогона алгоритм не ищет точное совпадение. Он проверяет, что обязательные состояния появились в правильном порядке. Если эталонная последовательность A → B → C, а агент выполнил A → X → B → Y → C, тест проходит: X и Y считаются случайными вставками. Если пропущено B или нарушен порядок — фиксируется конкретная ошибка с пояснением, какое состояние не достигнуто.</p><h2>Цифры: насколько это лучше</h2><p>Авторы сравнили свой метод PTA (Dominator Tree) с самооценкой агента Computer-Use Agent (CUA) на наборе тестов кастомного расширения VS Code. Разница оказалась впечатляющей.</p><ul><li><b>Accuracy:</b> CUA — 82,2%, PTA — 100% (+17,8 п. п.).</li><li><b>Precision:</b> CUA — 83,3%, PTA — 100% (+16,7 п. п.).</li><li><b>Recall:</b> CUA — 60,0%, PTA — 100% (+40,0 п. п.).</li><li><b>F1-Score:</b> CUA — 69,8%, PTA — 100% (+30,2 п. п.).</li></ul><p>Ещё важнее метрика «не баг, а шум» (not-a-bug). Сам агент не смог корректно классифицировать такие сценарии: F1 оказался 0%. Trust Layer на основе структурного анализа достиг F1 52,2%. Это означает, что разработчики тратят меньше времени на разбор ложных падений.</p><blockquote>We don’t need black-box models to judge other black-box models. We need structural guarantees developers can inspect, reason about, and trust.</blockquote><h2>Как это применить в своём CI/CD</h2><p>Полноценная реализация Trust Layer требует исследовательского прототипа, но идеи можно перенести и в повседневную работу команд.</p><ol><li><b>Собирайте «золотые» трассы.</b> Сохраняйте 2–10 успешных выполнений критичного сценария, чтобы у будущих прогонов была эталонная структура.</li><li><b>Отделяйте «должен быть» от «может быть».</b> Вместо проверки каждого шага фиксируйте ключевые чекпоинты: авторизация выполнена, данные сохранены, ответ получен.</li><li><b>Делайте тесты толерантными к порядку.</b> Если несколько допустимых путей ведут к одному результату, проверяйте результат и наличие обязательных промежуточных состояний, а не точную последовательность.</li><li><b>Используйте семантику, а не пиксели.</b> Визуальные регрессии должны понимать, что изменилось, а не просто считать разницу между скриншотами.</li><li><b>Не верьте агенту на слово.</b> Внешняя валидация по состояниям среды надёжнее самооценки модели, особенно в недетерминированных задачах.</li></ol><p>Для российских команд, работающих с ограниченным доступом к зарубежным API, важный вывод: если агент зависит от внешнего сервиса, валидация должна уметь отличать проблему сети от проблемы продукта. Иначе любой transient timeout будет превращаться в красный CI.</p><h2>Выводы</h2><p>ИИ-агенты переходят из демо в production, и вместе с ними должно эволюционировать тестирование. Проверять агента жёстким скриптом — всё равно что проверять водителя по тому, всегда ли он переключает передачи одной и той же рукой. Важно не это, важно — доехал ли он до пункта назначения и не нарушил ли правил.</p><p>Подход GitHub с Trust Layer, PTA и dominator analysis даёт объяснимую и лёгкую модель корректности, которую можно встроить в CI/CD. Она не требует тысяч примеров и не превращается в чёрный ящик. А главное — снижает количество ложных падений, за которыми теряются настоящие баги.</p><p>Источник: <a href="https://github.blog/ai-and-ml/generative-ai/validating-agentic-behavior-when-correct-isnt-deterministic/">Validating agentic behavior when “correct” isn’t deterministic — The GitHub Blog</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Я написал свой self-hosted MDM для смешанного парка корпоративных устройств</title>
      <link>https://tproger.ru/articles/ya-napisal-svoj-self-hosted-mdm-dlya-smewannogo-parka-korporativny</link>
      <comments>https://tproger.ru/articles/ya-napisal-svoj-self-hosted-mdm-dlya-smewannogo-parka-korporativny?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Павел Смирнов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/ya-napisal-svoj-self-hosted-mdm-dlya-smewannogo-parka-korporativny</guid>
      <description><![CDATA[<p>Self-hosted MDM/RMM на Go для Windows, macOS и Linux: gRPC + mTLS без VPN, инвентаризация, скрипт-политики, временные админ-права, блокировка устройства. Архитектура, модель доверия и ограничения.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/ya-napisal-svoj-self-hosted-mdm-dlya-smewannogo-parka-korporativny">Я написал свой self-hosted MDM для смешанного парка корпоративных устройств</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 29 Jul 2026 08:21:32 GMT</pubDate>
      <content:encoded><![CDATA[<p>Полгода назад я пришёл в новую организацию, и мне достался парк машин. Десяток на Windows, несколько маков, пачка линуксовых ноутов у разработчиков. Невыносимым было другое. Навешанные до меня политики и блокировки со стороны ИБ связывали руки так, что здраво администрировать домен было попросту нельзя: любое рутинное действие упиралось в чужие ограничения. Тогда я и полез искать решение, которое помогло бы мне нормально админить этот парк.</p><p>Готового, что легло бы на мою ситуацию, я так и не нашёл — и в итоге сел писать своё. Ниже — разбор инженерных решений, которые по дороге пришлось принять, и карта того, где у этой конструкции проходит настоящая граница безопасности. Последнее для меня важнее всей остальной механики: MDM по определению даёт слишком много власти над чужими машинами, и делать вид, что это не так, я не стал. Поэтому архитектуру ниже я описываю как ответ на вопрос «где это ломается».</p><figure><img src="https://media.tproger.ru/user-uploads/139596/2026-07-27/a5c16083-003f-4c47-87d4-2860f31cc618.webp" alt="" /></figure><h3>Откуда взялась задача</h3><p>Требований у меня было немного, но именно они всё и отсеяли: сервер должен стоять у меня, телеметрия парка не утекать на сторону, и всё это работать на смешанном парке сразу. Self-hosted-вариантов под такое оказалось немного, и те, что были, спотыкались об одно и то же: либо только маки, либо платные и при этом недоступны в России, либо разваливались на простом вопросе — а что с устройством, если агент две недели просидел офлайн. Ближе всего в этом поиске подобрался Fleet — серьёзный открытый проект, к нему я ещё вернусь ниже. Но развернуть его у себя оказалось тем ещё квестом: я в России, а fleetdm на российский IP не але, так что и сервер, и сборку агентов приходилось поднимать через VPN. Вдобавок агент на macOS в моём случае вставал через раз, а то и вовсе не ставился. Инструмент, который в итоге получился, я назвал RoutineOps; дальше по тексту буду говорить «агент», «сервер» и «панель».</p><p>Ещё одно соображение, которое я держал в голове: базовую защиту управляющего канала — mTLS, аудит, вменяемую политику паролей, подпись обновлений — я считаю БАЗОЙ, и держать её за пейволлом мне казалось неправильным. Это моё мнение, не претензия к рынку. Проект в итоге открыт под Apache-2.0; платный уровень существует, но вся базовая защита — в открытой части, и это не тема статьи.</p><h3>Почему постоянный gRPC/mTLS-канал, а не опрос через VPN</h3><p>Вечная головная боль: как дотянуться до ноутбука, который сейчас сидит в кафе за чужим NAT. Классических ответов два, и оба мне не понравились. Загнать всех в VPN — это лишняя инфраструктура и ещё одна точка отказа. Сделать агент, который раз в N минут дёргает HTTP-эндпоинт «не прилетело ли чего», — это шторм пустых запросов, а задержка команд упирается в период опроса.</p><p>Я пошёл третьим путём. Агент — Go-бинарь, который держит постоянный gRPC-стрим поверх mTLS наружу, по обычному интернету. Соединение инициирует сам агент: оно исходящее, а значит дружит с NAT. По этому же двунаправленному стриму сервер в любой момент проталкивает команду — запусти скрипт, заблокируй экран. Задержка доставки тут — это задержка сети, а не интервал, на который выставлен опрос.</p><p>Стек намеренно скучный — скучное не будит меня в три ночи.</p><p>- Агент и сервер — Go, сервер монолитом, без зоопарка микросервисов.</p><p>- Связь — gRPC + Protocol Buffers поверх mTLS: TLS 1.3, приватный CA с пиннингом на всём канале агентов.</p><p>- База — PostgreSQL 16, источник правды.</p><p>- Очередь задач — Redis + Asynq, с ретраями.</p><p>- Веб-интерфейс — React + TypeScript (Vite), раздаётся nginx-контейнером.</p><p>- Развёртывание — Docker Compose.</p><p>Порты минимальны: `443` — веб-интерфейс, REST API, enroll, отдача бинарей; `50051` — постоянный gRPC-канал агентов. Postgres и Redis наружу не торчат вообще. На парк до 50 устройств хватает 1 vCPU / 2 GB RAM / 20 GB SSD — и это стартовая планка. Heartbeat дешёвый, инвентарь редкий, поэтому один узел спокойно тянет тысячи устройств: предел задаёт железо машины, не архитектура.</p><h3>Сертификат — это идентичность, и всё</h3><p>Самый важный архитектурный вопрос: как агент доказывает, что он именно то устройство, за которое себя выдаёт. Ответ короткий. `device_id` — это CN клиентского сертификата, и только он. Идентификаторам в теле сообщений сервер не верит вообще. Прилетел heartbeat, а внутри указан чужой `device_id`? Игнорируется. Значение имеет одно — чем подписан TLS-хендшейк.</p><p>Отсюда и enrollment, устроенный так, чтобы приватный ключ устройства никогда не покидал устройство:</p><p>1. Админ в панели заводит устройство и получает одноразовый токен: TTL 24 часа, single-use, гонка при погашении закрыта на уровне БД.</p><p>2. Агент локально генерирует пару ключей и отправляет CSR на `POST /api/v1/enroll`.</p><p>3. Сервер подписывает сертификат своим приватным CA и сам проставляет CN. Повлиять на свой CN агент не может.</p><p>Подделать чужое устройство без его ключа не выйдет — и не потому, что «мы проверяем поля», а потому, что проверять тут в принципе нечего. Криптография здесь вырезает целый класс авторизационной логики. Решение нравится мне тем, что после него кода становится меньше.</p><h3>Вывод из эксплуатации — это отзыв сертификата</h3><p>Раз идентичность держится на сертификате, то и снятие устройства с учёта — операция того же уровня, а не косметика в списке. «Вывести из эксплуатации» прямо из карточки отдаёт агенту команду на полное самоудаление: служба, бинарь, ключи, локальное состояние. Удаление из инвентаря при этом отзывает сертификат — и устройство, с которого агент по каким-то причинам не ушёл, обратно не «воскресает»: его хендшейк отваливается на сервере, потому что предъявлять ему больше нечего.</p><p>Enrollment подтянулся туда же. Токены выписываются пачкой, есть список выданных, отзыв любого до истечения TTL и отдельная секция «выдан, но так и не подключился». После раскатки на два десятка машин именно этот список отвечает на вопрос, какие из них до сервера не доехали.</p><h3>Heartbeat и инвентаризация разведены нарочно</h3><p>Наивно было бы слить всё в один поток: раз в минуту слать полный отчёт о железе и заодно сообщать, что жив. На парке это дорого и бессмысленно — список установленного софта не меняется каждые тридцать секунд. Поэтому потока два, независимых.</p><p>Heartbeat — лёгкий и частый, примерно раз в 30 секунд, по постоянному стриму; по нему же едут задачи. Дёшево, потому что данных в нём кот наплакал. Инвентаризация — тяжёлая и редкая, примерно раз в 5 минут: ОС, железо, серийник, установленное ПО (на Linux — из dpkg/rpm/pacman/apk), версия агента.</p><p>Такое разделение держит постоянный канал дешёвым при любом размере парка. Если устройство пропало с радаров и heartbeat не приходит дольше порога (порог настраивается через `AGENT_UNREACHABLE_MINUTES`) — поднимается алерт `agent_unreachable`, с подавлением дребезга от сна и modern standby, иначе каждый закрытый на ночь ноут спамил бы в Tele... <b>Max</b> :).</p><p>Результаты скриптов идемпотентны. У каждого запуска есть `run_id`, и повторная доставка дедуплицируется на сервере. Связь рвётся, ack теряется, агент шлёт результат заново — без этой механики ловил бы дубли, а на неидемпотентных командах ещё и двойное исполнение.</p><figure><img src="https://media.tproger.ru/user-uploads/139596/2026-07-27/ebaadeb9-3b63-4fc0-a08e-d3912af1bdc2.webp" alt="" /></figure><h3>Скрипты, группы и вопрос «а на скольких машинах это сейчас так»</h3><p>Разовый запуск скрипта — самое простое, что можно сделать с постоянным каналом, и самое бесполезное в отрыве от остального: выбирать устройства мышкой нормально ровно до тех пор, пока их пятнадцать. Дальше нужны группы. Группа — это членство, цвет и точка привязки: к ней цепляются скрипт- и софт-политики, на неё же уходит фан-аут разового запуска.</p><p>У скрипт-политик три триггера: расписание (cron), при подключении агента и по событию. Третий появился из практики — реакция на «поставили запрещённое» полезна в момент установки, а не в ближайшие плановые три часа ночи. Софт-политики — правила allowed/forbidden по устройству, группе или платформе; они же кормят алерты: увидел агент в инвентаре то, чего быть не должно — прилетело событие.</p><p>А поверх этого — то, чего мне больше всего не хватало в чужих инструментах: по каждой политике видно охват и Pass / Fail. На сколько устройств она распространяется и сколько из них ей соответствуют. Политика без счётчика соответствия — не политика, а благое пожелание, лежащее в базе.</p><figure><img src="https://media.tproger.ru/user-uploads/139596/2026-07-27/e940b58d-ffbf-4eae-a419-901d9125c9a4.webp" alt="" /></figure><h3>Агенту не нужна постоянная связь</h3><p>Постоянный канал удобен, но агент не должен превращаться в кирпич, стоит серверу отвалиться. Cron-скрипт-политики крутит локальный планировщик прямо на устройстве: сервер лёг на обновление — политики по расписанию всё равно отработают.</p><p>Сложнее всего с блокировкой экрана. В офлайне полноэкранный overlay держится, а разблокировка идёт по локально хранимому bcrypt-хешу пароля — ходить за ней к серверу не нужно. Это осознанный компромисс: если бы разблокировка требовала сервер, любой обрыв связи превращал бы блокировку в невозможность войти в систему — а это уже хуже самой угрозы. Результаты и события тем временем копятся локально и досылаются, когда связь вернётся.</p><figure><img src="https://media.tproger.ru/user-uploads/139596/2026-07-27/c183f28c-3607-4280-a27e-051fa8b5b2a2.webp" alt="" /></figure><h3>Обход блокировки — это тоже событие</h3><p>Оверлей держится офлайн, но живёт он на машине, у пользователя которой есть руки. Поэтому у службы агента есть tamper-protection: на Windows — SafeBoot плюс реестр, на macOS — флаг `schg`. На Linux её нет, и это записано в docs/tamper-protection.md прямым текстом, а не подразумевается. Штатное снятие защиты — отдельная процедура, а не «убил процесс и пошёл дальше».</p><p>Попытка снять блокировку в обход службы поднимает событие ИБ. Логика та же, что и везде выше: при физическом доступе к железу механику рано или поздно обойдут — но пусть обход хотя бы не будет тихим. Не остановить, так зафиксировать.</p><figure><img src="https://media.tproger.ru/user-uploads/139596/2026-07-27/6b4624b3-1ada-499d-bd44-9b6e7cbccb12.webp" alt="" /></figure><h3>Временные админ-права — без поездки к машине</h3><p>Бытовой, но постоянный сценарий: пользователю нужно поставить программу, которая требует прав администратора. Раньше это значило либо дойти до машины ногами, либо подключиться к ней удалённо и вбить админский пароль руками — и так на каждую установку.</p><p>Теперь пользователь запрашивает временные локальные админ-права прямо из трея агента, я одобряю заявку в панели — и он ставит нужное сам, а по истечении срока повышение снимается. Ни подходить к машине, ни поднимать удалённую сессию ради одной инсталляции не надо. Мелочь на фоне остальной механики, но именно из таких мелочей и складывалось то самое «здраво администрировать парк», ради которого всё и затевалось.</p><figure><img src="https://media.tproger.ru/user-uploads/139596/2026-07-27/28911031-666f-41ad-8784-cd9bb5dafb62.webp" alt="" /></figure><h3>Конфигурация как код — потому что кликать второй раз я не хотел</h3><p>Банальность, которая доходит не сразу: скрипты, политики и группы, собранные мышкой, существуют ровно в одной базе на одном сервере. Поднять рядом стенд — значит проклацать всё заново, а потом гадать, чем он от боевого отличается.</p><p>Поэтому появился CLI `routineops` с YAML-экспортом и применением: выгрузил скрипты, политики и группы в файлы, положил в git, применил на другом сервере. Diff конфигурации теперь читается в ревью, а не реконструируется по журналу аудита задним числом.</p><h3>Fail-closed self-update и миграции</h3><p>Самообновление — самый опасный канал из всех. Тот, кто им рулит, кладёт свой бинарь на все устройства как root. Поэтому здесь всё fail-closed. Примерно раз в 6 часов агент тянет манифест и проверяет sha256 и ed25519-подпись по полному манифесту: версия, ОС, архитектура, хеш подписаны одним набором сразу. Так нельзя подсунуть валидный бинарь под чужую версию или платформу. Дальше агент атомарно заменяет себя и перезапускается. Даунгрейд невозможен — есть anti-rollback floor: битый релиз чинится только версией вперёд, назад дороги нет. Приватный ключ подписи уникален для конкретной инсталляции; потеря не катастрофа — новый раздаётся через переэнролл.</p><p>На сервере тот же принцип. Схему накатывает отдельный migrate-сервис — до старта сервера. Не прошла миграция — сервер просто не поднимется на несовместимой схеме. Down-миграций нет, и это намеренно: откат — только из бэкапа, причём бэкап БД update.sh снимает сам перед каждым обновлением. Пережить факап из снапшота я предпочту тому, чтобы полагаться на корректность down-скрипта, накатываемого поверх наполовину применённого состояния.</p><h3>Модель доверия: god-mode by design</h3><p>А вот тут льстить не буду — и это, пожалуй, самая важная часть текста. MDM по своей природе — это god-mode над парком. Скрипт-канал исполняет произвольный `bash -c` / `powershell -Command` как root/SYSTEM на каждом устройстве. Это не дыра, которую я забыл заткнуть. Это и есть продукт: весь смысл MDM в том, чтобы раскатать одну команду на сотню машин разом. А такой инструмент по определению — санкционированный RCE.</p><p><b>Скажу прямо.</b></p><p>- Подписи на скрипт-канале нет. И не будет. Ed25519-подпись защищает только канал самообновления — анти-тампер и анти-даунгрейд бинаря. Она никак не ограничивает то, что вы запускаете на устройствах. Тезис «скомпрометированный сервер не сможет выполнить код на парке» — неверное прочтение. Ещё как сможет: выполнение произвольного кода на парке — это его штатная функция.</p><p>- `JWT_SECRET` (симметричный HS256) — единственный корень доверия панели. Кто прочитал этот секрет, тот печатает себе сколько угодно валидных admin-токенов. Не «подобрать пароль», не «обойти MFA» — просто сгенерировать подписанный токен и зайти админом.</p><p>- Отсюда единственный вывод: реальный периметр безопасности — это хост, на котором крутится сервер. Не TLS, не RBAC, не аудит. Они важны, но вторичны. Увели сервер — увели весь парк.</p><p>Харденинг этого хоста — работа оператора, и в SECURITY.md под неё лежит чеклист: SSH только по ключам, наружу открыты только два порта, Postgres и Redis — на localhost, `JWT_SECRET` генерируется через `openssl rand -base64 48` и лежит в режиме `600`, панель — за VPN или IP-allowlist, аудит-лог — в append-only хранилище с алертом на появление новых админов.</p><p>Я специально не прячу этот раздел в мелкий шрифт. Любой MDM устроен ровно так же — просто не каждый проговаривает это вслух. Мне важно, чтобы человек ставил такой инструмент с открытыми глазами: в безопасности честность — это техническое свойство, а не тон голоса.</p><h3>Что закрыто по умолчанию</h3><p>Периметр — на операторе. Но всё, что можно закрыть кодом, закрыто по умолчанию, без единой галочки:</p><p>- Не стартует на слабом секрете. Требует `JWT_SECRET` от 32 байт и минимум 16 различных байт. Случайно уехать в прод на `changeme` не получится.</p><p>- Admin-JWT живёт 8 часов. Logout реально ревокирует токен через jti-блоклист. Смена или сброс пароля обнуляет все ранее выданные токены пользователя разом — через token-epoch.</p><p>- Lockout по IP и по аккаунту, bcrypt cost 12. Форма входа не выдаёт, какие аккаунты вообще существуют.</p><p>- Политика сложности пароля — для всех, включая seed-админа: от 8 символов, минимум 3 класса символов из 4. Даже первый администратор не заведётся с `admin/admin`.</p><p>- RBAC на две роли — `it_admin` (всё) и `viewer` (только чтение), с проверкой на сервере. Viewer, дёрнувший мутирующий эндпоинт прямо из DevTools, упрётся в 403 ещё на сервере.</p><p>- API-токены — отдельная сущность, а не админская сессия. Выпуск и отзыв из панели: интеграции ходят под своим токеном, и выключается такой доступ одним действием.</p><p>- Плюс одноразовые enroll-токены, журнал аудита на каждое привилегированное действие (retention по умолчанию 365 дней), security-заголовки (HSTS/CSP/X-Frame-Options/nosniff), rate-limit и cap на размер запроса.</p><p>Ни одна из этих механик не спасёт скомпрометированный хост — см. раздел про модель доверия. Они закрывают то, что реально можно закрыть на уровне приложения, и не притворяются, что закрывают больше.</p><h3>Мелочи, из которых на самом деле состоит эксплуатация</h3><p>Отдельного раздела каждая из них не заслуживает, но вместе они закрывают вопрос «а как я об этом узнаю»:</p><p>- Удалённая перезагрузка устройства или всей группы. Отсрочку отсчитывает сама ОС, а не таймер внутри агента: агент может умереть, ребут — нет.</p><p>- «Пользователь за консолью» в карточке. Кто прямо сейчас сидит за машиной. Без этого половина алертов повисает в воздухе.</p><p>- Владелец устройства — карточка человека. ФИО и почта, без аккаунта в панели и приглашения. Владелец — свойство железа, а не пользователь системы, и смешивать эти сущности я не стал.</p><p>- Расширенный инвентарь ПО: издатель, путь, архитектура, ключ снятия, машина/профиль. Инвентарь, по которому не отличить системную установку от пользовательской, для софт-политик бесполезен.</p><p>- `agent diag` на устройстве. Первый вопрос в поле всегда один — «почему агент не выходит на связь», и отвечать на него по логам сервера бессмысленно: сервер как раз ничего и не видит.</p><p>- Пагинация и серверные фильтры в списках устройств и в аудите. Скучно, но на 365 днях журнала это разница между инструментом и вечно думающей вкладкой.</p><h3>Честные ограничения</h3><p>Раз обещал честность — вот граница, без прикрас.</p><p>- Один узел — одна точка отказа. Для парка в режиме «поставил и работает» этого достаточно, но иллюзий про отказоустойчивость держать не стоит.</p><p>- Нет SSO и MFA. Вход по паролю плюс RBAC. Пока разумно держать панель за VPN или allowlist.</p><p>- macOS .pkg не подписан Apple. По двойному клику встретит Gatekeeper — ставится через `installer` из терминала.</p><p>- Скрипт-канал — это RCE by design. Подробно — в разделе про модель доверия выше.</p><p>- Интерфейс только на русском. Около 2000 строк захардкожены в компонентах, библиотеки локализации нет. Английский вторым языком — ближайший приоритет: публичный репозиторий с русским интерфейсом отсекает всех внешних.</p><p>- Оверлея блокировки на Linux нет. Состояние блокировки хранится, экрана нет.</p><p>- Запрещённое ПО детектится, но не удаляется. Алерт есть, автоматического устранения — нет.</p><p>- Под Windows нет сборки arm64. Для Linux и macOS arm64 есть.</p><h3>Про Fleet</h3><p>Ближайший открытый аналог, который я смотрел, — Fleet, тоже open source, ядро под MIT. Инструмент серьёзный и зрелый, и во многом он сильнее моего: настоящий нативный MDM с профилями конфигурации и zero-touch-энроллментом, live-запросы osquery по всему парку, расчёт на масштаб в сотни тысяч машин. Построен вокруг osquery, инфраструктура — MySQL плюс Redis за балансировщиком, под горизонтальное масштабирование.</p><p>Под мой случай он просто не сошёлся по устройству. Чтобы реально управлять маками, Fleet опирается на нативный Apple MDM — а это APNs-сертификат от Apple с ежегодным продлением плюс Apple Business Manager для zero-touch. Мне не нужна была SQL-аналитика по всему парку; нужен был лёгкий агент, офлайн-лок без APNs, инвентарь и скрипты. А поверх этого архитектурного несовпадения легли те самые бытовые проблемы с развёртыванием из России и капризным macOS-агентом, о которых я писал в начале.</p><h3>Чему это меня научило</h3><p>Самое неожиданное в проекте — что львиная доля инженерных решений оказалась не про «как добавить», а про «как убрать». Идентичность через CN вырезала целый класс серверной авторизации; fail-closed на миграциях и обновлениях — ветки «а что если накатилось наполовину». Разведённые heartbeat и инвентарь сняли лишний трафик. А карта модели доверия избавила меня самого от иллюзии, будто TLS и RBAC — это и есть безопасность. Настоящий периметр оказался в одном месте — на хосте сервера.</p><p>Исходники я открыл под Apache-2.0; прямую ссылку на репозиторий оставлю <a href="https://github.com/Floodww/RoutineOps" rel="nofollow">тут</a> :). Если вам будет интересно я бы с радостью пообщался по замечаниям именно по модели доверия — по местам, где приложение должно что-то enforce-ить, но не делает.</p>]]></content:encoded>
    </item>
    <item>
      <title>Своя self-hosted двухсерверная VPN-архитектура. Подробный путь разработки и ошибки, с которыми вы можете столкнуться</title>
      <link>https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r</link>
      <comments>https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Роман Фролов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r</guid>
      <description><![CDATA[<p>Проект представляет из себя быстрый способ воссоздать архитектуру состоящую из 2 серверов (локальный + удаленный) с определенными сервисами, которые решают специфические задачи. Проект сделан прежде всего для меня, а также для людей которые хотят свой готовый self-hosted сервер из коробки с полной системой обслуживания</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/svoya-self-hosted-dvuhservernaya-vpn-arhitektura-podrobnyj-put-r">Своя self-hosted двухсерверная VPN-архитектура. Подробный путь разработки и ошибки, с которыми вы можете столкнуться</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[unix]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Музыка]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[DIY]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[VPN]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[NFT]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[VPS]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 26 Jul 2026 15:46:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Всё
 началось с того, что меня перестал устраивать мой подход к 
развертыванию личных сервисов. Я решил переписать всё с нуля. К тому же 
это был отличный повод получить новые навыки и попробовать инструменты, 
до которых давно не доходили руки.</p><p>Арендовать мощные VPS под 
ресурсоемкие задачи в текущих реалиях выходит неоправданно дорого. При 
этом дома у меня уже был выделенный неттоп (мини-ПК) с 16 ГБ оперативной
 памяти на базе энергоэффективного процессора Intel N95.</p><p>Пройдя 
путь от простых Bash-скриптов и сторонних туннелей до полностью 
автоматизированной инфраструктуры, я создал проект ServeHub-2. В этой 
статье я подробно разберу, как эволюционировала сеть проекта, почему 
декларативный подход победил императивный и с какими неочевидными багами
 пришлось столкнуться в процессе автоматизации.</p><h2>История настройки сетевой архитектуры</h2><h3>Использование Tuna</h3><p>В
 самом начале проекта я еще не думал о VPN как о способе пробития NAT и 
основе, на которой будет строиться вся система. Первое, к чему я пришел —
 сервис Tuna. Если кратко, это аналог Cloudflare Tunnel за условные 300 
рублей. У него очень приятный веб-интерфейс и невероятно простая 
настройка. Однако для полноценной независимой архитектуры он не подошел 
по двум причинам:</p><ul><li>Сервера Tuna находятся вне контроля пользователя.</li><li>На удаленном сервере нельзя развернуть свои сопутствующие сервисы.</li></ul><p>В целом сервис действительно удобный, но для моих задач он оказался слишком ограничивающим.</p><p>Вот
 пример конфига для tuna (все максимально просто, создаем контейнеры для
 ssh туннеля, чтобы был доступ ssh, а также основной http туннель с 
привязкой к nginx или любому другому прокси если такой есть):</p><h3>В поисках гибкости: тесты Pangolin и переход к FRP</h3><p>После Tuna я решил двигаться в сторону собственного контроля и попробовал Pangolin.
 Однако решение быстро отвалилось: для дешёвого сервера оно оказалось 
слишком «тяжёлым» и избыточным. Главные минусы — ощутимый оверхед по 
ресурсам и лишний слой принудительной веб-аутентификации перед самими 
сервисами. Это ломало нормальное взаимодействие с родными мобильными 
клиентами (вроде Element для Matrix или Bitwarden для паролей), где 
повторная авторизация в браузере просто не нужна.</p><p>На смену пришел FRP (Fast Reverse Proxy).
 Он выполнял ту же функцию проброса, но хостил я его уже на собственном 
арендованном VPS в режиме Layer 4 (TCP). Это дало абсолютную гибкость: 
внешний VPS не заглядывал внутрь пакетов и ничего не расшифровывал, а 
просто пересылал сырой поток домой. Кроме того, это отлично 
оптимизировало расходы: вместо 300 рублей за Tuna и ещё 300 рублей за 
отдельный VPN, я стал платить всего 500 рублей за один стойкий VPS, 
который мог настраивать как хочу. (к тому же можно было обойтись даже 
дешевле, так как VPS с 4 гб оперативки загружен всего лишь на 40%, 
процессор всего на 20%-40%)</p><p>FRP состоит из 2 конфигурационных 
файлов (один на удаленном сервере frp server, другой на локальном frp 
client), все также довольно просто, однако его можно использовать на 
разных слоях. У меня он брал трафик за стандартный TCP и передавал его 
на локальный сервер.</p><p>Также доп. фишка в том что основная 
конфигурация происходит именно в frpc, который, в свою очередь, передает
 часть настроек на frp на удаленном сервере.</p><p>frpc.toml:</p><p>frps.toml:</p><h3>Полноценный переезд на WireGuard (AmneziaWG) и 8 часов отладки</h3><p>Со временем архитектура эволюционировала в сторону полноценной VPN-сети на базе WireGuard, а точнее — его модификации AmneziaWG. Причин для этого шага было несколько:</p><ul><li>Безопасность: FRP всё же открывал внутренние ресурсы в публичный интернет, оставляя их доступными для сканеров портов.</li><li>Удобство маршрутизации:
 Все участники сети стали равноправными узлами в одной виртуальной 
локальной подсети. Больше не нужно было настраивать постоянные 
односторонние пробросы.</li><li>Дополнительный бонус:
 Поскольку удаленный VPS был куплен в Нидерландах, через этот же VPN я 
автоматически получил безопасный доступ ко всем зарубежным ресурсам.</li></ul><p>Для реализации схемы на удаленном VPS был развернут контейнер wg-easy с поддержкой AmneziaWG, а на домашнем мини-ПК — клиентский контейнер Amnezia (сборка из Dockerfile с использованием amnezia-tools  и модулем ядра хоста).</p><p>И
 именно здесь я поймал самый изнурительный баг проекта. После 
развертывания трафик упорно шёл только в одну сторону. Часов 8 ушло на 
диагностику iptables, маршрутов и чтение зарубежных форумов (что 
бесполезно, учитывая специфику наших блокировок). Оказалось, провайдер 
просто дропал обратный трафик стандартного WireGuard, так как пакеты шли
 без маскировки. Причина крылась в docker-compose.yml: у меня было прописано image: ghcr.io/wg-easy/wg-easy:latest. Как выяснилось, тег latest  на Docker Hub намертво прилип к старой 14-й версии, а поддержка параметров AmneziaWG появилась только в ветке 15.x. Изменение тега на конкретную версию (15.3) решило проблему за секунду.</p><p>Благодаря
 переходу конфигурация получилась максимально простой, основные отличия 
от стандартной документации выделил в коде: (в основном то, на что 
пришлось долго рыть информацию)</p><h3>Настройка Nginx</h3><p>Чтобы
 сервисы были доступны исключительно внутри подсети VPN, я задействовал 
Nginx. Доступ к приложениям был жестко ограничен на уровне конфигурации —
 веб-сервер принимает запросы только из диапазона IP-адресов 10.8.0.0/24. Любые попытки постучаться на сервер из внешнего интернета без активного VPN-туннеля автоматически сбрасываются Nginx.</p><p>Логика
 распределения завязана на proxy-протоколе: Nginx на удаленном VPS 
выступает основным входным узлом, принимает зашифрованный трафик, 
заворачивает его в заголовки с реальным IP-адресом клиента и через 
туннель перекидывает на локальный Nginx домашнего сервера. Локальный 
веб-сервер уже сам расшифровывает SSL и распределяет трафик по конечным 
Docker-контейнерам, сохраняя реальные IP в логах безопасности.</p><p>Вставлю
 один кусок кода из nginx на удаленной машине для примера, так все 
остальное примерно похоже (конфиги использовались в виде .template):</p><h3>SSL-сертификаты</h3><p>Для получения валидных SSL-сертификатов я настроил работу через автоматический Certbot по challenge-валидации DNS-01 c API Webnames. Сам домен привязан к внутреннему IP-адресу 10.8.0.1.
 Проверка через DNS позволила выпустить единый wildcard-сертификат на 
весь домен и его поддомены без необходимости держать открытым 80-й порт 
веб-сервера наружу.</p><p>Уточню, что certbot запускается автоматически 
во время выполнения Ansible плейбука, поэтому самому кроме указания 
переменных ничего делать не нужно.</p><p>В
 итоге получилась схема, при которой все сервисы доступны по красивым 
доменным именам с HTTPS, но абсолютно невидимы для внешнего интернета.</p><p>Вот настройка certbot:</p><h2>История софта</h2><p>Параллельно
 с сетевой структурой развивался и сам набор приложений. Изначально я 
хотел собрать в одном месте утилиты, которыми пользуюсь каждый день, но в
 процессе селфхостинга быстро понимаешь: нельзя просто накидать 
контейнеров и надеяться, что мини-ПК справится, а конфигурационные файлы
 не превратятся в кашу.</p><h3>Первый стек и оптимизация</h3><p>Первыми на домашнем сервере прижились медиа-сервисы: Navidrome для стриминга музыки и Audiobookshelf
 для аудиокниг и подкастов. Они легковесные, имеют отличные мобильные 
клиенты с синхронизацией прогресса и полностью закрывают мои 
потребности. Позже к ним добавился Nextcloud как единое независимое облако для файлов, контактов и семейных документов.</p><p>Затем встал вопрос безопасного хранения паролей. Сначала я смотрел в сторону оригинального Bitwarden, но в итоге я выбрал Vaultwarden
 — альтернативный сервер на Rust, полностью совместимый с API Bitwarden.
 Он потребляет считанные мегабайты оперативной памяти и работает 
идеально. Дополнительно для удобства управления всей этой распределенной
 Docker-инфраструктурой в локальный стек был добавлен Portainer. (+ Portainer Agent на удаленный сервер)</p><p>Из интересных моментов, где мне пришлось немного больше возиться, чем с остальными сервисами это nextcloud настройка:</p><h3>Ошибки проектирования: почему я удалил Matrix (Synapse)</h3><p>Не все решения прошли проверку временем. На этапе использования Tuna и FRP я развернул сервер Matrix (Synapse)
 для защищенного обмена сообщениями. Мне казалось это крутой идеей, но 
когда я окончательно перешел на AmneziaWG, целесообразность мессенджера 
внутри закрытого туннеля сошла на нет.</p><p>Synapse требовал слишком 
много ресурсов, впустую расходовал оперативку домашнего ПК и усложнял 
конфиг Nginx. При этом реальной пользы для семьи он не приносил. Для 
критических алертов инфраструктуры и повседневного общения проще и 
эффективнее оказалось использовать Telegram. (плюс алертинг настроен 
именно через него) В итоге я полностью выпилил Synapse из стека, 
освободив ресурсы.</p><p>Вместо него я добавил в связку к wg-easy локальный AdGuard Home.
 Теперь он работает прямо внутри VPN-сети: очищает весь трафик от 
рекламы и трекеров на лету, кэширует DNS-запросы и не дает истории 
веб-серфинга улетать внешним провайдерам.</p><p>Основной проблемой с 
которой я столкнулся при использовании AdGuard Home, так это то что я 
так и не понял как заставить использовать AmneziaVPN клиент AdGuard как 
основной DNS, при этом AmneziaWG работает прекрасно. Как я понимаю дело в
 том что AmneziaWG работает намного проще на уровне ip и у него нету 
никаких доп фильтров, настроек и подобного, поэтому он просто берет 
данные из конфига.</p><h3>От костылей на Bash к декларативному Ansible</h3><p>Весь
 стек на обоих серверах разворачивался через bash скрипты, что было уж 
очень плохо с точки зрения идемпотентности. Во первых из-за bash мне 
постоянно приходилось очищать сервера, так как нормальных проверок у 
меня не было и писать я их не хотел, а также было много костылей с 
импортом переменных, записями в файлы и подобным.</p><p>Так я пришел к декларативному подходу и Ansible.
 Теперь вся конфигурация описывается в виде плейбуков и ролей, 
отражающих конечное желаемое состояние серверов. Конфиденциальные данные
 перенесены в файл secrets.yml, а хрупкие конструкции 
автоматизированы через шаблоны Jinja2. Проект стал идемпотентным: если 
шаги уже выполнены, Ansible их просто пропускает.</p><p>В итоге 
получилось несколько yaml файлов для стандартной настройки системы 
(bootstrap_os.yml) и для настройки каждого из хостов (setup_local.yml и 
setup_remote.yml). В итоге теперь все что нужно чтобы полностью с нуля 
развернуть проект - скачать Ansible, несколько других зависимостей на 
свой рабочий пк и запустить один manage_deploy.sh, в котором можно будет
 выбрать сценарий как будет вести себя Ansible и спокойно дождаться 
разворачивания сервисов.</p><p>Также благодаря Ansible я удобно 
реализовал переносимость проекта. Так как я решил не использовать тома 
docker, и вместо этого храню все в папках, чтобы перенести старые данные
 проекта нужно просто скопировать папку apps-data и положить ее в нужное
 место и все само заработает после повторного развертывания проекта. В 
Ansible выделяется отдельная пауза для этого.</p><p>Вот пример основного плейбука deploy.yml:</p><h3>Тестирование мультидистрибутивности с помощью Vagrant</h3><p>Проект
 изначально затачивался под работу на трех дистрибутивах: Ubuntu, Debian
 и Arch Linux. Тестировать Ansible-плейбуки прямо на рабочей локальной 
машине (в моем случае — EndeavourOS) слишком рискованно, а создавать 
виртуальные машины руками — долго и неудобно.</p><p>Решением стал Vagrant,
 позволяющий за пару минут развернуть чистые ОС в VirtualBox из готовых 
образов. Но в процессе настройки мультивендорного стенда в режиме 
сетевого моста (public_network) всплыли две критические проблемы:</p><ol><li>Конфликт DNS:
 По умолчанию Vagrant создает NAT-интерфейс для управления нодой. При 
включении второго (публичного) интерфейса для локальной сети ломался 
дефолтный DNS-резолвер. Проблему пришлось решать принудительной очисткой
 и перезаписью файла /etc/resolv.conf через inline-скрипт автоматизации Vagrant.</li><li>Проблема с GRUB на Debian: В используемом базовом образе generic/debian12
 конфигурация GRUB сохраняла жесткую привязку к конкретному имени диска 
из окружения сборщика. При повторном развертывании плейбуков на тестовом
 стенде это приводило к сбоям загрузчика. Чтобы автоматизировать 
очистку, пришлось внедрить скрипт, который на лету определяет имя 
системного диска через lsblk и автоматически передает правильные параметры в загрузчик через утилиту debconf-set-selections.</li></ol><p>Вот код Vagrantfile: (в node.vm.provision происходит основное решение ошибок)</p><p>Надежная система бэкапов на базе BorgmaticДля создания резервных копий я внедрил Borgmatic
 (удобную надстройку над дедуплицирующим инструментом Borg Backup). Весь
 процесс автоматизирован с помощью связки системных юнитов borgmatic.service и borgmatic.timer. В бэкап уходят две ключевые директории: apps-data (конфигурации приложений и баз данных) и PersonalData (медиатека: музыка, книги, подкасты, файлы Nextcloud).</p><p>Развертывание
 системы бэкапов полностью берет на себя Ansible. Мне достаточно указать
 UUID внешнего жесткого диска — скрипт сам проверит его наличие в 
системе, примонтирует в нужную директорию, создаст зашифрованный 
репозиторий и настроит политику ротации (хранение 7 ежедневных, 4 
еженедельных и 6 ежемесячных копий). Также в Prometheus выведен 
мониторинг самого репозитория .borg для отслеживания его размера и статуса успешности архивации.</p><p>Главная
 проблема при бэкапе работающих Docker-контейнеров — риск скопировать 
базу данных в «битом» или неконсистентном состоянии, если в момент 
создания архива в нее шла активная запись. Чтобы решить эту проблему, я 
задействовал механизм хуков в конфигурации Borgmatic.</p><p>Перед началом резервного копирования автоматически срабатывает команда остановки контейнеров проекта (docker-compose down),
 а после успешного завершения (или в случае возникновения непредвиденной
 ошибки) контейнеры автоматически поднимаются обратно в фоновом режиме. 
Для удобного просмотра архивов и быстрого восстановления файлов я 
развернул веб-интерфейс Borg UI.</p><p>Конфигурация borgmatic: (использую как Jinja2 шаблон, чтобы Ansible в плейбуках сам подставил переменные)</p><h2>Наблюдаемость (Observability) уровня Enterprise</h2><p>В последних релизах (v1.2.0 и v1.3.0) фокус проекта сместился на мониторинг и работу с логами.</p><h3>Эволюция алертинга и переход на Gatus</h3><p>Изначально для мониторинга доступности я смотрел на Uptime Kuma, но отказался из-за отсутствия удобной декларативной настройки через конфиги. Затем я развернул связку Blackbox Exporter и Alertmanager
 с уведомлениями в Matrix. Но тут крылась логическая несостыковка: весь 
алертинг был завязан на локальном ПК, и в случае его аппаратного отказа я
 бы просто лишился уведомлений.</p><p>Тогда я решил вернуть Uptime Kuma,
 но развернуть его на удаленном VPS в качестве внешнего «сторожа» и 
автоматизировать его настройку через Python-скрипт с библиотекой uptime-kuma-api. Но и тут ждали «грабли» — библиотека не обновлялась три года и намертво ломалась на свежих версиях Kuma.</p><p>В итоге идеальным решением стал Gatus.
 Он изначально проектировался под управление через YAML-конфиги и 
поддерживает отправку алертов, если сервер не отвечает. Из-за специфики 
фронтенда Gatus (он не умеет работать из подкаталога типа /gatus), мне пришлось перенести его и wg-easy на полноценные субдомены gatus. и wireguard.</p><p>Для Gatus получился простой конфиг:</p><p>Для мониторинга аппаратных ресурсов удаленного и локального серверов была развернута связка node-exporter + cAdvisor. Все уведомления теперь приходят мгновенно в Telegram-бота. Чтобы 
избежать лавины одинаковых сообщений (например, при перезагрузке хоста),
 в Alertmanager настроена жесткая группировка и дедупликация событий. 
Также добавлен экспортер для AdGuard Home, выводящий статистику 
заблокированных запросов в Grafana.</p><h3>Централизованные логи: Loki + Grafana Alloy</h3><p>В релизе v1.3.0 в стек была добавлена централизованная система сбора логов Loki. Вместо устаревшего Promtail в качестве агента сбора я применил Grafana Alloy.</p><p>Он
 эффективно собирает логи со всех запущенных Docker-контейнеров, парсит 
их и передает в Loki. Теперь вся история событий, ошибок веб-сервера 
Nginx или падений внутренних приложений доступна в едином интерфейсе 
Grafana с возможностью удобной фильтрации через LogQL, что значительно 
упрощает отладку.</p><p>Конфиг Loki:</p><p>Конфиг Grafana Alloy: (локальный конфиг)</p><h2>Интерфейс: переход на Homepage</h2><p>Изначально для 
домашней страницы я написал кастомную минималистичную HTML-панель с 
Glassmorphism-дизайном. Выглядело это красиво, но добавлять новые 
сервисы вручную через постоянную правку исходного кода было крайне 
неудобно.</p><figure><img src="https://media.tproger.ru/user-uploads/139471/2026-07-15/8a8f2752-8aac-4aa5-898e-98affd01cdff.webp" alt="" /><figcaption>HTML + CSS</figcaption></figure><p>В итоге я заменил самописную страницу на полноценный комьюнити-проект Homepage.
 Это дало некоторую гибкость: вся панель настраивается через простые 
YAML-файлы и поддерживает встроенные виджеты интеграции. Пока что она 
простенькая, но возможно в будущем сделаю что-то более продвинутое.</p><figure><img src="https://media.tproger.ru/user-uploads/139471/2026-07-15/90c65d4a-1310-4a30-b1ad-9e4d3083959d.webp" alt="" /><figcaption>Homepage</figcaption></figure><h2>Заключение</h2><p>Постарался
 подробно рассказать о структуре проекта и как я к этому пришел, очень 
много я не добавил, если пост зайдет, то я обязательно более подробно 
пройдусь по некоторым моментам: как я настраивал Matrix и на каком 
моменте я решил его убрать, как собирал локальный amnezia 
контейнер-клиент, что нового я добавил в релизе 1.4.0 и другое.</p><p>Также
 я перешел с manage_deploy.sh на отдельный GUI клиент, который 
будет полностью автоматизировать процесс подготовки к deploy. (написан на Go Wails). Про это тоже возможно сделаю статью.</p><p>Вся кодовая база проекта, подробная документация, инструкции по развертыванию открыты и доступны для сообщества:</p><p>🔗 GitHub-репозиторий: <a href="https://github.com/canntstand/ServeHub-2" rel="noopener noreferrer nofollow">https://github.com/canntstand/ServeHub-2</a></p><p>Это
 моя первая статья на этом сайте и в то же время первый личный проект, которому я 
отдал так много времени (3 месяца). Буду рад вашему фидбеку в 
комментариях!</p>]]></content:encoded>
    </item>
    <item>
      <title>Git в Telegram: как я избавился от JSON, победил Markdown и получил security by design</title>
      <link>https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu</link>
      <comments>https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Robin Gad]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu</guid>
      <description><![CDATA[<p>Git в Telegram? Без JSON, с SQLite, победой над Markdown и security by design. Код, схема БД, факапы и ссылка на бота.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/git-v-telegram--kak-ya-izbavilsya-ot-json--pobedil-markdown-i-polu">Git в Telegram: как я избавился от JSON, победил Markdown и получил security by design</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Markdown]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Jul 2026 06:39:38 GMT</pubDate>
      <content:encoded><![CDATA[<p>В своём Telegram-канале я время от времени предлагаю подписчикам выбрать очередную «бредовую» идею для реализации. На этот раз победил Git в Telegram: чтобы можно было инитить проекты, пушить файлы, коммитить — и всё это прямо в мессенджере.</p><p>С практической точки зрения проект на**й не нужен. Есть GitHub, GitLab и куча нормальных инструментов. Но как эксперимент — почему бы и нет? Чисто посмотреть, можно ли заставить Telegram работать как VCS.</p><h2>Почему не JSON</h2><p>На старте я думал: «Положу всё в JSON, на кой мне база данных?» Проектов мало, пользователей немного, файлы текстовые — чего заморачиваться?</p><p>Подергал JSON туда-сюда пару дней и понял: не варик.</p><ol><li>Конкурентный доступ. Два юзера одновременно коммитят — один перезаписывает файл другого.</li><li>Целостность данных. Если бот упал в середине записи — JSON остаётся в невалидном состоянии.</li><li>Версионность. Хранить историю изменений в JSON — это просто перенести проблему из кода в структуру файла.</li></ol><p>Вывод: JSON — для конфигов, а не для данных, которые меняются каждую секунду.</p><h2>Выбор SQLite и схема БД</h2><p>Выбрал SQLite, потому что:</p><ul><li>Не надо поднимать отдельный сервер</li><li>Целостность данных на уровне движка (транзакции, foreign keys, rollback)</li><li>Всё в одном файле — скопировал и унёс</li></ul><p>Сущности:</p><ul><li>users — telegram_id, username, current_project_id</li><li>projects — owner_id, name, thread_id (каждый проект живёт в своём треде канала)</li><li>files — filename, current_version, флаг modified (файл изменился и готов к коммиту)</li><li>file_versions — мясо. Каждая версия файла с полным содержимым. Привязана к file_id и опционально к commit_id</li><li>commits — сообщение, время, ссылка на проект</li><li>commit_files — связка коммитов с версиями файлов (many-to-many, чтобы поддержать ветки)</li></ul><p>Почему так: я хотел иметь возможность откатиться к любой версии любого файла. Да, база распухнет, но текстовые файлы — это не гигабайты видео. Плюс наличие file_versions и commit_files позволяет делать diff между версиями и смотреть историю изменений.</p><p>В коде вместо голых кортежей из SQL — датаклассы:</p><h2>Маркдауновый ад</h2><p>Казалось бы: взял код, обернул в тройные апострофы, кинул в Telegram. Telegram сам подсветит синтаксис, если указать язык. Красота. В теории.</p><p>На практике Telegram использует свой диалект Markdown, где куча служебных символов: _ * [ ] ( ) ~ &gt; # + - = | { } . !</p><p>Попытка 1: заэкранировать всё подряд. Результат: код превращается в кашу. Вместо<b> </b><i>def  __init__- </i> получается <i>def |_|_init|_|_ </i> — уже не запустишь, и в канале выглядит как говно.</p><p>Попытка 2: не экранировать вообще. Telegram шлёт на**й с ошибкой «can't parse entities».</p><p>Попытка 3: экранировать только то, что реально ломает разметку. Выяснилось, что порядок важен. Сначала экранируем точки и подчеркивания, потом обратную косую черту. Но и это не панацея — последовательности типа \*</p><p>после экранирования превращаются в \\*, и Telegram снова недоволен.</p><p>Попытка 4: разбивать на части. Для больших файлов делаю превью (первые 50 строк), экранирую их, отправляю как код, а полную версию — файлом. И тут начался ад: Telegram находил ошибки в тех частях кода, которых в превью вообще не было. Оказывается, он всё равно парсил полный код, даже если отправлялась только его часть.</p><p>Попытка 5 (финал): забил на Markdown и перешёл на HTML. Telegram умеет его принимать. Да, он не такой красивый, но зато предсказуемый:</p><p>Никаких точек, подчеркиваний, обратных слешей. Просто экранируем три символа — и код летит как надо.</p><h2>Security by design</h2><p>Когда бот начал обрастать функциями, я задумался о безопасности. Чтобы никто не мог коммитить или удалять чужие файлы, начал писать проверки в каждую команду:</p><p>Добавил в /commit. Потом решил с другого аккаунта потестировать команды на чужих файлах. И тут бот на каждую команду стал выдавать «файл не найден» или «проект не найден». И я понял: безопасность уже работает. С самого начала. Из коробки. Без единой строчки кода.</p><p>Как так вышло? В таблице projects с самого начала было поле owner_id. При создании проекта я писал туда telegram_id  владельца. Все запросы к БД фильтруются по этому полю:</p><p>Показать проекты — только свои. Найти файл — только в своих проектах. Выбрать проект — только из своих. Никаких лишних проверок. Просто SQL-запросы, которые с самого начала учитывали владельца.</p><h2>Команды: от семи до двух десятков</h2><p>Изначально казалось, что команд будет немного. Но...</p><p>Жизнь рассудила иначе.</p><ul><li>База: /start, /init, /use, /list, /ls, /commit, /log, /status</li><li>Удаление: /rm, /rmproject + подтверждение</li><li>Игнор: /ignore, /ignored, /unignore</li><li>Ветки: /branch, /branches, /checkout</li><li>Диффы и просмотр: /diff, /cat</li></ul><p>Итого — уже под два десятка. И это не предел.</p><h2>Простота &gt; абстракции</h2><p>В моём коде нет абстрактных базовых классов. Совсем. Потому что они нужны только когда у тебя есть минимум две разные реализации одного и того же. В GitGram всё проще: один способ работать с БД, один способ шифровать, один способ парсить .gitignore.</p><p>Если завтра появится вторая реализация — тогда и буду делать интерфейс. А пока это просто оверхед.</p><p>В GitGram:</p><ul><li>Хочешь понять, как работает add_file — идёшь в database.py и читаешь 10 строк кода.</li><li>Хочешь увидеть обработчик /commit — открываешь bot.py и смотришь.</li></ul><p>Никаких AbstractMinerShieldEventProcessor, BaseGitGramManager, InterfaceProviderFactory.</p><p>Код должен быть тупым. Чем тупее — тем проще его читать и отлаживать.</p><h2>Что дальше</h2><p>В планах:</p><ul><li>Докрутить коллаборацию (несколько человек над одним проектом)</li><li>Приватные репозитории</li><li>Кодспейс прямо в боте (да да знаю я сошёл с ума и бла бла бла..)</li></ul><h2>Итог</h2><p>GitGram принимает файлы, режет их на куски если надо, постит в канал с подсветкой. Коммиты ходят, ветки переключаются, диффы показываются. Всё это в тредах, каждый проект отдельно.</p><p>На практике GitGram ни к чему. Но сама задумка — Git в Telegram — это же так прикольно. Просто посмотреть, можно ли такое вообще запилить.</p><h2>Если хочешь поучаствовать</h2><ul><li><a href="https://t.me/Git_Gram/314" rel="nofollow">GitGram</a></li><li>Чат для хардкорных: <a href="http://t.me/sandbox_hardcore" rel="nofollow">@sandbox_hardcore</a> — вся сырая разработка, факапы и обсуждения (без цензуры)</li></ul><p>Подписывайся на мой <a href="https://t.me/+q0NBWy428y1hODEy" rel="nofollow">TГ-канал</a> — там я публикую все свои эксперименты, код и приглашаю к обсуждению. Только факты, мат и никакой политоты.</p>]]></content:encoded>
    </item>
    <item>
      <title>Кнопка «наверх» в Django: почему в проде это уже не три строки JavaScript</title>
      <link>https://tproger.ru/articles/knopka-naverh-v-django-pochemu-v-prode-eto-uzhe-ne-tri-stroki-j</link>
      <comments>https://tproger.ru/articles/knopka-naverh-v-django-pochemu-v-prode-eto-uzhe-ne-tri-stroki-j?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Фёдор Малков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/knopka-naverh-v-django-pochemu-v-prode-eto-uzhe-ne-tri-stroki-j</guid>
      <description><![CDATA[<p>Как добавить кнопку «наверх» в Django-сайт и Django Admin: настройка, CSP, доступность, мобильная версия и работа рядом с cookie-баннерами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/knopka-naverh-v-django-pochemu-v-prode-eto-uzhe-ne-tri-stroki-j">Кнопка «наверх» в Django: почему в проде это уже не три строки JavaScript</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[jQuery]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[CDN]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Jul 2026 13:01:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Как сделать scroll-to-top для сайта и Django Admin, не забыв про мобильные устройства, CSP, доступность, плавающие виджеты и нормальную настройку без правки шаблонов.</p><p>На первый взгляд кнопка «наверх» — задача на пять минут. Добавил<i> position: fixed</i>, обработчик window.scrollTo()  — готово.</p><p>Но стоит этой кнопке появиться в живом проекте, как выясняется, что она пересекается с cookie-баннером, мешает чату поддержки, выглядит иначе в мобильной версии, не дружит со строгим CSP или пропадает из Django Admin.</p><p>В итоге маленькая UI-деталь начинает обрастать условиями. Я решил собрать их в отдельный Django-пакет — django-scroll-to-top</p><figure><img src="https://media.tproger.ru/user-uploads/139342/2026-06-29/000bf08b-be8e-4252-82ce-dbef3556426e.webp" alt="Пример кнопки &quot;Наверх&quot; на демо сайте" /><figcaption>Пример кнопки "Наверх" на демо сайте</figcaption></figure><h2>Когда трёх строк JavaScript достаточно</h2><p>Для небольшого сайта, где нет сложной верстки, админки, CSP и требований к повторному использованию, самый простой вариант действительно выглядит примерно так:</p><p>Это нормальное решение. Не всегда стоит тянуть пакет ради одной кнопки.</p><p>Но в реальном Django-проекте быстро появляются дополнительные вопросы:</p><ul><li>когда именно показывать кнопку: после 300 пикселей, одного экрана или только при прокрутке вверх;</li><li>что делать на коротких страницах;</li><li>как не перекрыть cookie-баннер, чат, toast-уведомления или нижнюю мобильную навигацию;</li><li>как дать пользователю закрыть кнопку;</li><li>как не сломать клавиатурную навигацию и режим reduced motion;</li><li>как сделать отдельное оформление для сайта и Django Admin;</li><li>как не заставлять проект добавлять unsafe-inline в Content Security Policy;</li><li>как позволить редактору или администратору изменить цвет, положение и иконку без нового деплоя.</li></ul><p>Именно в этот момент «три строки JavaScript» превращаются в отдельный компонент.</p><h2>Что я хотел получить</h2><p>Цель была не в том, чтобы сделать ещё одну стрелку в правом нижнем углу. Хотелось собрать переиспользуемый компонент со следующими свойствами:</p><ol><li>Подключение сайта одной template-тегом.</li><li>Отдельная поддержка обычных страниц и стандартного Django Admin.</li><li>Настройка внешнего вида через админку, а не через постоянную правку CSS.</li><li>Без jQuery, CDN, фронтенд-фреймворка и обязательной сборки.</li><li>Безопасная работа при строгой CSP.</li><li>Прогрессивное улучшение: без JavaScript остаётся обычная ссылка в начало страницы.</li><li>Возможность жить рядом с другими фиксированными элементами интерфейса.</li></ol><p>Пакет в итоге хранит обычные настройки установки в settings.py, а визуальное поведение — в базе данных. Это позволяет менять кнопку через Django Admin, публиковать новую версию настроек и при необходимости откатываться на предыдущую. В проекте есть отдельные профили для публичного сайта и Django Admin, а ревизии могут быть черновыми, опубликованными или архивными.</p><h2>Быстрое подключение</h2><p>Базовый сценарий начинается с установки:</p><p>В settings.py добавляем приложение. Если нужна поддержка стандартной админки, пакет должен идти раньше django.contrib.admin:</p><p>Включаем области, где должна работать кнопка:</p><p>Для публичной части добавляем URLConf пакета:</p><p>А в общий шаблон сайта — один тег:</p><p>На стандартном Django Admin ничего дополнительно вставлять не нужно: пакет использует обычный механизм разрешения шаблонов Django. Если же в проекте переопределён admin/base_site.html  тег можно добавить вручную в блок footer</p><h2>Настройка без превращения админки в редактор CSS</h2><p>Мне не хотелось хранить в базе шаблоны, произвольный CSS или JavaScript. Это неудобно для сопровождения и создаёт лишнюю поверхность для ошибок.</p><p>Поэтому визуальная часть собрана из контролируемых вариантов:</p><ul><li>круг, квадрат, скруглённый квадрат или pill;</li><li>заливка solid, outline, soft, ghost, glass или gradient;</li><li>положение в любом углу экрана;</li><li>отдельные размеры для desktop и mobile;</li><li>светлая и тёмная тема;</li><li>встроенные иконки, иконки от разработчика или загружаемые SVG;</li><li>настройки тени, границы, opacity и focus ring.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/139342/2026-06-29/90107109-2271-460a-9dea-815592d468e7.webp" alt="Настройки кнопки" /><figcaption>Настройки кнопки</figcaption></figure><h2>Что происходит, когда рядом есть cookie-баннер или чат</h2><p>Нижний правый угол страницы редко бывает свободен. Там часто живут:</p><ul><li>cookie-баннер;</li><li>компактная кнопка после закрытия баннера;</li><li>чат поддержки;</li><li>кнопка обратного звонка;</li><li>мобильная навигация;</li><li>toast-уведомления.</li></ul><p>Пакет умеет рассматривать такие элементы как препятствия. Для этого можно пометить элемент атрибутом:</p><p>Дальше для кнопки можно выбрать поведение: игнорировать препятствия, сдвинуться вдоль края, попробовать другой угол или скрыться, если безопасного места не осталось.</p><p>Для сложных виджетов есть отдельный адаптер: он может отслеживать появление и исчезновение элементов, например компактного launcher после закрытия cookie-баннера. При этом ни cookie-пакет, ни чат не становятся зависимостями  django-scroll-to-top</p><h2>Доступность — не отдельная галочка в конце</h2><p>У кнопки есть понятное имя для screen reader, поддержка клавиатуры, видимый focus-visible, минимальный размер области нажатия и режим prefers-reduced-motion.</p><p>Если пользователь отключил анимации на уровне системы, плавная прокрутка не будет навязываться. Если JavaScript не загрузился, кнопка остаётся обычной ссылкой на начало документа.</p><p>Полный независимый аудит WCAG 2.2 AA и тестирование масштабирования 200% и 400% пока находятся в roadmap, поэтому называть компонент полностью сертифицированным по WCAG было бы неправильно. Но структурные требования — клавиатурная доступность, фокус, reduced motion, forced-colors и безопасная работа без JavaScript — уже заложены в компонент и покрываются тестами.</p><h2>CSP и загружаемые SVG</h2><p>В корпоративных проектах часто нельзя просто добавить inline-скрипт и включить unsafe-inline ради одной кнопки.</p><p>По умолчанию компонент использует same-origin CSS и JavaScript. Для него подходит политика такого вида:</p><p>Настраиваемые цвета и размеры отдаются не через inline-стили, а через версионированный stylesheet endpoint. Это позволяет сохранить простой контракт с одним template-тегом и не ослаблять CSP.</p><p>Отдельно пришлось подумать о загружаемых SVG. Админ не рендерит исходный файл как есть: SVG проходит санитарную обработку. Скрипты, обработчики событий, внешние ресурсы, встроенные документы и небезопасные namespace отклоняются. Для загружаемых иконок также хранится информация об авторе, источнике и лицензии.</p><h2>Ревизии, публикация и откат</h2><p>Одна из самых полезных вещей в пакете — не сама кнопка, а жизненный цикл её настроек.</p><p>Можно создать черновик, посмотреть результат в live preview, опубликовать изменения или вернуться к предыдущей версии. Это особенно удобно, когда кнопку настраивает не разработчик, а контент-менеджер или дизайнер.</p><figure><img src="https://media.tproger.ru/user-uploads/139342/2026-06-29/c9840966-4e32-4506-807a-ac78830fecfa.webp" alt="Живой предпросмотр" /><figcaption>Живой предпросмотр</figcaption></figure><p>У ревизий есть три состояния:</p><ul><li>draft — редактируемый черновик;</li><li>published — текущая активная конфигурация;</li><li>archived — сохранённая версия для отката.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/139342/2026-06-29/2fcf0cfc-b29e-4ce1-b1de-9c07aac1fce0.webp" alt="настройки ревизий профиля кнопки" /><figcaption>настройки ревизий профиля кнопки</figcaption></figure><h2>Где пакет уместен, а где нет</h2><p>django-scroll-to-top имеет смысл, когда кнопка нужна в нескольких проектах, должна работать в Django Admin, настраиваться без деплоя или жить в окружении со строгими требованиями к CSP и интерфейсу.</p><p>Для лендинга на одну страницу проще и правильнее написать несколько строк самостоятельно. Это будет быстрее, понятнее и дешевле в сопровождении.</p><p>Но если такая маленькая деталь начинает повторяться в нескольких продуктах, появляется необходимость поддерживать мобильную версию, доступность, независимые настройки для сайтов и админки, то отдельный компонент уже перестаёт быть избыточным.</p><p>Сейчас пакет выпущен как beta-версия 0.2.0, требует Python 3.10+ и поддерживает Django 4.2 LTS, 5.x и 6.0. Лицензия — MIT.</p><p>Исходный код, документация и примеры использования доступны в GitHub-репозитории проекта.</p><p>Пакет опубликован в PyPI под именем django-scroll-to-top.</p><p>Обратная связь, баг-репорты и предложения по интеграции с кастомными Django Admin-темами приветствуются в Issues.</p>]]></content:encoded>
    </item>
    <item>
      <title>Бесплатный WAF инструмент кибербезопасности, который я использую</title>
      <link>https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu</link>
      <comments>https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Неопознанный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu</guid>
      <description><![CDATA[<p>Разбор бесплатного open-source WAF SafeLine для защиты от OWASP Top 10, DDoS и ботов. Сравнение с ModSecurity и Cloudflare по точности обнаружения атак, минимальные ложные срабатывания, простая установка одной командой Docker.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/besplatnyj-waf-instrument-kiberbezopasnosti-kotoryj-ya-ispolzuyu">Бесплатный WAF инструмент кибербезопасности, который я использую</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Unity]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[CSR]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Jul 2026 05:55:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Решения с открытым исходным кодом достигли такого уровня зрелости, что сегодня они действительно могут конкурировать с коммерческими продуктами — не только по функциональности, но и по удобству использования и поддержке сообщества. Если вы управляете собственной инфраструктурой, больше нет оправдания тому, чтобы оставлять дверь открытой для угроз.</p><p>SafeLine WAF — это бесплатный инструмент, который я лично тестировал.</p><p>Это полностью open-source решения, продукт с действительно бесплатной Community Edition, где ключевые функции не урезаны.</p><p><b>SafeLine WAF — веб-приложенийный межсетевой экран, который действительно поставляется с разумными настройками по умолчанию</b></p><p><b>Что он делает:</b></p><p>Защищает веб-приложения от SQL-инъекций, XSS-атак, командных инъекций, CSRF, SSRF, атак включения файлов и других угроз из списка OWASP Top 10. Также поддерживает защиту от CC/DDoS-атак, управление ботами и может работать как шлюз аутентификации.</p><p><b>Почему он:</b></p><p>Большинство WAF с открытым исходным кодом достаточно сложно настроить. Можно потратить часы на настройку правил, пытаясь остановить ложные срабатывания, из-за которых легитимные пользователи блокируются.</p><p>SafeLine использует другой подход — вместо того чтобы полностью полагаться на сигнатурное обнаружение, он применяет движок семантического анализа, который фактически анализирует и понимает входящие HTTP-запросы. Это позволяет добиться более высокого уровня обнаружения при значительно меньшем количестве ложных срабатываний по умолчанию.</p><p>Некоторые показатели, которые стоит учитыват</p><ol><li>Уровень обнаружения - SafeLine (Balanced) (71.65%), ModSecurity (Level 1) (69.74%), Cloudflare (Free) (10.7%)</li><li>Уровень ложных срабатываний - SafeLine (Balanced) (0.07%), ModSecurity (Level 1) (17.58%), Cloudflare (Free) (0.07%)</li><li>Точность - SafeLine (Balanced) (99.45%), ModSecurity (Level 1) (82.20%), Cloudflare (Free) (98.40%)</li></ol><p>Сбалансированный профиль SafeLine обнаруживает более 70% атак, при этом блокируя легитимный трафик ошибочно всего в 0.07% случаев. Это именно тот уровень настроек по умолчанию, который можно использовать в промышленной среде без постоянного ручного контроля.</p><p>Установка выполняется одной командой</p><p>После запуска он разворачивается как набор Docker-контейнеров: Tengine (форк Nginx) используется в качестве reverse proxy, отдельный сервис отвечает за семантический анализ, PostgreSQL хранит конфигурации и логи, а удобная веб-панель администратора работает на порту 9443.Community Edition поддерживает до 10 сайтов, чего достаточно для большинства личных проектов и небольших бизнес-сценариев.</p><p>Сайт: <a href="https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fcodeby.net%2Fgoto%2Flink-confirmation%3Furl%3DaHR0cHM6Ly9jeWJlcnNlcnZhbC50ZWNoL2xhbmRpbmcvc2FmZWxpbmXvv7xHaXRIdWI%253D%26s%3D7008b60d8a0849ba0be350fe25edfa72&amp;postId=3005263" rel="nofollow noopener">https://cyberserval.tech/landing/safeline</a></p><p>GitHub:<a href="https://api.vc.ru/v2.8/redirect?to=http%3A%2F%2Fgithub.com%2Fchaitin%2FSafeLine&amp;postId=3005263" rel="nofollow noopener"> github.com/chaitin/SafeLine</a> (более 21 тыс. звёзд)</p><p>Лицензия: GPL-3.0 / MIT (Community Edition)</p>]]></content:encoded>
    </item>
    <item>
      <title>Как приручить legacy-код: безопасная модернизация без заморозки фич</title>
      <link>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</link>
      <comments>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[KODE]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</guid>
      <description><![CDATA[<p>Как модернизировать legacy-код без остановки продукта: Strangler Fig Pattern, feature flags, shadow testing и безопасная миграция данных. Практика и антипаттерны.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki">Как приручить legacy-код: безопасная модернизация без заморозки фич</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Twitter]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[OpenTelemetry]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Техника]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Jun 2026 06:16:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Legacy-код — одна из самых болезненных тем в инженерных командах. Обычно все понимают, что система устарела: архитектура мешает быстро выпускать изменения, новые фичи приходится встраивать через обходные пути, тесты либо неполные, либо отсутствуют, а любое изменение в одном модуле неожиданно ломает другой.</p><p>Но при этом к такому коду часто боятся прикасаться. И не без причины. В старых системах редко бывает понятная карта зависимостей. Документация устарела, часть знаний живет только в головах нескольких разработчиков, а бизнес при этом продолжает ждать новых релизов, интеграций и продуктовых экспериментов.</p><p>Так появляется классическая ловушка legacy: систему надо модернизировать, но остановить развитие нельзя. Переписать всё с нуля страшно, поддерживать как есть — всё дороже. В результате продукт обрастает временными решениями, скорость разработки падает, а стоимость каждого следующего изменения растет.</p><p>Хорошая новость в том, что модернизация legacy-кода не обязана быть большим взрывом. Старую систему можно менять постепенно, сохраняя рабочий продукт, не замораживая фичи и не устраивая один критический релиз, от которого зависит всё.</p><h2>Почему Big Bang-переписывание чаще всего заканчивается плохо</h2><p>Когда команда долго живет с устаревшей системой, идея переписать всё с нуля выглядит очень соблазнительно. Кажется, что можно наконец избавиться от технического долга, выбрать нормальную архитектуру, перепроектировать модули, покрыть всё тестами и начать «правильно».</p><p>На старте такой план часто звучит логично. Особенно если текущая система действительно мешает развитию. Например, мобильное приложение растет, у него уже миллионы пользователей, бэкенд написан несколько лет назад как монолит, а каждая новая фича требует изменений в десятке мест. Команда устала чинить регрессии, бизнес устал ждать, и всем хочется «один раз нормально переписать».</p><p>Проблема не в самой идее переписывания, а в условиях, при которых оно проваливается. Большой риск возникает, когда совпадают четыре фактора: переписывание занимает много месяцев, в это время бизнес продолжает развивать старую систему, новая версия покрывает сразу большую часть функциональности, а откат связан с миграцией данных. Если все четыре пункта присутствуют, Big Bang почти гарантированно превратится в долгий и дорогой проект.</p><p>Допустим, команда решила переписать модуль заказов в e-commerce-продукте. В старой версии есть корзина, промокоды, доставка и оплата. Команда планирует за полгода сделать новый сервис заказов. Но за эти полгода бизнес добавляет подписки, подарочные сертификаты, частичную оплату бонусами и новую логику возвратов. В итоге новая система, которую проектировали под старые требования, к моменту релиза уже нуждается в доработке.</p><p>Есть и другая проблема: большой релиз почти всегда несет максимальный риск. Если вы заменяете крупный кусок системы целиком, ошибка влияет сразу на большую часть пользователей. Откат тоже становится сложным, потому что новая логика уже связана с новыми данными, контрактами и интеграциями.</p><p>Big Bang всё-таки бывает оправдан — но в узких условиях. Если кодовая база молодая (год-два), пользователей мало, у системы нет критичного состояния в БД и продукт можно временно заморозить или вести в обоих контурах параллельно, полное переписывание может оказаться дешевле постепенной миграции. Это редкая ситуация, и она быстро исчезает по мере роста продукта. В зрелых системах безопаснее работает другой подход — постепенная архитектурная эволюция.</p><h2>Пример: как команда переписала сервис документов и потеряла полгода</h2><p>Команда сопровождала сервис — старый модуль на aiohttp с Pydantic v1, через который проходила вся обработка путевых листов и актов осмотра транспорта. Сервис существовал шесть лет, был покрыт тестами фрагментарно, а его API использовали мобильное приложение водителей, диспетчерская веб-панель и пакетный импорт.</p><p>Команда решила переписать сервис целиком: перейти на FastAPI, обновить Pydantic до v2, заодно почистить контракты и заменить внутреннее хранилище документов с MongoDB на PostgreSQL. План был рассчитан на четыре месяца.</p><p>Через восемь месяцев проект всё ещё не был готов к выкатке, а к десятому месяцу команда откатила миграцию полностью. Причин было несколько.</p><p>Во-первых, переписывание шло параллельно с продуктовой разработкой. За время миграции бизнес добавил два новых типа документов и изменил правила подписи актов. Новая система проектировалась под старые требования и к моменту готовности уже не соответствовала продукту.</p><p>Во-вторых, команда не написала характеристических тестов. Поведение «как есть» нигде не было зафиксировано, и расхождения находились только в продакшене после переключения.</p><p>В-третьих, у старого сервиса были скрытые побочные эффекты, о которых никто не помнил. При смене статуса документа публиковал событие в Kafka, которое читал биллинг и сервис аналитики. В новой реализации это поведение не было воспроизведено, потому что в коде оно выглядело как «лишний» вызов. После переключения биллинг перестал получать события, и расхождение обнаружили только через две недели — по жалобе финансового отдела.</p><p>В-четвёртых, переключение было сделано «в лоб»: маршрут в API Gateway просто перенаправили на новый сервис. Фича-флага не было, теневого запуска не было, плана отката не было. Когда выяснилось, что новый сервис строже валидирует исторические форматы документов и отклоняет часть старых записей, быстро вернуться на старую реализацию не получилось — её к тому моменту уже отключили на стенде, а в БД успели уйти записи в новом формате.</p><p>В итоге миграцию свернули, потратив около десяти человеко-месяцев и потеряв доверие бизнеса. Сервис до сих пор работает в исходной реализации, а команда переходит к плану, описанному ниже.</p><h2>Strangler Fig Pattern: как заменить систему по частям</h2><p>Один из самых практичных подходов к модернизации legacy-кода — Strangler Fig Pattern. В софтверном виде паттерн был сформулирован Мартином Фаулером в 2004 году под названием StranglerFigApplication. Идея проста: не переписывать систему целиком, а постепенно выносить отдельные части в новую реализацию.</p><p>Название пришло из биологии. Фикус-душитель растет вокруг дерева-хозяина и постепенно вытесняет его. В архитектуре принцип похожий: старая система продолжает работать, новая функциональность появляется рядом, а затем отдельные потоки постепенно переводятся на новую реализацию.</p><p>Представим старый монолит интернет-магазина. Внутри него есть каталог, корзина, заказы, платежи, скидки, личный кабинет и уведомления. Переписать всё сразу — рискованно. Но можно начать с относительно изолированного участка, например с уведомлений.</p><p>Сначала команда описывает текущий контракт: какие события приходят в модуль уведомлений, какие каналы используются, какие шаблоны отправляются, какие ошибки считаются допустимыми. Затем рядом создается новый сервис уведомлений, который реализует тот же контракт. На первом этапе он может даже не отправлять реальные сообщения, а только принимать события и логировать результат. После проверки часть трафика переводится на новую реализацию. Когда сервис стабилизируется, старый код уведомлений удаляется из монолита.</p><p>Strangler Fig хорошо работает там, где между старым и новым кодом есть сетевая граница: HTTP, message bus, RPC. Если такой границы нет — например, нужно постепенно заменить функцию или класс внутри одного процесса — используется родственный паттерн Branch by Abstraction: над старой реализацией создается абстракция, рядом пишется новая реализация, переключение происходит через конфигурацию или фича-флаг, после стабилизации старая ветка удаляется. Снаружи это выглядит как Strangler Fig, но без сетевого прокси.</p><p>Такой подход снижает риск. В системе нет одного большого релиза, где всё меняется сразу. Есть серия небольших контролируемых изменений. Каждое можно протестировать, измерить и откатить.</p><h2>Главное правило: сначала повторить поведение, потом улучшать</h2><p>Одна из частых ошибок при модернизации legacy-кода — попытка одновременно переписать систему и улучшить бизнес-логику. Команда смотрит на старый модуль и думает: «Раз уж мы его трогаем, давайте сразу сделаем нормальную архитектуру, изменим контракты, уберем странные кейсы и перепишем поведение».</p><p>Это опасный путь. В legacy-системах странное поведение часто существует не случайно. За ним может стоять неочевидное бизнес-правило, старый клиент, интеграция с внешней системой или исторический баг, на который уже кто-то завязался.</p><p>Например, в системе расчета налогов может быть правило: для контрактов, заключенных до 2018 года, НДС округляется в меньшую сторону до целого рубля, а для всех остальных — по математическим правилам. Новый разработчик может решить, что это ошибка, и «исправить» округление. Но потом выяснится, что часть крупных клиентов держит это поведение в своих сверках, а смена правила приведет к расхождениям в актах и претензиям.</p><p>Прежде чем менять поведение, его нужно зафиксировать. Для этого пишут характеристические тесты (characterization tests, иногда называемые golden master или approval tests). Идея простая: на реальных данных или их обезличенных копиях прогоняется старая реализация, её ответы сохраняются как эталон, и любые будущие изменения, отклоняющиеся от эталона, отлавливаются автоматически. Тесты пишутся не для красоты, а для того, чтобы зафиксировать существующее поведение — даже странное — перед тем, как его трогать. Подробно эта техника описана у Майкла Физерса в книге Working Effectively with Legacy Code; на практике её удобно реализовать через библиотеки семейства approval-tests (approvaltests-python, approvaltests-java и аналоги).</p><p>Поэтому первый этап модернизации — не улучшение, а воспроизведение текущего поведения. Новая реализация должна вести себя так же, как старая. Даже если старое поведение кажется странным. Только после стабилизации можно отдельно обсуждать, что именно стоит менять.</p><h2>Feature toggles: как включать новую логику без риска</h2><p>Feature toggles, или фича-флаги, — один из главных инструментов безопасной миграции. Они позволяют включать и выключать новую логику без деплоя.</p><p>В обычной разработке релиз часто выглядит бинарно: код либо выкатили, либо нет. При миграции legacy это неудобно. Гораздо безопаснее иметь возможность включить новую реализацию для 1% пользователей, затем для 10%, потом для половины аудитории и только после этого для всех.</p><p>Например, команда переносит расчет стоимости доставки из монолита в новый сервис. С помощью фича-флага это выглядит так:</p><p>user_id передается явно, чтобы решение «попал ли пользователь в новый сегмент» было стабильным от запроса к запросу. Иначе один и тот же клиент будет получать разные ответы при обновлении страницы, и поведение системы станет непредсказуемым.</p><p>На первом этапе флаг включают только для внутренней команды. Потом для тестового сегмента пользователей. Затем для небольшой доли реального трафика. Если метрики стабильны, долю увеличивают. Если появляются ошибки, флаг выключают, и пользователи снова идут в старую реализацию.</p><p>Важно различать два разных типа флагов. Флаг постепенной выкатки (rollout flag) меняется редко и контролирует, какой процент пользователей видит новую логику. Kill switch — отдельный флаг, единственная задача которого — мгновенно выключить новую реализацию при инциденте. Kill switch должен опрашиваться на каждом запросе, его кэширование должно жить секунды, а не минуты, и он принципиально не должен зависеть от той системы, которую он выключает. Иначе в момент аварии может оказаться, что выключатель сам недоступен.</p><p>В качестве инфраструктуры для флагов команды обычно берут одну из платформ: LaunchDarkly, Unleash, Flagsmith, GrowthBook, либо собирают собственную поверх Redis или конфигурационного сервиса. Для миграции важны три свойства: быстрое распространение изменений (секунды, а не минуты), поддержка таргетинга по пользователю/сегменту и аудит — кто и когда менял флаг.</p><p>Важно, что фича-флаг — это не просто if в коде. Для серьезной миграции нужны правила: кто может включать флаг, как быстро его можно отключить, какие метрики отслеживаются, когда флаг должен быть удален.</p><p>Последний пункт особенно важен. Если флаги не удалять, система быстро превращается в набор ветвлений, где никто уже не понимает, какая логика актуальна.</p><h2>Shadow testing: как проверить новую систему на реальном трафике</h2><p>Feature toggles помогают безопасно переключать пользователей. Но перед этим хорошо бы понять, совпадает ли новая логика со старой. Для этого используют shadow testing.</p><p>Shadow testing — это запуск новой реализации параллельно старой, но без влияния на пользователя. Пользовательский запрос по-прежнему обрабатывает старая система, а новая получает копию запроса и считает результат «в тени». Пользователю этот результат не показывается. Команда только сравнивает ответы.</p><p>Например, есть старый модуль расчета скидок. Он учитывает промокоды, сегмент пользователя, историю покупок, регион и партнерские условия. Команда пишет новый сервис скидок. Чтобы не переключать пользователей сразу, можно запустить теневой режим:</p><p>Два момента, на которые стоит обратить внимание в этом коде. Теневой вызов запускается через asyncio.create_task — корутина сразу планируется в event loop и начнёт выполняться, как только функция вернёт управление. И весь блок завернут в try/except: исключение в новой логике не должно ронять основной запрос. Без этих двух свойств shadow testing рискует ухудшить продакшен вместо того, чтобы безопасно его проверить.</p><p>Небольшая оговорка для продакшена: event loop держит на task только слабую ссылку, и без сохранённой ссылки задача может быть собрана сборщиком мусора прямо во время выполнения. В реальном коде Task имеет смысл класть в set фоновых задач и удалять оттуда через add_done_callback. В примере выше эта обвязка опущена для читаемости.</p><p>Для критичной доменной логики — платежей, биллинга, расчета тарифов — допустимый уровень расхождения должен быть около нуля: цель в shadow-режиме не «как можно меньше различий», а «понимаем каждое расхождение». Для менее чувствительных доменов (рекомендации, ранжирование результатов поиска) можно жить с расхождением в долях процента, но и там расхождения нужно классифицировать, а не игнорировать. Возможно, это баги новой реализации. А возможно, старая система содержит устаревшую логику, которую нужно отдельно обсудить с бизнесом.</p><p>Shadow testing особенно полезен для критичных доменных частей: платежей, биллинга, расчета тарифов, персональных предложений, транзакций. Там нельзя просто «попробовать на пользователях» и посмотреть, что будет.</p><p>При этом важно отличать теневую проверку чтения от теневой проверки записи. Чтение проверить относительно дёшево: запрос идёт в обе системы, ответы сравниваются, никаких внешних эффектов нет. С записью всё сложнее. Если новая реализация в shadow-режиме действительно создаст заказ, спишет деньги или отправит письмо, у пользователя возникнут двойные эффекты. Поэтому для writes либо вводят идемпотентные ключи и shadow-режим без реальных побочных действий (внешние вызовы заменены no-op-стабами, БД — отдельной shadow-копией), либо вообще отказываются от теневой проверки записи в пользу постепенной выкатки за фича-флагом.</p><p>Сравнение ответов в реальной системе тоже не сводится к одной функции compare. Нужно отдельно решать, как игнорировать «нормальный» шум (метки времени, идентификаторы, порядок коллекций), как сэмплировать трафик, чтобы не утопить хранилище расхождений, и как организовать триаж — кто и в каком ритме разбирает накопившиеся диффы. Готовые решения этого класса — GitHub Scientist (Ruby и его порты в другие языки), Twitter Diffy, либо собственный лёгкий регистратор поверх Kafka и таблицы расхождений.</p><h2>С чего начинать модернизацию</h2><p>Начинать лучше не с самого больного и не с самого центрального модуля. Это звучит контринтуитивно, потому что обычно хочется сразу взяться за главный источник проблем. Но если начать с ядра системы, команда быстро упрется в максимальное количество зависимостей и рисков.</p><p>Удобный способ выбрать первый кусок — оценить кандидатов по двум осям: насколько модуль критичен для бизнеса (low / high) и насколько сильно он связан с остальной системой (low / high). Начинать стоит с квадранта low-criticality + low-coupling: ошибки в нем не уронят бизнес-показатели, а малое количество зависимостей позволит провести миграцию полностью, не утянув за собой смежные модули. Высоко-критичные и сильно связанные части (платежи, ядро авторизации) трогают в последнюю очередь — на этот момент команда уже наберёт опыт безопасной миграции.</p><p>Хорошие точки входа обычно: уведомления, генерация отчетов, поиск, история операций, профиль пользователя, отдельная часть каталога. Важно, чтобы у команды была возможность описать контракт: какие данные входят, какие выходят, какие ошибки возможны, какие внешние системы участвуют.</p><p>Допустим, в банковском приложении есть старый модуль истории операций. Он медленный, сложно расширяется, но при этом не выполняет сами транзакции. Это хороший кандидат для первой миграции. Ошибка в истории операций неприятна, но обычно менее критична, чем ошибка в списании денег.</p><p>Команда может вынести чтение истории в отдельный сервис, сначала запустить его в shadow-режиме, потом включить для части пользователей, затем полностью перевести чтение на новую реализацию. При этом критичная транзакционная логика останется в старой системе до тех пор, пока команда не наберет опыт безопасной миграции.</p><h2>Миграция данных: самая сложная часть</h2><p>Большая часть статьи говорит о маршрутизации запросов и переключении трафика. Но в реальных проектах основная сложность лежит ниже — в данных. Старая и новая реализации почти всегда работают с общим состоянием: одной БД, одним хранилищем документов, одним набором очередей. Переехать туда «одним коммитом» нельзя.</p><p>Базовый рабочий приём — Expand-Contract (он же Parallel Change). Изменение схемы делается в три такта. На этапе expand в БД добавляются новые поля, таблицы или индексы, при этом старое поведение полностью сохраняется. Затем — migrate: обе реализации начинают писать и в старое, и в новое место (dual writes), а отдельный фоновый процесс делает backfill — заполняет новые поля историческими данными. После этого читатели по одному переключаются на новую схему. Только когда никто из читателей не использует старую структуру, наступает contract — удаление лишних колонок и таблиц.</p><p>Несколько практических деталей, которые часто упускают:</p><p>·         Dual writes — это не бесплатная операция. Две записи означают две точки отказа. Если одна из них упала, нужно решать, что делать: продолжать ли работу, ставить ли событие в очередь на повтор, помечать ли запись как несогласованную. Простое «сначала пишем туда, потом сюда» в продакшене на нагрузке приводит к расхождениям.</p><p>·         Backfill часто длиннее, чем кажется. На большой таблице миграция в одном UPDATE блокирует продакшен. Поэтому backfill делают батчами по N тысяч строк с паузами, отслеживают прогресс и предусматривают возможность остановить и продолжить.</p><p>·         Онлайн-изменения схемы на крупных таблицах делаются не штатным ALTER TABLE, а специализированными инструментами: gh-ost или pt-online-schema-change для MySQL, встроенные онлайн-механизмы PostgreSQL для индексов и колонок, Liquibase/Flyway — для управления версионированием изменений в репозитории.</p><p>·         Shadow testing данные не покрывает. Можно сравнить, что новая реализация возвращает то же, что и старая, но если за этим стоит другая схема в БД, проверка корректности самой миграции данных — это отдельная работа: сверки, контрольные суммы, выборочный аудит исторических записей.</p><p>Без этих шагов любая красивая фасадная архитектура наталкивается на разъезжающиеся данные — и тогда даже идеальный Strangler Fig снаружи не спасает.</p><h2>Прокси-слой как точка контроля</h2><p>Чтобы постепенно заменять legacy-код, нужно управлять маршрутизацией запросов. Для этого часто создают прокси-слой, API Gateway или фасад, через который проходит обращение к старой и новой логике. В терминах Domain-Driven Design такой слой часто называют Anti-Corruption Layer: он защищает новую реализацию от старых контрактов и наоборот, позволяя двум моделям сосуществовать без взаимного «загрязнения».</p><p>Без такой точки контроля миграция становится хаотичной. Часть клиентов ходит напрямую в старый модуль, часть — в новый, часть использует обходные пути, а команда теряет возможность централизованно переключать трафик.</p><p>Прокси-слой решает несколько задач. Он скрывает детали реализации от клиентов, позволяет направлять часть запросов в новую систему, поддерживает фича-флаги, собирает метрики и упрощает откат.</p><p>В качестве технической основы команды обычно берут один из трех вариантов: классический API gateway (Kong, AWS API Gateway), service mesh (Envoy, Istio) или более простой reverse proxy (NGINX, HAProxy). Service mesh особенно удобен, когда трафик уже идёт внутри Kubernetes-кластера: маршрутизацию можно менять конфигурацией, без правок кода клиентов и сервисов.</p><p>Например, мобильное приложение обращается к endpoint /orders/history. Раньше этот endpoint напрямую обслуживал монолит. После введения API Gateway приложение продолжает ходить по тому же контракту, но внутри gateway может решать, куда направить запрос: в legacy-модуль или новый сервис истории заказов.</p><p>Управление маршрутизацией обычно делается не «всё или ничего», а на основании атрибутов запроса: значения заголовка (X-Migration-Cohort: new), куки, хэша от user-id (стабильное разбиение пользователей на сегменты) или географического региона. Это позволяет выкатывать новую реализацию сначала на одну страну, на сотрудников самой компании или на тестовый сегмент — и только потом расширять охват.</p><p>Для клиента ничего не меняется. Для команды появляется управляемость.</p><h2>Наблюдаемость: без метрик миграция превращается в гадание</h2><p>Постепенная модернизация невозможна без нормальной наблюдаемости. Если команда не видит, что происходит внутри системы, она не сможет безопасно переключать трафик.</p><p>Минимальный набор — это логи, метрики и распределенная трассировка (distributed tracing). Нужно понимать, сколько запросов идет в старую и новую реализацию, сколько ошибок возникает, как меняется latency, где появляются таймауты, какие статусы возвращаются, какие бизнес-метрики проседают.</p><p>Технические метрики стоит формулировать не как «средний ответ» и «процент ошибок», а в терминах SLI и SLO: целевые показатели вида «99.9% запросов на /orders/history отвечают быстрее 300 ms за 30 дней» с явным error budget. Latency измеряется по перцентилям (p50, p95, p99) — среднее значение почти всегда обманчиво, а хвосты распределения говорят о реальном опыте пользователя. На время миграции имеет смысл выставить отдельные SLO для нового и старого пути и сравнивать их.</p><p>В качестве инструментов де-факто стандартом стал OpenTelemetry для трассировок, метрик и логов — единый протокол, который пишет в практически любое хранилище. Дальше — Prometheus и Grafana для метрик, Jaeger или Tempo для traces, Sentry или аналог для ошибок. Для миграции важна возможность фильтровать метрики по «варианту» — отдельно по старому и новому пути — иначе все цифры смешаются и реальную динамику будет не видно.</p><p>Технических метрик недостаточно. Если команда переносит оформление заказа, важно смотреть не только на 500 ошибки и время ответа, но и на конверсию в оплату, количество брошенных корзин, повторы запросов, обращения в поддержку.</p><p>Пример: новая система формально отвечает быстрее старой и не дает ошибок. Но после включения на 10% пользователей падает конверсия в оплату. Причина может быть не в серверной ошибке, а в изменении порядка полей, другом тексте сообщения или потере какого-то edge-case. Без бизнес-метрик команда может решить, что миграция успешна, хотя для продукта она уже создает проблему.</p><h2>Практическая последовательность миграции</h2><p>Рабочая последовательность обычно выглядит так.</p><p>Сначала команда выбирает ограниченный участок системы. На этом этапе важно не просто назвать модуль, а описать его границы. Какие сценарии он закрывает? Кто его вызывает? Какие данные он читает и пишет? Какие внешние интеграции использует? Какие неочевидные бизнес-правила в нем есть?</p><p>Затем поверх legacy-логики создается стабильный контракт. Это может быть API, фасад, gateway или отдельный слой внутри приложения. Главная задача — сделать так, чтобы клиенты зависели не от внутренней реализации, а от понятного интерфейса. На этом этапе полезно вспомнить про contract testing (Pact, Spring Cloud Contract): автотесты со стороны потребителей фиксируют, что именно они ожидают от API, и предупреждают о ломающих изменениях до того, как они доедут до продакшена.</p><p>После этого рядом пишется новая реализация. Она должна повторять текущее поведение, а не сразу становиться «идеальной версией будущего». На этом этапе полезно фиксировать все расхождения: где старая система работает странно, где требования не описаны, где бизнес-правила требуют уточнения.</p><p>Следующий этап — shadow testing. Новая система получает копии реальных запросов, считает результат, но пользователю по-прежнему возвращается ответ legacy. Команда сравнивает результаты и устраняет расхождения.</p><p>Когда новая реализация достаточно стабильна, начинается постепенное переключение через feature toggles. Сначала внутренние пользователи, потом 1% реального трафика, затем 5–10%, затем 50% и только после этого 100%.</p><p>На каждом этапе команда смотрит на метрики. Если всё стабильно, движение продолжается. Если появляются проблемы, флаг выключается, трафик возвращается в legacy, а команда разбирает причины.</p><p>Последний этап — удаление старого кода. Это не формальность, а обязательная часть миграции. И «удалить старый код» — это не один коммит, а явный Definition of Done: вырезана старая ветка кода, удалён фича-флаг, обновлена документация и схемы архитектуры, переименованы или удалены устаревшие дашборды и алерты, обновлены runbook’и для on-call и проведено короткое внутреннее обучение. Если этого не сделать, через полгода никто уже не вспомнит, какой путь актуален, и легаси-ветвление останется в коде навсегда.</p><h2>Откат миграций: дешёвый только пока не пошли записи</h2><p>Откатить миграцию, в которой ещё не было записи в БД, легко: достаточно переключить фича-флаг, и трафик снова идёт через старую реализацию. Откатить миграцию, в которой новая система уже неделю писала данные в новые таблицы, — отдельный, гораздо более тяжёлый разговор.</p><p>Поэтому ещё на этапе проектирования каждое изменение должно сопровождаться явным планом отката. Удобно различать три типа шагов.</p><p>Полностью обратимые шаги. Чтение через новый сервис, расчёт «в тени», новые метрики. Откат — выключить флаг. Это самый комфортный режим, и в нём стоит держать миграцию как можно дольше.</p><p>Обратимые с компенсацией. Новая реализация пишет дополнительные данные (например, дублирует операции в новую таблицу), но старый источник тоже обновляется. Откат возможен, но требует решить, что делать с уже записанными данными: оставить, очистить, синхронизировать. План этих действий должен быть написан до выкатки, не во время инцидента.</p><p>Forward-only. После некоторой точки откат становится невозможен — например, после того, как старая схема удалена или внешние интеграции перенастроены на новый сервис. Такие шаги допустимы, но к ним нужно приходить отдельно, осознанно, с особенно строгими SLO в предыдущем этапе. До forward-only-перехода имеет смысл подержать систему в режиме параллельной работы дольше, чем по графику.</p><p>Базовое правило: ни один шаг миграции не должен уходить в продакшен, если у команды нет письменного ответа на вопрос «как мы откатываемся в случае проблемы». Иначе при инциденте откатываться будут на ходу — и не факт, что успешно.</p><h2>Пример: как тот же сервис мигрировали со второй попытки</h2><p>После неудачного опыта команда взялась за тот же сервис заново, но изменила подход.</p><p>На первом шаге они зафиксировали поведение существующего сервиса. На самые часто используемые сценарии (создание путевого листа, подпись акта осмотра, выгрузка пакета документов за период) написали характеристические тесты на реальных продакшен-данных, обезличенных и сохранённых как фикстуры. Любое будущее изменение поведения теперь падало в CI как явное расхождение.</p><p>Параллельно команда провела инвентаризацию побочных эффектов. Из исходного кода и логов выяснилось, что сервис не только хранит документы, но и: публикует событие в Kafka при смене статуса, инкрементирует счётчик в Redis для рейтинга водителей, отправляет webhook во внешнюю систему партнёра, пишет в таблицу аудита. Каждый из этих эффектов попал в отдельный пункт чек-листа «что должно остаться» в новой реализации.</p><p>Затем команда выбрала первый кусок для выноса — не весь сервис, а только чтение документов (GET /documents/{id} и GET /documents/by-driver/{driver_id}). Это была наименее рискованная часть: ошибки в чтении неприятны, но не ломают финансовые потоки.</p><p>Новый сервис написали на FastAPI рядом со старым. На уровне API Gateway появилось правило маршрутизации: запросы на чтение шли в старый сервис, но в фоне дублировались в новый. Ответ пользователю всегда возвращал legacy, а ответ нового сервиса сравнивался с эталоном и записывался в отдельную таблицу для разбора. Использовали обёртку поверх asyncio.create_task — на ответ пользователя теневой вызов не влиял.</p><p>За три недели shadow-режима команда нашла четыре расхождения. Два оказались багами новой реализации (округление времени, неправильная сортировка вложений). Два — давно забытыми особенностями старого сервиса (одно поле возвращалось в UTC, другое — в локальной зоне; так было исторически, бизнес не возражал, но в новой реализации захотели единый формат). Все четыре зафиксировали явно: баги — починили, особенности — согласовали с продуктовой командой как осознанное изменение.</p><p>Когда расхождений не осталось, включили фича-флаг на сотрудников самой компании. Через неделю — на 1% реальных водителей. Дальше шаг по 5%, 25%, 50%, 100% с паузой в несколько дней между этапами. На каждом шаге следили не только за HTTP-ошибками и latency, но и за продуктовыми метриками: количество подписанных актов, время от открытия документа до подписи, доля повторных запросов. Один раз пришлось откатиться с 25% на 5% — в одном из регионов выросло время отклика из-за неэффективного запроса. Исправили, выкатили снова.</p><p>Через два месяца чтение полностью перешло в новый сервис. Старый код чтения и фича-флаг удалили в том же релизе. После этого по той же схеме мигрировали запись документов, потом публикацию событий, потом импорт из внешних систем. Полная миграция заняла девять месяцев — почти столько же, сколько провалившийся Big Bang, — но продукт всё это время продолжал развиваться, инцидентов не было, и в конце команда осталась с системой, которую понимает.</p><h2>Типичные ошибки при работе с legacy</h2><p>Первая ошибка — пытаться улучшить всё сразу. Команда одновременно меняет архитектуру, бизнес-логику, контракты и инфраструктуру. В результате становится невозможно понять, какая именно часть вызвала проблему. Правильнее сначала воспроизвести поведение, стабилизировать новую реализацию и только потом улучшать.</p><p>Вторая ошибка — недооценивать скрытые зависимости и побочные эффекты. Legacy-код часто делает больше, чем кажется. На один и тот же вызов могут быть навешаны: запись в таблицу аудита, инкремент счётчика в кэше, публикация события в очередь, обновление статуса связанной сущности, инвалидация кэша, дёрганье webhook’а во внешнюю систему. Если в новой реализации воспроизвести только явный путь, скрытые потребители молча перестанут получать данные — и узнают об этом через жалобу бизнеса, а не через ошибку в логах. Поэтому перед выносом любого модуля имеет смысл составить инвентаризацию побочных эффектов: пройтись по коду и логам и выписать каждое нелогичное действие отдельным пунктом чек-листа.</p><p>Третья ошибка — отсутствие наблюдаемости. Без логов, метрик и трассировки команда не управляет миграцией, а угадывает. Особенно опасно смотреть только на технические ошибки и игнорировать бизнес-показатели.</p><p>Четвертая ошибка — не договариваться с бизнесом. Модернизация не должна быть невидимой «инженерной активностью в стол». Её нужно встраивать в roadmap, объяснять эффект и договариваться о приоритетах. Если бизнес не понимает, зачем команда тратит время на миграцию, работа будет постоянно проигрывать новым фичам.</p><p>Пятая ошибка — не удалять старый код. Временное сосуществование старой и новой логики нормально. Вечное сосуществование — нет. Если legacy не удаляется, технический долг не уменьшается, а просто меняет форму.</p><p>Шестая ошибка — не удалять фича-флаги после миграции. Флаг, который сыграл свою роль и больше никогда не выключается, превращается в постоянное ветвление в коде. Через год команда не помнит, можно ли удалить такую ветку или там сидит важный edge-case. Через два — кода с такими «мёртвыми» флагами становится больше, чем основной логики. Поэтому каждый флаг должен заводиться с условием удаления («после полной выкатки и двух недель стабильной работы») и иметь ответственного, кто этим удалением займётся.</p><p>Отдельно стоит упомянуть организационную сторону. Закон Конвея работает и в обратную сторону: если новый и старый код владеются разными командами с разными приоритетами, миграция будет тормозиться независимо от выбранного паттерна. На время миграции имеет смысл явно проговорить, кто отвечает за переход, и не разделять старую и новую реализации между несовместимыми roadmap’ами.</p><h2>Компромиссы, к которым нужно быть готовыми</h2><p>Постепенная модернизация безопаснее Big Bang-переписывания, но она не бесплатна. Некоторое время система будет сложнее, чем раньше. В ней появятся старый и новый код, прокси-слой, фича-флаги, дублирование логики, дополнительные метрики.</p><p>Shadow testing увеличит нагрузку на инфраструктуру, потому что часть запросов будет обрабатываться дважды. Команде придется поддерживать дисциплину: документировать контракты, отслеживать флаги, удалять старую реализацию после миграции, поддерживать contract-тесты в актуальном состоянии.</p><p>Но это контролируемая сложность. Она распределена во времени и управляется инженерными практиками. В отличие от Big Bang-риска, где команда долго работает с минимальной обратной связью, а потом выкатывает один большой релиз с максимальной неопределенностью.</p><h2>Когда Strangler Fig особенно оправдан</h2><p>Постепенная миграция особенно хорошо подходит для систем, где downtime невозможен или слишком дорог. Это финтех, e-commerce, биллинг, мобильные бэкенды с большой аудиторией, высоконагруженные продукты, старые монолиты и системы с большим количеством интеграций.</p><p>Если продуктом ежедневно пользуются сотни тысяч или миллионы людей, нельзя позволить себе «переписать и посмотреть, что будет». Нужно менять архитектуру так, чтобы пользователь не замечал процесса миграции.</p><p>Этот подход также полезен там, где бизнес продолжает активно развивать продукт. Если фичи нельзя заморозить на полгода, модернизация должна идти параллельно с продуктовой разработкой.</p><h2>Когда модернизацию лучше не делать</h2><p>Постепенная миграция — мощный инструмент, но у неё тоже есть стоимость, и иногда правильный ответ — оставить систему как есть. Несколько сценариев, в которых модернизация плохо окупается.</p><p>Продукт, который уходит из эксплуатации. Если через год сервис будет выключен или заменён на покупное решение, тратить квартал на его рефакторинг бессмысленно. Достаточно стабилизировать то, что есть.</p><p>Модуль, который никто не трогает. Если код десятилетней давности продолжает работать, не падает, не требует изменений и не вызывает инцидентов, его «уродливость» — не повод его переписывать. Цель модернизации — упростить будущие изменения; если будущих изменений нет, цели тоже нет.</p><p>Регулируемые системы с тяжёлой ресертификацией. В банковских, медицинских и государственных контурах любое изменение в критичной системе может потребовать повторной сертификации, перепрохождения аудитов, обновления договорной обвязки. В таких условиях стоимость модернизации может на порядок превышать стоимость поддержки текущей реализации, и решение нужно принимать вместе с владельцем продукта и юристами, а не только инженерным составом.</p><p>Простой тест: если на вопрос «какой бизнес-сценарий мы откроем после миграции» нет внятного ответа — модернизацию имеет смысл отложить и заняться чем-то другим.</p><h2>Что получает команда</h2><p>Главный результат постепенной модернизации — управляемость. Команда начинает лучше понимать систему, контролировать изменения и снижать риск инцидентов.</p><p>Появляются понятные контракты, наблюдаемость, практика безопасных релизов, культура удаления старого кода. Разработчики перестают бояться legacy, потому что у них появляется метод, а не только желание «когда-нибудь всё переписать».</p><p>Для бизнеса это тоже выгодно. Продукт продолжает развиваться, сроки становятся более прогнозируемыми, риски крупных сбоев снижаются, а технический долг постепенно уменьшается.</p><h2>Модернизация — это процесс, а не проект</h2><p>Legacy нельзя «починить за квартал». Если система развивалась годами, она не станет простой после одного рефакторинга. Но её можно системно улучшать.</p><p>Strangler Fig Pattern, Branch by Abstraction, feature toggles, shadow testing и аккуратная миграция данных дают рабочую модель: выбрать ограниченный участок, описать контракт, реализовать новую версию, проверить её на реальном трафике, постепенно переключить пользователей и удалить старый код.</p><p>Это не самый быстрый путь. Зато он управляемый. А в зрелых продуктах управляемость важнее скорости.</p><p>Потому что цель модернизации — не написать красивую новую систему. Цель — сделать так, чтобы продукт продолжал развиваться, команда могла безопасно вносить изменения, а пользователи не становились участниками инженерного эксперимента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое Git worktrees и зачем их использовать</title>
      <link>https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat</link>
      <comments>https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat</guid>
      <description><![CDATA[<p>Git worktrees появились ещё в 2015 году, но популярность обрели только недавно. Разбираем, что это такое, как использовать в терминале и зачем они пригодятся.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/chto-takoe-git-worktrees-i-zachem-ih-ispolzovat">Что такое Git worktrees и зачем их использовать</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 18 Jun 2026 03:00:07 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перевод статьи Cassidy Williams из GitHub Blog, оригинал: <a href="https://github.blog/ai-and-ml/github-copilot/what-are-git-worktrees-and-why-should-i-use-them/">https://github.blog/ai-and-ml/github-copilot/what-are-git-worktrees-and-why-should-i-use-them/</a></p><p>Git worktrees позволяют держать несколько рабочих копий одного репозитория на разных ветках — и сейчас эта возможность в тренде. Забавно, что в Git она появилась ещё в 2015 году. Но worktrees действительно удобны, и в этой статье разберёмся, зачем они нужны, чем отличаются от обычных веток и почему внезапно стали популярны.</p><p>worktree — это дополнительная рабочая копия репозитория на другой ветке, привязанная к тому же .git.</p><p>С их помощью можно переключаться между задачами, не прерывая текущую работу и не используя stash.</p><p>Они особенно полезны при параллельной работе с ИИ-агентами и в приложении GitHub Copilot.</p><p>У worktrees есть ограничения: раздувание зависимостей, необходимость убирать папки, правила .gitignore и запрет на одновременный checkout одной ветки в нескольких worktrees.</p><h2>Переключение контекста через ветки и stash</h2><p>Представьте: вы работаете над задачей и вдруг получаете срочный баг. Нужно срочно переключить контекст.</p><p>Сначала, скорее всего, спрячете текущие изменения в stash:</p><p>Потом перейдёте на main и обновите её:</p><p>Затем создадите ветку с хотфиксом:</p><p>Пофиксите, закоммитите и запушите ветку:</p><p>После слияния pull request вы вернётесь к компьютеру, подтянете main и удалите ветку с багфиксом:</p><p>А потом сможете вернуться к задаче, над которой работали:</p><p>Фух. На чём мы остановились?</p><p>Переключение туда-сюда, перезагрузка файлов, переустановка node_modules в зависимости от того, что изменилось, — всё это отнимает много сил. Нагрузка от смены контекста серьёзная.</p><p>Это базовый пример, но иногда разработчики справлялись с таким хаосом сложными командами git stash или даже несколькими клонами одного репозитория (я сама грешила этим).</p><p>А потом появились… worktrees!</p><h2>Переключение контекста через worktrees</h2><p>С worktrees вы никогда не покидаете свою ветку и не используете stash, а редактор с вашей текущей фичей остаётся нетронутым.</p><p>Эта команда мгновенно создаёт соседнюю папку hotfix-workspace, базирует её на main и создаёт новую ветку hotfix-bug.</p><p>Теперь можно открыть эту папку в новом окне редактора (или перейти в неё через cd) и чинить баг. Исходное окно редактора остаётся в том же состоянии, в котором вы его оставили.</p><p>Pull request сливаете онлайн, как обычно, а после слияния можно просто удалить временную папку.</p><p>Гораздо плавнее! Нет риска конфликтов stash, редактор не перезагружается, и вы действительно можете работать параллельно.</p><h2>Так почему же сейчас?</h2><p>Долгое время worktrees были относительно неизвестны. Большинство разработчиков никогда о них не слышали, потому что либо Git GUI не поддерживали их (или относились как к второсортной функции), либо все привыкли к знакомой схеме: feature-ветка, работа, PR, merge и повтор.</p><p>Сейчас наша работа изменилась. ИИ заставляет нас работать параллельно больше, чем когда-либо в истории разработки ПО. Разработчики запускают множество сессий одновременно, а «культура код-ревью» растёт быстрее, чем «культура написания кода».</p><p>Агенты и люди могут делать больше параллельно с помощью worktrees. Это режим по умолчанию в приложении GitHub Copilot и во многих других современных инструментах.</p><blockquote>Агенты и люди могут делать больше параллельно с помощью worktrees.</blockquote><h2>В чём подвох?</h2><p>Worktrees решают кучу проблем, но есть нюансы, на которые стоит обращать внимание.</p><ul><li>Раздувание зависимостей: каждая папка worktree требует собственную копию зависимостей проекта. Если запускать npm install или pip install в нескольких worktrees, диск может быстро закончиться.</li><li>Управление папками: нужно удалять папки worktree, чтобы со временем не засорять родительский каталог. Приложение GitHub Copilot часто делает это за вас, но если вы работаете в терминале, придётся следить самостоятельно.</li><li>Требования к глобальному .gitignore: если создавать worktree внутри основного репозитория, их нужно вручную добавить в .gitignore, чтобы случайно не закоммитить. Можно создавать worktree за пределами основного репозитория (GitHub Copilot делает это по умолчанию), но это стоит учитывать.</li><li>Ограничение «одна ветка»: Git не позволяет одновременно checkout’ить одну и ту же ветку в двух разных worktrees, чтобы избежать повреждения данных.</li></ul><h2>Как использовать git worktrees в приложении GitHub Copilot?</h2><p>Отличный вопрос! Здорово, что там всё работает «из коробки». Когда вы открываете приложение, на главном экране есть выпадающий список, который спрашивает, где запускать новую сессию. По умолчанию выбран новый worktree.</p><p>Когда вы запускаете новую сессию, можно нажать на имя сессии вверху приложения и увидеть (забавное!) сгенерированное имя вашего worktree, а также путь, где он находится, проект, для которого он создан, и сведения о внесённых изменениях.</p><p>Проще простого!</p><h2>Стоит ли использовать worktrees?</h2><p>Я дам вам самый senior-ответ, который только можно: зависит от ситуации! Вам может быть удобнее работать по-другому. Возможно, вы не так много работаете параллельно и привыкли к ментальной модели веток и stash. Возможно, теперь вы будете использовать только worktrees. А может, захотите и то, и другое!</p><p>Мир у ваших ног, и попробовать всё это можно уже сегодня в приложении GitHub Copilot.</p><p><b>Об авторе.</b> Cassidy Williams — старший директор по адвокации разработчиков в GitHub. Она создаёт ПО, консультирует стартапы и учит разработчиков строить лучше. Подписаться на её еженедельную рассылку можно на <a href="https://cassidoo.co/newsletter">cassidoo.co/newsletter</a>.</p><h2>Выводы</h2><p>Git worktrees — способ работать с несколькими ветками одновременно, не прерывая текущую задачу и не рискуя запутаться в stash. Они особенно удобны при параллельной работе с ИИ-агентами и встроены в приложение GitHub Copilot по умолчанию. Попробуйте — возможно, именно они упростят ваш рабочий процесс.</p>]]></content:encoded>
    </item>
    <item>
      <title>Microsoft обратилась к Amazon за мощностями AWS, чтобы спасти GitHub от сбоев из-за ИИ</title>
      <link>https://tproger.ru/news/microsoft-obratilas-k-amazon-za-moshhnostyami-aws-chtoby-spasti-gi</link>
      <comments>https://tproger.ru/news/microsoft-obratilas-k-amazon-za-moshhnostyami-aws-chtoby-spasti-gi?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/microsoft-obratilas-k-amazon-za-moshhnostyami-aws-chtoby-spasti-gi</guid>
      <description><![CDATA[<p>GitHub наращивает мощности через AWS из-за всплеска ИИ-кода и сбоев. Разбираем, почему Microsoft пошла на сделку с Amazon и что это значит для разработчиков.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/microsoft-obratilas-k-amazon-za-moshhnostyami-aws-chtoby-spasti-gi">Microsoft обратилась к Amazon за мощностями AWS, чтобы спасти GitHub от сбоев из-за ИИ</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Amazon]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 16 Jun 2026 14:45:05 GMT</pubDate>
      <content:encoded><![CDATA[<p>Microsoft арендует дополнительные облачные мощности у Amazon Web Services, чтобы GitHub справлялся с наплывом кода, который создают ИИ-инструменты. Если ваш репозиторий тормозил или был недоступен в последние месяцы — вот почему это происходит.</p><p><a href="https://www.businessinsider.com/microsoft-github-amazon-ai-cloud-capacity-2026-6">Business Insider</a> со ссылкой на двух знакомых с планами людей сообщает: <b>Microsoft</b>, владелец GitHub, вынуждена арендовать дополнительные вычислительные мощности у <b>Amazon Web Services</b>. Официальный представитель Microsoft подтвердил лишь использование нескольких облачных провайдеров, но отказался комментировать участие Amazon. AWS — главный конкурент Microsoft Azure на рынке облаков, поэтому конкуренты вынуждены сотрудничать.</p><ul><li>Microsoft планирует разместить часть нагрузки GitHub на Amazon Web Services из-за нехватки собственных мощностей.</li><li>При сохранении текущего темпа число коммитов на платформе может вырасти с 1 млрд в 2025 году до 14 млрд в 2026 году.</li><li>В 2026 году GitHub пережил десятки крупных сбоев.</li><li>Microsoft намеревалась полностью перевести GitHub на Azure к 2027 году, но ИИ-бум ускорил потребность в дополнительных мощностях.</li></ul><h2>Что произошло</h2><p>GitHub — популярная платформа для хранения и совместной работы над кодом. До поглощения Microsoft в 2018 году она в основном использовала собственные дата-центры. Корпорация планировала полностью <a href="https://tproger.ru/news/microsoft--dozhala---github-otkazalsya-ot-svoih-data-centrov---teper-vse-pereedet-v-azure">перевести GitHub на Azure</a> к 2027 году, но всплеск активности, связанный с разработкой на базе ИИ-агентов и ассистентов, заставил пересмотреть сроки и искать мультиоблачную схему.</p><h3>Рост коммитов в 14 раз</h3><p>По данным директора по операциям GitHub Кайла Дейгла, при сохранении текущего темпа число коммитов — записей об изменениях в коде — в 2026 году может достичь <b>14 млрд</b> против <b>1 млрд</b> в 2025. Microsoft, со своей стороны, прогнозирует общие капитальные затраты корпорации в <b>$190 млрд</b> в 2026 году, в основном на расширение дата-центров, но часть проектов откладывается.</p><h2>Почему Microsoft идёт на сделку с AWS</h2><p>Конкуренция между Azure и AWS не отменяет главную задачу — не допустить сбоев в работе сервиса. В 2026 году GitHub пережил десятки крупных сбоев. Кроме того, на рынке появляются альтернативы вроде Cursor и Claude Code, которые конкурируют с экосистемой GitHub и <a href="https://tproger.ru/news/github-copilot-s-24-aprelya-obuchaetsya-na-vawem-kode-po-umolchaniyu">Copilot</a>, и Microsoft приходится ускорять модернизацию инфраструктуры.</p><h3>Конкуренция за разработчиков</h3><blockquote>GitHub больше не место для серьёзной работы, если он ежедневно выбрасывает вас на несколько часов.</blockquote><h2>Часто задаваемые вопросы</h2><h2>Выводы</h2><p>Сделка Microsoft и Amazon — признак того, что спрос на ИИ-инфраструктуру превышает возможности даже крупнейших игроков. Для разработчиков главное — чтобы GitHub оставался стабильным: следите за статус-страницей сервиса и не используйте GitHub как единственное хранилище критичных данных. Первоисточник: <a href="https://www.businessinsider.com/microsoft-github-amazon-ai-cloud-capacity-2026-6">Business Insider</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Подрядчик CISA полгода держал пароли и ключи AWS в публичном репозитории GitHub</title>
      <link>https://tproger.ru/articles/podryadchik-cisa-polgoda-derzhal-paroli-i-klyuchi-aws-v-publichnom-rep</link>
      <comments>https://tproger.ru/articles/podryadchik-cisa-polgoda-derzhal-paroli-i-klyuchi-aws-v-publichnom-rep?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/podryadchik-cisa-polgoda-derzhal-paroli-i-klyuchi-aws-v-publichnom-rep</guid>
      <description><![CDATA[<p>Подрядчик CISA полгода держал в публичном GitHub-репозитории 844 МБ паролей, токенов AWS GovCloud и Kubernetes-конфигов. Разбираем, как защитить свою команду.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/podryadchik-cisa-polgoda-derzhal-paroli-i-klyuchi-aws-v-publichnom-rep">Подрядчик CISA полгода держал пароли и ключи AWS в публичном репозитории GitHub</a>»</p>]]></description>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Облачные технологии]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Утечка данных]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 20 May 2026 06:45:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Каждый разработчик хотя бы раз ставил git push и через секунду холодел: «А я .env точно вычеркнул из коммита?». Подрядчик американского агентства по кибербезопасности CISA, судя по всему, этот вопрос себе ни разу не задал — и шесть месяцев держал в публичном репозитории GitHub пароли в открытом виде, токены к закрытому облаку <b>AWS GovCloud</b> (изолированный регион Amazon для госструктур США) и сертификаты <b>Microsoft Entra ID</b> (бывший Azure AD, корпоративный сервис единого входа).</p><p>Историю обнародовал журналист Брайан Кребс <a href="https://krebsonsecurity.com/2026/05/cisa-admin-leaked-aws-govcloud-keys-on-github/">в материале от 18 мая</a> по наводке исследователя из <a href="https://www.gitguardian.com">GitGuardian</a>. Репозиторий назывался без лишней скромности — Private-CISA — и был виден любому, кто откроет GitHub.</p><ul><li>Подрядчик CISA с 13 ноября 2025 года вёл публичный репозиторий <b>Private-CISA</b> размером 844 МБ с паролями, ключами AWS GovCloud, сертификатами Entra ID SAML и Kubernetes-манифестами.</li><li>Пароли лежали в открытом виде в <b>CSV-файле</b>, а среди файлов был <b>importantAWStokens</b> с админ-доступом к трём серверам AWS GovCloud.</li><li>Чтобы такое стало возможным, в аккаунте было <b>выключено</b> стандартное правило GitHub, блокирующее коммиты с секретами.</li><li>GitGuardian называет утечку «худшей в карьере» исследователя, но CISA утверждает, что «нет признаков компрометации чувствительных данных».</li><li>Репозиторий закрыли вечером 15 мая 2026 года, спустя около 26 часов после уведомления исследователей — но он был публичным <b>около полугода</b>.</li></ul><h2>Что лежало в Private-CISA</h2><p>GitGuardian, компания, у которой <a href="https://blog.gitguardian.com/how-we-got-a-cisa-github-leak-taken-down-in-26-hours/">сканер постоянно обходит публичные репозитории GitHub</a> в поисках утёкших секретов, наткнулась на репозиторий 14 мая 2026 года. По объёму это 844 МБ — 498 МБ в рабочем дереве, остальное в истории Git. Среди папок и файлов исследователи нашли:</p><ul><li><b>importantAWStokens</b> — административные токены к трём серверам AWS GovCloud (изолированный облачный регион Amazon для госструктур США).</li><li><b>AWS-Workspace-Firefox-Passwords.csv</b> — экспорт сохранённых паролей Firefox с десятками логинов и паролей от внутренних систем CISA в открытом виде.</li><li><b>CAWS GitHub Token.txt</b> — отдельный токен GitHub-организации.</li><li><b>Kube-Config.txt</b> — конфигурации Kubernetes для доступа к кластерам.</li><li>Папку <b>ENTRA ID — SAML Certificates</b> с сертификатами для единого входа через Microsoft Entra ID.</li><li>Папки <b>All Backups</b>, <b>Backup-April-2026</b>, <b>LZ-Artifactory</b>, <b>Kubernetes-Important-Yaml-Files</b> — внутренние бэкапы, манифесты ArgoCD и YAML-файлы с секретами.</li><li>Terraform-код инфраструктуры и GitHub Actions, описывающие, как CISA собирает, тестирует и выкатывает свой софт.</li><li>Резервные копии внутренней документации в форматах OneNote и DOCX, плюс скрипты для GitHub, Kubernetes, ArgoCD.</li></ul><p>Один из попавших в репозиторий хостов назывался LZ-DSO — по словам исследователей это сокращение от <b>Landing Zone DevSecOps</b>, то есть от среды, в которой CISA «безопасно» собирает свой код. Иронично: ключи от пайплайна, который должен защищать всё остальное, лежали публично.</p><blockquote>Это худшая утечка, которую я видел за свою карьеру.</blockquote><p>Сначала команда GitGuardian приняла находку за розыгрыш: слишком уж красноречивые названия папок и файлов. Но личные документы, имена хостов и аккуратная структура повторных бэкапов убедили — это рабочая копия чьего-то ноутбука, которую регулярно «синхронизировали» через git push в открытый репозиторий.</p><h2>Как нашли и сообщили</h2><p>Согласно <a href="https://blog.gitguardian.com/how-we-got-a-cisa-github-leak-taken-down-in-26-hours/">подробному разбору GitGuardian</a>, программа Good Samaritan компании первой обнаружила утечку и автоматически отправила <b>девять писем</b> владельцу коммитов. К утру 15 мая в ответ пришли только автоответчики.</p><p>Тогда исследователи <a href="https://krebsonsecurity.com/2026/05/cisa-admin-leaked-aws-govcloud-keys-on-github/">связались с Брайаном Кребсом</a>, чтобы он передал утечку напрямую своим контактам в CISA. Параллельно подключились партнёры с прямой линией в агентство. Около 16:00 по центральноевропейскому времени удалось дозвониться, а в районе 18:00 по восточному времени США репозиторий стал недоступен. От первого выявленного слива до закрытия прошло чуть больше суток — но создан репозиторий был 13 ноября 2025 года, так что окно для злоумышленника составляло около полугода.</p><h3>Хронология</h3><ul><li><b>13 ноября 2025</b> — создан публичный репозиторий Private-CISA, первые секреты залиты.</li><li><b>13 мая 2026</b> — автоматический сканер GitGuardian Good Samaritan уже успел отправить владельцу репозитория девять писем-предупреждений.</li><li><b>14 мая 2026, 16:14 CET</b> — GitGuardian фиксирует инцидент и подаёт его в CERT/CC (координационный центр по реагированию на киберинциденты), параллельно ища личные контакты в CISA.</li><li><b>15 мая 2026</b> — GitGuardian параллельно выходит на Кребса для эскалации через его контакты и на собственных партнёров с прямой линией в агентство; около 16:00 CET до CISA дозваниваются.</li><li><b>15 мая, около 18:00 EST</b> — репозиторий удалён.</li></ul><h2>Почему secret scanning не сработал</h2><p>GitHub давно предлагает push protection — функцию, которая не даёт залить в публичный репозиторий распознанные секреты вроде токенов AWS, ключей SSH или ключей API. Для бесплатных публичных репозиториев она включена по умолчанию с 2024 года. Но защита от дурака легко выключается одним кликом, и в случае с Private-CISA её действительно отключили — Кребс цитирует исследователей, которые нашли в истории коммитов следы того, что владелец аккаунта вручную убрал блокировку секретов.</p><p>Это распространённый паттерн: разработчик сталкивается с блокировкой пуша, не разбирается, почему сработала защита, и снимает её через настройки. Иногда — в личном репозитории «для удобства», иногда — потому что коммит уже содержит что-то более чувствительное, чем тестовый ключ. Результат предсказуем: репозитории, в которых годами лежат «временные» .env-файлы с продакшен-доступами, и автоматические сканеры вроде GitGuardian, TruffleHog или GitHub Secret Scanning, которые рано или поздно их находят.</p><p>По версии <a href="https://gizmodo.com/the-worst-leak-that-ive-witnessed-u-s-cybersecurity-agency-leaves-its-digital-keys-out-in-public-on-github-2000760330">Gizmodo</a>, сотрудник подрядчика Nightwing использовал GitHub как личную папку «Загрузки»: коммитил файлы с рабочего ноутбука, чтобы открыть их на домашнем компьютере. То же самое многие делают через личную почту, только публичный репозиторий ещё хуже — он проиндексирован поисковиками и сканируется ботами в режиме реального времени.</p><h2>Кто такая CISA и почему это важно</h2><p>Особый цинизм истории — в том, кто оказался виновником. CISA (Cybersecurity and Infrastructure Security Agency) — молодое подразделение Министерства внутренней безопасности США, отвечающее за кибербезопасность всех федеральных гражданских сетей. Это именно та организация, которая публикует руководства про «никогда не храните пароли в спредшитах». При этом, по данным <a href="https://techcrunch.com/2026/05/19/us-cyber-agency-cisa-exposed-reams-of-passwords-and-cloud-keys-to-the-open-web/">TechCrunch</a>, у CISA с 20 января 2025 года нет постоянного директора, агентство потеряло около трети штата после сокращений и отпусков, а ни один временно исполняющий обязанности не был утверждён Сенатом. В таких условиях процессы по контролю подрядчиков и аудиту репозиториев предсказуемо проседают — и тот факт, что утечку у регулятора по кибербезу нашёл частный сканер, а не внутренние инструменты, красноречивее любого внутреннего отчёта.</p><h2>Что делать в своей команде, чтобы не повторить историю CISA</h2><p>История CISA читается как готовый чеклист «как не надо». Перевернём его в «как надо» — для команд от стартапа до крупного бизнеса.</p><ol><li><b>Включите GitHub push protection на уровне организации</b> и запретите её отключать. Owner organization → Security → Secret protection → Push protection: Enabled.</li><li><b>Запретите коммитеры-индивидуумам быть owner репозиториев в проде.</b> Любой публичный репозиторий компании должен принадлежать организации с настроенными правилами.</li><li><b>Сканируйте свою историю</b>, а не только новые коммиты. Один раз пропущенный .env остаётся в Git forever — поможет <a href="https://github.com/trufflesecurity/trufflehog">TruffleHog</a>, <a href="https://gitguardian.com">GitGuardian</a>, GitHub Advanced Security или встроенный git-secrets.</li><li><b>Не используйте Git как файлообменник между домашним и рабочим компьютером.</b> Для этого есть VPN, корпоративный OneDrive, S3-бакет с IAM, в конце концов — scp.</li><li><b>Включите автоматическую ротацию ключей AWS и сервис-токенов</b>. Даже если они утекут, окно использования закроется через сутки-двое.</li><li><b>Настройте мониторинг подозрительных вызовов API в облаке</b>. Для AWS — <a href="https://aws.amazon.com/cloudtrail/">CloudTrail</a> + <a href="https://aws.amazon.com/guardduty/">GuardDuty</a> с алертами на новые регионы, необычные IAM-действия и обращения к AWS API из неизвестных IP. Если ключ всё-таки утёк — вы узнаете об этом по логам, а не из новостей.</li><li><b>Раз в квартал проводите аудит публичных репозиториев</b>: gh repo list ORG --visibility public и быстрая проверка, что там должно лежать публично.</li></ol><p>GitHub в своём блоге называет push protection <a href="https://github.blog/security/application-security/push-protection-is-now-generally-available-and-free/">первой линией защиты</a> и приводит цифру: с момента включения по умолчанию на бесплатных публичных репозиториях функция предотвратила сотни тысяч случайных утечек. Эту настройку выключают именно те, кто потом попадает в новости.</p><h2>Что говорят сами CISA и эксперты</h2><p>Сводный ответ агентства <a href="https://krebsonsecurity.com/2026/05/cisa-admin-leaked-aws-govcloud-keys-on-github/">для Кребса</a> и <a href="https://techcrunch.com/2026/05/19/us-cyber-agency-cisa-exposed-reams-of-passwords-and-cloud-keys-to-the-open-web/">TechCrunch</a> звучит как стандартная PR-формула. TechCrunch уточняет, что комментарий дал пресс-секретарь CISA Марко ДиСандро:</p><blockquote>На данный момент нет признаков того, что в результате инцидента были скомпрометированы чувствительные данные. Мы продолжаем расследование и работаем над дополнительными мерами защиты, чтобы предотвратить повторение подобных случаев в будущем.</blockquote><p>Проблема в формулировке «нет признаков»: при шестимесячном окне публичности любые токены стоит считать скомпрометированными по умолчанию. Стандартный план действий — отозвать всё, выпустить новое, проанализировать логи AWS CloudTrail на предмет обращений с этих токенов и опубликовать честный разбор инцидента. До такого разбора инцидента публично CISA пока не дошла, и в TechCrunch агентство не ответило, отозваны ли ключи.</p><h2>Что в итоге</h2><p>Сюжет «подрядчик слил ключи в публичный git» повторяется в индустрии раз в пару месяцев, но обычно героем оказывается стартап или подрядчик банка. Случай с CISA выделяется тем, что виновником стало именно то агентство, которое выпускает рекомендации по защите от подобных утечек.</p><p>Хорошая новость: исследователи и журналисты сработали быстро, а сама CISA закрыла репозиторий за сутки — большинство компаний реагирует месяцами. Плохая: пока агентство не подтвердило ротацию ключей и не опубликовало детальный отчёт, любые токены из этого репозитория стоит считать публичным достоянием.</p><p>Для разработчиков вывод предельно практичный: <b>включите push protection, проверьте свои публичные репозитории, не подсовывайте секреты в Git ни на минуту</b>. История CISA — это просто очень громкая иллюстрация того, как один человек, перетаскивающий файлы с ноутбука на ноутбук через git, способен поставить под угрозу целое ведомство.</p><p><b>Источники:</b> <a href="https://krebsonsecurity.com/2026/05/cisa-admin-leaked-aws-govcloud-keys-on-github/">Krebs on Security — CISA Admin Leaked AWS GovCloud Keys on Github</a>; <a href="https://blog.gitguardian.com/how-we-got-a-cisa-github-leak-taken-down-in-26-hours/">GitGuardian Blog — How We Got a CISA GitHub Leak Taken Down in Under a Day</a>; <a href="https://techcrunch.com/2026/05/19/us-cyber-agency-cisa-exposed-reams-of-passwords-and-cloud-keys-to-the-open-web/">TechCrunch — US cyber agency CISA exposed reams of passwords and cloud keys to the open web</a>; <a href="https://gizmodo.com/the-worst-leak-that-ive-witnessed-u-s-cybersecurity-agency-leaves-its-digital-keys-out-in-public-on-github-2000760330">Gizmodo — «The Worst Leak That I've Witnessed»</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub Dungeons: рогалик из вашего репозитория с Copilot CLI</title>
      <link>https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu</link>
      <comments>https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu</guid>
      <description><![CDATA[<p>Разработчик GitHub написал рогалик на Go с помощью Copilot CLI: BSP из хеша коммита, команды /delegate и /yolo, pre-commit хук со ставками. Попробуйте.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu">GitHub Dungeons: рогалик из вашего репозитория с Copilot CLI</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 14 May 2026 11:55:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ваш последний коммит теперь определяет планировку подземелья. Сотрудник GitHub Ли Рейли (Lee Reilly) принял участие в GitHub Copilot CLI Challenge и написал <b>GitHub Dungeons</b> — расширение для GitHub CLI, которое превращает любой репозиторий в рогалик прямо в терминале. Уровни генерируются на основе хеша коммита, враги случайно заполняют коридоры, а выход спрятан за пятью уровнями процедурно созданных комнат.</p><p>Проект написан на Go — языке, с которым автор раньше почти не работал. Весь процесс разработки прошёл через GitHub Copilot CLI: вместо того чтобы разбираться в деталях синтаксиса незнакомого языка, можно было описать нужное поведение и получить работающий код.</p><p><b>GitHub Dungeons</b> — расширение gh extension, которое генерирует рогалик из вашего репозитория прямо в терминале.</p><p><b>Процедурная генерация</b> работает через Binary Space Partitioning (BSP), засеянный SHA последнего коммита — один и тот же код всегда даёт одно и то же подземелье.</p><p><b>Команда /delegate</b> в Copilot CLI передаёт задачу облачному агенту, который работает асинхронно и открывает готовый PR.</p><p><b>«Опасный режим»</b>: можно настроить pre-commit хук, который удалит все несохранённые изменения, если проиграть.</p><p>Установка одной командой: gh extension install leereilly/gh-dungeons.</p><h2>Что такое GitHub Dungeons</h2><p>GitHub Dungeons — это терминальная игра в жанре рогалик, где каждый уровень генерируется на основе вашей кодовой базы. Комнаты, коридоры и враги строятся из структуры репозитория и отрисовываются прямо в консоли. Навигация — стрелками, WASD или Vim-клавишами. Цель — найти скрытый выход, преодолев пять уровней с нарастающей сложностью.</p><p>Рогалики (roguelikes) ведут историю с игры Rogue 1980-х — терминальных приключений, где каждое прохождение генерировало новые подземелья, а смерть означала начало сначала (permadeath). GitHub Dungeons обращается к этой традиции, добавляя инженерный твист: ваш последний коммит задаёт seed генерации — один и тот же код всегда даёт одно и то же подземелье, но каждое изменение перестраивает его.</p><h2>Как репозиторий превращается в подземелье</h2><p>Генерация уровней построена на алгоритме Binary Space Partitioning (BSP) — классическом методе процедурной генерации карт в играх. В качестве seed используется SHA последнего коммита репозитория, что обеспечивает детерминированность: один коммит — одно подземелье. Изменился код — изменилась карта.</p><p>Процедурная генерация (или procgen) — это создание контента алгоритмически, а не вручную. Вместо того чтобы проектировать одно подземелье, вы проектируете систему, которая генерирует их бесконечно. Именно это даёт рогаликам высокую реиграбельность: каждое прохождение структурно отличается от предыдущего.</p><h3>Как работает Binary Space Partitioning</h3><p>BSP — это рекурсивное разбиение пространства на прямоугольные регионы. Алгоритм прост в объяснении, но даёт именно тот баланс между структурой и хаосом, который нужен рогаликам:</p><ol><li>Начало. Весь уровень — один большой прямоугольник.</li><li>Разбиение. Пространство делится на два региона (горизонтально или вертикально). Каждый регион снова делится. И снова.</li><li>Остановка. Разбиение прекращается, когда регион становится слишком маленьким для комнаты.</li><li>Комнаты. Каждый конечный регион становится комнатой. Позиция и размер слегка рандомизируются — чтобы карта не выглядела как сетка.</li><li>Коридоры. Алгоритм обходит дерево разбиений в обратном порядке и соединяет соседние комнаты L-образными коридорами.</li><li>Результат. Карта выглядит спроектированной, хотя создана алгоритмически. Все комнаты достижимы, нет тупиков.</li></ol><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/37595259-b651-48fb-90df-8723e5b05370.webp" alt="" /><figcaption>Шаг 1. Старт: всё подземелье — один прямоугольник.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/6f46dad9-30d5-42bd-b38e-6be09284526f.webp" alt="" /><figcaption>Шаг 2. Первое разбиение — на две зоны.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/e7c426de-384e-4f5b-841d-a2c93d5a90b4.webp" alt="" /><figcaption>Шаг 3. Рекурсивно: одна из зон разбита ещё раз.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/e9914d85-103a-4801-9463-77ba9cf593d0.webp" alt="" /><figcaption>Шаг 4. После нескольких проходов — шесть листовых регионов.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/b8f23b77-bdcf-48c8-99d4-877ca4f787db.webp" alt="" /><figcaption>Шаг 5. Каждый регион превращается в комнату — с небольшим рандомом по размеру.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/4c632fc4-3b1c-4219-97f0-ad37b629998f.webp" alt="" /><figcaption>Шаг 6. Соседние комнаты пока не соединены.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/250f28d8-6a7e-4bb2-bf65-cdf13d2848fe.webp" alt="" /><figcaption>Шаг 7. Сиблинги по дереву связываются L-образными коридорами.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/0b89dd5b-a23e-417d-8df4-78f1ebd5c606.webp" alt="" /><figcaption>Шаг 8. Финальный layout: структурно, но каждый раз разный.</figcaption></figure><p>BSP решает две главные проблемы процедурной генерации: чистый рандом даёт хаотичные карты, регулярные сетки — предсказуемые. BSP находит баланс: структурированный хаос, где каждый забег выглядит по-разному, но остаётся проходимым.</p><h2>Разработка с GitHub Copilot CLI</h2><p>Ли Рейли написал GitHub Dungeons на Go — языке, которым он не пользовался регулярно. Copilot CLI позволил сосредоточиться на поведении игры, а не на синтаксисе: вместо того чтобы вспоминать, как работают горутины, можно было описать нужное поведение и получить работающий код.</p><h3>Команда /delegate: асинхронный агент</h3><p>Ключевым инструментом в разработке стала команда /delegate. В отличие от обычного автодополнения, /delegate передаёт задачу облачному агенту Copilot, который работает асинхронно. Разработчик описывает задачу на естественном языке, запускает делегирование и может заниматься чем-то другим. Когда агент завершает работу, он открывает pull request с результатами.</p><p>Например, команда /delegate с описанием задачи на естественном языке вернула готовую реализацию прогрессии сложности в виде PR. Автор просмотрел результат, подправил баланс и влил изменения. Тот же подход использовался для читкодов, системы туман войны и документации.</p><blockquote>Работа с Copilot (особенно через /delegate) — это как иметь армию NPC, готовых делать всё, что я скажу.</blockquote><h3>Команда /yolo: живёшь только раз</h3><p>Для проекта о рогалике команда /yolo оказалась особенно уместной: это алиас для /allow-all, который разрешает Copilot CLI выполнять все действия без дополнительных подтверждений. «You only live once» — именно это слоган permadeath-механики рогаликов. В разработке /yolo ускоряет итерации: не нужно подтверждать каждое действие агента.</p><p>Copilot также сгенерировал «dungeon scribe» — вспомогательного агента, который добавил документацию и ASCII-диаграммы, объясняющие генерацию подземелий. Это органично вписалось в стиль терминального рогалика.</p><h2>Установка и игра</h2><p>Для запуска нужен установленный GitHub Copilot CLI. Расширение устанавливается одной командой:</p><p>После установки запустите игру в директории любого репозитория:</p><p>Управление: стрелки, WASD или Vim-клавиши (hjkl). Цель — найти скрытую дверь и сбежать через пять уровней, сражаясь с врагами и собирая зелья здоровья. Автоатака, туман войны, счётчик убийств и уровней входят в комплект. Остальные возможности придётся обнаружить самостоятельно.</p><h2>Опасная зона: pre-commit хук с ставками</h2><p>Для тех, кто хочет испытать настоящий permadeath в духе рогаликов, автор предлагает привязать игру к git-коммитам. Pre-commit хук запускает GitHub Dungeons перед каждым коммитом: если проигрываете — все несохранённые изменения удаляются.</p><p><b>Внимание:</b> не устанавливайте этот хук, если не понимаете последствий. Поражение в игре ведёт к безвозвратной потере всех незакоммиченных изменений. Редакция GitHub прямо предупреждает: ответственность за последствия несёт автор хука, а не GitHub.</p><h2>Выводы</h2><p>GitHub Dungeons — эксперимент, который демонстрирует несколько интересных вещей одновременно. Во-первых, Copilot CLI меняет паттерн разработки: когда агент берёт на себя незнакомый синтаксис и рутину, разработчик остаётся в режиме дизайнера механик, а не кодировщика. Для этого рогалика это означало итерации по балансу, тайным кодам и пасхалкам вместо бесконечной отладки Go-специфики. Во-вторых, классические алгоритмы вроде BSP решают современные задачи: детерминированный seed из SHA коммита — это не случайность, а осмысленная связь между состоянием кода и состоянием игры. Каждый мердж меняет карту.</p><p>Попробовать GitHub Dungeons можно в любом репозитории: <a href="https://github.com/leereilly/gh-dungeons">github.com/leereilly/gh-dungeons</a>. Оригинальный разбор от автора — <a href="https://github.blog/ai-and-ml/github-copilot/dungeons-desktops-building-a-procedurally-generated-roguelike-with-github-copilot-cli/">на GitHub Blog</a>. Установите, запустите gh dungeons в своём репозитории — и посмотрите, каким подземельем стал ваш последний коммит.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как я перестал метаться между нейросетями и устроил им общий экзамен</title>
      <link>https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz</link>
      <comments>https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[AIguide]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz</guid>
      <description><![CDATA[<p>Я рассказываю, как перестал доверять рандомным «вау»-кадрам и устроил честный экзамен нейросетям для генерации изображений. Замерял качество, скорость, форматы и стоимость на реальных задачах, а в итоге собрал понятный пайплайн выбора AI-сервисов без магии и маркетинга.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ya-perestal-metatsya-mezhdu-nejrosetyami-i-ustroil-im-obshhij-ekz">Как я перестал метаться между нейросетями и устроил им общий экзамен</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 12 May 2026 09:54:04 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Оглавление</h2><ol><li>Как я утонул в генерациях</li><li>Экзамен вместо «прыжков» по сервисам</li><li>Небольшой технический конвейер</li><li>Зачем цифры важнее впечатлений</li><li>Простой тест на форматы</li><li>Как ведут себя Riverflow, Flux и Seedream</li><li>Отчёты, артефакты и спокойная аналитика</li><li>Сценарий «восемь формулировок»</li><li>Зрелый подход к выбору AI</li></ol><p>В прошлой статье я рассказывал, как собрал тестовый стенд для AI‑генерации. Теперь — про то, как превратил его в живой процесс с разными сценариями и метриками.</p><h2>1. Как я утонул в генерациях</h2><p>Я осознал что  в очередной раз листал чат и не мог найти тот самый удачный вариант обложки.</p><p>Ситуация повторялась по одному и тому же шаблону. Запускаю один сервис — получаю результат, морщу лицо и сразу иду в другой. Там промпт приходится переформулировать: движок по-другому читает слова. В третьем генераторе наконец складывается приятная композиция, но детализация рушит весь смысл. Через пару дней на диске лежит россыпь PNG, а я уже не понимаю, где оказался осознанный успех, а где просто повезло. В какой-то момент я сказал себе: стоп. Случайные «попробую тут, попробую там» не ведут никуда.</p><h2>2. Экзамен вместо «прыжков» по сервисам</h2><p>Тогда я придумал простое правило. Любой сервис, который претендует на место в моём рабочем наборе, должен пройти экзамен. Не приятную беседу с общими вопросами, а одинаковый для всех, жёсткий сценарий. Без исключений и любимчиков.</p><h2>3. Небольшой технический конвейер</h2><p>Реализация получилась до обидного простой. Node.js, TypeScript, запуск через tsx. Список моделей вынесен в отдельный конфиг, API-ключ лежит в .env, а команды запуска выглядят вроде npm run test:niche или npm run test:collage-2x2-eight-prompts. Я взял творческий хаос и сложил его в аккуратный pipeline.</p><p>Дальше всё происходит автоматически: запускаешь тест — и один и тот же набор задач последовательно проходит через всех кандидатов. Мой вклад заканчивается на нажатии Enter.</p><h2>4. Зачем цифры важнее впечатлений</h2><p>Зачем вообще так усложнять? Потому что мантра «любая нейросеть — она и есть нейросеть» на практике не работает. Разброс колоссальный. Один сервис очень аккуратно держит геометрию кадра, но мелкие детали превращает в мыло. Другой рисует фактуру так, что хочется печатать и вешать, но при запросе «коллаж 3×3 с чёткими границами» внезапно решает творчески переосмыслить сетку. Третий стабильно отвечает и по времени, и по предсказуемости, но на сотне запросов выписывает такой чек, что хочется закрыть вкладку.</p><p>Если не фиксировать метрики, всё превращается в разрозненные ощущения. Сегодня это кажется идеальным инструментом, завтра тот же сервис тихо сжигает бюджет на десятке однотипных задач. И ты не можешь точно сказать, в какой момент всё поехало.</p><h2>5. Простой тест на форматы</h2><p>Возьмём самый базовый пример — проверка соотношения сторон. Формулировка элементарная: закат над горами, три варианта — 3:4, 1:1 и 16:9. Казалось бы, минимальный уровень адекватности. Но нет.</p><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/967623f7-34c5-4109-ae88-7c3ccd8122f0.webp" alt="" /><figcaption>таблица 1</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/c77d406d-862c-492c-bc89-733b8cb50349.webp" alt="" /><figcaption>таблица 2</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/2b48f70f-e37d-4ab1-bc2a-826a5fa72d56.webp" alt="" /><figcaption>таблица 3</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/1b27a8d8-19e1-4a94-968b-475fc8cea34c.webp" alt="" /><figcaption>таблица 4</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/138437/2026-05-12/ad59138a-e1f9-49f7-ae5c-03c3819768e9.webp" alt="" /><figcaption>таблица 5</figcaption></figure><p>Достаточно пробежать глазами столбец со статусом. Три запроса — три быстрых проверки «на глаз». Там, где на 3:4 и 16:9 горит FAIL, модель откровенно игнорирует задачу и рисует квадрат или удобный для себя формат. И это при том, что промпт простейший: не сложная сцена, не коллаж — всего лишь «закат, горы и нужная рамка».</p><h2>6. Как ведут себя Riverflow, Flux и Seedream</h2><p>Если посмотреть на результаты, riverflow-v2-pro аккуратно соблюдает все три формата. Но за эту аккуратность приходится платить временем: портретная картинка генерируется около 360 секунд. Шесть минут — роскошь, если у вас в руках горящий дедлайн. Упрощённая версия, riverflow-v2-fast, выдаёт правильные форматы за секунды и остаётся в адекватных рамках по времени — это уже инструмент для реальных задач.runware+2</p><p>С моделями Flux история другая. Почти вся линейка black-forest-labs стабильно промахивается по нестандартным форматам: колонка «Соотношение» упорно показывает 4/3 или 1/1, хотя в запросе чётко указано «16:9, wide landscape». Относительно ровно ведёт себя только flux.2-max, который хотя бы честно выдаёт квадрат, но проблемы с другими соотношениями никуда не деваются.github+1</p><p>Seedream-4.5 от Bytedance, напротив, поражает скоростью: ответы прилетают за 7–8 секунд, но модель регулярно игнорирует заданный формат и возвращает квадрат 2048×2048. Для макета, привязанного к конкретным пропорциям — сторис, постера или баннера — такая «быстрота» только ломает всю вёрстку.eachlabs+1</p><h2>7. Отчёты, артефакты и спокойная аналитика</h2><p>Вся эта конструкция нужна ради пары простых эффектов. Каждый запуск сохраняет статус, итоговый размер, время генерации и, где это важно, стоимость. После завершения прогона скрипты собирают HTML-отчёт. Открываешь его в браузере — и на одном экране сразу видно, кто действительно справился, а кто только шумит.</p><p>Особенно сильно это помогает в задачах, где критична композиция: нужна ровная сетка 2×2 или 3×3 без самодеятельности в духе «я тут чуть подвину, так красивее». Это как раз те случаи, когда от сервиса нужна дисциплина, а не внезапные художественные «инициативы».</p><h2>8. Сценарий «восемь формулировок»</h2><p>Отдельный пласт наблюдений даёт сценарий «восемь формулировок» (collage-2x2-eight-prompts). Суть задачи не меняется, контент остаётся одним и тем же. Я варьирую только подачу: где-то пишу запрос грубо и коротко, где-то — щадяще и структурно, местами добавляю лишний контекст.</p><p>На этом месте становится видно, как модель реагирует не на саму тему, а на стиль запроса. Одна и та же нейросеть спокойно выдерживает строгое техническое ТЗ и проваливается при формулировке «сделай красиво, сам понимаешь». После таких тестов по-другому относишься к промптам: начинаешь формулировать точнее, понимая, какая модель как «слушает» текст. И внезапно исчезают загадки в духе «почему здесь получилось, а там всё развалилось».</p><h2>9. Зрелый подход к выбору AI</h2><p>Главный вывод из всей этой истории довольно приземлённый. Выбирать AI-сервисы по рекламе, по восторженным постам в Telegram или по одному удачному демо-кадру — путь к разочарованию. Их нужно ставить в одинаковые условия. Прогонять по своим реальным задачам, а не по чужим презентациям. Сохранять результаты и сравнивать их по конкретным цифрам.</p><p>Когда делаешь так, выбор перестаёт быть эмоциональной пыткой в стиле «нравится / не нравится». Он превращается в спокойное рабочее решение: этот сервис — для быстрых черновиков, этот — для вылизанной композиции, этот — для длинных и сложных запросов, в которых ошибка по смыслу недопустима. В этот момент генерация перестаёт быть магическим ритуалом с сюрпризами и превращается в нормальный, предсказуемый инструмент. Таким, каким он и должен был быть изначально.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub переписал план мощностей в 30 раз — AI-агенты пишут код быстрее CI</title>
      <link>https://tproger.ru/news/github-perepisal-plan-moshhnostej-v-30-ai-agenty-piwut-kod-byst</link>
      <comments>https://tproger.ru/news/github-perepisal-plan-moshhnostej-v-30-ai-agenty-piwut-kod-byst?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-perepisal-plan-moshhnostej-v-30-ai-agenty-piwut-kod-byst</guid>
      <description><![CDATA[<p>CTO GitHub Влад Фёдоров: октябрьский план мощностей в 10 раз устарел за 4 месяца — нужен в 30 раз из-за AI-агентного кода. Bottleneck — валидация, не CI.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-perepisal-plan-moshhnostej-v-30-ai-agenty-piwut-kod-byst">GitHub переписал план мощностей в 30 раз — AI-агенты пишут код быстрее CI</a>»</p>]]></description>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 11:23:28 GMT</pubDate>
      <content:encoded><![CDATA[<p>CTO GitHub Влад Фёдоров <a href="https://github.blog/news-insights/company-news/an-update-on-github-availability/">опубликовал апдейт</a> о двух апрельских инцидентах с пометкой, которую стоит прочитать каждому, кто строит CI/CD: октябрьский план нарастить мощности GitHub в 10 раз к 2026 году пришлось переделывать в 30-кратный — и не потому, что прошлый был плох, а потому, что AI-агенты пишут код быстрее, чем валидация успевает его проверять.</p><p>Это не рутинное объявление об увеличении кластера. Если самый закалённый разработческой инфраструктуры игрок планеты говорит «в 10 раз — уже мало», значит фундаментальные предположения о том, как производится софт, сместились быстрее, чем GitHub успел заложить в собственные планы. Все, кто строит ниже по течению — на тех же предположениях, — попадают под тот же сдвиг.</p><p><b>Сигнал.</b> CTO GitHub Влад Фёдоров: октябрьский план мощностей в 10 раз к 2026 году устарел уже к февралю — нужен план в 30 раз из-за роста AI-агентного кода.</p><p><b>Bottleneck не в железе.</b> CI справится с любым потоком; не справляется валидация — очередь ревью, стенды staging, интеграционные тесты.</p><p><b>Стоимость поиска бага растёт по стадиям.</b> Внутри цикла разработки — почти ноль; в CI — полный цикл сборки; в staging — деплой и очередь к стенду; в production — инцидент, откат и отдельный revert-PR.</p><p><b>Структурный ответ.</b> Сдвиг валидации в inner-loop, где агент сам прогоняет изменение против реальной системы до создания PR.</p><p><b>Что делать командам.</b> Отделить «compile-clean» от «correct», встроить эфемерные окружения в inner-loop агента, не наращивать слепо мощности CI.</p><h2>Почему GitHub переписал план мощностей</h2><p>В апреле 2026 года у GitHub было два крупных инцидента — внутренний апдейт об их разборе содержал ключевой абзац:</p><blockquote>Мы начали в октябре 2025 года план по 10-кратному наращиванию мощностей GitHub с целью существенно улучшить надёжность и failover. К февралю 2026 стало ясно, что нужно проектировать под будущее, требующее 30-кратного объёма от текущего.</blockquote><p>Перевести с менеджерского на инженерный это можно так: производство кода ускорилось не на проценты, а в разы, и инфляция объёма не закладывалась в годовое планирование самых опытных платформенных команд. Точка перегиба совпадает с переходом агентов для кодинга из ранних прототипов в дефолтный инструмент инженерных команд.</p><h2>Объём становится проблемой, когда не конвертируется в throughput</h2><p>30-кратный рост производства кода в идеальном мире давал бы 30-кратный рост поставленных фич. На практике SDLC никогда не превращал объём кода в релизную функциональность 1:1. Конверсия теряется на одном и том же этапе — валидация.</p><p>До прихода агентов это уже было больно: тест-сьюты по часу, постоянно перегруженные стенды staging, интеграционные баги, всплывающие на release candidate, очереди review, в которых сидят единственные люди, способные определить, безопасно ли изменение. Валидация — самая медленная, самая зависящая от человека и самая ошибкоёмкая часть цикла, и она встроена между «код написан» и «код задеплоен».</p><p>В cloud-native архитектурах эта проблема обостряется. Современное приложение — это граф сервисов, каждый со своим состоянием, зависимостями, темпом релизов. Изменение одного сервиса прокатывается по половине соседних, а ломается обычно то, что не видно в исходниках: contract drift (несовпадение договорённостей между сервисами), race conditions, edge-кейсы мульти-тенантности, поведение под нагрузкой.</p><h2>Где ловить баг — там и платить</h2><p>Стоимость найденного бага компаундится в зависимости от стадии:</p><ul><li>Inner loop (агент или разработчик ещё итерирует) — почти ноль.</li><li>CI — полный цикл сборки.</li><li>Staging — деплой + слот в очереди + время валидаторов.</li><li>Production — инцидент, rollback, revert PR, который сам идёт через тот же pipeline.</li></ul><p>При человеческой скорости разработки SDLC поглощал часть этой неэффективности — объём ограничивался числом инженеров. На скорости и масштабе агентов поглощать перестаёт: задержка превращается в постоянно растущий backlog. Поэтому ответ — не «больше мощностей CI, больше стендов staging, больше ревьюеров». Это тактический отклик на структурный сдвиг.</p><h2>Замкнуть петлю — там, где код пишется</h2><p>Структурный ответ — сдвинуть валидацию максимально влево, прямо в inner loop, где агент порождает код. Сегодня агенты для кодинга — это половина рабочей системы: они пишут код на беспрецедентной скорости, но не могут самостоятельно проверить, правильно ли он ведёт себя в распределённой системе. Compile-clean ≠ correct. Unit-тесты проверяют ровно то, что они скоупят.</p><p>Поэтому агент делает единственное, что может — объявляет изменение готовым и пушит вниз по pipeline, где работа по «а оно вообще пашет?» падает на ревьюера, интеграционные тесты, деплой на staging или инцидент в production. И вся компаундящаяся стоимость валидации включается на полную.</p><p>Замкнуть петлю — значит дать агенту способ автономно прогнать кандидатное изменение против реальной системы: реальные сервисы, реальные зависимости, реальные паттерны трафика. Быстро и дёшево настолько, чтобы агент мог итерировать, наблюдать, что сломалось, и пробовать ещё раз — без человека, без конкуренции за общий стенд staging, на скорости и масштабе агентов.</p><h2>Почему не справляются текущие подходы</h2><ul><li>Mocks — подделывают поведение зависимостей и проходят мимо реальных.</li><li>Unit-тесты — покрывают индивидуальные функции, не интеграционную поверхность.</li><li>Зелёный CI — говорит, что протестированное прошло. Это не равно «изменение корректно».</li></ul><p>Чтобы петля действительно замкнулась, агенту нужно прогнать кандидата против настоящего состояния системы, а не модельного. И это требует инфраструктуры, которой массово в командах ещё нет: эпемерные окружения, изолированные на уровне one-PR-one-environment, с реальными зависимостями.</p><h2>Чек-лист для тимлидов</h2><ol><li>Замерить текущую валидационную «вилку»: время от commit до зелёного staging для среднего PR. Если оно растёт — bottleneck уже здесь.</li><li>Посчитать долю PR-ов с rollback или revert. Если rollback-rate растёт месяц к месяцу — петля у агентов открытая.</li><li>Запустить пилот с ephemeral environments на одном из сервисов с самым большим интеграционные накладные расходы. Сравнить за 4 недели: процент PR-ов, прошедших валидацию с первого раза.</li><li>Не наращивать мощности CI «в ширину» как первый ответ. Это лечит симптом, не причину.</li><li>Дать агенту сигналы во время выполнения (не только compile + unit). Без них следующий шаг качества кода невозможен.</li></ol><h2>Выводы</h2><p>Объём кода, генерируемого AI-агентами, растёт быстрее, чем планировали даже в GitHub. Стратегический вопрос для каждой инженерной организации сейчас простой: ваши агенты работают в замкнутой петле или открытой? Замкнутая — мультипликатор на throughput команды. Открытая — мультипликатор на те самые валидационные bottleneck-и, которые и так были самым узким местом.</p><p>Похожий тренд мы недавно <a href="https://tproger.ru/news/tokenmaxxing-ii-assistenty-dayut-2-vyrabotku-koda-pri-10-zatra">разбирали в материале про tokenmaxxing</a>: AI-ассистенты дают двукратную выработку кода ценой десятикратных затрат токенов и роста code churn на 861%. Природа проблемы одна: код производится массой, а инфраструктура к этому не готова.</p><p>Источник: <a href="https://thenewstack.io/agent-code-validation-bottleneck/">The agent code explosion is here. We need to rethink our pipelines, fast — The New Stack</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как я написал E2EE-мессенджер на Spring Boot и WebCrypto — и почему сервер не видит сообщения</title>
      <link>https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch</link>
      <comments>https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Василенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch</guid>
      <description><![CDATA[<p>Разбор архитектуры E2EE-мессенджера на Spring Boot 3, React и WebCrypto: X3DH, symmetric ratchet, AES-GCM, WebSocket, multi-device и ограничения реализации.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-ya-napisal-e2ee-messendzher-na-spring-boot-i-webcrypto-i-poch">Как я написал E2EE-мессенджер на Spring Boot и WebCrypto — и почему сервер не видит сообщения</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Stack Overflow]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Алиса]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[5g]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 05 May 2026 05:35:02 GMT</pubDate>
      <content:encoded><![CDATA[<figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/240e412b-4307-49f9-b24f-bde7e0a7fd9a.webp" alt="" /></figure><p>Я Java-разработчик и в основном работаю с backend: Spring Boot, базы данных, интеграции, авторизация, WebSocket — всё то, что обычно находится за интерфейсом.</p><p>В какой-то момент я поймал себя на мысли: я каждый день пользуюсь мессенджерами, но плохо понимаю, как они устроены внутри. Окей, JWT, WebSocket, PostgreSQL, Redis — это понятно. Но что технически означает фраза "end-to-end encryption"? Как сервер доставляет сообщения, если он не должен их читать? Где живут ключи? Что хранится в базе? Что происходит, если у пользователя два устройства?</p><p>Решил разобраться через практику. Написал мессенджер с нуля. Назвал Chaos Messenger.</p><p>Сразу честно: криптографическую часть я изучал вместе с Claude и ChatGPT — читал спецификации X3DH и Double Ratchet, разбирал примеры, задавал вопросы, пока не сложилась цельная картина. Frontend тоже делался с активной помощью ChatGPT: я backend-разработчик, React для меня не основная среда. Но архитектура, backend, интеграция WebCrypto, модель конвертов, хранение сообщений и принципиальные решения — мои.</p><p>Для меня AI здесь был не заменой понимания, а инструментом — примерно как документация, Stack Overflow и ревью коллег. Без понимания threat model и архитектуры такой проект всё равно не собрать.</p><p>В статье расскажу, как работает E2EE изнутри: как устанавливается сессия через X3DH, как каждое сообщение получает отдельный ключ через Symmetric Ratchet, почему сервер хранит только зашифрованные конверты, и какие ошибки я допустил по дороге.</p><p>Стек: Spring Boot 3, React 18, WebCrypto API, PostgreSQL, Redis, WebSocket/STOMP, Prometheus, Grafana.</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/4b028f37-2de1-46ea-a247-567f74fb3081.webp" alt="" /></figure><h2>Важная оговорка про web-E2EE</h2><p>Когда я говорю, что сервер не может прочитать сообщения, я имею в виду backend, базу данных, WebSocket-слой и уже сохранённые ciphertext-конверты. У них нет ключей и plaintext.</p><p>Но у web-E2EE есть отдельная проблема: frontend-код тоже приходит с сервера. Теоретически скомпрометированный сервер может отдать изменённый JavaScript, который украдёт ключи или plaintext до шифрования. Это ограничение не конкретно моего проекта, а браузерной модели в целом.</p><p>Поэтому корректная формулировка такая: backend не получает ключи и не может расшифровать уже переданные или сохранённые сообщения. Защита от подмены клиентского кода — отдельный слой безопасности: подпись сборок, независимая верификация клиента, desktop/mobile-приложения, reproducible builds.</p><h2>Почему обычный подход не работает</h2><p>Большинство "мессенджеров" на GitHub выглядят примерно так:</p><p>Сервер знает всё. Видит каждое сообщение. Если БД утекла — утекла вся переписка. Если сервер взломали — читай что хочешь. Если завтра компания решит продать данные — технически ничего не мешает.</p><p>E2EE решает это радикально: backend не получает ключи и не хранит plaintext. Сообщение шифруется на устройстве отправителя до отправки в сеть, а расшифровывается только на устройстве получателя.</p><p>Это уже не вопрос политики конфиденциальности в стиле "мы обещаем не читать". Это архитектурное ограничение: если у сервера нет ключа, он не может превратить ciphertext обратно в текст.</p><p>Звучит как магия. На самом деле — два протокола и немного WebCrypto.</p><h2>Главная идея: конверты</h2><p>Представь что Алиса хочет написать Бобу. Вместо того чтобы положить письмо на стол и надеяться что никто не прочитает — она кладёт его в запечатанный конверт. Конверт может открыть только Боб своим ключом. Сервер просто передаёт конверт не заглядывая внутрь.</p><p>Именно так это работает в коде. В базе данных у меня это выглядит так:</p><p>Когда я впервые увидел</p><p>в своей БД вместо текста — стало понятно, что модель наконец работает правильно: сервер создал сообщение, доставил его, сохранил метаданные, но так и не узнал содержимое.</p><p>А вот что сервер возвращает при запросе списка чатов через API:</p><p>Не</p><p>. Не</p><p>. Буквально</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/b466ad91-20da-4e64-8b78-f6e08d2851d5.webp" alt="" /></figure><p>(DevTools → Network → ответ API с</p><p>)</p><h2>Откуда берутся ключи: X3DH</h2><p>Главный вопрос: как Алиса и Боб получают общий секрет, если они никогда раньше не общались? И как сделать это так, чтобы сервер только помог передать публичные данные, но сам не смог вычислить итоговый ключ?</p><p>Для этого используется X3DH — Extended Triple Diffie-Hellman, протокол из экосистемы Signal. Его задача — установить общий секрет между двумя устройствами, используя долгосрочные и временные ключи.</p><h2>Что хранится на сервере</h2><p>Когда пользователь регистрирует устройство, он загружает на сервер пакет публичных ключей:</p><p>На сервер уходят только публичные части. Приватные ключи сериализуются и хранятся локально в браузере — и никогда не покидают устройство в сеть.</p><p>Здесь важно сказать честно: хранение приватных ключей в</p><p>Более строгий вариант — использовать Web Crypto API с</p><p>, чтобы приватный ключ жил внутри браузерного crypto runtime и его нельзя было экспортировать в байты. Но у этого подхода есть практическая сложность: ключи нужно переживать между перезагрузками страницы, синхронизировать с IndexedDB, аккуратно восстанавливать состояние устройства и не сломать UX.</p><p>В браузерных E2EE-приложениях обычно приходится выбирать между несколькими вариантами:</p><ul><li>Сериализуемые ключи в localStorage или IndexedDB — проще реализовать, но нужно очень серьёзно относиться к XSS и целостности frontend-кода.</li><li>extractable: false + IndexedDB — безопаснее, но сложнее в реализации и восстановлении состояния.</li><li>Нативное secure storage вроде Android Keystore или iOS Secure Enclave — лучший вариант для мобильных клиентов, но он недоступен обычному web-приложению.</li></ul><p>В текущей версии Chaos Messenger используется первый вариант. Это осознанный компромисс для pet/open-source проекта и удобного запуска в браузере. Переход на non-extractable ключи и более строгую модель хранения стоит в roadmap.</p><p>Ключевой момент: backend всё равно не получает приватные ключи и не может расшифровать сохранённые ciphertext-конверты. Но защита ключей на клиенте — отдельная задача, и её нельзя честно замалчивать.</p><h2>Установка сессии</h2><p>Когда Алиса открывает переписку с Бобом впервые, происходит следующее:</p><p>В классическом X3DH четвёртая DH-операция с one-time prekey опциональна: она выполняется, если сервер выдал доступный OPK получателя. В моей реализации устройство публикует набор one-time prekeys при регистрации, поэтому первое сообщение обычно использует DH4. Если OPK закончились, сессию всё равно можно установить через остальные DH-компоненты, но это уже менее сильный вариант.</p><p>Боб, получив конверт с эфемерным публичным ключом Алисы, повторяет те же операции со своими приватными ключами и получает тот же самый</p><p>. Математика симметрична.</p><p>Сервер в этот момент видит только публичные ключи и зашифрованный конверт. Он помогает устройствам найти друг друга, но не участвует в вычислении секрета.</p><p>Получить</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/e7bbacf3-4fd2-4710-863a-2c710b1f6759.webp" alt="" /></figure><h2>Как шифруется каждое сообщение: Symmetric Ratchet</h2><p>X3DH даёт нам стартовый</p><p>. Но использовать один и тот же ключ для всех сообщений — плохая идея. Если использовать один ключ для всей переписки, компрометация этого ключа сразу открывает весь поток сообщений.</p><p>Решение — симметричный ratchet. После каждого сообщения цепочка ключей продвигается вперёд:</p><p>Визуально это выглядит так:</p><p>используется для шифрования одного сообщения через AES-GCM, после чего уничтожается. Если атакующий компрометирует</p><p>— он прочитает только второе сообщение.</p><p>В рамках такой симметричной цепочки это даёт forward secrecy назад по цепочке: зная текущий или отдельный</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/939a74f7-60c5-4816-85f0-05b5afdc9845.webp" alt="" /><figcaption>(диаграмма схемы chainKey → messageKey)</figcaption></figure><p>Само шифрование сообщения:</p><p>А вот что уходит на сервер — живой пример из DevTools:</p><p>Сервер получает</p><p>и</p><p>. Расшифровать без</p><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/b5e24cda-6fd9-4b15-9f27-3eb9b4f843b0.webp" alt="" /></figure><h2>Важная оговорка: это ещё не полный Double Ratchet</h2><p>В этом проекте реализован Symmetric Ratchet — цепочка, где из</p><p>для каждого сообщения выводится отдельный</p><p>Это защищает прошлые сообщения: если атакующий узнает текущий ключ или отдельный</p><p>, он не сможет откатить HMAC назад и получить старые ключи.</p><p>Но это не полный Double Ratchet из Signal Protocol.</p><p>В полном Double Ratchet есть ещё DH ratchet step: стороны периодически выполняют новый Diffie-Hellman обмен и обновляют root key. Это даёт break-in recovery — возможность восстановить безопасность будущих сообщений после компрометации части состояния.</p><p>В моей реализации DH ratchet step пока нет. Если атакующий получит актуальное состояние сессии на устройстве и сможет продолжать его читать, он сможет расшифровывать будущие сообщения до переустановки сессии. Это честное ограничение текущей версии, и оно стоит первым пунктом в roadmap.</p><h2>Мультиустройство: один пользователь, несколько конвертов</h2><p>Первый неочевидный момент: в E2EE сообщение адресуется не просто пользователю, а конкретным устройствам пользователя.</p><p>Если у Боба два устройства — телефон и ноутбук — нужен отдельный encrypted envelope для каждого устройства. Сервер не может взять один конверт, расшифровать его и "переупаковать" для второго устройства: у него нет ключей и он не знает plaintext.</p><p>Значит при отправке сообщения нужно зашифровать его отдельно для каждого устройства каждого участника чата.</p><p>Для чата где у каждого по 2 устройства — 4 конверта на одно сообщение. Для группы из 10 человек — потенциально 20 конвертов. Это нормально, это цена безопасности.</p><h2>Сервер: хранение и доставка конвертов</h2><p>На сервере сообщение создаётся с контентом</p><p>, а конверты сохраняются отдельно:</p><p>После сохранения — fanout по WebSocket. Каждое устройство получает свой конверт и только его:</p><p>Это важное отличие от обычного WebSocket-чата. В обычном чате сервер рассылает одно и то же событие всем участникам. В E2EE-чате сервер рассылает разные события разным устройствам: payload для каждого устройства содержит свой</p><p>Топик</p><p>— строго персональный. Устройство А не получает конверт устройства Б. Никакого broadcast — только адресная доставка.</p><h2>Архитектура целиком</h2><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/de0e3257-d893-459f-86ed-7ed8eace5d56.webp" alt="" /></figure><h2>Баг который долго не замечал</h2><p>В панели чатов показывается превью последнего сообщения. Я реализовал это через</p><p>Запускаю — в списке чатов у всех написано</p><p>.</p><p>Конечно. Сервер же не знает что там написано.</p><p>Я полчаса думал как решить это на сервере. Потом дошло: нельзя решить это на сервере — у него нет ключей. Решение только на клиенте.</p><p>После того как пользователь открыл чат и сообщения расшифровались — кешируем последнее в памяти:</p><p>Это хороший пример того, как E2EE меняет привычное мышление backend-разработчика. В обычном приложении preview — это поле в SQL-запросе. В E2EE-приложении preview — это локальное клиентское состояние, потому что только клиент видел plaintext.</p><p>Простое решение. Но чтобы к нему прийти нужно было полностью принять идею что сервер здесь просто не при делах — и перестать пытаться решить задачу на его стороне.</p><h2>Rate limiting: дыра которую легко не заметить</h2><p>Эндпоинт</p><p>отправляет SMS с кодом. Без защиты любой скрипт может дёргать его тысячи раз — это называется SMS pumping fraud, SMS стоят реальных денег.</p><p>Redis у нас уже был для хранения онлайн-статусов. Добавил rate limiting поверх него:</p><p>При превышении — HTTP 429 с заголовком</p><p>. Клиент знает через сколько секунд можно повторить.</p><p>Важный нюанс: в текущей реализации, если Redis недоступен, сервис не блокирует авторизацию полностью. Для pet-проекта это приемлемый компромисс: лучше рискнуть одним лишним SMS, чем положить вход в приложение.</p><p>В production я бы сделал строже: fallback in-memory лимит на инстанс, отдельные лимиты по IP и телефону, антифрод-логику и алерты на всплески отправки кодов.</p><h2>Авторизация WebSocket</h2><p>Отдельная история — авторизация WebSocket соединений. HTTP-эндпоинты защищены Spring Security автоматически, но WebSocket — другое дело. STOMP-соединение устанавливается один раз, и нужно проверять JWT при каждом подключении.</p><p>Отдельно важно не только проверить JWT, но и связать WebSocket-соединение с конкретным устройством. Пользователь может быть один, но устройств у него несколько, а encrypted envelope адресован именно</p><p>Поэтому при подключении я проверяю не только токен, но и</p><p>: устройство должно быть зарегистрировано и принадлежать текущему пользователю. Иначе легко случайно превратить per-device E2EE-доставку обратно в обычный broadcast по пользователю.</p><h2>Что получилось — живые скрины</h2><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/1fdfa006-f5c6-4731-a40f-50559be8832d.webp" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/137649/2026-04-29/c99164a5-021c-49ac-bcc4-3e38f9cd1c31.webp" alt="" /></figure><p>Что реализовано:</p><ul><li>E2EE-модель с per-device encrypted envelopes</li><li>X3DH session setup + Symmetric Ratchet + AES-GCM</li><li>Мультиустройство</li><li>Личные и групповые чаты</li><li>Realtime доставка через WebSocket/STOMP</li><li>Статусы SENT → DELIVERED → READ</li><li>Редактирование и soft delete сообщений</li><li>Online presence, typing indicator</li><li>Фото-вложения</li><li>Поиск пользователей</li><li>Rate limiting на SMS через Redis</li><li>Prometheus метрики + Grafana дашборд</li><li>Swagger UI с JWT авторизацией</li><li>24 backend-теста на Testcontainers, 12 frontend на Vitest, E2E на Playwright</li><li>GitHub Actions CI</li></ul><p>Что ещё не сделано:</p><ul><li>Полный Double Ratchet с DH ratchet step и break-in recovery</li><li>Ротация signed prekey и аккуратное пополнение one-time prekeys</li><li>Более строгая модель хранения приватных ключей на клиенте: non-extractable CryptoKey + IndexedDB</li><li>Защита от подмены frontend-кода: подпись сборок, независимая верификация клиента, reproducible builds</li><li>Android-клиент с Android Keystore</li><li>Реальный SMS-провайдер вместо кода в backend-логах</li><li>Push-уведомления без утечки содержимого сообщений</li><li>Более строгая metadata-модель для групповых чатов</li></ul><h2>Главный инсайт</h2><p>E2EE — это архитектурное решение, а не библиотека.</p><p>Нельзя взять обычный Spring Boot чат и просто "включить шифрование". Нужно с самого начала проектировать систему так, чтобы backend не был участником доверенной зоны: он не должен получать plaintext, не должен иметь ключи и не должен уметь пересобирать сообщение из данных в базе.</p><p>Это меняет почти всё:</p><ul><li>структуру БД — вместо текста появляются encrypted envelopes</li><li>API — сервер отдаёт [encrypted], а не preview сообщения</li><li>WebSocket — доставка идёт не по пользователю, а по конкретному устройству</li><li>мультиустройство — одно сообщение превращается в несколько ciphertext-конвертов</li><li>frontend — становится полноценной криптографической частью системы, а не просто UI</li></ul><p>Второй инсайт: мессенджер — это не "чат с WebSocket". В E2EE-модели это система доставки зашифрованных конвертов с адресацией по устройствам. Как только это принимаешь, многие странные на первый взгляд решения становятся логичными.</p><h2>Репозиторий</h2><p>Код открыт: <a href="https://github.com/vaazhen/chaos-messenger">github.com/vaazhen/chaos-messenger</a></p><p>В репозитории есть README на русском и английском, диаграммы, скриншоты, security audit, Docker Compose и запуск одной командой.</p><p>Проект не претендует на уровень production-криптомессенджера вроде Signal. Это учебный и инженерный open-source прототип, цель которого — показать, как E2EE меняет архитектуру backend, frontend и realtime-доставки.</p><p>Если вы делали что-то похожее — особенно интересно сравнить подходы к ротации prekey-ов, хранению non-extractable ключей в браузере и реализации DH ratchet step. Вопросы и критика приветствуются.</p>]]></content:encoded>
    </item>
    <item>
      <title>Адаптация открытого симулятора InferSim для оценки загрузки промышленных GPU</title>
      <link>https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom</link>
      <comments>https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Дмитрий Ходыкин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom</guid>
      <description><![CDATA[<p>Рассказываем, как доработали симулятор InferSim от Alibaba: добавили поддержку новых GPU (включая MetaX C500), расширили список моделей с гибридными архитектурами и сделали визуализацию на Streamlit. Инструмент позволяет оценивать задержки и требуемую память без запуска реального инференса и помогает избежать грубых ошибок при планировании закупок оборудования.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/adaptaciya-otkrytogo-simulyatora-infersim-dlya-ocenki-zagruzki-prom">Адаптация открытого симулятора InferSim для оценки загрузки промышленных GPU</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Визуализация]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Hardware]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 04 May 2026 08:09:55 GMT</pubDate>
      <content:encoded><![CDATA[<p>Планирование аппаратных ресурсов под обслуживание больших языковых моделей — задача с высоким порогом ошибки. Потратишь лишнего — получишь неоправданные расходы. Сэкономишь — столкнёшься с деградацией пользовательского опыта. На российском рынке, где доступ к современным ускорителям ограничен, эта задача становится особенно острой.</p><p>Мы остановились на открытом симуляторе InferSim от Alibaba. Он умеет считать TTFT, TPOT и пропускную способность без запуска реального инференса. Но из коробки поддерживает только несколько топовых GPU и фиксированный набор моделей — для наших сценариев этого было недостаточно. Пришлось дорабатывать.</p><p><b>Как устроен InferSim</b></p><p>В основе симулятора — двухфазная схема. Сначала на целевом железе запускаются микро-бенчмарки: измеряется реальная производительность на типовых операциях внимания и матричных умножениях. Получается таблица коэффициентов Model FLOPs Utilization (MFU) — сколько процентов от теоретического максимума выдаёт конкретная карта на конкретной операции. Затем, уже без доступа к GPU, симулятор на основе этих MFU и аналитической модели вычисляет задержки. Именно такой подход даёт более точные предсказания, чем оценка по паспортной пропускной способности памяти.</p><p><b>Добавляем своё железо</b></p><p>Первым делом мы внесли в hardware/gpu.py поддержку MetaX C500 64GB. Характеристики добавляются через dataclass-экземпляры:</p><p>После этого c500 попадает в словарь gpu_map, и симулятор запускается с ключом --device-type C500 --world-size 2. Значения FLOPS и пропускной способности пришлось оценивать по косвенным источникам — производитель не публикует точных цифр. Позже планируем уточнить их через бенчмаркинг на реальном оборудовании. Таким же способом добавили Nvidia 1xH100 и A100.</p><p><b>Конфигурация моделей и одна болезненная ошибка</b></p><p>Симулятор ожидает стандартный config.json в формате Hugging Face. Для Qwen3-32B подготовили файл qwen3_32b_config.json:</p><p>Ключевой момент — правильное значение head_dim. У Qwen3-32B оно равно hidden_size / num_attention_heads = 5120 / 64 = 80. У нас ушло некоторое время, чтобы понять, почему симулятор выдаёт невалидные результаты: изначально в конфиге стояло значение 128. Пока не исправили — KV-кеш переоценивался, и метрики улетали в неадекватные цифры. После исправления всё встало на свои места.</p><p>Позже добавили поддержку Qwen3.5‑9B с её гибридной архитектурой, построенной на чередовании Gated DeltaNet и Gated Attention. Главная особенность модели в том, что около трёх четвертей слоёв не создают привычного KV‑кеша, а используют линейное внимание – компактное скрытое состояние, которое лишь обновляется с каждым новым токеном, не увеличиваясь в объёме. Это кардинально снижает расход памяти на длинных контекстах, но привносит и свою цену: на коротких дистанциях такая модель проигрывает в скорости Prefill, потому что Gated DeltaNet работает последовательно и хуже утилизирует матричные вычисления GPU.</p><p>Симулятор изначально не умел различать слои двух типов и считал весь KV‑кеш одинаково. Чтобы поддержать Qwen3.5, пришлось доработать расчёт задержек в классе HybridModel: теперь он отдельно обсчитывает full‑attention‑слои с полным кешем и linear‑attention‑слои без кеша, используя параметры num_full_attn_layers и num_linear_attn_layers из конфигурации. В директорию проекта models добавили hybrid_model.py, в котором сделали дополнительные расчёты:</p><p>Без такой дифференциации симулятор для Qwen3.5‑9B показывал E2E порядка 2 500 секунд вместо реальных нескольких секунд – та ошибка, которую мы долго отлавливали.</p><p><b>Визуализация и эксплуатация</b></p><figure><img src="https://media.tproger.ru/user-uploads/137657/2026-04-30/d68ad2ca-cbc0-4fe3-a4af-2f082a55ecdf.webp" alt="" /><figcaption>Пользовательский интерфейс на Streamlit</figcaption></figure><p>Чтобы не разбирать каждый раз текстовый вывод InferSim, сделали веб-интерфейс на Streamlit. Симулятор дёргается через subprocess, результаты парсятся из stdout и визуализируются:</p><ul><li>тепловые карты задержек (Prefill, Decode, E2E Total) для разных длин входных и выходных токенов;</li><li>анализ RPS с расчётом требуемой параллельности и сравнением с доступной памятью;</li><li>информация о занятой памяти в формате «X ГБ из Y ГБ».</li></ul><p>Кэширование через @st.cache_data позволило избежать повторных запусков симуляции при неизменных параметрах. Интерфейс получился достаточно удобным, чтобы даже коллеги без погружения в командную строку могли осмысленно сравнивать конфигурации.</p><p>Приложение упаковано в Docker и лежит в репозитории на <a href="https://github.com/DmitriyKhodykin/InferSim" rel="nofollow">GitHub</a>. Сервисы — сам Streamlit и Nginx в качестве обратного прокси с SSL-терминацией и базовой HTTP-аутентификацией. Деплой на VDS автоматизирован через GitHub Actions: собрали образ, отправили на сервер, перезапустили контейнеры. SSL-сертификаты Let's Encrypt обновляются по cron.</p><p><b>Что в итоге</b></p><p>Адаптированный InferSim не претендует на абсолютную точность — она ограничена качеством бенчмарков и коэффициентов MFU. Но инструмент позволяет избежать грубых ошибок при планировании, что в условиях ограниченного доступа к GPU и их высокой стоимости само по себе немало. Мы продолжаем калибровку симулятора и готовим обновлённые конфигурации для следующих моделей.</p><p>Репозиторий проекта открыт, будем рады замечаниям и предложениям от тех, кто решает схожие задачи.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub: один git push с лишним символом давал RCE — что было в CVE-2026-3854</title>
      <link>https://tproger.ru/news/github-odin-git-push-s-liwnim-simvolom-daval-rce-chto-bylo-v-c</link>
      <comments>https://tproger.ru/news/github-odin-git-push-s-liwnim-simvolom-daval-rce-chto-bylo-v-c?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-odin-git-push-s-liwnim-simvolom-daval-rce-chto-bylo-v-c</guid>
      <description><![CDATA[<p>Wiz нашли в обработке git push инжекцию через делимитер push-опций — RCE на серверах GitHub. github.com закрыли 4 марта, GHES — публично. Что обновить.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-odin-git-push-s-liwnim-simvolom-daval-rce-chto-bylo-v-c">GitHub: один git push с лишним символом давал RCE — что было в CVE-2026-3854</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 30 Apr 2026 13:37:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если у вас аккаунт на github.com — за вас уже всё пропатчили: GitHub закрыл уязвимость 4 марта, через час с небольшим после получения репорта от Wiz, и форензика по логам никаких следов эксплуатации не нашла. Если вы админ GitHub Enterprise Server — обновляйтесь сейчас, патчи опубликованы 28 апреля. Любой git push с точкой с запятой в push-опциях давал атакующему shell на сервере, обрабатывающем этот пуш — <a href="https://github.blog/security/securing-the-git-push-pipeline-responding-to-a-critical-remote-code-execution-vulnerability/">официальный пост в GitHub Blog</a>.</p><p>CVE-2026-3854 — RCE-уязвимость в обработке push-опций git, CVSS 8.7. Нашли её исследователи <a href="https://www.wiz.io/blog/github-rce-vulnerability-cve-2026-3854">Wiz</a>, отправили в bug bounty программу 4 марта 2026 года. GitHub воспроизвёл уязвимость за 40 минут, выкатил фикс на github.com ещё через 35 — итого «менее чем за два часа», как сами они округлили. Bounty payout — один из крупнейших в истории <a href="https://bounty.github.com">GitHub Bug Bounty</a>; публично программа платит от $30 000 за критические RCE-находки.</p><p>Под удар попали все варианты GitHub: github.com, GitHub Enterprise Cloud (включая <b>Data Residency</b> — изолированные облачные инстансы для регулируемых отраслей — и <b>Enterprise Managed Users</b> — корпоративный SSO-tenant), и GitHub Enterprise Server (GHES, самохостинг). Клиентам Cloud делать ничего не нужно — там пропатчили в день репорта. Админам GHES — обновиться до последнего патча в вашей мажорной ветке и пройтись по аудит-логам.</p><p><b>CVE-2026-3854 (CVSS 8.7) — RCE через push-опции git.</b> Любой пользователь с push-доступом к репозиторию мог выполнить команды на сервере, обрабатывающем его пуш. Один git push --push-option=... и сервер выполнял чужой код.</p><p><b>Нашёл Wiz, репорт через bug bounty 4 марта 2026 года.</b> github.com закрыли в тот же день, через 1 час 15 минут после получения. Форензика следов эксплуатации не нашла — все срабатывания уязвимого кодового пути в логах сошлись на тестах самих Wiz.</p><p><b>Затронуты:</b> github.com, GitHub Enterprise Cloud (плюс Data Residency и Enterprise Managed Users), GitHub Enterprise Server. Cloud-варианты пропатчены 4 марта, GHES — теперь публично.</p><p><b>Для GHES — обновляться сейчас.</b> Патчи: 3.14.25 / 3.15.20 / 3.16.16 / 3.17.13 / 3.18.7 / 3.19.4 / 3.20.0 и новее. Эксплуатация требует пользователя с push-доступом, но на корпоративном инстансе это часто весь штат разработчиков.</p><p><b>Bounty payout — один из самых больших в истории GitHub Bug Bounty</b>, по словам самих GitHub. Точную сумму не назвали, но программа публично платит от $30 000 за критические RCE-находки и допускает доплаты сверху за исключительные репорты.</p><h2>Что такое push-опции и зачем они нужны</h2><p>git push --push-option=foo=bar — это легитимная фича git: при пуше клиент передаёт серверу произвольные пары ключ-значение. На сервере хуки видят их через переменные окружения GIT_PUSH_OPTION_* и могут использовать для сигналов вроде «обойти проверку pre-receive в этот раз», «уведомить вот такой пайплайн в CI», «явно пометить пуш как hotfix». Сама фича в git с сентября 2016 года (релиз 2.10), включить можно флагом, конфигом push.pushOption или git-алиасом.</p><p>Внутри GitHub push-опции едут через служебный межсервисный протокол: метаданные о пуше — тип репозитория, кто пушит, в какое окружение его обработать — складываются в служебную строку и передаются между микросервисами. Именно в этой строке и обнаружилась дыра.</p><h2>Что было в инъекции</h2><p>Разделителем полей во внутреннем протоколе была точка с запятой ;. GitHub в техническом разделе своего блога её прямо не называет, но в рекомендациях для админов GHES просит искать ; в /var/log/github-audit.log — оттуда видно, какой именно символ был делимитером. Та же точка с запятой могла оказаться в значении push-опции, переданной пользователем, из-за чего и появлялась инъекция.</p><p>Дальше — классическая инъекция, как SQL-injection, только не в базу, а в служебный протокол между микросервисами GitHub. Пользователь подсовывает push-опцию вида foo=bar;trustedField=..., сервер бережно складывает её в строку метаданных, downstream-сервис парсит строку, видит «лишнее» поле и интерпретирует его как доверенное внутреннее значение. Сцепив несколько таких полей подряд, исследователи добились трёх вещей: переопределили окружение, в котором обрабатывался пуш; обошли sandbox, который обычно ограничивает выполнение хуков; и выполнили произвольные команды на сервере.</p><p>Самое неприятное — для атаки не нужен был никакой доступ к чужим репозиториям. Достаточно собственного приватного репозитория, который можно создать за 5 секунд и закрыть от всех остальных. С push-доступом к этому репозиторию атакующий получал shell на инфраструктуре, обрабатывающей пуш — на github.com это shared-инфраструктура, через которую идут пуши всех пользователей.</p><h2>Хронология: 55 дней приватного фикса</h2><ul><li>4 марта 2026, 17:45 UTC — Wiz отправляют репорт в bug bounty.</li><li>4 марта 2026, 18:25 UTC — GitHub воспроизводит уязвимость внутри (через 40 минут).</li><li>4 марта 2026, 19:00 UTC — фикс выкачен на github.com (через 1 час 15 минут после репорта).</li><li>4 марта — параллельно закрыто на GitHub Enterprise Cloud (все варианты).</li><li>Март-апрель — приватная работа над GHES патчами + форензика по логам.</li><li>28 апреля 2026 — публичный пост, релизы GHES, выдан CVE-2026-3854.</li></ul><p>Полтора месяца молчания — потому что у GHES медленный цикл релизов и нужно было параллельно подготовить патчи для всех поддерживаемых мажорных веток. Параллельно GitHub перерыл логи: уязвимый кодовый путь в нормальной работе не дёргается совсем, поэтому любое его срабатывание в телеметрии — кандидат на exploit. Все обнаруженные срабатывания сошлись на тестовой активности самих Wiz, других следов не нашли.</p><p>Сама архитектура атаки им в этом помогла. Эксплойт заставляет сервер пройти по кодовому пути, который никогда не используется в нормальной работе github.com — это прямое следствие того, как именно работает инъекция. Атакующий не может «спрятаться» в обычном трафике: каждое его срабатывание остаётся в телеметрии как явная аномалия.</p><h2>Кого затронуло</h2><p>Под уязвимость попали все площадки GitHub:</p><ul><li>github.com (публичная площадка) — пропатчена 4 марта 2026.</li><li>GitHub Enterprise Cloud — пропатчен 4 марта.</li><li>GitHub Enterprise Cloud with Data Residency — пропатчен 4 марта.</li><li>GitHub Enterprise Cloud with Enterprise Managed Users — пропатчен 4 марта.</li><li>GitHub Enterprise Server (GHES, self-hosted) — патчи 28 апреля 2026.</li></ul><p>Эксплуатация на GHES требует <b>аутентифицированного пользователя с push-доступом</b> на конкретный инстанс. На корпоративных серверах это, как правило, весь штат разработчиков и любой внешний контрактник, которого пустили в проект. То есть для большинства компаний это эквивалент «локальный пользователь → root на сервере GitHub».</p><h2>Что делать админам GHES</h2><p>Обновитесь до одного из следующих релизов в вашей мажорной ветке (или новее):</p><ul><li>GitHub Enterprise Server 3.14.25</li><li>GitHub Enterprise Server 3.15.20</li><li>GitHub Enterprise Server 3.16.16</li><li>GitHub Enterprise Server 3.17.13</li><li>GitHub Enterprise Server 3.18.7</li><li>GitHub Enterprise Server 3.19.4</li><li>GitHub Enterprise Server 3.20.0 или позже</li></ul><p>После обновления — пройдитесь по /var/log/github-audit.log и поищите push-операции, в push-опциях которых встречается символ ;. GitHub рекомендует это сделать «из соображений предосторожности» — exploitation на github.com они не нашли, но GHES — это ваш инстанс, и логи только у вас. Команда на коленке:</p><p>Если что-то нашли — копайте дальше: смотрите учётку, время, репозиторий, уходите в конкретные хуки и их вывод. Если ничего нет — фиксируйте патч-уровень и продолжайте жить, в Cloud-вариантах эта же история обошлась без жертв.</p><h2>Defense in depth: как туда попал лишний код-путь</h2><p>GitHub в том же посте признаются в дополнительной находке. Уязвимый кодовый путь не должен был быть доступен в той среде, в которой он отрабатывал. Раньше деплой явно его исключал — путь нужен был только для другой конфигурации продукта. Когда модель деплоя поменяли, исключение не перенесли, и код-путь начал лежать на диске рядом с продакшен-обработчиком пушей.</p><p>Это не первичный баг — без injection до этого кода всё равно было не дотянуться. Но это второй слой обороны, которого здесь не оказалось. GitHub отдельно зачистил окружения от лишнего, и теперь даже при гипотетической второй injection через push-опции там просто нечего эксплуатировать.</p><p>Урок: при смене модели деплоя пересматривайте список того, что в этой модели не должно быть доступно. Каждый кодовый путь — отдельный кусок атак-поверхности, и держать его «на всякий случай» обходится дороже, чем удалить.</p><h2>Выводы</h2><p>CVE-2026-3854 — учебный пример инъекции через делимитер во внутреннем протоколе. Ничего экзотического: пользовательский ввод попал в служебную строку, разделитель совпал, downstream-парсер посчитал «лишнее» доверенным. То, что такая дыра прожила какое-то время в одном из самых внимательных к безопасности продуктов индустрии, — отдельная иллюстрация, насколько живучи такие классы багов даже у зрелых команд.</p><p>40 минут на репродукцию и 1 час 15 минут на патч в продакшен — впечатляющие цифры incident response. GitHub отрабатывает такие кейсы постоянно, но всё равно показательно: расследование, фикс, прогон через CI и выкат на github.com уместились в один кофе-брейк команды.</p><p>Источники: <a href="https://github.blog/security/securing-the-git-push-pipeline-responding-to-a-critical-remote-code-execution-vulnerability/">официальный пост в GitHub Blog</a>, <a href="https://github.com/advisories/CVE-2026-3854">advisory CVE-2026-3854</a>, <a href="https://www.wiz.io/blog/github-rce-vulnerability-cve-2026-3854">технический разбор Wiz</a>. Если у вас GHES — обновитесь, проверьте логи, идите дальше. Если только аккаунт на github.com — благодарите security-команду GitHub: вы узнали об этой истории, когда её уже не было.</p>]]></content:encoded>
    </item>
    <item>
      <title>Взлом Bitwarden CLI на npm: 1,5 часа кражи токенов и SSH-ключей</title>
      <link>https://tproger.ru/news/bitwarden-cli-na-npm-podmenili-na-1-5-chasa-versiya-2026-4-0-kra</link>
      <comments>https://tproger.ru/news/bitwarden-cli-na-npm-podmenili-na-1-5-chasa-versiya-2026-4-0-kra?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/bitwarden-cli-na-npm-podmenili-na-1-5-chasa-versiya-2026-4-0-kra</guid>
      <description><![CDATA[<p>Bitwarden CLI 2026.4.0 на npm 22 апреля около 1,5 часа содержал малварь, крадущую GitHub/npm-токены, SSH-ключи и конфиги ИИ-ассистентов. Что делать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/bitwarden-cli-na-npm-podmenili-na-1-5-chasa-versiya-2026-4-0-kra">Взлом Bitwarden CLI на npm: 1,5 часа кражи токенов и SSH-ключей</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Кибербезопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 24 Apr 2026 08:30:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Подменили @bitwarden/cli в npm на 1 час 33 минуты — за это окно <a href="https://www.bleepingcomputer.com/news/security/bitwarden-cli-npm-package-compromised-to-steal-developer-credentials/">успевали воровать</a> GitHub/npm-токены, SSH-ключи и конфиги ИИ-ассистентов Claude, Kiro, Cursor, Codex CLI и Aider у всех, кто зашёл поставить пакет. Окно атаки — с 17:57 до 19:30 по времени Нью-Йорка 22 апреля (с 00:57 до 02:30 МСК 23 апреля). Vault-пароли самого менеджера Bitwarden не трогали — взломали только npm-канал доставки CLI. Если ставили версию 2026.4.0 — считайте ключи с этой машины скомпрометированными и ротируйте их прямо сейчас.</p><ul><li>Скомпрометирована одна npm-версия @bitwarden/cli@2026.4.0. Окно атаки — 1 час 33 минуты 22 апреля 2026 года.</li><li>Vault-данные пользователей Bitwarden не затронуты. Пострадал только npm-канал доставки CLI и те, кто успел поставить эту сборку.</li><li>Вектор — скомпрометированный action checkmarx/ast-github-action, который Bitwarden подтягивал в свой CI. По словам исследователей, это первый зафиксированный взлом пакета через npm trusted publishing.</li><li>Малварь таргетит ИИ-ассистенты Claude, Cursor, Codex CLI, Aider и AWS-based Kiro — отдельный модуль собирает их конфиги и API-ключи.</li><li>Если ставили — ротируйте npm/GitHub-токены, SSH-ключи и облачные креденшлы AWS/Azure/GCP; проверьте CI/CD-пайплайны и публичные репозитории со строкой «Shai-Hulud» в имени.</li></ul><h2>Что случилось с пакетом</h2><p>По <a href="https://thehackernews.com/2026/04/bitwarden-cli-compromised-in-ongoing.html">данным The Hacker News</a>, в ночь с 22 на 23 апреля 2026 года в npm-реестре появилась версия @bitwarden/cli@2026.4.0 с дополнительным файлом bw1.js внутри. Сборка была доступна 1 час 33 минуты — с 17:57 до 19:30 по времени Нью-Йорка, — после чего её сняли с публикации. Первыми на неё обратили внимание исследователи Socket, JFrog и OX Security. JFrog <a href="https://x.com/jfrog/">описал поведение</a> как «кражу GitHub/npm-токенов, содержимого .ssh, .env, истории shell, секретов GitHub Actions и облачных провайдеров с выгрузкой на внешние домены и в виде коммитов в GitHub».</p><p>Bitwarden подтвердил инцидент и уточнил, что «расследование не обнаружило признаков доступа к данным пользовательских хранилищ и компрометации продакшн-систем». По словам компании, доступ нарушителя был отозван, вредоносный релиз помечен как deprecated, по версии 2026.4.0 заводится отдельный CVE. Пострадавшие — только те, кто успел скачать пакет в полуторачасовом окне и выполнил его установку.</p><h2>Как устроен троян</h2><p>Механика по отчёту <a href="https://socket.dev/blog">Socket</a> проста, но многоступенчата. В package.json зловредной версии добавлен preinstall-хук, который запускает скрипт bw_setup.js. Тот проверяет наличие Bun — альтернативного JS-рантайма — и, если его нет, скачивает. Затем Bun-ом запускается обфусцированный загрузчик bw1.js. Bun тащат с собой не случайно: на машине жертвы его, скорее всего, нет, а корпоративный EDR (антивирус нового поколения для рабочих станций и серверов) реагирует на неожиданный бинарник хуже, чем на стандартный npm-скрипт. Preinstall-хук при этом срабатывает ещё до того, как код пакета формально «установлен».</p><ul><li>npm- и GitHub-токены из локальных конфигов и переменных окружения;</li><li>приватные SSH-ключи из ~/.ssh;</li><li>содержимое .env-файлов и историю shell (.bash_history, .zsh_history);</li><li>секреты GitHub Actions из переменных окружения CI;</li><li>креденшлы облачных провайдеров — AWS, Azure, Google Cloud;</li><li>конфиги и API-ключи ИИ-ассистентов Claude, Cursor, Codex CLI, Aider и AWS-based Kiro.</li></ul><p>Собранные данные шифруются AES-256-GCM и выгружаются двумя каналами. Основной — POST на домен audit.checkmarx[.]cx (конкретно путь /v1/telemetry), который притворяется инфраструктурой Checkmarx. Резервный — малварь создаёт публичные GitHub-репозитории в аккаунте жертвы и кладёт туда зашифрованный payload. В названиях репозиториев встречается строка «Shai-Hulud: The Third Coming» — отсылка к прошлогодней одноимённой кампании в npm. OX Security подчёркивает, что такой тайник (по терминологии безопасников — dead-drop) через GitHub опасен отдельно: утёкшие секреты становятся доступны любому, кто ищет по публичным репозиториям, — а системы защиты почти не следят за исходящим трафиком в GitHub.</p><p>Поверх этого в бинарнике есть модуль-червь: с украденным npm-токеном малварь находит все пакеты, которые жертва имеет право публиковать, и вбрасывает в них тот же payload. <a href="https://www.endorlabs.com/blog">Endor Labs называет</a> его «CanisterSprawl» и считает один из самых полных npm supply chain-пейлоадов на сегодняшний день: шесть разных поверхностей для сбора секретов, OIDC- и cloud-кража, самораспространение через npm-публикации и отдельный модуль для ИИ-ассистентов.</p><h2>Отдельный удар по ИИ-ассистентам</h2><p>Отдельный модуль малвари специально ищет артефакты ИИ-кодеров — API-ключи OpenAI и Anthropic из конфигов Claude, Cursor и Codex CLI, токены Aider, настройки AWS-based Kiro. Endor Labs считает, что это один из первых публично задокументированных случаев, когда supply chain-атака отдельной веткой целится на «кошельки разработчиков у ИИ». Ключ к Anthropic или OpenAI — это не только деньги на балансе аккаунта жертвы, но и возможность с его помощью заставить ИИ-ассистента писать закладки в код при следующих авто-запросах.</p><h2>Почему малварь пропускает русскую локаль</h2><p>Малварь завершается без выполнения, если в системе выставлена русская локаль. Socket отмечает три возможных причины: отдельный оператор, использующий общую инфраструктуру, отколовшаяся группа с идеологическими мотивами или эволюция самой кампании. На практике для российских разработчиков это не даёт защиты: большинство dev-машин, серверов и CI-раннеров работают с англоязычной локалью по умолчанию (обычно en_US.UTF-8), поэтому пропуск по локали чаще всего не срабатывает.</p><h2>Что делать, если могли установить 2026.4.0</h2><ul><li>Сначала убедитесь, что пакет действительно попал в ваши машины и раннеры: прогрепайте package-lock.json, pnpm-lock.yaml и yarn.lock на @bitwarden/cli версии 2026.4.0, посмотрите логи npm-установок в ночь на 23 апреля МСК.</li><li>Ротируйте все токены с этих машин: npm-токены, GitHub PAT (включая fine-grained), SSH-ключи, AWS access/secret keys и STS-сессии, Azure SP, GCP service accounts.</li><li>Замените секреты в GitHub Actions и других CI-системах, где пакет мог запускаться, — включая secrets, variables и OIDC-конфигурации.</li><li>Пройдитесь по API-ключам ИИ-ассистентов (Anthropic, OpenAI, Cursor, Aider) и отзовите их в кабинетах провайдеров; сверьте биллинг на предмет аномальных трат.</li><li>Проверьте публичные репозитории в своём GitHub-аккаунте: ищите имена в формате &lt;слово&gt;-&lt;слово&gt;-&lt;3 цифры&gt; (например, fremen-muaddib-042) со строкой «Shai-Hulud» в README и удалите.</li><li>Откатитесь на безопасную версию CLI — 2026.3.x или актуальную стабильную, которую Bitwarden опубликовал после инцидента. Ставьте её через npm i @bitwarden/cli@&lt;версия&gt;, а не через latest или диапазон.</li></ul><h2>Связь с Checkmarx и первый взлом через npm trusted publishing</h2><p>Накануне, 21 апреля, Checkmarx раскрыла собственный инцидент — компрометацию KICS Docker-образов, GitHub-расширений и пакета checkmarx/ast-github-action, который используется во многих CI-пайплайнах. По данным Endor Labs, репозиторий Bitwarden подтягивал именно этот action, и через него злоумышленники получили доступ к npm-каналу. Socket приводит прямые пересечения: тот же домен audit.checkmarx[.]cx, тот же паттерн обфускации __decodeScrambled с seed-значением 0x3039 — технический отпечаток, указывающий на одних и тех же авторов, — плюс тот же приём «украсть → выгрузить в GitHub → распространиться дальше».</p><p>Исследователь <a href="https://x.com/AdnanTheKhan">Аднан Хан утверждает</a>, что это первый зафиксированный случай компрометации пакета, использующего npm trusted publishing — механизм OIDC-публикации, при котором GitHub Actions обменивается на короткоживущий npm-токен без долгоживущих секретов в CI. Его как раз продвигали в ответ на регулярные утечки npm-токенов у мейнтейнеров. На деле trusted publishing оказался не панацеей: если нарушитель получает доступ к GitHub Actions-воркфлоу с правом публиковать пакет, OIDC-токен ему выдаёт сам npm. Атрибуция у исследователей — группа TeamPCP, уже засветившаяся на <a href="https://tproger.ru/news/volna-supply-chain-atak-na-pypi--razbiraem-litellm--telnyx-i-tri">взломах LiteLLM и Trivy</a>. Аккаунт TeamPCP в X на момент выхода материала заблокирован.</p><h2>Выводы для npm-экосистемы и supply chain</h2><p>Случай укладывается в серию ударов по цепочке доставки последних двух недель: <a href="https://tproger.ru/news/volna-supply-chain-atak-na-pypi--razbiraem-litellm--telnyx-i-tri">Trivy и LiteLLM на PyPI</a>, <a href="https://tproger.ru/news/supply-chain-ataki-2026--axios--pypi-i-prompt-injection---chto-pr">Axios и PyPI</a>, теперь Checkmarx и Bitwarden. Характерная деталь — защитный слой не спасает: trusted publishing, OIDC и короткоживущие токены не помогают, если злоумышленник уже получил доступ к CI-воркфлоу. Практический вывод: pin-версии в лок-файлах, отдельный CI-аккаунт с минимальными правами, еженедельная ревизия CI-секретов и мониторинг собственного GitHub на появление незнакомых публичных репозиториев. Инвентаризация секретов, которые ходят через CI/CD, перестала быть теоретическим упражнением.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub закрыл регистрацию на Copilot Pro и убрал Opus — что с тарифами</title>
      <link>https://tproger.ru/news/github-zakryl-registraciyu-na-copilot-pro-i-ubral-opus-chto-s-ta</link>
      <comments>https://tproger.ru/news/github-zakryl-registraciyu-na-copilot-pro-i-ubral-opus-chto-s-ta?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-zakryl-registraciyu-na-copilot-pro-i-ubral-opus-chto-s-ta</guid>
      <description><![CDATA[<p>GitHub 21 апреля 2026 года закрыл регистрацию на Copilot Pro, Pro+ и Student. С Pro убрали Opus. Лимиты ужесточили. Refund до 20 мая. Разбираем, что делать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-zakryl-registraciyu-na-copilot-pro-i-ubral-opus-chto-s-ta">GitHub закрыл регистрацию на Copilot Pro и убрал Opus — что с тарифами</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 23 Apr 2026 15:30:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы собирались подписаться на <b>Copilot Pro</b> — прямо сейчас не получится. GitHub 21 апреля 2026 года приостановил новые регистрации на планы Pro, Pro+ и Student одновременно. Цена не выросла, но на существующем Pro урезали лимиты, убрали Claude Opus и ужесточили политику использования. Pro+ при этом получил весь каталог моделей и лимиты в 5 раз выше базовых.</p><p>Формально это не повышение цен ($10 Pro / $39 Pro+ / $0 Free остаются). Фактически у Pro-подписчика снизились возможности при прежней цене, а у Pro+ — выросли относительно других тарифов. GitHub объясняет это взрывным ростом агентных рабочих процессов.</p><p>— <b>Новые регистрации.</b> На Pro, Pro+ и Student регистрации приостановлены до особого уведомления. Enterprise и Business — работают.</p><p>— <b>Opus.</b> С Pro убраны все версии Claude Opus. В Pro+ остаётся Opus 4.7; Opus 4.5 и 4.6 по changelog скоро уйдут и оттуда.</p><p>— <b>Лимиты.</b> Две оси — session (пиковая защита) и weekly (7-дневный потолок токенов с учётом мультипликатора модели). Premium requests остались: 300/мес Pro, 1500/мес Pro+, $0,04 за каждый сверх.</p><p>— <b>Refund.</b> До 20 мая можно отменить Pro/Pro+ и вернуть деньги за неиспользованную часть.</p><p>— <b>Прозрачность.</b> VS Code и Copilot CLI теперь показывают оставшееся usage прямо в UI — когда лимит близко, это видно.</p><h2>Что именно изменилось</h2><h3>Pro — урезан</h3><p>Claude Opus с Pro удалён. Пользователь, подписанный на $10 в месяц, теряет доступ к флагманской модели Anthropic. Остаются Haiku 4.5, GPT-5 mini и остальной уровень менее мощных моделей. Weekly-лимит стал жёстче, а session-лимит защищает от всплесков, которые случаются при длинных агентных циклах.</p><p>Формально цена $10/мес не изменилась — но по функциональности тариф сократился. Те, кому критичен Opus, фактически вынуждены переходить на Pro+ за $39/мес — это +$29, то есть почти 4-кратный рост.</p><h3>Pro+ — расширен</h3><p>Pro+ сохраняет весь каталог моделей, получает лимиты «более чем в 5 раз выше Pro» и 1500 premium-запросов в месяц (у Pro — 300). Плюс остаётся доступ к GitHub Spark. По changelog, Opus 4.5 и 4.6 скоро уйдут и отсюда — останется только Opus 4.7 как единственный Opus-вариант на платформе. С плана Pro весь Opus уже убрали.</p><h3>Free — без изменений</h3><p>На Free-тарифе по-прежнему 50 запросов в режиме чата/агента и 2000 автодополнений в месяц. Модели — Haiku 4.5 и GPT-5 mini. Регистрация на Free открыта. Это базовая точка входа для разработчиков, которые только знакомятся с Copilot.</p><h2>Почему GitHub закручивает гайки</h2><p>Главная причина — <b>агентные сценарии</b>. Copilot Agent Mode и параллельные подпроцессы — например, через команду /fleet, которая запускает сразу несколько агентов на одну задачу — разворачивают один «запрос» в десятки вызовов модели. GitHub прямо пишет:</p><blockquote>Agentic workflows have fundamentally changed Copilot's compute demands… it's now common for a handful of requests to incur costs that exceed the plan price.</blockquote><p>Перевод: несколько агентных задач у одного пользователя могут стоить GitHub больше, чем месячная подписка. Weekly-лимит — попытка ограничить активных пользователей на уровне плана, а не выставлять им счёт за перерасход. Overage-ставка $0,04 за premium-запрос остаётся, но теперь есть дополнительный недельный потолок.</p><h2>Как устроены новые лимиты</h2><p>Лимиты теперь работают в двух плоскостях:</p><ul><li><b>Session-лимит</b> — защита от пиков. Поглощает всплеск токенов в одной активной сессии; точную длительность окна GitHub не публикует, сбрасывается относительно быстро</li><li><b>Weekly-лимит</b> — 7-дневный потолок усреднённых токенов с учётом мультипликатора модели. Дорогие модели (Opus) съедают квоту в несколько раз быстрее, дешёвые (Haiku 4.5) — медленнее</li><li><b>Premium-запросы</b> — отдельная квота: 300/мес Pro, 1500/мес Pro+ (арифметика 5×300), $0,04 за каждый сверх</li></ul><p>Важный момент: premium-квота и weekly-квота независимы. Можно иметь 295 неиспользованных premium-запросов и всё равно упереться в weekly cap, если весь месяц пользоваться Opus на длинных контекстах.</p><h2>Что делать Pro-подписчику</h2><p>Три варианта, в порядке возрастания затрат:</p><ol><li>Перейти на дешёвые модели на Pro ($10 сохраняется). Haiku 4.5 и GPT-5 mini хорошо справляются с типовыми задачами — автодополнение кода, рефакторинг, комментарии. Opus нужен не всегда</li><li>Апгрейд на Pro+ ($39/мес). Подходит, если часто пользуетесь Claude Opus или запускаете агентные задачи с длинным контекстом. В 5 раз выше лимиты</li><li>Отменить подписку и получить refund до 20 мая. GitHub возвращает пропорциональную часть оплаты. Полезно, если после изменений Copilot больше не отвечает вашим потребностям</li></ol><h2>Что с этим делать из России</h2><p>Copilot официально не оплачивается с российских карт с 2022 года. Обычный путь — иностранная карта + VPN при оформлении. С апрельской паузой на регистрации подписаться на Pro/Pro+/Student сейчас нельзя вообще, даже с иностранной картой. Остаётся только <b>Free tier</b> (50 чат-запросов и 2000 автодополнений в месяц).</p><p>Дополнительный нюанс: с 24 апреля 2026 года входные и выходные данные, а также фрагменты кода пользователей Free, Pro и Pro+ по умолчанию используются для обучения моделей. Opt-out есть, но включать его надо вручную — <a href="https://tproger.ru/news/github-copilot-s-24-aprelya-obuchaetsya-na-vawem-kode-po-umolchaniyu">разбирали отдельно</a>. Это отдельное изменение, не связанное с тарифами, но вступает в силу одновременно.</p><p>Альтернативы: <b>Cursor</b>, <b>Zed</b> (оба также требуют иностранной карты для pro-тарифов), <b>Copilot CLI с BYOK</b> — «bring your own key»-режим, где вы подключаете собственный API-ключ Anthropic или OpenAI через свой биллинг у провайдера модели. Anthropic принимает оплату через ряд неамериканских методов, так что для ряда российских разработчиков это самый реалистичный путь. Остаётся также <a href="https://tproger.ru/news/--u-yandeksa-poyavilsya-analog-github-copilot-dlya-pomoshhi-s-napisaniem-koda">Yandex Code Assistant</a> — без санкций, но с менее продвинутыми моделями.</p><h2>Что это значит</h2><p>Формально цены не изменились, но это скрытое сужение Pro-тарифа и защита Pro+ от активных пользователей с агентными нагрузками. GitHub откровенно говорит, что длинные агентные задачи обходятся компании дороже, чем подписка, — и перекладывает часть стоимости на пользователей через weekly-лимит и апгрейд-путь к Pro+.</p><p>Для частного разработчика, использующего Copilot для рутинных задач, ничего не изменилось — Haiku и GPT-5 mini работают как раньше, premium-квоты те же. Для тех, кто гоняет длинные агентные цепочки через Opus — либо переход на Pro+, либо пересмотр рабочего процесса: использовать plan-mode (агент формирует план без немедленного запуска кода, экономит токены) вместо /fleet, дешёвые модели на простых шагах, точечные premium-запросы на сложных.</p><p>Шире — экономика ИИ-моделей всё меньше укладывается в фиксированную месячную подписку. В ближайший год можно ожидать аналогичные шаги у Cursor, Zed и других — либо через изменения лимитов, либо через чистый usage-based-биллинг. <a href="https://github.blog/news-insights/company-news/changes-to-github-copilot-individual-plans/">Официальный анонс GitHub</a>, <a href="https://github.com/features/copilot/plans">актуальные тарифы</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>На GitHub нашли 6 млн фейковых звёзд — большинство ведут на malware</title>
      <link>https://tproger.ru/news/na-github-nawli-6-mln-fejkovyh-zvyozd-bolwinstvo-vedut-na-malw</link>
      <comments>https://tproger.ru/news/na-github-nawli-6-mln-fejkovyh-zvyozd-bolwinstvo-vedut-na-malw?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/na-github-nawli-6-mln-fejkovyh-zvyozd-bolwinstvo-vedut-na-malw</guid>
      <description><![CDATA[<p>CMU и Socket нашли на GitHub 6 млн фейковых звёзд за 5,5 лет. Большинство — фишинг и malware. Как ловят и что проверить перед установкой зависимости.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/na-github-nawli-6-mln-fejkovyh-zvyozd-bolwinstvo-vedut-na-malw">На GitHub нашли 6 млн фейковых звёзд — большинство ведут на malware</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 20 Apr 2026 13:21:16 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы выбираете open-source-зависимости по числу звёзд на GitHub — пора пересмотреть критерий. Исследователи из CMU, NCSU и Socket за пять с половиной лет нашли <b>около 6 миллионов фейковых звёзд</b> на 18 617 репозиториях, и большинство этих репозиториев — не маркетинг, а фишинг и malware. В июле 2024 года ≈ 16,66% всех репозиториев с 50+ звёздами были замечены в фейк-кампаниях.</p><p>Работа «Six Million (Suspected) Fake Stars on GitHub» <a href="https://arxiv.org/abs/2412.13459">принята на ICSE 2026</a> — ведущую конференцию по программной инженерии. Команда выложила <a href="https://github.com/hehao98/StarScout">StarScout</a> — открытый инструмент, которым любой разработчик может проверить подозрительный репозиторий.</p><p><b>≈ 6 миллионов фейковых звёзд</b> на 18 617 репозиториях за июль 2019 — декабрь 2024. Раздавали их ≈ 301 000 аккаунтов.</p><p><b>Пик — июль 2024:</b> 16,66% всех репозиториев с 50+ звёздами засветились в фейк-кампаниях. До 2022 года таких было около нуля.</p><p><b>GitHub валидировал находки:</b> 90,42% помеченных репозиториев и 57,07% аккаунтов сам платформа удалила к январю 2025.</p><p><b>Большинство фейк-кампаний — не маркетинг, а malware:</b> фишинг под видом читов, крипто-ботов и пиратского софта. Остальные — ИИ/LLM-проекты, блокчейн, утилиты, демо.</p><p><b>Растёт только короткое время.</b> Эффект фейковых звёзд держится менее двух месяцев — потом trending смещается к свежим проектам, а репозиторий оседает в публичных списках подозрительных.</p><h2>Почему звёзды стали валютой</h2><p>Звёзды на GitHub — это аналог лайков. Главный публичный сигнал «этому проекту доверяют». На них смотрят разработчики, выбирающие зависимость; рекрутеры, оценивающие пет-проекты; инвесторы, оценивающие стартапы вокруг open source. Сам GitHub использует звёзды для ранжирования в trending, в поиске и в рекомендациях.</p><p>В 2024 году рынок фейковых звёзд выглядит так: «boost-сервисы» открыто продают пакеты в Google по запросу buy github stars. Цена — <b>от $0,10 до $2 за звезду</b>, доставка — за часы. Есть и обменники: «я звёздочку тебе, ты — мне». Чем больше боты в группе, тем больше «органических» звёзд они могут раздать одному репозиторию.</p><blockquote>Если ты продавец фейковых звёзд, доставка обязана быть быстрой — иначе клиент будет недоволен.</blockquote><h2>Как ловят: две сигнатуры StarScout</h2><p>Команда написала <a href="https://github.com/hehao98/StarScout">StarScout</a> — сканер, который пробежался по 20 терабайтам публичных метаданных GitHub за 2019–2024 годы из <a href="https://www.gharchive.org/">GHArchive</a>. Аномалия определяется по двум независимым сигнатурам.</p><h3>Сигнатура 1 — пустые аккаунты</h3><p>Аккаунт без публичной активности, с дефолтным аватаром и пустым профилем, поставивший звезду «горячему» репозиторию. Один такой аккаунт — статистический шум. Сотни одинаковых аккаунтов вокруг одного проекта за неделю — кампания.</p><h3>Сигнатура 2 — аккаунты, действующие синхронно</h3><p>Метод <a href="https://research.facebook.com/publications/copycatch-stopping-group-attacks-by-spotting-lockstep-behavior-in-social-networks/">CopyCatch</a> от Facebook: ищем кластеры аккаунтов, которые ставят звёзды одним и тем же репозиториям в близкие промежутки времени. Если 200 аккаунтов накидали звёзд тому же набору из пяти проектов в течение двух часов — это не совпадение, это автоматизация.</p><p>Совпадение по обеим сигнатурам — высокая уверенность в фейке. <b>GitHub косвенно подтвердил методологию:</b> к январю 2025 года платформа сама удалила 90,42% репозиториев и 57,07% аккаунтов из списка StarScout. Без участия исследователей.</p><h2>Что прячется за фейковой популярностью</h2><p>Самый неприятный вывод: <b>большинство репозиториев с фейк-кампаниями — это malware</b>, а не безобидные стартапы, пытающиеся выглядеть популярнее. Типичный паттерн — обёртка под утилиту, которая нужна аудитории с низким порогом критичности: читы для игр, активаторы Windows, торренты-клиенты, крипто-боты, скачивалки видео из закрытых источников.</p><p>Похожая, но отдельная история — «<a href="https://research.checkpoint.com/2024/stargazers-ghost-network/">Stargazers Ghost Network</a>» от Check Point Research: сеть из более чем 3000 фейковых аккаунтов, которая распространяет Atlantida Stealer, Rhadamanthys, RisePro, Lumma Stealer и RedLine. Атрибутируется группе Stargazer Goblin. Эта сеть анализировалась отдельной командой и, вероятно, частично пересекается с 301 000 аккаунтов из списка StarScout. Общий паттерн один: звёзды как главный инструмент маскировки.</p><p>Меньшая часть фейк-кампаний — без явного malware: проекты вокруг ИИ/LLM, блокчейна, тулов, туториалов и демо. Авторы таких проектов покупают звёзды ради growth hacking или венчурной видимости. По исследованию, выгода всё равно недолгая: эффект исчезает через два месяца. Причина прозаичная — trending у GitHub смещается к свежим проектам, а без органического роста популярность проседает. Вдобавок репозиторий попадает в публичные списки подозрительных, и метка «были фейки» остаётся надолго.</p><p>Фейковые звёзды — это новый слой атак на supply chain, то есть на цепочку зависимостей, из которых собирается любой современный софт. В отличие от точечных инцидентов вроде <a href="https://research.swtch.com/xz-timeline">XZ Utils backdoor</a> или <a href="https://tproger.ru/news/glassworm-zarazhaet-vse-ide-na-mawine-cherez-fejkovyj-wakatime-na">GlassWorm</a> в OpenVSX, это массовый инструмент: дешёвый, автоматизированный, работает пока жертва доверяет звёздам как метрике.</p><h2>Что делать разработчику</h2><p>Простое правило: <b>звёзды — не доказательство доверия, а только сигнал к проверке</b>. Если выбираете зависимость или клонируете утилиту с GitHub, стоит за минуту пробежаться по чек-листу.</p><ol><li>Посмотреть на возраст репозитория и историю коммитов. Проект с 2 тыс звёзд и 3 коммитами от одного автора за неделю — почти всегда buy-кампания.</li><li>Ткнуть на вкладку Stargazers и открыть 5–10 случайных аккаунтов. Если у большинства пустой профиль, дефолтный аватар и ноль собственных репозиториев — это бот-сеть.</li><li>Посмотреть на даты звёзд. 500 звёзд за один день, а потом тишина — признак накрутки. У здорового проекта звёзды копятся плавно.</li><li>Сверить зависимость перед установкой с <a href="https://socket.dev/">Socket</a> или <a href="https://snyk.io/advisor/">Snyk Advisor</a> — они уже проверяют репозитории на supply-chain-риски.</li><li>Для дотошных: запустить <a href="https://github.com/hehao98/StarScout">StarScout</a> локально (нужен доступ к GHArchive) или посмотреть в релизах репозитория готовые датасеты с помеченными кампаниями.</li></ol><h2>Выводы</h2><p>Главное практическое следствие: <b>звёздами больше нельзя пользоваться как самостоятельной метрикой доверия</b>. Они полезны как первичный фильтр — обрезать заведомо мёртвые проекты — но сами по себе ничего не доказывают. С июля 2024 года ≈ 16% всех «популярных» репозиториев на GitHub имели хотя бы одну фейк-кампанию. Это не маргинальное явление, а фоновый шум.</p><p>Авторы исследования предлагают платформе пересмотреть систему репутации: например, не считать все звёзды равными — давать вес только аккаунтам со своей собственной репутацией и историей. Параллельно стоит отказаться от ранжирования по звёздам в trending и поиске — они уже скомпрометированы.</p><p><b>Источники:</b> <a href="https://arxiv.org/abs/2412.13459">paper «Six Million (Suspected) Fake Stars on GitHub», ICSE 2026</a> · <a href="https://www.cs.cmu.edu/news/2025/fake-github-stars">пресс-релиз CMU</a> · <a href="https://github.com/hehao98/StarScout">репозиторий StarScout</a> · <a href="https://socket.dev/blog/3-7-million-fake-github-stars-a-growing-threat-linked-to-scams-and-malware">первая версия исследования (Socket, 3,7 млн)</a> · <a href="https://research.checkpoint.com/2024/stargazers-ghost-network/">Check Point про Stargazers Ghost Network</a></p><p><i>Если используете GitHub-зависимости в проде — добавьте проверку через <a href="https://github.com/hehao98/StarScout">StarScout</a> или supply-chain-сканер в свой CI. Звёзды — больше не сигнал.</i></p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub запустил нативные Stacked PRs — альтернатива Graphite</title>
      <link>https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr</link>
      <comments>https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr</guid>
      <description><![CDATA[<p>GitHub в Private Preview добавил нативные stacked PRs: разбивайте большую диффу на цепочку и мерджите одним кликом. CLI gh stack, Skills для ИИ-агентов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-vypustil-nativnye-stacked-prs-konec-graphite-i-spr">GitHub запустил нативные Stacked PRs — альтернатива Graphite</a>»</p>]]></description>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 16 Apr 2026 10:30:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваши пулл-реквесты разрастаются до 2000 строк и ревьюеры тонут в диффе — у GitHub теперь появился родной способ разбить большую задачу на стэк маленьких PR. <a href="https://github.github.com/gh-stack/">Stacked PRs</a> пока в Private Preview: чтобы получить UI со стек-картой и cascading rebase, нужно записаться в waitlist. Но открытый <a href="https://github.com/github/gh-stack">CLI-клиент gh stack</a> уже можно ставить — авторы пишут, что в нынешнем виде он работает против репозитория только если для вас включили preview.</p><p>Раньше стэки делали сторонними инструментами: облачный сервис <a href="https://graphite.dev">Graphite</a>, консольные клиенты <a href="https://github.com/ezyang/ghstack">ghstack</a> (от Meta) или <a href="https://github.com/getcord/spr">spr</a>. Все они симулировали стэки поверх обычного GitHub и ломались на ребейзах, merge queue и branch protection. Нативная реализация решает именно эти проблемы — о том, что с ней не так на старте и кому есть смысл пробовать прямо сейчас, разбираемся ниже.</p><ul><li><b>Статус:</b> Private Preview, нужен waitlist для репозитория</li><li><b>Что внутри платформы:</b> stack map в UI, cascading rebase, корректная работа branch protection и merge queue</li><li><b>CLI:</b> расширение gh stack открыто в гитхабе, алиас gs — команды init, add, push, submit</li><li><b>ИИ-агенты:</b> npx skills add github/gh-stack учит Claude Code и Codex разбивать задачи на слои</li><li><b>Кому идти сразу:</b> командам с регулярными PR 1500+ строк или большими диффами от ИИ-ассистентов</li><li><b>Кому подождать:</b> тем, кто уже на Graphite или делает в основном PR на 200 строк</li></ul><h2>Что такое stacked PRs</h2><p>Stacked PR (стек пулл-реквестов) — это цепочка PR, где каждый таргетит не main, а ветку PR ниже. Вместо одного огромного пулл-реквеста с пятью разными по смыслу изменениями вы делаете пять маленьких PR, которые читаются независимо и строятся один на другом.</p><p>Пример. Вы делаете фичу, которая требует нового API, роутов и фронтенда. Обычно это превращается в PR на 2000 строк, где ревьюер сначала вникает в API, потом забывает про него, когда смотрит роуты, путается в фронтенде и в итоге пишет «LGTM, не читал». Со стэком:</p><ul><li><b>PR #1</b> — auth-layer: новый API-слой (200 строк, одна тема)</li><li><b>PR #2</b> — api-routes: роуты на базе auth-layer, таргетит ветку PR #1</li><li><b>PR #3</b> — frontend: UI на базе роутов, таргетит ветку PR #2</li></ul><p>Ревьюеры читают по одному PR, дают фидбек по конкретной теме, и вы мержите всё разом, когда каждый слой одобрен. Подход называется «small PR culture» — мы <a href="https://tproger.ru/news/perestante-otpravljat-na-revju-1500-strok-kak-stekat-prs-chtoby-ne-utopljat-revjuerov">уже разбирали, почему команды переосмысляют формат пулл-реквестов</a>.</p><h2>Что GitHub сделал на уровне платформы</h2><p>Сторонние тулы уже давно давали стек на Git-уровне, но работали поверх обычного GitHub и ломались на ребейзах, merge queue и branch protection. Нативная поддержка закрывает эти углы:</p><ul><li><b>Stack map в UI</b> — навигация между PR прямо в интерфейсе, видно статус каждого слоя сразу</li><li><b>Cascading rebase</b> — ребейзнули PR внизу стэка, один клик — и все PR выше автоматически ребейзятся</li><li><b>Branch protection</b> — правила (ревью-апрув, passing checks) применяются против финальной целевой ветки (обычно main), а не против промежуточной</li><li><b>CI</b> — прогоняется для каждого PR в стэке так, будто он уже таргетит финальную ветку (не промежуточную)</li><li><b>Merge queue</b> — очередь GitHub, которая последовательно ребейзит и мерджит PR. Теперь понимает стэки: можно ставить в очередь как весь стэк, так и его часть</li><li><b>Частичный мердж стэка</b> — если одобрены только нижние два PR, можно слить их, а верхние оставить на доработку</li><li><b>API</b> — управление стэками через GraphQL и REST, интеграция с вашими CI-тулами</li></ul><h2>CLI gh stack: что внутри</h2><p>CLI — опциональное расширение к стандартному gh. Сокращает рутину: не надо вручную создавать ветки, проставлять base, делать серию rebase. Базовые команды следуют <a href="https://tproger.ru/news/vsem-rebjatam-primer-pochemu-pora-perestat-ispolzovat-git-flow">той же логике, что и современные workflow поверх Git</a> — работать мелкими слоями и синхронизироваться автоматически.</p><p>Базовый сценарий от GitHub:</p><p>Дальше — работа как с обычными PR, только с визуальной картой стэка. Хотите ребейзнуть auth-layer на свежий main — gs rebase, и вышележащие слои автоматически подтягивают новую базу.</p><h2>Интеграция с ИИ-агентами</h2><p>GitHub явно заточил stacked PRs под сценарий совместной работы с ИИ-агентами. Skills — это документированный формат инструкций для кодовых ассистентов: одна папка с markdown-файлами и примерами, которую агент читает и использует как расширение своего поведения. Команда npx skills add github/gh-stack добавляет такой скилл для <a href="https://github.com/anthropics/claude-code">Claude Code</a>, <a href="https://github.com/openai/codex">OpenAI Codex</a> и других агентов, которые поддерживают формат.</p><p>Скилл учит агента двум вещам: брать большую задачу и заранее разбивать её на слои (вместо того чтобы генерировать один огромный коммит), и работать поверх существующего стэка — добавлять новые слои или чинить нижние. Это решает одну из главных проблем ИИ-разработки: агент делает «всё сразу», ревью превращается в кошмар, а откатить часть изменений невозможно. Похожая мотивация была <a href="https://tproger.ru/news/github-copilot-teper-rabotaet-kak-agent-delaet-pr-bez-vas">у Copilot-агента, который собирает PR сам</a>, но без стэков он быстро упирается в размер диффа.</p><h2>Как попасть в Private Preview</h2><ol><li>Зайти на <a href="https://github.github.com/gh-stack/">github.github.com/gh-stack</a> и записаться в waitlist (кнопка «Sign up for the waitlist»)</li><li>Дождаться, пока GitHub включит фичу для вашей организации или репозитория — точных сроков они не называют</li><li>Включить в настройках репо: появится новая секция Stacked PRs в Settings → Pull Requests</li><li>Поставить расширение CLI: gh extension install github/gh-stack</li></ol><p>CLI-расширение распространяется свободно — его можно поставить уже сейчас из <a href="https://github.com/github/gh-stack">открытого репозитория github/gh-stack</a>. Но README расширения предупреждает: без включённого Private Preview на стороне сервера команды gs push и gs submit упрутся в API, который отвечает 404 или ошибкой доступа. Поставить CLI и посмотреть gh stack --help можно, реально прогонять стэки — только после активации preview в репозитории.</p><h2>Зачем это, если есть Graphite, ghstack и spr</h2><p>Существующие решения делятся на две группы. Graphite — коммерческий сервис: у него свой веб-интерфейс, бэкенд и платные тарифы, он синхронизирует стэк через GitHub API. Ghstack (Meta) и spr (Cord) — консольные клиенты: держат локальный граф стэка и пушат PR напрямую. Общее у них одно — стэк живёт где-то вне GitHub, а синхронизируется с ним через API.</p><p>Из-за этого все они ломаются в одном классе сценариев: когда кто-то из команды мержит через веб-интерфейс, делает force-push из терминала или запускает merge queue, локальный граф CLI или состояние сервиса Graphite разъезжаются с реальностью — и стэк приходится чинить руками.</p><p>Нативная реализация снимает этот класс проблем: стэк живёт на стороне сервера GitHub, UI и CLI синхронизируются с ним автоматически. Branch protection, merge queue, CI — всё работает без костылей. Для базового сценария «разбить большую диффу на стэк и слить её» стороннее звено становится необязательным.</p><p>У сторонних тулов остаётся ниша: автогенерация описаний PR через ИИ у Graphite, интеграция с Jira и Linear, аналитика по времени ревью — всё это GitHub не закрывает. Если вы уже платите Graphite за эту часть — ничего не сломается, тулы совместимы со Stacked PRs на уровне API.</p><p>Для российских разработчиков: GitHub работает с ограничениями для аккаунтов, подключённых из РФ с 2022 года — возможны блокировки при создании организаций и проблемы с оплатой приватных репозиториев. Нативные Stacked PRs становятся особенно полезны, если переходить на <a href="https://gitflic.ru">GitFlic</a>, <a href="https://gitverse.ru">GitVerse</a> или self-hosted GitLab, где аналогов стэков на платформенном уровне пока нет — но CLI-клиенты ghstack и spr работают и на них.</p><h2>Что делать прямо сейчас</h2><p>Если ваша команда регулярно сталкивается с ревью на 1500+ строк, PR, которые висят неделями, или большими диффами от ИИ-ассистентов — <a href="https://github.github.com/gh-stack/">встаньте в waitlist</a>, поставьте CLI gh extension install github/gh-stack и подготовьтесь к следующей крупной задаче. Пока ждёте активации — попробуйте разбить текущую большую задачу руками через последовательные PR с правильными base-ветками: это работает и в обычном GitHub, а CLI потом сделает то же самое автоматически.</p><p>Если вы уже на Graphite и довольны — переезд имеет смысл после выхода фичи из Private Preview и появления миграционного сценария. Небольшим командам с PR на 200 строк фича пока не нужна: инвестиции в стэки окупаются там, где большие задачи — частая история.</p><p>Нативная поддержка закрывает больную для крупных команд зону: большие изменения теперь можно разбивать без костылей, а ревью — делать по смыслу, а не по количеству строк.</p><p><b>Источники:</b> <a href="https://github.github.com/gh-stack/">официальный анонс GitHub Stacked PRs</a>, <a href="https://github.com/github/gh-stack">репозиторий CLI-расширения</a>, <a href="https://news.ycombinator.com/item?id=47757495">обсуждение на Hacker News</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub Trending недели: Hermes-агент от NousResearch, on-device ML от Google и опенсорсный Screen Studio</title>
      <link>https://tproger.ru/digest/github-trending-nedeli-gemma-agent-ot-nousresearch-on-device-m</link>
      <comments>https://tproger.ru/digest/github-trending-nedeli-gemma-agent-ot-nousresearch-on-device-m?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/digest/github-trending-nedeli-gemma-agent-ot-nousresearch-on-device-m</guid>
      <description><![CDATA[<p>Hermes Agent с памятью, OpenScreen вместо Screen Studio, TimesFM от Google и ещё 6 опенсорс-проектов с топа GitHub Trending за неделю с 3 по 10 апреля.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/digest/github-trending-nedeli-gemma-agent-ot-nousresearch-on-device-m">GitHub Trending недели: Hermes-агент от NousResearch, on-device ML от Google и опенсорсный Screen Studio</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Ретроперспектива недели]]></category>
      <category><![CDATA[Подборки]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 10 Apr 2026 14:45:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если у вас не хватает времени следить за Trending-страницей вручную — мы собрали подборку самых популярных опенсорс-проектов недели с 3 по 10 апреля 2026 года. Подборка — для тех, кто хочет быстро понять, куда сейчас смотрит комьюнити, что стоит добавить в закладки, а что — запустить на выходных.</p><p>Источник — официальная <a href="https://github.com/trending?since=weekly">страница Trending</a>. Сортировка по количеству звёзд за неделю. Для каждого проекта — что это, кому полезно и стоит ли тратить время.</p><ul><li><b>Hermes Agent</b> (NousResearch) — +19,7 тыс. звёзд за неделю, фреймворк для LLM-агентов с долговременной памятью</li><li><b>OpenScreen</b> — +12,2 тыс., опенсорсная альтернатива Screen Studio без водяных знаков и подписок</li><li><b>TimesFM</b> (Google Research) — +3,1 тыс., foundation-модель для временных рядов, zero-shot forecasting</li><li><b>Multica</b> — +3,2 тыс., платформа управления командами кодинг-агентов</li><li><b>Gallery</b> (Google AI Edge) — +4,3 тыс., демо-приложение on-device ML и GenAI на Android</li><li><b>DeepTutor</b>, <b>LiteRT-LM</b>, <b>PersonaPlex</b>, <b>Onyx</b> — остальные заметные проекты недели</li></ul><h2>NousResearch / hermes-agent — агент с долговременной памятью</h2><p>⭐ 49 247, <b>+19 765 за неделю</b> · Python · <a href="https://github.com/NousResearch/hermes-agent">github.com/NousResearch/hermes-agent</a></p><p>NousResearch — команда, известная по серии открытых моделей Hermes на базе Mistral и Llama, — выпустила собственный фреймворк для LLM-агентов с акцентом на долговременную память и персонализацию. Слоган проекта — «The agent that grows with you»: агент накапливает контекст о пользователе между сессиями, учится на взаимодействиях и адаптирует поведение.</p><p>Зачем смотреть: если вы строите ассистента, который должен помнить историю работы с конкретным пользователем, — Hermes Agent предлагает готовую механику memory layer без привязки к облачной модели. Работает с open-weights моделями серии Hermes, но архитектура позволяет подключать и другие LLM.</p><h2>siddharthvaddem / openscreen — опенсорсный Screen Studio</h2><p>⭐ 27 315, <b>+12 278 за неделю</b> · TypeScript · <a href="https://github.com/siddharthvaddem/openscreen">github.com/siddharthvaddem/openscreen</a></p><p>Единственный не-ИИ проект в топе недели. OpenScreen — опенсорсная альтернатива Screen Studio, инструмента для записи красивых демо (плавные переходы, zoom-эффекты, курсор-акценты, автоматические скругления). Без подписок, без водяных знаков, лицензия позволяет использовать коммерчески.</p><p>Зачем смотреть: если вы делаете видео-туториалы, демо для лендингов продукта или онбординги, хороший скринкаст сильно повышает воспринимаемое качество. Screen Studio стоит $29 в месяц по подписке — OpenScreen закрывает базовые сценарии бесплатно. Это нативное десктоп-приложение на Electron (Mac, Windows, Linux).</p><h2>onyx-dot-app / onyx — открытая ИИ-платформа для чата</h2><p>⭐ 26 299, <b>+5 556 за неделю</b> · Python · <a href="https://github.com/onyx-dot-app/onyx">github.com/onyx-dot-app/onyx</a></p><p>Ещё один open-source конкурент платным ChatGPT-подобным интерфейсам. Onyx — ИИ-чат с поддержкой любой LLM через провайдер-абстракцию, RAG по загруженным документам, поддержкой плагинов и корпоративными фичами (SSO, аудит, разделение доступа). Позиционируется как замена OpenAI-подобным сервисам для команд, которым важно контролировать данные.</p><p>Зачем смотреть: если у вас стоит задача развернуть корпоративный чат-интерфейс с подключением к собственным документам и запретом утечки данных наружу — Onyx закрывает большую часть требований без покупки Enterprise-лицензии у вендора.</p><h2>google-ai-edge / gallery — демо on-device ML для Android</h2><p>⭐ 20 072, <b>+4 326 за неделю</b> · Kotlin · <a href="https://github.com/google-ai-edge/gallery">github.com/google-ai-edge/gallery</a></p><p>Официальное приложение-галерея от команды Google AI Edge. Показывает живые примеры on-device ML и GenAI-кейсов: генерация текста, классификация изображений, перевод речи, всё локально на устройстве без отправки данных в облако. В последней версии приложение работает на открытых моделях Gemma, используя LiteRT (бывший TensorFlow Lite) и MediaPipe как runtime. Доступно и на Android, и на iOS.</p><p>Зачем смотреть: если вы Android-разработчик и хотите добавить в приложение GenAI-фичу, которая не требует интернета — это проще всего запустить и изучить код. В подборке — готовые примеры того, что уже работает на флагманских Pixel и Samsung устройствах.</p><h2>multica-ai / multica — платформа для команд кодинг-агентов</h2><p>⭐ 5 140, <b>+3 201 за неделю</b> · TypeScript · <a href="https://github.com/multica-ai/multica">github.com/multica-ai/multica</a></p><p>Проект адресует проблему, которую начали обсуждать в последние месяцы: как управлять парком из нескольких ИИ-агентов, которым вы делегируете задачи параллельно. Multica — это оркестратор: вы назначаете задачи разным агентам, отслеживаете прогресс, а агенты обмениваются знаниями через общий контекст.</p><p>Зачем смотреть: если вы уже используете кодинг-агентов и чувствуете, что один агент превратился в узкое место, — идея запустить несколько параллельно с общей координацией может освободить время. Проект пока сырой — используйте как референс архитектуры.</p><h2>HKUDS / DeepTutor — агент-преподаватель</h2><p>⭐ 15 552, <b>+3 233 за неделю</b> · Python · <a href="https://github.com/HKUDS/DeepTutor">github.com/HKUDS/DeepTutor</a></p><p>Проект от Data Intelligence Lab Университета Гонконга (HKU). «Agent-Native Personalized Learning Assistant» — ИИ-репетитор, который подстраивает объяснения под конкретного ученика: учитывает уровень знаний, стиль обучения и прошлые заблуждения. Открытый исходный код, документированный, с примерами использования в разных образовательных сценариях.</p><p>Зачем смотреть: если вы делаете EdTech-продукт или просто хотите построить себе персонального тьютора по новой теме — можно взять за основу. Особенно интересен механизм памяти ученика, которая не просто хранит историю диалогов, а формирует «модель ученика».</p><h2>google-research / timesfm — foundation-модель для временных рядов</h2><p>⭐ 16 158, <b>+3 095 за неделю</b> · Python · <a href="https://github.com/google-research/timesfm">github.com/google-research/timesfm</a></p><p>TimesFM (Time Series Foundation Model) — предобученная модель от Google Research для прогнозирования временных рядов, аналог GPT/LLaMA, но для числовых последовательностей. Zero-shot: можно передать свою серию данных без дообучения и получить прогноз на N шагов вперёд.</p><p>Зачем смотреть: если вы работаете с прогнозированием метрик (посещаемость, продажи, нагрузка на сервис) — обычно приходится обучать отдельную модель под каждую задачу. TimesFM позволяет попробовать foundation-подход: одна модель, любой ряд, никакого fine-tuning. Для продакшена может быть рано, для R&amp;D — удобно.</p><h2>NVIDIA / personaplex — speech-to-speech модель с контролем персоны</h2><p>⭐ 8 853, <b>+2 745 за неделю</b> · Python · <a href="https://github.com/NVIDIA/personaplex">github.com/NVIDIA/personaplex</a></p><p>На самом деле это не про аватары, как можно подумать по названию. PersonaPlex — full-duplex speech-to-speech conversational модель от NVIDIA на базе архитектуры Moshi (разработка Kyutai). Главная фича — управление персоной ассистента через текстовые промпты ролей и audio-кондишенинг голоса. Репозиторий даёт рабочий инференс-сервер, веса лежат на Hugging Face.</p><p>Зачем смотреть: если вы строите голосового ассистента и хотите, чтобы он разговаривал не дежурным TTS-голосом, а с узнаваемой персоной — PersonaPlex показывает, как это делается на уровне модели, а не на уровне промптов. Low-latency интерактив в стиле Moshi уже из коробки.</p><h2>google-ai-edge / LiteRT-LM — runtime для локальных LLM на edge</h2><p>⭐ 3 260, <b>+2 157 за неделю</b> · C++ · <a href="https://github.com/google-ai-edge/LiteRT-LM">github.com/google-ai-edge/LiteRT-LM</a></p><p>Второй проект Google AI Edge в подборке. LiteRT-LM — это runtime (время выполнения) для запуска LLM на edge-устройствах: мобильные телефоны, embedded-железо, IoT. Продолжение линии LiteRT (бывший TensorFlow Lite), но с акцентом именно на большие языковые модели.</p><p>Зачем смотреть: если вы хотите запускать 3–7B модель локально на телефоне или Raspberry Pi и вам надоело разбираться с llama.cpp под каждую архитектуру — LiteRT-LM предлагает единый runtime с поддержкой Google-оптимизаций под мобильные чипсеты.</p><h2>Что можно брать в работу прямо сегодня</h2><p>Из девяти проектов подборки три — от Google (Gallery, LiteRT-LM, TimesFM). Компания явно толкает on-device ML и foundation-модели для едж-устройств. Четыре проекта — про ИИ-агентов (Hermes, Multica, DeepTutor, Onyx): агентский слой окончательно перекочевал из ресёрча в рабочий инструментарий.</p><p>Если нужно выбрать что-то одно на этот уикенд — возьмите OpenScreen: он работает прямо сейчас, решает конкретную задачу и не требует погружения в теорию агентов. А если вы строите что-то с памятью и персонализацией — Hermes Agent заслуживает как минимум получаса внимания.</p><p>Источник: <a href="https://github.com/trending?since=weekly">GitHub Trending</a> на 10 апреля 2026 года. Числа звёзд актуальны на момент публикации.</p>]]></content:encoded>
    </item>
    <item>
      <title>Франкенштейн в медицине: как я скрестил ViT и ruGPT-3, чтобы научить ИИ читать рентген на русском</title>
      <link>https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau</link>
      <comments>https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[максим митин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau</guid>
      <description><![CDATA[<p>Практический кейс: создание русскоязычной мультимодальной нейросети (Vision-Language) для анализа рентгеновских снимков. Скрещиваем ViT и ruGPT-3, решаем проблемы с датасетами на Kaggle и выкатываем ИИ в продакшн на Hugging Face. Открытый код на Python.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/frankenwtejn-v-medicine--kak-ya-skrestil-vit-i-rugpt-3--chtoby-nau">Франкенштейн в медицине: как я скрестил ViT и ruGPT-3, чтобы научить ИИ читать рентген на русском</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Сбер]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[GPU]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 05 Apr 2026 06:30:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сейчас из каждого утюга рассказывают про мультимодальные нейросети: GPT-4o смотрит через камеру, Gemini анализирует видео. В медицине тоже есть крутые открытые ИИ-модели для анализа снимков (например, на базе датасетов MIMIC-CXR), но у них всех есть один фатальный недостаток для нашего рынка — они говорят исключительно на английском.</p><p>Мне стало интересно: а можно ли на бесплатных мощностях, буквально "на коленке", собрать русскоязычного ИИ-рентгенолога? Спойлер: можно. В этой статье расскажу, как я скрестил Vision Transformer от Google с ruGPT-3 от Сбера, как боролся с датасетами на Kaggle и что из этого вышло. В конце — ссылки на GitHub и рабочее демо.</p><h2>Архитектура: как пришить глаза к мозгу</h2><p>Чтобы нейросеть могла посмотреть на снимок и написать текст, нужна архитектура Vision-Language Model. Обучать такого монстра с нуля у меня не было ни ресурсов, ни желания. Поэтому я пошел по пути Hugging Face VisionEncoderDecoderModel.</p><p>Идея проста как кирпич:</p><ol><li>Энкодер (Глаза): Берем предобученный google/vit-base-patch16-224-in21k. Он отлично дробит картинку на патчи и извлекает визуальные фичи (понимает, где ребра, а где легкие).</li><li>Декодер (Язык): Берем ai-forever/rugpt3small_based_on_gpt2. У нее нет глаз, она умеет только генерировать текст.</li></ol><p>Чтобы их сшить, пришлось немного "взломать" конфиг ruGPT-3, принудительно сказав ей: «Теперь ты декодер, и у тебя есть слои кросс-внимания» (is_decoder=True, add_cross_attention=True). Hugging Face заботливо создал новые пустые веса между двумя моделями. Именно эти связи мне и предстояло обучить.</p><h2>Data Engineering: боль, страдания и Kaggle</h2><p>Найти 7-10 тысяч рентгеновских снимков с подробными заключениями на русском языке в открытом доступе — задача нереальная.</p><p>Поэтому я взял открытый американский датасет Indiana University Chest X-Ray (IU X-Ray). Там есть картинки и тексты от американских врачей.</p><p>Прямо на Kaggle я поднял пайплайн машинного перевода на базе Helsinki-NLP/opus-mt-en-ru. Закинул тексты в GPU батчами по 32 штуки и за 10 минут перевел более 7000 медицинских заключений на вполне сносный русский медицинский язык.</p><p>Но тут платформа подкинула сюрприз: Kaggle прячет часть файлов в виртуальной файловой системе (снимков 7000, а стандартный скрипт видел только 4). Пришлось писать суровый маппинг с глубоким сканированием (os.walk), отрезать расширения и жестко связывать ID в CSV с реальными путями на диске.</p><h2>Обучение: выжимаем все соки из бесплатных T4</h2><p>Обучение проходило на Kaggle (2x NVIDIA T4). Чтобы модель не умерла от нехватки памяти (OOM), а сессия не отвалилась по тайм-ауту, пришлось шаманить:</p><ul><li>Включил Mixed Precision (fp16) — ускорило обучение в 2 раза.</li><li>Настроил Gradient Accumulation — размер батча на видеокарту был всего 4, но виртуально мы накапливали до 16.</li><li>Столкнулся с тем, что Seq2SeqTrainer крашится при попытке сохранить промежуточный чекпоинт мультимодального "франкенштейна". Решение? Выключить промежуточные сохранения (save_strategy="epoch") и молиться, чтобы Kaggle не завис. (Кстати, спасает JS-скрипт в консоли браузера, делающий клик раз в 60 секунд).</li></ul><p>На 15 эпох ушло около 2.5 часов.</p><h2>Что получилось в итоге? (Потрогать руками)</h2><p>Получилась нейросеть, которая реально понимает, что изображено на рентгене, и сыпет терминами вроде «кальцифицированная гранулема» или «легочная васкулярность». Да, иногда она "галлюцинирует" (датасет в 7к снимков — это капля в море для ML), но базовые вещи вроде чистых легких или пневмоторакса сечет неплохо.</p><p>Я завернул модель в Gradio и выложил на Hugging Face Spaces. Можно зайти с телефона или ПК, загрузить любой снимок рентгена из гугла и посмотреть, что она выдаст.</p><p>👉 Потыкать лайв-демо тут: <a rel="noopener noreferrer" href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Fhuggingface.co%2Fspaces%2Flivadies%2FAI-Radiologist-RU">Hugging Face Space</a></p><p>👉 Весь код, пайплайны и веса тут: <a rel="noopener noreferrer" href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Fgithub.com%2Flivadies-collab%2FMultimodal-XRay-Analyzer-RU">GitHub Репозиторий</a></p><p>Буду рад, если кому-то этот код сэкономит время при создании своих мультимодальных сеток. Залетайте в репу, ставьте звездочки, форкайте. Если есть идеи, как улучшить датасет (может, прогнать переводы через LLM для чистки медицинского сленга) — пишите в комменты!</p><p>(Дисклеймер: модель обучена в исследовательских целях за вечер. Не суйте ей свои снимки вместо похода к реальному врачу)</p>]]></content:encoded>
    </item>
    <item>
      <title>LinkedIn тайно сканирует компьютеры пользователей и передаёт данные третьим сторонам — расследование BrowserGate</title>
      <link>https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan</link>
      <comments>https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan</guid>
      <description><![CDATA[<p>Расследование BrowserGate: LinkedIn сканирует ПО и расширения, выявляя религию и поиск работы. Данные уходят третьим сторонам. Подробности и как защититься.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/linkedin-tajno-skaniruet-kompyutery-polzovatelej-i-peredayot-dan">LinkedIn тайно сканирует компьютеры пользователей и передаёт данные третьим сторонам — расследование BrowserGate</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Юмор]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 14:25:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ассоциация коммерческих пользователей LinkedIn — <a href="https://browsergate.eu/">Fairlinked e.V.</a> — опубликовала расследование под названием BrowserGate. Согласно их данным, LinkedIn тайно сканирует компьютеры пользователей, определяя установленное ПО и передаёт результаты третьим сторонам.</p><p>Каждый раз, когда любой из миллиарда пользователей LinkedIn заходит на сайт, скрытый код проверяет, какие программы и расширения браузера установлены на компьютере. Результаты отправляются на серверы LinkedIn и третьим компаниям, включая американо-израильскую фирму HUMAN Security (ранее PerimeterX). Пользователя не предупреждают и не спрашивают согласия.</p><ul><li>LinkedIn тайно сканирует установленное ПО на компьютерах пользователей при каждом визите на сайт</li><li>Сканирование выявляет религиозные убеждения, политические взгляды, инвалидность и поиск работы — через расширения браузера</li><li>LinkedIn определяет более 6000 продуктов, включая 200+ конкурирующих инструментов продаж</li><li>Данные передаются третьим сторонам без уведомления и согласия</li><li>По мнению исследователей, это нарушает GDPR и может быть уголовным преступлением в ЕС</li></ul><h2>Что именно сканирует LinkedIn</h2><p>По данным расследования, LinkedIn сканирует расширения браузера, которые раскрывают чувствительную информацию о пользователях:</p><ul><li>Религиозные убеждения — расширения для практикующих мусульман</li><li>Политическая ориентация — расширения, связанные с политическими предпочтениями</li><li>Нейроотличность — расширения для пользователей с СДВГ, аутизмом и другими особенностями</li><li>Поиск работы — 509 инструментов для поиска вакансий, которые выдают тех, кто тайно ищет новое место</li></ul><p>Поскольку LinkedIn знает реальное имя, работодателя и должность каждого пользователя, это не анонимное сканирование — это сбор данных о конкретных людях в конкретных компаниях.</p><h2>Корпоративный шпионаж: сканирование конкурентов</h2><p>LinkedIn сканирует более 200 продуктов, напрямую конкурирующих с его собственными инструментами продаж — Apollo, Lusha, ZoomInfo и другие. Зная работодателя каждого пользователя, платформа может составить карту: какие компании используют какие конкурирующие продукты.</p><p>По утверждению исследователей, LinkedIn уже использует эти данные — отправляет угрозы пользователям сторонних инструментов, идентифицируя их через скрытое сканирование. Список сканируемых продуктов вырос с около 461 в 2024 году до более чем 6000 к февралю 2026 года.</p><h2>Обман европейских регуляторов</h2><p>В 2023 году ЕС признал LinkedIn регулируемым гейткипером по Digital Markets Act и обязал открыть платформу для сторонних инструментов. LinkedIn опубликовал два ограниченных API, обрабатывающих около 0,07 запросов в секунду. При этом внутренний API Voyager, на котором работают все продукты LinkedIn, обрабатывает 163 000 запросов в секунду.</p><p>В 249-страничном отчёте Microsoft для Еврокомиссии слово «API» встречается 533 раза. Слово «Voyager» — ноль раз.</p><blockquote>ЕС потребовал от LinkedIn впустить сторонние инструменты. LinkedIn построил систему слежки, чтобы находить и наказывать каждого пользователя этих инструментов.</blockquote><h2>Передача данных третьим сторонам</h2><p>LinkedIn загружает невидимый трекинговый элемент от HUMAN Security — нулевой ширины, скрытый за пределами экрана — который устанавливает куки без ведома пользователя. Отдельный скрипт фингерпринтинга работает с серверов LinkedIn. Третий скрипт от Google выполняется молча при каждой загрузке страницы. Всё зашифровано. Ничего не раскрыто в политике конфиденциальности.</p><p><b>Важный контекст:</b> сканирование расширений браузера — известная техника борьбы с ботами и мошенничеством. HUMAN Security (PerimeterX) — именно anti-bot компания. LinkedIn может аргументировать, что сканирование нужно для защиты платформы. Расследование Fairlinked e.V. представляет одну сторону — независимая верификация их утверждений пока не проводилась.</p><h2>Правовые последствия</h2><p>Исследователи утверждают, что действия LinkedIn нарушают GDPR, поскольку сканирование выявляет данные особых категорий (религия, политика, здоровье) без согласия и без правовой основы. По законодательству ЕС такие данные не просто регулируются — их обработка запрещена без явного согласия.</p><p>Fairlinked e.V. собирает доказательную базу и средства для судебного разбирательства. На момент публикации Microsoft и LinkedIn не прокомментировали расследование.</p><h2>Выводы</h2><p>Расследование BrowserGate — одно из крупнейших обвинений в корпоративном шпионаже в истории веба. Если данные подтвердятся, LinkedIn и Microsoft могут столкнуться с серьёзными штрафами по GDPR и Digital Markets Act.</p><p><a href="https://browsergate.eu/">Полное расследование</a> и доказательная база доступны на сайте BrowserGate.</p>]]></content:encoded>
    </item>
    <item>
      <title>ASPA — как новый стандарт проверяет путь интернет-трафика и защищает от утечек маршрутов</title>
      <link>https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi</link>
      <comments>https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi</guid>
      <description><![CDATA[<p>Как ASPA дополняет RPKI/ROA, проверяя не только пункт назначения, но и весь путь трафика. Перевод статьи Cloudflare о новом стандарте безопасности BGP.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/aspa---kak-novyj-standart-proveryaet-put-internet-trafika-i-zashhi">ASPA — как новый стандарт проверяет путь интернет-трафика и защищает от утечек маршрутов</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[смарт-контракты]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 12:37:12 GMT</pubDate>
      <content:encoded><![CDATA[<p>Это перевод с адаптацией <a href="https://blog.cloudflare.com/aspa-secure-internet/">статьи</a> Mingwei Zhang и Bryton Herdes из блога <a href="https://blog.cloudflare.com/">Cloudflare</a>.</p><p>BGP (Border Gateway Protocol) — протокол, по которому автономные системы (AS) обмениваются информацией о маршрутах. Автономная система — это сеть под управлением одного оператора: провайдера, облачной платформы, крупной компании. Когда вы открываете сайт, трафик проходит через цепочку таких AS. Но иногда он уходит не туда — из-за ошибок конфигурации или злонамеренных действий. Такие инциденты называются утечками маршрутов (route leaks). Новый криптографический стандарт ASPA (Autonomous System Provider Authorization) призван решить эту проблему — он проверяет не только пункт назначения, но и весь путь трафика.</p><ul><li>ASPA — новый стандарт криптографической проверки маршрутов BGP, дополняющий существующий RPKI/ROA</li><li>ROA проверяет пункт назначения трафика, ASPA проверяет путь — цепочку сетей, через которые он проходит</li><li>ASPA обнаруживает утечки маршрутов, проверяя, что трафик движется по «горной» модели: вверх к провайдеру, через пиринг, вниз к получателю</li><li>Создать ASPA-запись можно за пару кликов в RIPE или ARIN</li><li>Cloudflare Radar теперь отслеживает глобальное внедрение ASPA в реальном времени</li></ul><h2>Как сейчас защищён BGP: RPKI и ROA</h2><p>Сегодня сети используют инфраструктуру <a href="https://blog.cloudflare.com/rpki/">RPKI</a> (Resource Public Key Infrastructure), внедрение которой значительно выросло за последние годы. В рамках RPKI сети публикуют криптографические записи — ROA (Route Origin Authorizations). ROA — это верифицируемое цифровое удостоверение, подтверждающее, что конкретная автономная система (AS) авторизована анонсировать определённые IP-адреса. Это решает проблему origin hijacks — когда одна сеть выдаёт себя за другую.</p><p>Но ROA проверяет только пункт назначения. А что насчёт пути?</p><h2>Что такое ASPA и как он работает</h2><p>ASPA (Autonomous System Provider Authorization) надстраивается над RPKI. Если ROA проверяет <b>куда</b> идёт трафик, то ASPA проверяет <b>как</b> он туда добирается.</p><p>Когда данные путешествуют по интернету, каждая сеть на пути записывается в лог — AS_PATH. ASPA позволяет сетям официально публиковать список авторизованных апстрим-провайдеров в системе RPKI. Любая принимающая сеть может посмотреть на AS_PATH, проверить ASPA-записи и убедиться, что трафик прошёл только через одобренную цепочку сетей.</p><h3>Модель «горы»: как устроена здоровая маршрутизация</h3><p>В нормальной топологии (valley-free routing) трафик движется по «горной» модели:</p><ol><li><b>Подъём (Up-Ramp)</b> — трафик идёт от клиента вверх через всё более крупных провайдеров (ISP)</li><li><b>Вершина (Apex)</b> — на уровне магистрали трафик может пересечь один пиринговый линк</li><li><b>Спуск (Down-Ramp)</b> — трафик спускается через провайдеров к получателю</li></ol><p>Один из типов утечки — «долина» в этой модели. Она происходит, когда трафик спускается к клиенту и неожиданно пытается снова подняться к другому провайдеру. Клиентские сети не предназначены для транзита трафика между крупными провайдерами.</p><h3>Как ASPA валидирует маршруты</h3><p>ASPA проверяет цепочку отношений с обоих концов маршрута:</p><ol><li><b>Проверка подъёма</b> — начинаем от источника и двигаемся вперёд. На каждом хопе спрашиваем: «Авторизовала ли эта сеть следующую как своего провайдера?»</li><li><b>Проверка спуска</b> — то же самое, но в обратном направлении от получателя BGP-обновления</li></ol><p>Если «подъём» и «спуск» встречаются или пересекаются на вершине — маршрут <b>валидный</b>. Форма горы сохранена.</p><p>Если пути не сходятся и в середине есть разрыв — ASPA отмечает маршрут как проблемный. Этот разрыв и есть «долина», то есть утечка.</p><h3>Пример: обнаружение утечки маршрута</h3><p>Допустим, сеть AS65539 получает подозрительный маршрут от клиента AS65538. Клиент пытается отправить трафик, полученный от одного провайдера (AS65537), «вверх» к другому провайдеру (AS65539) — действуя как мост между провайдерами. Это классическая утечка маршрута.</p><p>Процесс валидации ASPA:</p><ol><li>Проверяем подъём: источник (AS65536) авторизует своего провайдера — проверка пройдена</li><li>Проверяем спуск: начинаем от получателя и смотрим назад — видим клиента (AS65538)</li><li>Несовпадение: подъём заканчивается на AS65537, спуск — на AS65538. Пути не соединяются</li></ol><p>Результат: маршрут отмечен как <b>ASPA Invalid</b>. Без подписанных ASPA-объектов в RPKI невозможно определить, какие сети авторизованы анонсировать префиксы горизонтально (пирам) или вверх (провайдерам).</p><h2>ASPA против forged-origin hijacks</h2><p>ASPA эффективно защищает от forged-origin hijacks — атак, при которых злоумышленник обходит проверку ROV: он анонсирует реальный IP-префикс с правильным origin AS, но вставляет себя в AS_PATH как промежуточный хоп. ROV это не замечает, так как проверяет только origin. Источник формально правильный, но связь между атакующим и жертвой — сфабрикована.</p><p>ASPA разоблачает это: сеть-жертва криптографически объявляет своих реальных провайдеров, и поскольку атакующий не входит в этот список, маршрут отклоняется.</p><p><b>Ограничение:</b> ASPA не защищает от всех случаев. Провайдер может подделать пиринговый линк с другой AS, чтобы привлечь трафик клиента коротким AS_PATH, даже если такого пирингового линка в реальности не существует. ASPA работает только с информацией о провайдерах и ничего не знает о пиринговых отношениях.</p><h2>Как создать ASPA-запись: пара кликов</h2><p>Создание ASPA-объекта для вашей сети стало простым в реестрах <a href="https://www.ripe.net/">RIPE</a> и <a href="https://www.arin.net/">ARIN</a>. Всё, что нужно — ваш номер AS и номера AS ваших провайдеров, у которых вы покупаете транзит. В обратном направлении это сети, которым вы разрешаете присылать полную таблицу маршрутизации — карту достижимости остального интернета.</p><p>Пример Cloudflare: для AS203898 (офис в Лондоне) с тремя интернет-провайдерами (AS8220, AS2860, AS1273) процесс занимает три шага:</p><ol><li>Войти в RPKI-дашборд RIPE и перейти в раздел ASPA</li><li>Нажать «Create ASPA» для нужного AS</li><li>Указать список провайдеров</li></ol><p>Через короткое время ASPA-запись появляется в глобальной RPKI-экосистеме.</p><p>Отдельный случай — запись с <b>AS0</b> в качестве провайдера. Это означает, что у сети нет апстрим-провайдеров. По определению, каждая транзитно-свободная сеть Tier-1 в будущем должна будет подписать ASPA только с «AS0» — если у неё действительно только пиринговые и клиентские отношения.</p><h2>Мониторинг ASPA в Cloudflare Radar</h2><p><a href="https://radar.cloudflare.com/">Cloudflare Radar</a> добавил новые возможности мониторинга внедрения ASPA:</p><ul><li>Графики роста внедрения ASPA по пяти региональным реестрам (RIR)</li><li>Интеграция ASPA-данных в страницы маршрутизации по странам и ASN</li><li>Для каждой AS — список провайдеров из ASPA-объекта, проверка BGP-апстримов и история изменений</li></ul><h2>Что нужно для полного внедрения ASPA</h2><p>ASPA — это криптографический фундамент для валидации путей. Но, как показал опыт RPKI/ROA, внедрение займёт время. Необходимы обновления:</p><ul><li>RPKI Relying Party (RP) — программы проверки криптографических записей</li><li>RTR (RPKI-to-Router protocol) — протокол передачи данных маршрутизаторам</li><li>BGP-реализации на маршрутизаторах — для валидации путей с использованием ASPA</li></ul><p>Помимо создания ASPA-записей, операторам рекомендуется настроить <b>BGP roles</b> (<a href="https://www.rfc-editor.org/rfc/rfc9234">RFC 9234</a>). BGP roles привязывают предполагаемые отношения между AS к конкретным BGP-сессиям, помогая ASPA определить, какой алгоритм валидации применять — для апстрима или даунстрима. Уточните у своих вендоров оборудования, поддерживают ли они BGP roles и атрибут OTC (Only-to-Customer).</p><blockquote>Управление ASPA-записями не отличается от управления ROA. В будущем, когда сети начнут активно блокировать невалидные пути, пропуск легитимного провайдера может привести к потере трафика. Но это тот же риск, который операторы уже научились контролировать.</blockquote><h2>Выводы</h2><p>ASPA — следующий логичный шаг в безопасности интернет-маршрутизации после RPKI/ROA. Если ROA закрепил за каждой AS право анонсировать свои IP-адреса, то ASPA закрепляет право на транзит — описывает авторизованный путь трафика.</p><p>Для операторов сетей: <a href="https://radar.cloudflare.com/">проверьте в Cloudflare Radar</a>, есть ли у вашей AS ASPA-запись, и создайте её в RIPE или ARIN. Чем больше сетей подпишут ASPA, тем быстрее стандарт начнёт реально блокировать утечки маршрутов.</p>]]></content:encoded>
    </item>
    <item>
      <title>Переосмысление пулл-реквестов: почему code review должен учить, а не только ловить баги</title>
      <link>https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--</link>
      <comments>https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--</guid>
      <description><![CDATA[<p>Как стековые PR, приоритет файлов в диффе и единая страница ревью сокращают comprehension debt. Перевод статьи создателя Lubeno о будущем code review.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/pereosmyslenie-pull-rekvestov--pochemu-code-review-dolzhen-uchit--">Переосмысление пулл-реквестов: почему code review должен учить, а не только ловить баги</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Организация разработки]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Apr 2026 12:28:46 GMT</pubDate>
      <content:encoded><![CDATA[<p>Это перевод с адаптацией <a href="https://lubeno.dev/blog/reinventing-the-pull-request">статьи</a> Bernard Kolobara, автора платформы <a href="https://lubeno.dev">Lubeno</a>.</p><p>Пулл-реквесты задумывались как инструмент для совместной работы над кодом. На практике они превратились в бюрократическую процедуру: гигантские диффы, комментарии в разных вкладках, коллапсированные «outdated»-ветки обсуждений. Bernard Kolobara считает, что проблема не в самой идее code review, а в инструментах — и предлагает конкретные решения.</p><ul><li>Comprehension debt (долг понимания) — главная проблема, которую должен решать code review, а не только ловля багов</li><li>Стековые пулл-реквесты: разбиение изменений на мелкие самодостаточные коммиты, которые ревьюятся независимо</li><li>Приоритет файлов: тесты и зависимости показываются первыми в диффе через .gitattributes</li><li>Всё на одной странице: код и обсуждение вместе, без вкладок</li><li>ИИ не убил code review — он обнажил хрупкость инструментов, которые не справляются с растущим объёмом кода</li></ul><h2>Comprehension debt: долг понимания кода</h2><p>Addy Osmani <a href="https://addyosmani.com/blog/comprehension-debt/">описал</a> comprehension debt как разрыв между объёмом кода в проекте и тем, сколько из этого кода команда реально понимает. Чем больше разрыв — тем медленнее работа. Проектировать систему, которую полностью понимаешь, проще, чем ту, которую «примерно знаешь». С появлением ИИ-агентов в рабочих процессах этот разрыв значительно вырос.</p><p>Paul Graham в эссе <a href="https://paulgraham.com/greatwork.html">о великой работе</a> пишет, что лучшие идеи приходят вне клавиатуры — на прогулке, в душе, перед сном. Но для этого «фонового процессинга» нужно, чтобы контекст проекта уже был в голове. Сначала нужна осознанная работа с кодом.</p><p>Code review — идеальный момент для сокращения этого разрыва. Каждый ревью — возможность узнать, как кодовая база развивается, каковы её границы и ограничения. Не обязательно проверять каждую строку дифа — достаточно понять ключевые части, чтобы обновить ментальную модель. Ловля багов — лишь <a href="https://www.davidpoll.com/2026/02/code-review-is-not-about-catching-bugs">одна часть</a> ценности ревью.</p><h2>Как сократить разрыв: конкретные решения</h2><h3>Стековые пулл-реквесты</h3><p>Разбить большой PR на маленькие — самый эффективный способ помочь ревьюеру. В теории для этого подходят коммиты: каждый — самодостаточная единица, <a href="https://youtu.be/GOrKfCs-mr0?si=SWndwJF0IWOF-SG7&amp;t=102">рассказывающая историю</a>. На практике это не работает из-за Git.</p><p>Git заточен под append-only workflow. Вернуться в старый коммит и отредактировать его — мучительно. Даже если вы аккуратно структурировали историю, рано или поздно появляется серия коммитов «fix», «actual fix», «ok now really fix». Когда смотришь на отдельный коммит, не видишь полной картины — правки могут быть размазаны по нескольким коммитам дальше по истории.</p><p>Bernard и его коллега Luísa решают эту проблему с помощью <a href="https://docs.jj-vcs.dev/latest/">Jujutsu</a> — VCS, которая позволяет прыгнуть в любой коммит и отредактировать его на месте, а затем автоматически пропагирует изменения через всю историю. Это позволяет «вылепить» идеальную историю коммитов.</p><p>В Lubeno стековые PR детектятся автоматически. Каждый PR показывается как дифф относительно родительского PR — ревью и одобрение идут независимо. Автор не ждёт, пока предыдущий PR смёржат, и может продолжать работу.</p><h3>Приоритет файлов в диффе</h3><p>При ревью автор первым делом смотрит тесты: были ли изменены существующие, тестируют ли новые что-то полезное. Затем — зависимости: добавляется ли новая и зачем. Но все платформы для code review показывают файлы в алфавитном порядке — важные изменения легко пропустить в большом диффе.</p><p>Lubeno использует кастомный атрибут priority в .gitattributes (это не стандартный атрибут Git, а расширение Lubeno):</p><p>Файлы с высоким приоритетом показываются первыми на странице PR. Простое решение, но оно гарантирует, что самые важные изменения вы увидите сразу.</p><h3>Всё на одной странице</h3><p>Почти все платформы для code review разносят комментарии, коммиты и код по разным вкладкам. Автор признаётся: «Я нажимал на вкладку Commits только по ошибке — ни разу намеренно». Обсуждение тесно связано с кодом, но чтобы следить за ним, приходится постоянно скроллить наверх, переключать вкладки и искать нужный фрагмент.</p><p>В Lubeno нет вкладок на странице PR. Код и обсуждение живут в одном месте.</p><h2>Эволюция кода в рамках PR</h2><p>PR — не статичная сущность. Это место для обсуждения и итераций. Знакомая ситуация: вы оставили комментарий, вернулись — и обнаружили несколько новых коммитов, а все ваши комментарии свёрнуты как «outdated». Непонятно, учтены ли ваши замечания, что изменилось с момента вашего последнего просмотра.</p><p>Lubeno отслеживает комментарии к коду и наложение interdiff (разницу между версиями файла в рамках PR): если код был изменён более поздним коммитом (или force push), разница видна прямо в контексте комментария. Не нужно переключаться между вкладками, чтобы понять, что произошло.</p><h2>Будущее пулл-реквестов</h2><p>Некоторые <a href="https://boristane.com/blog/the-software-development-lifecycle-is-dead/">называют</a> PR «реликтом прошлого» и призывают от них отказаться. Автор не согласен: процесс ревью кода сегодня ценнее, чем когда-либо. ИИ не убил code review — он обнажил хрупкость инструментов. Больше строк кода просто сделали их непригодными.</p><p>Code review находится в идеальной точке жизненного цикла: после всей творческой работы и прямо перед продакшном. Это последний шанс разобраться, что именно поедет к пользователям. Если вы хотите создавать продукт, который радует пользователей, вам нужно понимать, что происходит в коде.</p><h2>Выводы</h2><p>Статья Bernard Kolobara — не абстрактные размышления, а описание конкретных решений, реализованных в <a href="https://lubeno.dev">Lubeno</a>. Даже если вы не планируете переходить с GitHub — идеи стековых PR, приоритета файлов и unified-страницы ревью стоит примерить к своему workflow.</p><p>Ключевой тезис: code review — не бюрократия, а инструмент обучения. Каждый ревью должен делать команду чуть умнее, а не просто ставить галочку.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub отключил рекламу Copilot в pull-реквестах после бэклэша — затронуты 11 400 PR</title>
      <link>https://tproger.ru/news/github-otklyuchil-reklamu-copilot-v-pull-rekvestah-posle-beklewa--</link>
      <comments>https://tproger.ru/news/github-otklyuchil-reklamu-copilot-v-pull-rekvestah-posle-beklewa--?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-otklyuchil-reklamu-copilot-v-pull-rekvestah-posle-beklewa--</guid>
      <description><![CDATA[<p>Copilot вставлял промо Raycast в чужие PR без согласия авторов. Более 11 000 PR затронуты. GitHub отключил функцию за сутки. Разбираем инцидент.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-otklyuchil-reklamu-copilot-v-pull-rekvestah-posle-beklewa--">GitHub отключил рекламу Copilot в pull-реквестах после бэклэша — затронуты 11 400 PR</a>»</p>]]></description>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Apr 2026 10:24:39 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub отключил промо-подсказки Copilot в pull-реквестах после того, как разработчики обнаружили рекламу сторонних приложений в более чем 11 400 PR.</p><p><a href="https://www.techspot.com/news/111892-github-disables-copilot-pr-edits-after-ai-quietly.html">TechSpot сообщает</a>: 30 марта австралийский разработчик Зак Мэнсон заметил, что Copilot добавил промо-текст приложения <a href="https://www.raycast.com/">Raycast</a> в pull-реквест коллеги. Поиск по GitHub показал, что аналогичные «подсказки» оказались в тысячах PR. В течение суток руководство GitHub признало проблему и отключило функцию.</p><ul><li>Copilot вставлял промо-подсказки (Raycast и другие инструменты) в PR, которые он не создавал — без согласия авторов</li><li>Более 11 400 pull-реквестов затронуты</li><li>GitHub VP Martin Woodward: «GitHub не размещает и не планирует размещать рекламу»</li><li>Copilot PM Tim Rogers признал: «Это было неправильное решение»</li><li>Функция отключена — промо-подсказки больше не появятся в PR</li></ul><h2>Как обнаружили проблему</h2><p>Зак Мэнсон <a href="https://www.theregister.com/2026/03/30/github_copilot_ads_pull_requests/">рассказал The Register</a>, что коллега использовал Copilot для исправления опечатки в PR. При ревью Мэнсон обнаружил, что ИИ добавил строку:</p><blockquote>Quickly spin up Copilot coding agents from anywhere on your macOS or Windows machine with Raycast.</blockquote><p>Первая реакция — подозрение на компрометацию: повреждённые обучающие данные, prompt injection или маркетинговый эксперимент от Raycast. Дальнейший поиск по GitHub показал масштаб: <b>более 11 400 PR</b> содержали почти идентичные промо-сообщения. Нашлись и подсказки, продвигающие другие инструменты — все вставлены автоматически.</p><p>Больше всего Мэнсона удивило не содержание подсказок, а сам факт: Copilot редактировал чужой контент без согласия. «Я даже не знал, что интеграция GitHub Copilot Review может редактировать описания и комментарии других пользователей», — <a href="https://www.theregister.com/2026/03/30/github_copilot_ads_pull_requests/">написал он</a>.</p><h2>Реакция GitHub: отключение за сутки</h2><p><a href="https://www.microsoft.com/">Microsoft</a>-овский GitHub отреагировал в тот же день. Вице-президент по DevRel Мартин Вудвард <a href="https://x.com/martinwoodward">объяснил в X</a>, что Copilot вставлял «подсказки» в свои собственные PR и раньше — это была задуманная функция. Проблема возникла, когда добавили возможность вызывать Copilot через @-упоминание в чужих PR:</p><blockquote>Когда мы добавили возможность вызывать Copilot в любом PR через @-упоминание, поведение стало неприятным.</blockquote><p>Продукт-менеджер Copilot Тим Роджерс <a href="https://www.techspot.com/news/111892-github-disables-copilot-pr-edits-after-ai-quietly.html">уточнил</a>, что подсказки задумывались как обучающий контент — чтобы разработчики узнавали о новых возможностях агента. Но после бэклэша признал:</p><blockquote>Оглядываясь назад, позволить Copilot вносить изменения в pull-реквесты, написанные людьми, было неправильным решением.</blockquote><p>GitHub отключил промо-подсказки в PR, созданных или затронутых Copilot. Вудвард добавил: «GitHub не размещает и не планирует размещать рекламу».</p><h2>Почему это важно для разработчиков</h2><p>Инцидент выявил три проблемы:</p><ol><li><b>ИИ-агент добавлял контент в чужие PR без согласия</b> — Copilot мог изменять описания и комментарии в PR других пользователей. Многие разработчики не знали об этой возможности</li><li><b>Граница между функцией и рекламой размыта</b> — GitHub позиционировал подсказки как «обучение», но содержимое продвигало конкретные сторонние продукты (Raycast) со ссылками на установку</li><li><b>Доверие к ИИ-инструментам хрупко</b> — достаточно одного инцидента, чтобы разработчики начали отключать Copilot Review. По данным <a href="https://www.techspot.com/news/111892-github-disables-copilot-pr-edits-after-ai-quietly.html">TechSpot</a>, множество пользователей уже деактивировали функцию</li></ol><p>Положительный момент: GitHub отреагировал быстро — менее чем за сутки — и два топ-менеджера публично признали ошибку. Для сравнения: многие компании в аналогичных ситуациях замалчивают проблему или списывают её на «баг».</p><h2>Что в итоге</h2><p>GitHub быстро откатил спорную функцию и публично признал ошибку. Но инцидент поставил вопрос, который не исчезнет: где проходит граница между «умным помощником» и «рекламной площадкой» в ИИ-инструментах разработчика? С ростом монетизации ИИ-агентов ответ на этот вопрос будет определять доверие к целому классу продуктов.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub Copilot вставляет рекламу в pull-реквесты — затронуты 1,5 млн PR</title>
      <link>https://tproger.ru/news/github-copilot-vstavlyaet-reklamu-v-pull-rekvesty-bez-vedoma-razr</link>
      <comments>https://tproger.ru/news/github-copilot-vstavlyaet-reklamu-v-pull-rekvesty-bez-vedoma-razr?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/github-copilot-vstavlyaet-reklamu-v-pull-rekvesty-bez-vedoma-razr</guid>
      <description><![CDATA[<p>Copilot вписывает рекламу в описания PR через скрытые HTML-маркеры. Затронуты более 1,5 млн PR на GitHub и GitLab. Разбираем механизм и способы защиты.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/github-copilot-vstavlyaet-reklamu-v-pull-rekvesty-bez-vedoma-razr">GitHub Copilot вставляет рекламу в pull-реквесты — затронуты 1,5 млн PR</a>»</p>]]></description>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 30 Mar 2026 14:42:24 GMT</pubDate>
      <content:encoded><![CDATA[<p>GitHub Copilot начал вписывать рекламные сообщения прямо в описания pull-реквестов — без ведома и согласия разработчиков. Рекламные вставки с пометкой COPILOT CODING AGENT TIPS уже <a href="https://www.neowin.net/news/microsoft-copilot-is-now-injecting-ads-into-pull-requests-on-github-gitlab/">обнаружены</a> в более чем 1,5 млн PR на GitHub.</p><p>Проблему <a href="https://notes.zachmanson.com/copilot-edited-an-ad-into-my-pr/">обнаружил</a> мельбурнский разработчик Зак Мэнсон: коллега вызвал Copilot для исправления опечатки в PR, но ИИ заодно дописал в описание рекламу расширения <a href="https://www.raycast.com/">Raycast</a>. Тот же рекламный текст <a href="https://www.neowin.net/news/microsoft-copilot-is-now-injecting-ads-into-pull-requests-on-github-gitlab/">нашли</a> более чем в 11 000 pull-реквестов на GitHub и в merge-реквестах на <a href="https://gitlab.com/">GitLab</a>.</p><p>— GitHub Copilot вставляет рекламные «советы» в описания PR как обычный текст после скрытого HTML-маркера.</p><p>— Затронуты более 1,5 млн pull-реквестов на GitHub и merge-реквесты на GitLab.</p><p>— Продвигаются расширения из экосистемы Microsoft: Raycast, Slack, Teams, VS Code, JetBrains.</p><p>— Способа отключить вставки пока нет — Microsoft не комментирует.</p><blockquote>Коллега вызвал Copilot, чтобы исправить опечатку в моём PR. Copilot исправил опечатку — и заодно отредактировал описание PR, вставив рекламу самого себя и Raycast.</blockquote><h2>Как работает инъекция рекламы</h2><p>Когда Copilot выполняет задачу в pull-реквесте, он добавляет в описание PR скрытый HTML-маркер &lt;!-- START COPILOT CODING AGENT TIPS --&gt;. Сам маркер не виден при просмотре — это обычный HTML-комментарий. А вот рекламный текст, который идёт сразу после него, отображается как часть описания PR и виден всем участникам.</p><p>Среди обнаруженных рекламных вставок — предложения запускать задачи агента Copilot из <a href="https://slack.com/">Slack</a>, <a href="https://www.microsoft.com/ru-ru/microsoft-teams/">Teams</a>, <a href="https://code.visualstudio.com/">VS Code</a>, <a href="https://visualstudio.microsoft.com/">Visual Studio</a>, <a href="https://www.jetbrains.com/">JetBrains IDE</a> и <a href="https://eclipseide.org/">Eclipse</a>. Все продвигаемые продукты — часть экосистемы Microsoft или её партнёров.</p><h2>Кто стоит за рекламой</h2><p>На первый взгляд могло показаться, что рекламу вставляет <a href="https://www.raycast.com/">Raycast</a> — приложение для macOS и Windows с набором ИИ-инструментов, включая расширение для Copilot. Однако перечень продвигаемых сервисов (Slack, Teams, VS Code) и структура HTML-маркеров указывают на то, что «советы» встраиваются через сам механизм агента Copilot — то есть, судя по всему, за вставками стоит Microsoft.</p><p>Ни <a href="https://www.raycast.com/">Raycast</a>, ни <a href="https://github.com/">Microsoft</a> пока не прокомментировали ситуацию.</p><h2>Как обнаружить и убрать рекламу из PR</h2><p>Рекламные вставки можно найти по маркеру в описании PR. Откройте любой PR, отредактированный Copilot, и переключитесь в режим редактирования — вы увидите HTML-комментарий и следующий за ним промо-текст.</p><p>Для автоматического удаления можно настроить CI-проверку или pre-commit hook, который ищет строку COPILOT CODING AGENT TIPS в описаниях PR и удаляет блок от маркера до следующего раздела. На момент публикации Microsoft не предоставила штатного способа отключить «советы».</p><h2>Выводы</h2><p>Разработчики платят за Copilot подпиской ($19/мес за Individual, $39/мес за Business), но Microsoft дополнительно монетизирует их рабочий процесс, встраивая промо-тексты прямо в код-ревью. Пока компания не дала объяснений и не предложила способа отключить вставки — остаётся проверять описания PR вручную или автоматизировать удаление через CI.</p>]]></content:encoded>
    </item>
    <item>
      <title>Студент собрал пайплайн на $500 GPU, который обходит Claude Sonnet на бенчмарке кодинга</title>
      <link>https://tproger.ru/news/student-sobral-pajplajn-na--500-gpu--kotoryj-obhodit-claude-sonn</link>
      <comments>https://tproger.ru/news/student-sobral-pajplajn-na--500-gpu--kotoryj-obhodit-claude-sonn?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/student-sobral-pajplajn-na--500-gpu--kotoryj-obhodit-claude-sonn</guid>
      <description><![CDATA[<p>Open-source пайплайн ATLAS набирает 74,6% на LiveCodeBench с Qwen3-14B на RTX 5060 Ti — против 71,4% у Claude Sonnet 4.5. Разбираем, как это работает.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/student-sobral-pajplajn-na--500-gpu--kotoryj-obhodit-claude-sonn">Студент собрал пайплайн на $500 GPU, который обходит Claude Sonnet на бенчмарке кодинга</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[NVIDIA]]></category>
      <category><![CDATA[GPU]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 Mar 2026 15:11:59 GMT</pubDate>
      <content:encoded><![CDATA[<p>Студент из колледжа собрал на одной видеокарте за $500 пайплайн, который <a href="https://github.com/itigges22/ATLAS">обходит Claude Sonnet 4.5</a> на бенчмарке кодинга — без файнтюнинга, без облака, без API-ключей. Проект <a href="https://www.reddit.com/r/BlackboxAI_/comments/1s3ja5n/500_gpu_outperforms_claude_sonnet_on_coding/">взорвал Reddit</a> и <a href="https://news.ycombinator.com/item?id=47533297">Hacker News</a>.</p><p>ATLAS (Adaptive Test-time Learning and Autonomous Specialization) — open-source система, которая оборачивает замороженную квантизированную модель Qwen3-14B в трёхфазный пайплайн генерации, верификации и починки кода. На бенчмарке <a href="https://livecodebench.github.io/leaderboard.html">LiveCodeBench v5</a> (599 из 880 задач) система <a href="https://github.com/itigges22/ATLAS">набрала</a> 74,6% — против 71,4% у Claude Sonnet 4.5.</p><p>— ATLAS набирает 74,6% на LiveCodeBench v5, используя замороженную Qwen3-14B на одной RTX 5060 Ti за ~$430</p><p>— Базовая модель набирает лишь ~55% — пайплайн добавляет почти 20 п.п. за счёт генерации нескольких решений, тестирования и починки</p><p>— Стоимость — ~$0,004 за задачу (электричество) против ~$0,066 за вызов API Claude Sonnet</p><p>— Сравнение не прямое: ATLAS использует best-of-3 + итеративную починку, а Claude тестировали в режиме single-shot на другом наборе задач</p><p>— На других бенчмарках (GPQA Diamond — 47%, SciCode — 14,7%) ATLAS значительно уступает фронтирным моделям</p><p>Автор проекта, студент Исаак Тиггес, <a href="https://github.com/itigges22/ATLAS">собрал</a> всё это на одной потребительской видеокарте RTX 5060 Ti 16 ГБ. Весь инференс локальный — данные не покидают машину, API-ключи не нужны.</p><h2>Как работает ATLAS</h2><p>ATLAS — это не новая модель, а инженерная обвязка вокруг существующей. В основе — замороженная квантизированная <a href="https://huggingface.co/Qwen">Qwen3-14B-Q4_K_M</a> от Alibaba, запущенная через патченный llama-server на K3s. Система работает в три фазы:</p><h3>Фаза 1: генерация</h3><p><b>PlanSearch</b> извлекает ограничения из задачи и генерирует несколько различных планов решения. <b>BudgetForcing</b> контролирует количество thinking-токенов. <b>DivSampling</b> обеспечивает разнообразие кандидатов. На выходе — три варианта решения (k=3).</p><p>Одна эта фаза поднимает результат с 54,9% до 67,3% — прирост 12,4 процентных пункта.</p><h3>Фаза 2: отбор лучшего кандидата</h3><p><b>Geometric Lens</b> — компонент, который оценивает качество каждого кандидата по внутренним представлениям модели и отправляет лучшего на исполнение в песочницу.</p><p>Важный нюанс: в текущей версии эта фаза <a href="https://github.com/itigges22/ATLAS/blob/main/V3_STATUS.md">не дала прироста</a> (+0,0 п.п.), потому что C(x) обучалась всего на ~60 примерах — слишком мало для осмысленного энергетического ландшафта. Автор планирует исправить это в V3.1.</p><h3>Фаза 3: починка провалов</h3><p>Если все кандидаты провалились, модель генерирует собственные тест-кейсы и запускает <b>PR-CoT</b> (multi-perspective chain-of-thought repair) — итеративную починку через рассуждение с нескольких точек зрения. Модель никогда не видит правильные ответы — только свои собственные тесты.</p><p>PR-CoT спасает 36 из 42 задач, попавших в фазу починки — 85,7% успеха. Суммарный прирост фазы 3 — ещё 7,3 п.п.</p><h2>Бенчмарки: что показывают цифры</h2><p>Результаты ATLAS V3 на трёх бенчмарках:</p><p>Метрика pass@1-v(k=3) означает, что для каждой задачи генерируются три кандидата, из которых выбирается лучший. Это значительно легче, чем классический pass@1, где модель даёт ровно один ответ без права на повторную попытку.</p><p>Для контекста — сравнение стоимости и результата на LiveCodeBench:</p><h2>Почему сравнение не совсем честное</h2><p>Автор ATLAS <a href="https://github.com/itigges22/ATLAS#cost-and-performance-context">сам признаёт</a> ключевое ограничение: сравнение — не контролируемый head-to-head.</p><ul><li>ATLAS тестировали на 599 задачах LiveCodeBench v5, а Claude — на 315 задачах из данных <a href="https://artificialanalysis.ai/">Artificial Analysis</a>. Это разные наборы задач</li><li>ATLAS генерирует три кандидата, отбирает лучшего и итеративно чинит провалы. Claude тестировали в режиме single-shot (один запрос, один ответ, без повторов)</li><li>ATLAS оптимизировался именно под LiveCodeBench — на GPQA Diamond (47%) и SciCode (14,7%) результаты значительно скромнее</li><li>Метрика ATLAS — pass@1-v(k=3), а не классический pass@1. Это принципиально разные вещи</li></ul><p>Как <a href="https://fordelstudios.com/research/500-dollar-gpu-beating-cloud-ai-means-nothing">отмечает</a> Fordel Studios, бенчмарки измеряют способность решать изолированные задачи с чёткими условиями — это около 5% того, что важно в продакшене. Остальные 95% — длинный контекст, неоднозначные требования, мультишаговое планирование.</p><h2>Что действительно впечатляет</h2><p>Несмотря на оговорки, проект демонстрирует несколько важных вещей:</p><ol><li><b>Инженерия побеждает масштаб.</b> Базовая Qwen3-14B набирает ~55% — пайплайн ATLAS добавляет почти 20 п.п. без единой строчки файнтюнинга. Это чистая системная инженерия</li><li><b>Порог входа падает.</b> Два года назад для локального инференса нужна была видеокарта за $2000+. Сегодня — RTX 5060 Ti за ~$430. Через два года это может быть карточка за $200</li><li><b>Полная автономность.</b> Данные не покидают машину. Нет API-ключей, нет счетов, нет зависимости от провайдера. Для сценариев с чувствительными данными — это принципиально</li><li><b>Стоимость.</b> ~$0,004 за задачу (электричество при $0,12/кВт·ч) — в 16 раз дешевле одного вызова Claude Sonnet API</li></ol><h2>Ограничения и планы</h2><p>Автор честно <a href="https://github.com/itigges22/ATLAS#known-limitations">документирует</a> проблемы текущей версии:</p><ul><li>Geometric Lens (фаза 2) не работает — обучалась на 60 примерах, что слишком мало</li><li>Метрический тензор G(x) неактивен — будет переработан или удалён в V3.1</li><li>Задачи обрабатываются последовательно — нет параллелизма</li><li>Баг SandboxAdapter со stdin — не работает tiebreaking через distinguishing input</li><li>Система оптимизирована только под LiveCodeBench — кросс-доменная генерализация на повестке V3.1</li></ul><p>В версии V3.1 <a href="https://github.com/itigges22/ATLAS#v31----in-progress">планируется</a> переход на Qwen3.5-9B с архитектурой DeltaNet (ускорение в 3–4 раза), переобучение Geometric Lens, параллелизация задач и расширение набора бенчмарков. Целевой результат — 80–90% на LiveCodeBench.</p><h2>Требования к железу</h2><p>Проект пока не plug-and-play — V3.1 обещает улучшить портативность. На текущий момент настройка под конкретное железо может потребовать ручной работы с параметрами: количество параллельных слотов, квантизация KV-кеша, размер контекста на слот.</p><h2>Выводы</h2><p>ATLAS — впечатляющая демонстрация того, как системная инженерия может компенсировать разрыв в масштабе моделей. Студент, одна видеокарта за $430, замороженная open-source модель — и результат, который на конкретном бенчмарке обходит коммерческую фронтирную модель.</p><p>Но важно не путать бенчмарк-результат с готовностью к продакшену. ATLAS решает задачи LiveCodeBench, генерируя и перебирая варианты. Фронтирные модели решают принципиально другой класс задач — работа с огромным контекстом, понимание неоднозначных требований, мультишаговое планирование.</p><blockquote>Бенчмарки измеряют, может ли модель решить игрушечную задачу. Продакшен измеряет, может ли она думать.</blockquote><p>Настоящий сигнал здесь — не в том, что локальный инференс «победил» облачный ИИ. А в том, что порог доступа к мощному ИИ-инференсу продолжает стремительно падать. Если у вас есть NVIDIA GPU с 16+ ГБ VRAM — <a href="https://github.com/itigges22/ATLAS">попробуйте ATLAS</a> на своих задачах и оцените результат.</p><p><b>Источники:</b> <a href="https://github.com/itigges22/ATLAS">ATLAS на GitHub</a> (1,2K звёзд) · <a href="https://livecodebench.github.io/leaderboard.html">LiveCodeBench Leaderboard</a> · <a href="https://news.ycombinator.com/item?id=47533297">обсуждение на Hacker News</a> · <a href="https://fordelstudios.com/research/500-dollar-gpu-beating-cloud-ai-means-nothing">анализ Fordel Studios</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Фейковые алерты VS Code в GitHub заражают разработчиков — как защититься</title>
      <link>https://tproger.ru/news/fejkovye-alerty-bezopasnosti-vs-code-v-github-discussions-raspro</link>
      <comments>https://tproger.ru/news/fejkovye-alerty-bezopasnosti-vs-code-v-github-discussions-raspro?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/fejkovye-alerty-bezopasnosti-vs-code-v-github-discussions-raspro</guid>
      <description><![CDATA[<p>Тысячи фейковых security advisories в GitHub Discussions заражают разработчиков через вредоносные расширения VS Code. Узнайте, как распознать такую атаку.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/fejkovye-alerty-bezopasnosti-vs-code-v-github-discussions-raspro">Фейковые алерты VS Code в GitHub заражают разработчиков — как защититься</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Кибербезопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 Mar 2026 05:26:42 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вам пришло email-уведомление от GitHub с заголовком «Severe Vulnerability — Immediate Update Required» и ссылкой на Google Drive — <b>не переходите по ней</b>. Исследователи из компании <a href="https://socket.dev/blog/fake-vscode-alerts-github-discussions">Socket</a> обнаружили масштабную кампанию по распространению вредоносного ПО через GitHub Discussions. Злоумышленники публикуют тысячи фейковых предупреждений о безопасности, маскируясь под мейнтейнеров популярных проектов, и направляют разработчиков на загрузку заражённых расширений для VS Code.</p><p>Атака затрагивает пользователей множества репозиториев на GitHub — уведомления о «критических уязвимостях» приходят прямо на почту всем подписчикам и участникам проектов.</p><p>- Тысячи фейковых security-алертов публикуются в GitHub Discussions по множеству репозиториев
- Злоумышленники выдают себя за мейнтейнеров и используют поддельные CVE ID
- Ссылки ведут на вредоносные расширения VS Code, размещённые на Google Drive
- За фасадом — Traffic Distribution System с JS-разведкой и фильтрацией исследователей
- GitHub Discussions автоматически рассылает email-уведомления всем подписчикам репозиториев</p><h2>Как работает атака</h2><p>Кампания построена на злоупотреблении функцией <b>GitHub Discussions</b> — раздела для обсуждений внутри репозиториев. Атакующие создают новые аккаунты или используют малоактивные учётные записи и за считаные минуты публикуют <b>тысячи постов</b> с одинаковым шаблоном.</p><p>Каждый пост оформлен как срочное предупреждение о безопасности с заголовком вида Severe Vulnerability — Immediate Update Required. В тексте указаны поддельные CVE-идентификаторы (CVE — Common Vulnerabilities and Exposures, стандартная система нумерации известных уязвимостей) и ссылка на «пропатченную» версию расширения. Злоумышленники тщательно имитируют стиль настоящих security advisories и подписываются именами реальных мейнтейнеров или исследователей безопасности.</p><p>Ключевой рычаг атаки — механизм уведомлений GitHub. Все пользователи, которые подписаны на репозиторий (watchers) или участвовали в обсуждениях (participants), автоматически получают email с содержимым фейкового алерта. Таким образом, одна публикация в Discussions может охватить сотни и тысячи разработчиков.</p><h2>Цепочка заражения</h2><p>Ссылка из фейкового алерта ведёт на Google Drive, где размещён файл, замаскированный под обновлённое расширение VS Code. Далее запускается многоступенчатая цепочка:</p><ol><li>Жертва переходит по ссылке на Google Drive и скачивает файл</li><li>Файл инициирует цепочку cookie-driven редиректов, которая приводит на домен drnatashachinn[.]com</li><li>На этом домене выполняется JavaScript-скрипт разведки — он собирает данные о системе: часовой пояс, локаль, user agent, операционную систему и индикаторы автоматизации</li><li>Собранные данные отправляются на C2-сервер (Command and Control — управляющий сервер атакующих) через POST-запрос</li><li>Сервер работает как <b>Traffic Distribution System</b> (TDS) — фильтрует ботов и ИБ-исследователей, пропуская к следующему этапу только реальных пользователей</li></ol><p>Исследователям из Socket не удалось перехватить финальную полезную нагрузку (payload — вредоносный код второго этапа) — TDS-система определяла их как аналитиков и блокировала доставку. Важно: сам JS-скрипт разведки <b>не крадёт пароли и не перехватывает учётные данные</b> — он только собирает информацию о системе для фильтрации. Что именно получают прошедшие фильтрацию жертвы — пока неизвестно.</p><h2>Как распознать фейковый алерт</h2><p>Разработчикам стоит проявлять бдительность при получении уведомлений о безопасности из GitHub Discussions. Вот чеклист для проверки:</p><ol><li>Проверьте автора поста — кликните на профиль. Новый аккаунт без активности или с минимальной историей — красный флаг</li><li>Настоящие security advisories публикуются во вкладке Security репозитория, а не в Discussions</li><li>Проверьте CVE ID через официальную базу <a href="https://cve.mitre.org">cve.mitre.org</a> или <a href="https://nvd.nist.gov">nvd.nist.gov</a> — фейковые идентификаторы там не найдутся</li><li>Не скачивайте расширения VS Code из Google Drive или любых внешних источников — используйте только официальный VS Code Marketplace</li><li>Обращайте внимание на язык поста: паникёрские формулировки вроде «Immediate Update Required» нехарактерны для реальных мейнтейнеров</li><li>Если получили email-уведомление — перейдите в репозиторий и проверьте обсуждение в контексте, а не переходите по ссылкам из письма</li></ol><h2>Прецеденты: атаки через GitHub в 2024–2025</h2><p>Это не первый случай использования инфраструктуры GitHub для распространения вредоносного ПО:</p><ul><li><b>Март 2025</b> — масштабная кампания затронула более 12 000 репозиториев. Злоумышленники публиковали фейковые security alerts и через них направляли разработчиков на авторизацию вредоносного OAuth-приложения, получая доступ к их аккаунтам</li><li><b>Июнь 2024</b> — атакующие использовали спам-комментарии и pull requests для запуска email-уведомлений GitHub, перенаправляя разработчиков на фишинговые страницы</li></ul><p>Общий тренд очевиден: злоумышленники всё активнее эксплуатируют доверие разработчиков к платформе GitHub и её встроенные механизмы уведомлений для доставки вредоносного контента.</p><h2>Как защититься прямо сейчас</h2><p>Вот конкретные шаги, которые стоит предпринять уже сегодня:</p><ol><li>Отключите email-уведомления для Discussions: Settings → Notifications → Watching → Custom → снимите галочку с Discussions</li><li>Включите двухфакторную аутентификацию на GitHub: Settings → Password and authentication → Enable two-factor authentication</li><li>Проверьте список установленных расширений VS Code: откройте Extensions (Ctrl+Shift+X) → убедитесь, что все расширения установлены из официального <a href="https://marketplace.visualstudio.com">VS Code Marketplace</a></li><li>Не переходите по ссылкам из email-уведомлений GitHub — открывайте репозиторий напрямую в браузере</li><li>Сообщайте о подозрительных постах через кнопку Report в GitHub Discussions — это помогает платформе быстрее блокировать вредоносный контент</li></ol><h2>Выводы</h2><p>Атака через GitHub Discussions показывает, что даже доверенные платформы могут стать каналом доставки вредоносного ПО. Злоумышленники комбинируют социальную инженерию (срочность, имитация авторитетных фигур), легитимную инфраструктуру (Google Drive, email-уведомления GitHub) и техническую изощрённость (TDS-фильтрация, JS-разведка). Подробности — в <a href="https://www.bleepingcomputer.com/news/security/fake-vs-code-alerts-on-github-spread-malware-to-developers/">отчёте BleepingComputer</a>.</p><p>Главное правило остаётся прежним: не устанавливайте ПО из непроверенных источников, даже если предупреждение выглядит правдоподобно. Настоящие обновления безопасности для расширений VS Code всегда доступны через официальный <a href="https://marketplace.visualstudio.com">VS Code Marketplace</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое Git и GitHub: руководство для начинающих</title>
      <link>https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih</link>
      <comments>https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih</guid>
      <description><![CDATA[<p>Что такое Git и GitHub: как работает VCS, основные команды, сравнение с GitLab и пошаговая инструкция для новичков. Начните работать с Git прямо сейчас.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih">Что такое Git и GitHub: руководство для начинающих</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 29 Mar 2026 05:09:28 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы только начинаете путь в разработке, то наверняка уже слышали слова «Git» и «GitHub» — они звучат на каждом собеседовании, в каждом туториале и в каждом open-source проекте. Но что это такое на самом деле и зачем это нужно? В этой статье разберём всё с нуля: от первой команды в терминале до создания собственного репозитория на GitHub.</p><h2>Что такое Git</h2><p><b>Git</b> — это распределённая система контроля версий (Version Control System, VCS), которая отслеживает изменения в файлах и позволяет нескольким разработчикам работать над одним проектом одновременно. Git был создан Линусом Торвальдсом в 2005 году для разработки ядра Linux и сегодня является стандартом индустрии: по данным Stack Overflow Developer Survey, его используют около 93–95% профессиональных разработчиков. С помощью Git можно в любой момент вернуться к предыдущей версии кода, сравнить изменения и объединить работу нескольких людей с минимумом конфликтов — хотя конфликты при слиянии (merge conflicts) иногда возникают, Git помогает их разрешить.</p><p>- Git — бесплатная и открытая система контроля версий, созданная в 2005 году
- Используется в более чем 93% профессиональных проектов по всему миру
- GitHub — это облачный хостинг для Git-репозиториев, а не сам Git
- Три состояния файла в Git: рабочая директория, staging area, репозиторий
- Основные команды: git init, git add, git commit, git push, git pull
- GitLab и Bitbucket — альтернативы GitHub с похожим функционалом
- Первый коммит можно сделать за 5 минут после установки</p><h2>Зачем нужна система контроля версий</h2><p>Представьте: вы работаете над проектом и случайно удаляете важный файл или ломаете рабочий функционал. Без системы контроля версий восстановить данные практически невозможно. Именно для таких ситуаций и создавались VCS.</p><p>Вот основные задачи, которые решает Git:</p><ul><li>История изменений — вы видите, кто, когда и что изменил в коде</li><li>Откат к предыдущей версии — если новый код сломал проект, достаточно одной команды</li><li>Параллельная работа — несколько человек могут работать над разными частями проекта одновременно</li><li>Эксперименты без риска — создайте отдельную ветку, попробуйте идею, и если не понравится — просто удалите ветку</li><li>Резервное копирование — код хранится не только локально, но и в удалённом репозитории</li></ul><h2>Как работает Git</h2><p>Git управляет файлами через три уровня. Понимание этой модели — ключ к тому, чтобы не путаться в командах и не терять изменения.</p><h3>Рабочая директория (Working Directory)</h3><p>Это обычная папка на вашем компьютере с файлами проекта. Здесь вы пишете и редактируете код. Git следит за изменениями, но пока не сохраняет их в историю — файлы просто находятся в состоянии «изменён» или «не отслеживается».</p><h3>Staging Area (индекс)</h3><p>Промежуточная зона, куда вы добавляете файлы перед сохранением. Думайте о ней как о корзине для покупок: вы выбираете нужные товары (изменения) и кладёте их туда, прежде чем оформить заказ (сделать коммит). Команда git add перемещает файлы в staging area.</p><h3>Репозиторий и коммиты</h3><p>Когда вы выполняете команду git commit, Git делает снимок всех файлов из staging area и сохраняет его в историю репозитория. Каждый коммит — это точка в истории проекта с уникальным идентификатором (SHA-хешем), автором, датой и сообщением. В любой момент можно вернуться к любому коммиту.</p><blockquote>Ключевое отличие Git от большинства других VCS — распределённость. Каждый разработчик хранит полную копию репозитория со всей историей локально. Это означает, что можно работать офлайн и не зависеть от центрального сервера.</blockquote><h2>Основные команды Git</h2><p>Большинство повседневных задач решается с помощью 7–10 команд. Разберём их по порядку.</p><h3>git init — создать репозиторий</h3><p>Инициализирует новый Git-репозиторий в текущей папке. После выполнения команды появится скрытая папка .git, в которой Git хранит всю историю. Папку .git удалять нельзя — в ней хранится вся история проекта.</p><h3>git add и git status — добавить файлы в staging area</h3><p>Команда git status показывает текущее состояние репозитория — какие файлы изменены, какие добавлены в staging area. Команда git add добавляет файлы в staging area.</p><h3>git commit — сохранить изменения</h3><p>Создаёт коммит из файлов, добавленных в staging area. Сообщение коммита должно кратко описывать, что именно изменилось. Хороший формат: глагол в повелительном наклонении + что сделано.</p><h3>git push и git pull — синхронизация с удалённым репозиторием</h3><p>Команда git push отправляет локальные коммиты на удалённый сервер (например, GitHub). Команда git pull загружает изменения с сервера и объединяет их с локальной версией.</p><h3>git branch и git merge — ветки</h3><p>Ветки — одна из самых мощных функций Git. Ветка — это независимая линия разработки. Вы можете создать ветку для новой функциональности, работать в ней, не затрагивая основной код, а потом объединить (merge) с главной веткой.</p><h2>Что такое GitHub</h2><p><b>GitHub</b> — это облачная платформа для хостинга Git-репозиториев. Если Git — это инструмент на вашем компьютере, то GitHub — это место в интернете, где вы храните свой код и делитесь им с другими. Главная страница GitHub — github.com — основана в 2008 году и сегодня насчитывает более 100 миллионов разработчиков и свыше 420 миллионов репозиториев.</p><p>GitHub добавляет поверх Git множество удобных возможностей:</p><ul><li>Pull Request (PR) — предложение изменений с обсуждением кода перед слиянием</li><li>Issues — система задач и багов прямо внутри репозитория</li><li>Actions — автоматизация: тесты, деплой, сборка при каждом коммите</li><li>GitHub Pages — бесплатный хостинг статических сайтов прямо из репозитория</li><li>Discussions — форум для обсуждений внутри проекта</li><li>Code Review — удобный интерфейс для ревью кода с комментариями к строкам</li></ul><blockquote>Git — это технология, а GitHub — это сервис поверх этой технологии. Можно использовать Git без GitHub (например, хранить репозиторий на собственном сервере), но нельзя использовать GitHub без Git.</blockquote><h2>Git vs GitHub vs GitLab vs Bitbucket</h2><p>Разработчики часто путают эти понятия. Вот краткое сравнение четырёх основных инструментов экосистемы.</p><ul><li>Git — локальная система контроля версий, работает без интернета, устанавливается на компьютер</li><li>GitHub — крупнейший хостинг для Git-репозиториев, принадлежит Microsoft с 2018 года, идеален для open-source</li><li>GitLab — альтернатива GitHub с упором на DevOps, есть self-hosted версия, популярен в корпоративной среде</li><li>Bitbucket — продукт Atlassian (Jira, Confluence), хорошо интегрируется с их экосистемой, популярен в командах</li></ul><p>Для новичков рекомендуем начать с GitHub: он самый популярный, имеет лучшую документацию на русском языке и огромное сообщество. Бесплатный план включает неограниченное количество публичных и приватных репозиториев.</p><h2>Как начать работать с Git: пошаговая инструкция</h2><p>Следуйте этой инструкции, и через 10–15 минут у вас будет первый репозиторий на GitHub.</p><h3>Шаг 1. Установка Git</h3><ul><li>Windows: скачайте установщик с git-scm.com/download/win и запустите его</li><li>macOS: откройте терминал и выполните brew install git (или xcode-select --install)</li><li>Linux (Ubuntu/Debian): sudo apt install git</li></ul><h3>Шаг 2. Настройка имени и почты</h3><p>Git подписывает каждый коммит вашим именем и почтой. Настройте их один раз — они будут использоваться во всех проектах.</p><h3>Шаг 3. Создать аккаунт на GitHub</h3><p>Перейдите на github.com, нажмите «Sign up» и заполните форму регистрации. Выберите бесплатный тарифный план — для начинающих он полностью достаточен.</p><h3>Шаг 4. Создать первый репозиторий и сделать коммит</h3><h2>Выводы</h2><p>Git — это не просто инструмент для разработчиков, это основа профессиональной работы с кодом. Без него невозможно представить ни командную разработку, ни open-source проекты, ни современный DevOps. Хорошая новость: базовые команды можно освоить за один вечер, а дальше — практика и опыт.</p><p>Что делать дальше:</p><ol><li>Установите Git и создайте аккаунт на GitHub прямо сейчас</li><li>Сделайте первый репозиторий по инструкции из этой статьи</li><li>Попрактикуйтесь с ветками: создайте ветку, внесите изменения, слейте в main</li><li>Попробуйте сделать Pull Request в любой open-source проект — даже исправление опечатки в README считается</li><li>Изучите команды git stash, git cherry-pick и git bisect — они пригодятся на следующем уровне</li></ol><p>Знание Git сегодня — обязательное требование для любого разработчика. Если вы только начинаете — это один из первых инструментов, который нужно освоить. Если уже работаете — углубляйтесь в продвинутые возможности: rebase, stash, cherry-pick, подмодули. Подробнее о всех возможностях можно прочитать в <a href="https://git-scm.com/book/ru">официальной документации Git</a>.</p><p>Git лежит в основе всей современной DevOps-экосистемы. Следующий шаг — освоить <a href="https://tproger.ru/articles/chto-takoe-docker-prostymi-slovami--kontejnery--obrazy-i-docker-c">Docker</a> для контейнеризации приложений: именно связка Git + Docker образует фундамент любого CI/CD-пайплайна. А если хотите автоматизировать тестирование и доставку кода — читайте нашу статью о том, <a href="https://tproger.ru/articles/chto-takoe-ci-cd--nepreryvnaya-integraciya-i-dostavka">что такое CI/CD</a>.</p><p>Если хотите собрать из Git, Docker, CI/CD, Kubernetes и Helm единый маршрут, посмотрите <a href="https://tproger.ru/articles/roadmap-devops-inzhenera-v-2026-godu--chto-uchit-i-v-kakom-poryadke">план обучения DevOps-инженера</a>. Там видно, почему Git идёт первым и как из него вырастает вся следующая цепочка инструментов.</p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub Actions убивает вашу команду — и вот почему</title>
      <link>https://tproger.ru/translations/github-actions-ubivaet-vawu-komandu---i-vot-pochemu</link>
      <comments>https://tproger.ru/translations/github-actions-ubivaet-vawu-komandu---i-vot-pochemu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/github-actions-ubivaet-vawu-komandu---i-vot-pochemu</guid>
      <description><![CDATA[<p>Бывший инженер CircleCI разбирает все проблемы GitHub Actions — от крашей логов до ловушки YAML. Узнайте, почему Buildkite лучше для продакшена.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/github-actions-ubivaet-vawu-komandu---i-vot-pochemu">GitHub Actions убивает вашу команду — и вот почему</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Организация разработки]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 28 Mar 2026 05:33:42 GMT</pubDate>
      <content:encoded><![CDATA[<p>Автор этого текста — Иэн Данкан, один из первых инженеров <a href="https://circleci.com/">CircleCI</a>. За свою карьеру он перепробовал практически все CI-системы, которые существуют: <a href="https://www.jenkins.io/">Jenkins</a>, <a href="https://www.travis-ci.com/">Travis CI</a>, <a href="https://circleci.com/">CircleCI</a>, <a href="https://semaphoreci.com/">Semaphore</a>, <a href="https://www.drone.io/">Drone</a>, <a href="https://concourse-ci.org/">Concourse</a>, <a href="https://en.wikipedia.org/wiki/Wercker">Wercker</a>, <a href="https://www.jetbrains.com/teamcity/">TeamCity</a>, <a href="https://www.atlassian.com/software/bamboo">Bamboo</a>, <a href="https://docs.gitlab.com/ee/ci/">GitLab CI</a>, <a href="https://aws.amazon.com/codebuild/">CodeBuild</a> и другие, названия которых милосердно стёрлись из памяти. Его вердикт: <a href="https://github.com/features/actions">GitHub Actions</a> — это не хорошо. Даже не «нормально». У него есть доля рынка ровно по одной причине — он уже там, прямо в вашем репозитории. Как плесень на стенах съёмной квартиры: вы не выбирали её, но она идёт в комплекте.</p><blockquote>Если вы используете <a href="https://nixos.org/">Nix</a>, присмотритесь к <a href="https://garnix.io/">Garnix</a> — он анализирует ваш flake, определяет, что нужно собрать, и делает это. Никакого YAML. Лучший CI-конфиг — это отсутствие CI-конфига. Но эта статья не для вас. Эта статья — для всех остальных.</blockquote><h2>Часть I: Нисхождение</h2><h2>Просмотрщик логов, или Куда уходит ваш день</h2><p>Билд упал. Красный крестик. Вы нажимаете на него и попадаете... нет, не в логи. Вы попадаете на страницу Checks Summary. Оттуда — в Workflow Runs. Оттуда — в Jobs. Каждый шаг свёрнут. Каждая страница — это новый спиннер. Три-четыре клика, чтобы добраться до собственно ошибки. Это не отладка — это квест.</p><p>Просмотрщик логов, надо отдать ему должное, стабильно роняет браузер. Не один раз, не случайно — воспроизводимо, надёжно. Откройте лог длинного билда, попробуйте поискать текст — Chrome ляжет. Это не баг, это фича: система предлагает вам отдохнуть от мониторов.</p><p>На длинных логах скроллбар становится декоративным. Он есть, он выглядит как скроллбар, но прокрутить до конца вы не сможете. Приходится скачивать raw-логи и открывать в текстовом редакторе, как будто на дворе 2003 год и вы только что поставили Gentoo.</p><p>Кнопка «Назад» — это рулетка. Вы ожидаете вернуться на PR, но попадаете на случайную страницу GitHub Actions, которую видите впервые в жизни.</p><p>А теперь — отладка. Вы пушите коммит, ждёте, смотрите логи. Что-то падает. Добавляете run: env. Пушите снова. Ждёте. Двадцатиминутный цикл обратной связи ради однострочного изменения. Повторяете четырнадцать раз. Ваш вечер закончился.</p><blockquote>В этом опыте есть что-то медитативное — ритуал кликов и ожидания, почти религиозный по своей бессмысленности.</blockquote><h2>Ловушка YAML</h2><p>Любая CI-система рано или поздно сводится к «куче YAML-файлов». Но YAML в GitHub Actions — это нечто особенное. Свой язык выражений, своя объектная модель контекста, свои правила интерполяции строк. Это уже не конфигурация — это программирование. Только без отладчика, без типов и без чувства собственного достоинства.</p><p>Синтаксис ${{ }} — это танец. Неправильно поставили кавычку? Ждите четыре минуты, пока раннер запустится, чтобы узнать, что ваша строка была молча проглочена. Этот язык выражений «рос в темноте, без присмотра» — слишком сложный для конфига, слишком ограниченный для настоящего языка программирования.</p><h2>«А как же маркетплейс!»</h2><p>GitHub Actions Marketplace — это npm для CI. Комьюнити-экшены разного качества: shell-скрипты с Dockerfile и мечтой.</p><p>uses: some-stranger/cool-action@v2 — вы только что дали незнакомцу доступ к вашему репозиторию, секретам и среде сборки. Можно, конечно, пригвоздить версию к SHA. Никто этого не делает.</p><p>Энергетика ночного рынка: каждый лоток обещает решить вашу проблему, а некоторые продавцы преследуют совсем другие цели.</p><h2>Вы не владеете своими вычислениями</h2><p>Вы арендуете раннеры у Microsoft — медленные, ограниченные в ресурсах, не поддающиеся настройке. Это породило целую индустрию стартапов: <a href="https://namespace.so/">Namespace</a>, <a href="https://blacksmith.sh/">Blacksmith</a>, <a href="https://actuated.dev/">Actuated</a>, <a href="https://runs-on.com/">Runs-on</a>, <a href="https://buildjet.com/">BuildJet</a> — компании, которые существуют исключительно потому, что штатные раннеры GitHub Actions непригодны для продакшена.</p><p>Self-hosted раннеры решают проблему вычислений, но вы по-прежнему пишете YAML для GitHub Actions — это как поставить новый двигатель в машину, которая загорается каждый раз, когда вы включаете радио.</p><p>Microsoft — это место, куда амбициозные инструменты для разработчиков приходят, чтобы стать корпоративными SKU.</p><h2>Мелочи, которые накапливаются</h2><ul><li>actions/cache — ключи кеша непонятные, промахи молчаливые, вытеснение непрозрачное.</li><li>Reusable workflows нельзя вкладывать друг в друга, и у них нет чистого доступа к контексту вызывающего воркфлоу.</li><li>GITHUB_TOKEN permissions — лабиринт. permissions: write-all — это кувалда, а fine-grained permissions — это пазл на 500 деталей без картинки на коробке.</li><li>Concurrency controls — топорные. Отменить текущий запуск? Одна строка. Что-нибудь более тонкое? Нет.</li><li>Секреты нельзя использовать в условиях if: — обоснованное ограничение безопасности, но с точки зрения DX — катастрофа.</li></ul><p>Каждая из этих мелочей по отдельности — переживаемая. Но вместе они составляют убедительный аргумент в пользу того, чтобы просто уйти и не вернуться.</p><h2>«Просто напиши баш-скрипты»</h2><p>Искушение велико: просто засунуть всё в run: и написать большой shell-скрипт.</p><p>И это работает! А потом скрипт растёт. Условия, функции, парсинг аргументов, второй скрипт, обработка ошибок, логирование, «ну и чуть-чуть параллелизма».</p><p>Проходит три месяца — и вот у вас 800 строк баша, которые переизобретают параллельное выполнение задач при помощи wait и PID-файлов.</p><p>Race condition в cleanup-trap только на ядре Linux 6.x, вы в отпуске, телефон звонит.</p><blockquote>Вы не избежали CI. Вы построили CI-систему. Просто она хуже.</blockquote><p>Bash хорош как клей. Но он не система сборки. Не тестовый фреймворк. Не оркестратор. Каждый раз, когда кто-то говорит «просто напиши баш-скрипт», где-то в мире рождается ещё один 800-строчный ci.sh.</p><h2>Часть II: Выход</h2><h2>Просмотрщик логов, который не убивает браузер</h2><p>У <a href="https://buildkite.com/">Buildkite</a> просмотрщик логов — это веб-страница, которая показывает логи и не падает. Звучит как минимальное требование к продукту, но после GitHub Actions это ощущается как роскошь.</p><ul><li>ANSI-цвета работают — вывод тестового фреймворка приходит в первозданном виде, а не в виде кашицы из escape-последовательностей.</li><li>Аннотации — богатый Markdown-вывод прямо на странице билда.</li><li>Отладка: агент крутится на вашем железе, вы можете зайти на машину по SSH. Как нормальный человек, а не как археолог, расшифровывающий логи по слоям.</li></ul><h2>YAML, который знает своё место</h2><p>YAML в <a href="https://buildkite.com/">Buildkite</a> описывает пайплайн: шаги, команды, плагины. Это структура данных, а не язык программирования. Когда нужна логика — пишите скрипт на нормальном языке. Запускайте локально. Как человек, у которого есть достоинство.</p><blockquote>Оркестрацию — в конфиг, логику — в код. Buildkite уважает эту границу.</blockquote><h2>Вы владеете своими вычислениями</h2><p>Агент <a href="https://buildkite.com/">Buildkite</a> — это один бинарник на ваших машинах. Ваш облачный провайдер, ваш дата-центр, ваше странное кастомное железо.</p><p>Никакой побочной индустрии «Buildkite, только быстрее» — просто поставьте машины помощнее.</p><p>GitHub Actions выдаст вам стандартную Ubuntu-виртуалку с эмоциональной теплотой зала ожидания в районной поликлинике.</p><h2>Динамические пайплайны</h2><p>Шаги пайплайна — это данные. Вы можете генерировать их динамически в рантайме.</p><p>Скрипт смотрит на монорепо, определяет, что изменилось, и загружает именно те шаги, которые нужны. Никаких захардкоженных матриц, никаких спагетти из if: contains(...).</p><h2>По поводу плагинов</h2><p>Честно говоря, структурно плагины Buildkite похожи на маркетплейс GitHub Actions.</p><p>Но: тонкие shell-хуки вместо целых Docker-образов, меньше поверхности атаки. И главное — всё запускается на вашем железе, так что радиус поражения — под вашим контролем.</p><h2>Маленькие радости</h2><p>В Buildkite можно поставить кастомные эмодзи рядом с шагами пайплайна — :parrot:, :docker:, что угодно.</p><p>Объективно — бесполезная мелочь. Но она рассказывает вам о людях, которые создали этот продукт.</p><p><a href="https://github.com/features/actions">GitHub Actions</a> — это продукт, спроектированный комитетом, который ни разу не задал вопрос: «А пользователю от этого радостно?»</p><h2>Заключение</h2><p><a href="https://github.com/features/actions">GitHub Actions</a> победил не потому, что он хорош, а потому что он стоит по умолчанию. Internet Explorer от мира CI.</p><p>Если у вас маленькая команда и простое приложение — он сойдёт. Серьёзно, не переезжайте ради принципа.</p><p>Но если у вас продакшен-системы, монорепо, билды дольше пяти минут — присмотритесь к <a href="https://buildkite.com/">Buildkite</a>.</p><blockquote>GitHub Actions — это самая простая CI-система для старта. Buildkite — это лучшая CI-система для жизни.</blockquote><p>Если ваш CI воюет с вами больше, чем помогает — проблема не в вас. Проблема в инструменте.</p><blockquote>Это литературный перевод и адаптация статьи Иэна Данкана (Ian K. Duncan) <a href="https://www.iankduncan.com/engineering/2026-02-05-github-actions-killing-your-team">GitHub Actions is Killing Your Team</a>. Мнение автора оригинала может не совпадать с мнением редакции.</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Исследователь предложил метод промптинга DEO — он делает LLM на 40% креативнее</title>
      <link>https://tproger.ru/news/issledovatel-predlozhil-metod-promptinga-deo---on-delaet-llm-na-</link>
      <comments>https://tproger.ru/news/issledovatel-predlozhil-metod-promptinga-deo---on-delaet-llm-na-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/issledovatel-predlozhil-metod-promptinga-deo---on-delaet-llm-na-</guid>
      <description><![CDATA[<p>DEO — метод промптинга из когнитивной психологии. На 3 open-source LLM показал прирост креативности до 55%. Разбираем с готовыми промптами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/issledovatel-predlozhil-metod-promptinga-deo---on-delaet-llm-na-">Исследователь предложил метод промптинга DEO — он делает LLM на 40% креативнее</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Наука]]></category>
      <category><![CDATA[Промпты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 27 Mar 2026 17:02:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Вы просите ChatGPT или Llama решить нестандартную задачу, а модель выдаёт банальный ответ? Возможно, проблема не в модели, а в том, <b>как</b> вы формулируете промпт. Исследователь из Турции предложил метод, который заставляет LLM переключаться между аналитическим и эмоциональным мышлением — и результаты впечатляют.</p><p>Distance-Engagement Oscillation (DEO) — это метод промптинга, основанный на теории перцептивного рефрейминга (Perceptual Reframing Theory, PRT). Рефрейминг — это способность посмотреть на проблему под другим углом, сменив «рамку» восприятия. DEO заставляет языковую модель чередовать два когнитивных режима: аналитическую дистанцию (анализ проблемы со стороны) и эмоциональное вовлечение (проживание проблемы изнутри). Автор метода — <a href="https://github.com/gokmengokhan">Гёкхан Гёкмен</a> из Технического университета Бурсы.</p><p>Результаты эксперимента на трёх open-source LLM показали: DEO-промптинг повышает качество креативного мышления модели на 40–55% по сравнению с обычными промптами. Эффект подтверждён тремя независимыми оценщиками с размером эффекта Cohen's d от 1.29 до 1.63 («очень большой»).</p><p><b>Главное:</b><br />— DEO-промптинг улучшает креативное мышление LLM на 40–55% (Cohen's d = 1.29–1.63)<br />— Предсказанный порядок DEO &gt; Distance &gt; Engagement ≥ Vanilla подтвердился во всех 9 комбинациях модель×оценщик (p &lt; .001)<br />— Метод работает без дообучения — только через структуру промпта<br />— Тестировалось на Llama 3.3 70B, Qwen3 32B и Llama 4 Scout<br />— Код и данные открыты на GitHub под лицензией CC BY 4.0</p><h2>Как работает DEO-промптинг</h2><p>В основе метода лежит Perceptual Reframing Theory (PRT) — теория, объединяющая исследования из области инсайтов, самодистанцирования, теории уровней конструирования и психотерапии. PRT описывает девять когнитивных путей, которыми люди переключают восприятие при решении творческих задач.</p><p>DEO использует четыре шага, чередуя аналитическую дистанцию и эмоциональное вовлечение:</p><ol><li><b>ANALYSE</b> (дистанция) — модель анализирует проблему со стороны, выявляя скрытые допущения и рамки мышления</li><li><b>FEEL</b> (вовлечение) — модель «проживает» проблему, подключая эмпатию и эмоциональный контекст</li><li><b>REFRAME</b> (дистанция) — модель формулирует альтернативные интерпретации на основе обоих режимов</li><li><b>ENVISION</b> (вовлечение) — модель представляет конкретную реализацию нового решения</li></ol><p>Ключевая идея: ни дистанция, ни вовлечение по отдельности не дают максимального эффекта. Именно <b>чередование</b> между ними создаёт качественный сдвиг в мышлении модели.</p><h2>Дизайн эксперимента</h2><p>Исследование включало два анализа с общим объёмом в <b>13 500 вызовов генерации</b>:</p><h3>Анализ 1: промпты с рефреймингом vs обычные промпты</h3><ul><li><b>50 оригинальных задач</b> из 8 категорий когнитивных ловушек: якорение, ложная бинарность, функциональная фиксированность, фрейминговая ловушка, нарративный замок, нулевая сумма, эффект Эйнштеллунга, многоходовые задачи</li><li><b>3 open-source LLM</b>: Llama 3.3 70B, Qwen3 32B, Llama 4 Scout 17B-16E</li><li><b>5 запусков</b> на каждое условие (temperature 0.7) с усреднением</li><li><b>3 независимых оценщика</b>: самооценка модели + Claude Sonnet 4 + GPT-4.1 (все слепые к условию)</li><li><b>5 критериев оценки</b>: разнообразие фреймов, выявление допущений, новизна решения, ревизия предпосылок, корректность</li></ul><h3>Анализ 2: четыре условия DEO</h3><p>Для 20 задач с чистыми путями дистанции сравнивались четыре условия:</p><ul><li><b>Vanilla</b> — обычный промпт без дополнительной структуры</li><li><b>Distance-only</b> — только аналитическая дистанция</li><li><b>Engagement-only</b> — только эмоциональное вовлечение</li><li><b>DEO</b> — полная осцилляция между дистанцией и вовлечением</li></ul><h2>Результаты</h2><p>Предсказанный теорией порядок <b>DEO &gt; Distance &gt; Engagement ≥ Vanilla</b> подтвердился во всех 9 комбинациях модель × оценщик (все Friedman p &lt; .001).</p><h3>Анализ 1: рефрейминг значимо лучше обычных промптов</h3><p>Средние баллы по 5-балльной шкале рефрейминга:</p><ul><li><b>Llama 3.3 70B</b> — vanilla: 2.84, рефрейминг: 3.99 (Δ = +1.15, d = 1.29)</li><li><b>Qwen3 32B</b> — vanilla: 2.86, рефрейминг: 4.00 (Δ = +1.14, d = 1.56)</li><li><b>Llama 4 Scout</b> — vanilla: 2.82, рефрейминг: 3.98 (Δ = +1.16, d = 1.42)</li></ul><p>Все 9 пар модель × оценщик показали статистическую значимость на уровне p &lt; .001. При этом корректность ответов не снизилась — напротив, также значимо выросла.</p><h3>Анализ 2: осцилляция эффективнее любого режима по отдельности</h3><p>Средние баллы по четырём условиям (оценщик OpenAI, Llama 3.3 70B):</p><ul><li><b>Vanilla</b>: 2.37</li><li><b>Engagement-only</b>: 2.92</li><li><b>Distance-only</b>: 3.61</li><li><b>DEO</b>: 4.06</li></ul><p>Дистанция значительно превосходит вовлечение во всех 9 случаях — это подтверждает гипотезу PRT о том, что <b>увидеть фрейм</b> мышления сложнее, чем прочувствовать проблему. DEO добавляет значимое улучшение поверх дистанции в 4 из 9 случаев (d = 0.40–1.06).</p><h3>Какие задачи выигрывают больше всего</h3><p>Максимальный эффект DEO наблюдается на задачах с <b>нарративным замком</b> (narrative lock-in) — когда модель застревает в одной истории или интерпретации. Здесь прирост достигает Δ = +2.14, d = 3.23. На втором месте — задачи с <b>фрейминговой ловушкой</b> и <b>эффектом Эйнштеллунга</b> (фиксация на привычном методе решения).</p><h2>Девять путей рефрейминга PRT</h2><p>Теория PRT выделяет девять когнитивных путей, которые используются как промпт-стратегии:</p><ol><li><b>Name the Frame</b> — назвать скрытую рамку мышления (Δ до +1.60)</li><li><b>Decompose to Generic</b> — разложить задачу на абстрактные компоненты</li><li><b>Distant Analogy</b> — применить аналогию из другой области (Δ до +1.64)</li><li><b>Incubate &amp; Reset</b> — сделать паузу и вернуться к задаче заново</li><li><b>Invert</b> — перевернуть задачу наоборот (Δ до +1.38)</li><li><b>Premise Reflection</b> — поставить под сомнение исходные предпосылки (Δ до +1.56)</li><li><b>Surprise as Signal</b> — использовать удивление как сигнал для рефрейминга (Δ до +1.87)</li><li><b>Confidence Calibration</b> — калибровать уверенность в ответе</li><li><b>Step Outside</b> — посмотреть на задачу глазами другого человека (Δ до +1.34)</li></ol><p>Самые эффективные пути: <b>Name the Frame</b>, <b>Distant Analogy</b> и <b>Surprise as Signal</b>. Все три связаны с дистанцией — способностью модели "увидеть" рамку, в которой она мыслит.</p><h2>Как попробовать DEO самому</h2><p><a href="https://github.com/gokmengokhan/deo-llm-reframing">Репозиторий</a> включает slash-команду <b>/reframe</b> для <a href="https://docs.anthropic.com/en/docs/claude-code">Claude Code</a>. Она применяет четырёхшаговую осцилляцию DEO к любой задаче:</p><p>Claude пройдёт четыре этапа — ANALYSE, FEEL, REFRAME, ENVISION — и выдаст рефреймированный ответ с альтернативными интерпретациями проблемы.</p><p>Для воспроизведения полного эксперимента:</p><p>Полный эксперимент (3 модели, 4 условия, 5 запусков, 3 оценщика) обходится примерно в $15–20.</p><h2>FAQ</h2><h3>Что такое DEO-промптинг?</h3><p>DEO (Distance-Engagement Oscillation) — это метод промптинга, в котором языковая модель чередует аналитический режим (дистанция) и эмоциональный режим (вовлечение). Такое чередование помогает модели выйти за рамки привычного мышления и находить более креативные решения. Метод основан на теории перцептивного рефрейминга (PRT) из когнитивной психологии.</p><h3>На каких моделях работает DEO?</h3><p>В исследовании метод тестировался на трёх open-source моделях: Llama 3.3 70B, Qwen3 32B и Llama 4 Scout 17B-16E. Эффект был стабильно значимым на всех трёх. Поскольку DEO работает на уровне промпта (zero-shot, без дообучения), он применим к любой LLM, способной следовать структурированным инструкциям.</p><h3>Чем DEO отличается от Chain-of-Thought?</h3><p>Chain-of-Thought заставляет модель рассуждать пошагово в одном когнитивном режиме. DEO добавляет <b>переключение между режимами</b> — от анализа к эмпатии и обратно. Это помогает модели не просто "думать дольше", а "думать иначе", выявляя скрытые предпосылки и рамки мышления, которые блокируют креативные решения.</p><h3>Снижается ли корректность ответов при использовании DEO?</h3><p>Нет. В эксперименте корректность ответов значимо выросла во всех 9 комбинациях модель × оценщик (p &lt; .001). DEO не жертвует точностью ради креативности — оба показателя улучшаются одновременно.</p><h3>Можно ли использовать DEO в продакшене?</h3><p>Код и данные открыты под лицензией CC BY 4.0. Метод не требует дообучения или специальной инфраструктуры — достаточно модифицировать системный промпт. Четырёхшаговая структура ANALYSE–FEEL–REFRAME–ENVISION легко интегрируется в любой пайплайн.</p><h2>Выводы</h2><blockquote>Аналитическая дистанция показывает модели, что рамка мышления существует. Эмоциональное вовлечение делает сдвиг восприятия устойчивым. Именно осцилляция между ними даёт максимальный эффект.</blockquote><p>Исследование Гёкмена — первый эмпирический тест механизма DEO и одна из немногих работ, применяющих когнитивную психологию рефрейминга к промпт-инжинирингу. Результаты показывают, что структура промпта важнее, чем размер модели: правильно организованное чередование дистанции и вовлечения даёт стабильный и воспроизводимый прирост креативного мышления LLM.</p><p>Полный код эксперимента, 307 JSON-файлов с ответами моделей и статистический анализ доступны в <a href="https://github.com/gokmengokhan/deo-llm-reframing">репозитории на GitHub</a>. Препринт статьи опубликован на <a href="https://zenodo.org/records/19252225">Zenodo</a> (DOI: 10.5281/zenodo.19252225).</p><p>Попробуйте DEO-промптинг на своих задачах — возможно, ваша LLM способна на большее, чем вы думаете.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как пакет для работы с нейросетями стал стилером: полный разбор атаки на LiteLLM</title>
      <link>https://tproger.ru/news/kak-paket-dlya-raboty-s-nejrosetyami-stal-stilerom--polnyj-razbor-</link>
      <comments>https://tproger.ru/news/kak-paket-dlya-raboty-s-nejrosetyami-stal-stilerom--polnyj-razbor-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/kak-paket-dlya-raboty-s-nejrosetyami-stal-stilerom--polnyj-razbor-</guid>
      <description><![CDATA[<p>Версии LiteLLM 1.82.7 и 1.82.8 содержали стилер. Разбор атаки TeamPCP: хронология, технический анализ, IoC и чек-лист действий. Проверьте свои системы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/kak-paket-dlya-raboty-s-nejrosetyami-stal-stilerom--polnyj-razbor-">Как пакет для работы с нейросетями стал стилером: полный разбор атаки на LiteLLM</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Кибербезопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 27 Mar 2026 04:44:10 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если между 24 и 25 марта 2026 года вы обновляли LiteLLM — проверьте версию прямо сейчас. Ваши API-ключи от OpenAI, Anthropic и облачных провайдеров могли утечь.</p><p><a href="https://github.com/BerriAI/litellm">LiteLLM</a> — это open-source прокси для работы с API различных LLM-провайдеров: OpenAI, Anthropic, Azure, Bedrock и ещё сотней других. Библиотека позволяет переключаться между моделями через единый интерфейс с автоматическими фоллбэками, ретраями и трекингом расходов. При <b>97 миллионах загрузок в месяц</b> (около 3,4 млн в день) это один из самых популярных инструментов в AI-инфраструктуре.</p><p>В скомпрометированных версиях 1.82.7 и 1.82.8, опубликованных на PyPI, обнаружили встроенный стилер учётных данных. Он крал SSH-ключи, токены облачных сервисов, API-ключи и пароли, а затем расползался по Kubernetes-кластерам.</p><p><b>Ключевое:</b> Версии LiteLLM 1.82.7 и 1.82.8 на PyPI содержали стилер, крадущий SSH-ключи, облачные токены и API-ключи. Версия 1.82.8 запускала вредоносный код при каждом старте Python — даже без импорта библиотеки. Если вы устанавливали LiteLLM 24 марта 2026 года — <a href="https://tproger.ru/#remediation">проверьте свои системы</a>. Последняя чистая версия — 1.82.6.</p><p>Но эта атака — не изолированный инцидент. Это финал пятидневной <b>supply chain атаки</b> (атаки через цепочку поставок — внедрение вредоносного кода в легитимный пакет через компрометацию его инфраструктуры). За ней стоит группировка <b>TeamPCP</b> — ранее неизвестная группа, которая за последнюю неделю марта целенаправленно атаковала инструменты безопасности и разработки. Кампания началась с компрометации сканера уязвимостей Trivy и через цепочку украденных CI/CD-креденшалов дотянулась до LiteLLM.</p><p>Разбираем всю цепочку атаки от начала до конца — подробнее, чем где-либо ещё.</p><h2>Хронология: пять дней, три вендора, пять экосистем</h2><p>Чтобы понять, как LiteLLM оказался скомпрометирован, нужно отмотать на пять дней назад. Атакующие не ломали LiteLLM напрямую — они добрались до него через цепочку компрометаций, каждая из которых давала доступ к следующей цели.</p><h3>19 марта: Trivy — точка входа</h3><p>Всё началось с <a href="https://github.com/aquasecurity/trivy">Trivy</a> — open-source сканера уязвимостей от Aqua Security, которым пользуются тысячи компаний для проверки контейнеров и кода.</p><p>Атакующие использовали скомпрометированные учётные данные мейнтейнера, чтобы:</p><ul><li>Опубликовать вредоносный релиз <b>Trivy v0.69.4</b>, который прошёл через стандартную release-машинерию и попал в GHCR, ECR Public, Docker Hub, deb/rpm-пакеты</li><li>Подменить <b>76 из 77 тегов</b> aquasecurity/trivy-action на вредоносные коммиты</li><li>Заменить все 7 тегов aquasecurity/setup-trivy</li></ul><p>Вредоносный код в GitHub Actions сканировал память процесса Runner.Worker, собирал креденшалы, шифровал данные AES+RSA и отправлял на подставной домен scan.aquasecurtiy[.]org — обратите внимание на опечатку в слове «security». Если прямая эксфильтрация не удавалась, малварь создавала публичный репозиторий tpcp-docs через GitHub-токен жертвы и сливала данные туда.</p><h3>20–22 марта: npm-червь и дефейс</h3><p>Уже на следующий день украденные токены пошли в дело. Атакующие запустили <b>самораспространяющегося npm-червя</b>: 28 пакетов в @EmilGroup, 16 в @opengov, плюс отдельные пакеты в других скоупах. Червь крал npm-токены из скомпрометированных окружений, проверял, к каким пакетам они дают доступ, поднимал patch-версию, подставлял оригинальный README для маскировки и переиздавал пакет с вредоносной начинкой.</p><p>К 22 марта та же инфраструктура начала обслуживать Kubernetes-скрипт с <b>разделением жертв по геолокации</b>. На иранских системах деплоился DaemonSet с контейнером kamikaze, который удалял файловую систему хоста и перезагружал ноду. На остальных — устанавливал персистентный бэкдор.</p><p>В тот же день атакующие дефейснули <b>44 репозитория внутренней GitHub-организации Aqua Security</b> (aquasec-com), переименовав их с префиксом tpcp-docs- и описанием «TeamPCP Owns Aqua Security».</p><h3>23 марта: Checkmarx</h3><p>Кампания добралась до <b>Checkmarx</b> — ещё одного крупного вендора в сфере безопасности приложений. Были скомпрометированы:</p><ul><li>Checkmarx/kics-github-action — сканер инфраструктурного кода</li><li>Checkmarx/ast-github-action — GitHub Action для платформы Checkmarx</li><li>Расширения VS Code в реестре Open VSX: ast-results v2.53.0 (около 36 000 загрузок) и cx-dev-assist v1.7.0 (около 500 загрузок)</li></ul><p>Паттерн тот же: стилер креденшалов, привязанный к домену checkmarx[.]zone, с фоллбэком на публичный репозиторий docs-tpcp для эксфильтрации.</p><h3>24 марта: LiteLLM</h3><p>В <b>10:52 UTC</b> на PyPI появилась версия LiteLLM 1.82.8. Соответствующий тег или релиз на GitHub отсутствовал — пакет был загружен напрямую, в обход стандартного процесса. По <a href="https://www.reversinglabs.com/blog/teampcp-supply-chain-attack-spreads">данным ReversingLabs</a>, был скомпрометирован GitHub-аккаунт сооснователя и CEO LiteLLM Криша Дхолакии — предположительно, через CI/CD-пайплайн, где Trivy использовался <b>без пиннинга версии</b>.</p><p>Через три часа команда безопасности PyPI поставила проект на карантин. Скомпрометированные версии были удалены. Последняя чистая версия — <b>1.82.6</b>. Но при 3,4 миллионах загрузок в день даже три часа — это огромное окно.</p><p>Мейнтейнеры LiteLLM <a href="https://docs.litellm.ai/blog/security-update-march-2026">опубликовали security-апдейт</a>, подтвердив компрометацию и рекомендовав всем пользователям обновиться до версии 1.82.6 или выше (после снятия карантина). Issue #24512 на GitHub, описывающий уязвимость, был закрыт — предположительно, самим атакующим через скомпрометированный аккаунт.</p><h2>Как работает вредоносный код</h2><p>Теперь разберём, что именно попадало на машины жертв. LiteLLM оказался скомпрометирован в двух версиях, и они существенно различаются по механизму запуска.</p><h3>Версия 1.82.7: инъекция в proxy_server.py</h3><p>В версии 1.82.7 вредоносный код был внедрён в файл litellm/proxy/proxy_server.py. Малварь запускалась только при реальном использовании LiteLLM Proxy в приложении. Если пакет был установлен, но прокси-сервер не запускался, код мог не сработать.</p><h3>Версия 1.82.8: .pth-файл — запуск без импорта</h3><p>Версия 1.82.8 принципиально опаснее. В wheel-пакет был добавлен файл litellm_init.pth размером 34 628 байт, содержащий <b>дважды закодированный</b> в base64 вредоносный код.</p><p>.pth-файлы — малоизвестная особенность Python. Согласно <a href="https://docs.python.org/3/library/site.html">документации модуля site</a>, исполняемые строки в .pth-файлах выполняются автоматически при каждом запуске интерпретатора. Не при импорте библиотеки, а при запуске <b>любого</b> Python-процесса в окружении, где установлен пакет.</p><p>Это означает: достаточно было выполнить pip install litellm==1.82.8, и <b>каждый последующий запуск Python</b> на этой машине активировал стилер. Не нужно писать import litellm — даже python -c "print('hello')" запускал вредоносный код.</p><h3>Три стадии: сбор, шифрование, эксфильтрация</h3><p><b>Стадия 1 — сбор.</b> Скрипт прочёсывает машину и собирает:</p><ul><li>SSH-ключи и конфигурации (~/.ssh/)</li><li>.env-файлы с секретами</li><li>Креденшалы AWS (Access Key, Secret Key), GCP (ADC), Azure</li><li>Конфигурации Kubernetes (~/.kube/config)</li><li>Docker-конфиги (~/.docker/config.json)</li><li>Пароли баз данных</li><li>Историю шелла (bash_history, zsh_history)</li><li>Файлы криптокошельков</li><li>Все переменные окружения</li><li>Данные с облачных metadata-эндпоинтов (IMDS)</li></ul><p><b>Стадия 2 — шифрование.</b> Собранные данные упаковываются в tar-архив и шифруются гибридной схемой: случайный сессионный ключ <b>AES-256-CBC</b> для данных, зашифрованный захардкоженным <b>4096-битным RSA</b>-публичным ключом.</p><p><b>Стадия 3 — эксфильтрация.</b> Зашифрованный архив отправляется POST-запросом на models.litellm[.]cloud (домен не имеет отношения к настоящему litellm.ai) с заголовком X-Filename: tpcp.tar.gz.</p><h3>Горизонтальное распространение в Kubernetes</h3><p>Если на машине обнаружен токен сервисного аккаунта Kubernetes, малварь переходит в режим горизонтального распространения (lateral movement):</p><ol><li>Читает <b>все секреты кластера</b> во всех неймспейсах</li><li>Создаёт привилегированный pod на <b>каждой ноде</b> в kube-system на основе образа alpine:latest</li><li>Каждый pod монтирует <b>корневую файловую систему хоста</b></li><li>Устанавливает персистентный бэкдор в /root/.config/sysmon/sysmon.py</li><li>Регистрирует systemd user service для автозапуска</li></ol><p>Таким образом, компрометация одного pip-пакета превращается в <b>полную компрометацию всего Kubernetes-кластера</b>.</p><h3>Персистентность и бэкдор</h3><p>На локальной машине малварь создаёт:</p><ul><li>~/.config/sysmon/sysmon.py — скрипт-бэкдор</li><li>~/.config/systemd/user/sysmon.service — systemd unit для автозапуска</li></ul><p>После установки бэкдор периодически обращается к https://checkmarx[.]zone/raw, скачивает файл в /tmp/pglog и выполняет его содержимое. Это даёт атакующим возможность удалённо выполнять произвольный код на скомпрометированных машинах в любой момент.</p><h2>Как обнаружили: баг в малвари устроил fork-бомбу</h2><p>Ирония истории в том, что атаку обнаружили благодаря <b>ошибке самих хакеров</b>.</p><p>Команда <a href="https://futuresearch.ai/blog/litellm-pypi-supply-chain-attack/">FutureSearch</a> столкнулась с проблемой случайно: MCP-плагин в IDE Cursor подтянул LiteLLM как транзитивную зависимость. Вредоносный .pth-файл запускал дочерний Python-процесс через subprocess.Popen. Но поскольку .pth-файлы срабатывают при каждом запуске интерпретатора, дочерний процесс тоже запускал малварь, та порождала ещё один процесс — и так далее.</p><p>Результат — <b>экспоненциальная fork-бомба</b>, которая мгновенно съедала всю оперативную память и вешала систему. Без этого бага стилер мог бы работать незамеченным значительно дольше.</p><blockquote>Мы были взломаны… тысячи людей, вероятно, прямо сейчас под атакой</blockquote><h2>Что делать, если вы затронуты</h2><p>Если в ваших проектах, CI/CD-пайплайнах или на рабочих машинах устанавливался LiteLLM 24 марта или позже — проверьте версию:</p><p>Если обнаружена версия 1.82.7 или 1.82.8:</p><ol><li><b>Удалите пакет и очистите кэши:</b> pip cache purge, rm -rf ~/.cache/uv</li><li><b>Проверьте наличие бэкдора:</b> файлы ~/.config/sysmon/sysmon.py и ~/.config/systemd/user/sysmon.service</li><li><b>В Kubernetes:</b> аудит kube-system на наличие подов node-setup-*, проверка секретов на несанкционированный доступ</li><li><b>Ротация всех креденшалов:</b> SSH-ключи, облачные токены (AWS, GCP, Azure), API-ключи, пароли БД, .env-файлы</li><li><b>Сетевые логи:</b> проверьте обращения к models.litellm[.]cloud, checkmarx[.]zone, scan.aquasecurtiy[.]org</li><li><b>Восстановление:</b> не ограничивайтесь удалением пакета — пересобирайте системы из известных чистых образов с закреплёнными (pinned) зависимостями</li></ol><p>На момент публикации публичных подтверждений массовой эксплуатации украденных ключей не зафиксировано, однако учитывая трёхчасовое окно и объём загрузок, число затронутых окружений может исчисляться тысячами.</p><h2>Индикаторы компрометации (IoC)</h2><p><b>Вредоносные домены:</b></p><ul><li>models.litellm[.]cloud — C2 для LiteLLM</li><li>checkmarx[.]zone — C2, используемый для персистентности и Checkmarx-атаки</li><li>scan.aquasecurtiy[.]org — C2 для Trivy-атаки</li></ul><p><b>Файлы на диске:</b></p><ul><li>litellm_init.pth в site-packages/</li><li>~/.config/sysmon/sysmon.py</li><li>~/.config/systemd/user/sysmon.service</li><li>/tmp/pglog</li><li>/tmp/.pg_state</li></ul><p><b>Kubernetes-артефакты:</b></p><ul><li>Поды с именами node-setup-* в kube-system</li><li>Контейнеры с именами kamikaze или provisioner</li></ul><p>Инциденту присвоен идентификатор <b>CVE-2026-33634</b>. Полный список IoC в формате CSV доступен в <a href="https://github.com/DataDog/security-labs-pocs">репозитории Datadog Security Labs</a>.</p><h2>Частые вопросы</h2><h3>Что такое LiteLLM и зачем его используют?</h3><p>LiteLLM — это open-source Python-библиотека и прокси-сервер, который предоставляет единый интерфейс для работы с более чем 100 LLM-провайдерами (OpenAI, Anthropic, Azure, AWS Bedrock и другие). Библиотека позволяет переключаться между моделями без изменения кода, автоматически обрабатывает фоллбэки и ретраи, отслеживает расходы. По данным PyPI, пакет загружается около 3,4 миллионов раз в день.</p><h3>Какие версии LiteLLM скомпрометированы?</h3><p>Скомпрометированы версии <b>1.82.7</b> и <b>1.82.8</b>, опубликованные на PyPI 24 марта 2026 года. Обе версии удалены. Последняя безопасная версия — <b>1.82.6</b>. Версия 1.82.8 опаснее: она запускает вредоносный код при каждом старте Python через механизм .pth-файлов, тогда как 1.82.7 активируется только при использовании прокси-сервера.</p><h3>Как проверить, затронут ли я?</h3><p>Выполните pip show litellm для проверки версии и find ~/.cache/uv -name "litellm_init.pth" для поиска вредоносного файла в кэше. Также проверьте наличие бэкдора: файлы ~/.config/sysmon/sysmon.py и ~/.config/systemd/user/sysmon.service. В Kubernetes ищите поды node-setup-* в namespace kube-system.</p><h3>Кто стоит за атакой?</h3><p>Атака приписывается группировке <b>TeamPCP</b>, которая за последнюю неделю марта 2026 года провела серию supply chain атак на инструменты разработки и безопасности: сканер уязвимостей Trivy (Aqua Security), GitHub Actions и расширения VS Code от Checkmarx, npm-пакеты, и в финале — LiteLLM. Инциденту присвоен идентификатор CVE-2026-33634.</p><h3>Что такое .pth-файл и почему он опасен?</h3><p>Файлы с расширением .pth, размещённые в директории site-packages, автоматически обрабатываются модулем site Python при каждом запуске интерпретатора. Исполняемые строки в таких файлах выполняются без явного импорта библиотеки. В случае LiteLLM 1.82.8 файл litellm_init.pth содержал дважды закодированный в base64 вредоносный скрипт, который запускался при каждом вызове python в скомпрометированном окружении.</p><h2>Выводы</h2><p>Ирония инцидента — в том, что LiteLLM по определению хранит API-ключи ко всем LLM-провайдерам организации. Атакующие выбрали пакет, который гарантированно имеет доступ к самым ценным секретам.</p><blockquote>Одна зависимость. Одна цепная реакция. Пять экосистем supply chain скомпрометированы менее чем за месяц</blockquote><p>TeamPCP целенаправленно атаковали инструменты безопасности — сканер уязвимостей, анализатор инфраструктурного кода, прокси для LLM. Эти инструменты по своей природе имеют широкий доступ, и компрометация одного из них даёт атакующим доступ ко всем секретам, которые этот инструмент должен был защищать.</p><p>Устанавливать пакеты из публичного реестра без проверки хешей и без lock-файлов — значит фактически отдать root-доступ любому, кто сможет скомпрометировать аккаунт мейнтейнера. Как ёмко выразилась Ноэлль Мурата, старший инженер по безопасности в Xcape: «Это цифровой эквивалент того, чтобы съесть бутерброд, найденный в метро, и удивиться пищевому отравлению».</p><p>Подробный технический анализ от Datadog Security Labs доступен <a href="https://securitylabs.datadoghq.com/articles/litellm-compromised-pypi-teampcp-supply-chain-campaign/">здесь</a>. Оригинальный отчёт FutureSearch — <a href="https://futuresearch.ai/blog/litellm-pypi-supply-chain-attack/">здесь</a>. Официальный security-апдейт LiteLLM — <a href="https://docs.litellm.ai/blog/security-update-march-2026">здесь</a>.</p><p><b>Проверьте свои зависимости сегодня.</b> Команды для аудита — <a href="https://tproger.ru/#remediation">в разделе выше</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Trivy: полный чек-лист по защите CI/CD и разбор инцидента</title>
      <link>https://tproger.ru/articles/ataki-na-trivy--kak-skaner-uyazvimostej-stal-vektorom-ataki-i-chto</link>
      <comments>https://tproger.ru/articles/ataki-na-trivy--kak-skaner-uyazvimostej-stal-vektorom-ataki-i-chto?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Свидетель пятничного деплоя]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/ataki-na-trivy--kak-skaner-uyazvimostej-stal-vektorom-ataki-i-chto</guid>
      <description><![CDATA[<p>Разбор двух атак на Trivy в феврале-марте 2026: CVE-2026-28353, ретроактивное отравление тегов GitHub Actions, CanisterWorm. Как проверить проект и защитить CI/CD.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/ataki-na-trivy--kak-skaner-uyazvimostej-stal-vektorom-ataki-i-chto">Trivy: полный чек-лист по защите CI/CD и разбор инцидента</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 22 Mar 2026 08:48:29 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Что произошло: компрометация Trivy в 2026 году</h2><p>В марте 2026 <b>Trivy</b> — один из наиболее популярных open-source сканеров уязвимостей — был скомпрометирован дважды за три недели. Пострадали тысячи CI/CD-пайплайнов по всему миру. Если ваш проект использует Trivy или связанные с ним GitHub Actions, эта информация критически важна для защиты вашей инфраструктуры.</p><h2>Хронология инцидентов: две атаки за три недели</h2><h3>Первая атака: CVE-2026-28353 и hackerbot-claw</h3><p>Даты: 21–28 февраля 2026</p><p>Злоумышленники эксплуатировали критическую уязвимость в GitHub Actions-воркфлоу через механизм <b>pull_request_target</b>. Автономный бот <b>hackerbot-claw</b> автоматически создал Pull Request #10252, что позволило выполнить произвольный код в контексте с доступом к секретам репозитория. Через эту атаку было скомпрометировано VSCode-расширение Trivy, а вредоносная версия v1.8.12 попала в Open VSIX Registry.</p><p>Инцидент получил идентификатор <b>CVE-2026-28353</b> с максимальной оценкой критичности <b>CVSS 10.0</b>. Это означает полную компрометацию конфиденциальности, целостности и доступности системы. Причём исходный disclosure discussion (#10265) был удалён во время второго инцидента, что вызвало критику сообщества за недостаточную прозрачность в обработке уязвимостей.</p><h3>Вторая атака: TeamPCP и ретроактивное отравление тегов</h3><p>Дата: 19 марта 2026</p><p>Группа <b>TeamPCP</b> использовала учётные данные, украденные в первом инциденте, и опубликовала вредоносный релиз <b>v0.69.4</b>. Однако главная особенность этой атаки — <b>ретроактивное отравление тегов</b>: атакующие переместили (force-push) 76 из 77 существующих тегов релизов так, чтобы они указывали на вредоносный код.</p><p>Это означает, что даже если вы использовали «старую стабильную версию», вы также могли получить малварь. Команды, которые зафиксировали версии через теги, оказались под ударом, поскольку теги были изменены задним числом. Полезная нагрузка обеих атак была направлена на кражу секретов CI/CD: GitHub-токенов, npm-токенов, API-ключей и других данных из GitHub Secrets.</p><h3>Каскадный эффект: CanisterWorm</h3><p>Ситуация усугубилась каскадным эффектом: украденные npm-токены запустили <b>CanisterWorm</b> — самораспространяющегося червя, который заразил от 28 до 47 пакетов в npm-реестре.</p><h2>Как проверить свой проект на компрометацию: инструкция</h2><p>Если вы использовали Trivy или связанные GitHub Actions в период с февраля по март 2026 года, по умолчанию считайте, что ваш пайплайн скомпрометирован. Выполните следующие проверки в указанном порядке.</p><h3>1. Проверьте версии Trivy и GitHub Actions</h3><p>Откройте ваши workflow-файлы (.github/workflows/*.yml) и найдите использования trivy-action и setup-trivy. Обратите особое внимание на версии.</p><p><b>Статус версий на момент публикации (22.03.2026, 14:30 GMT+3):</b></p><figure><img src="https://media.tproger.ru/user-uploads/134134/2026-03-22/aa57f0fb-e90f-4282-9da5-d17718ce7cbe.webp" alt="Статус версий Trivy и связанных расширений на момент публикации" /><figcaption><br /></figcaption></figure><h3>2. Проанализируйте логи CI/CD на подозрительную активность</h3><p>Вредоносный код выполнял запросы к внешним серверам для эксфильтрации данных. При анализе логов workflow-запусков обращайте внимание на следующие индикаторы компрометации:</p><ul><li>Необъяснимые HTTP-запросы к неизвестным доменам или IP-адресам.</li><li>Запросы к canister-контейнерам на блокчейне Internet Computer (ICP), это характерный признак CanisterWorm.</li><li>Странное поведение переменных окружения, особенно GITHUB_TOKEN и NPM_TOKEN.</li><li>Подозрительные base64-кодированные строки в выводе, которые могут маскировать полезную нагрузку.</li></ul><h3>3. Проверьте npm-пакеты на заражение CanisterWorm</h3><p>Если ваши npm-токены были скомпрометированы, злоумышленники могли опубликовать через них вредоносные версии ваших пакетов. CanisterWorm самораспространяется: каждый заражённый пакет пытается заразить другие пакеты, к которым имеет доступ.</p><p>Используйте инструменты для сканирования ваших npm-пакетов на наличие вредоносного кода, зарубежные кибербез-издания рекомендуют <b>Socket.dev</b> или <b>Snyk</b>.</p><p>Особое внимание стоит уделить пакетам, опубликованным или обновлённым в период <b>с 19 по 22 марта 2026 года</b> — именно в это время происходила первичная волна распространения CanisterWorm.</p><h3>4. Проведите аудит учётных данных и токенов</h3><p>Надо определить, какие секреты были доступны скомпрометированным workflow. Проверьте следующие категории токенов:</p><p><b>GITHUB_TOKEN</b> — автоматически предоставляется workflow → доступ к репозиторию и коду<br /><b>NPM_TOKEN</b> — публикация npm-пакетов → публикация вредоносных версий<br /><b>DOCKER_USERNAME/PASSWORD</b> — публикация контейнеров → компрометация образов<br /><b>AWS_ACCESS_KEY_ID/SECRET</b> — доступ к облаку → несанкционированный доступ к инфраструктуре</p><h2>Как защитить CI/CD пайплайн: практическое руководство</h2><h3>1. Немедленно ротируйте все секреты</h3><p>Делать надо при наличии хотя бы минимальной вероятности компрометации. Не ждите подтверждения: к тому моменту злоумышленники уже могут использовать ваши токены для дальнейших атак.</p><p><b>Последовательность действий:</b><b></b></p><ol><li>Сгенерируйте новые токены для всех сервисов (GitHub, npm, Docker Hub, AWS и других).</li><li>Обновите секреты в настройках репозитория</li><li>Проверьте, что новые токены работают корректно (запустите тестовый workflow).</li><li>Отзовите старые токены.</li></ol><h3>2. Закрепляйте версии GitHub Actions через SHA-хеши</h3><p>Вместо тегов используйте <b>неизменяемые ссылки по SHA-хешу</b>. Это один из наиболее эффективных методов защиты от атак на зависимости.</p><p>Для получения SHA-хеша конкретной версии перейдите на страницу релиза или используйте команду git ls-remote для получения хеша конкретного тега.</p><h3>3. Реализуйте принцип минимальных привилегий для GITHUB_TOKEN</h3><p>По умолчанию GITHUB_TOKEN имеет достаточно широкие права доступа. Ограничьте их до минимально необходимых для каждого конкретного workflow:</p><ul><li>Отключите запись, если workflow только читает данные</li><li>Используйте блок permissions в каждом workflow для явного указания требуемых прав</li><li>Не передавайте токен в шаги, которым он не нужен</li></ul><h3>4. Защитите pull_request_target</h3><p>Этот тип триггера особенно опасен: workflow выполняется в контексте базовой ветки с доступом к секретам. Если вам необходим pull_request_target, применяйте следующие меры защиты:</p><p><b>Никогда не выполняйте код из PR</b> в контексте с секретами — сначала проверяйте источник. <br /><br /><b>Используйте явные проверки</b> на доверенные источники перед выполнением кода. <br /><br /><b>Рассмотрите альтернативные паттерны</b> запуска workflow, например pull_request вместо pull_request_target. <br /><br /><b>Изолируйте привилегированные операции</b> в отдельные workflow с ограниченным доступом.</p><h3>5. Настройте мониторинг и оповещения</h3><p>Настройте мониторинг на все критичные точки входа в ваш CI/CD процесс:</p><ul><li>Уведомления о необычных workflow-запусках — особенно в нерабочее время или из незнакомых источников.</li><li>Алерты на подозрительные исходящие запросы из CI/CD (особенно на неизвестные домены и IP).</li><li>Контроль публикаций пакетов — отслеживайте, кто, когда и откуда публикует пакеты в ваши реестры.</li></ul><p>А ещё чистите зубы, мойте руки с мылом и надевайте шапку.</p><h2>Технические детали для юных детективов: как сработали атаки на Trivy</h2><h3>Бот hackerbot-claw</h3><p>Инцидент начался 27 февраля 2026 года, когда автономный бот hackerbot-claw создал Pull Request #10252 в репозитории Trivy. Бот эксплуатировал workflow с использованием pull_request_target, который позволял выполнить произвольный код в контексте с доступом к секретам репозитория.</p><p>Результат атаки — скомпрометированное VSCode-расширение Trivy. Версия 1.8.12, попавшая в Open VSIX Registry, содержала вредоносный код, который выполнял следующие действия:</p><ol><li>Собирал конфиденциальные данные из среды разработки пользователя.</li><li>Эксфильтрировал украденные данные на командный сервер злоумышленников.</li><li>Создавал персистентный бэкдор для повторного доступа.</li></ol><p>NVD зарегистрировала инцидент как <b>CVE-2026-28353</b> с оценкой CVSS 10.0 — максимально возможной оценкой, указывающей на полную компрометацию информационной безопасности.</p><h3>Ретроактивное отравление тегов</h3><p>Группа TeamPCP получила write-доступ к репозиторию Trivy через скомпрометированные учётные данные, украденные в первом инциденте.</p><p>Ключевая инновация атаки — ретроактивное отравление тегов. Атакующие не просто опубликовали новую вредоносную версию — они переместили 76 из 77 существующих тегов так, чтобы те указывали на вредоносный код. Это означает, что под удар попадает любой пользователь, который:</p><ul><li>Использовал trivy-action@latest</li><li>Использовал конкретную версию через тег</li><li>Фиксировал зависимости через теги</li></ul><h3>CanisterWorm: блокчейн как командный сервер</h3><p>Отдельного внимания заслуживает CanisterWorm — малварь, распространившаяся через скомпрометированные npm-токены.</p><p><b>Ключевые особенности CanisterWorm:</b></p><ol><li>Использование блокчейна Internet Computer (ICP) как C2-сервера — децентрализованная инфраструктура, устойчивая к традиционным методам блокировки доменов и IP-адресов.</li><li>Автоматическое распространение — каждый заражённый пакет пытается заразить другие пакеты в экосистеме.</li><li>Кража токенов из среды разработчиков и CI/CD окружения для расширения сферы влияния.</li><li>Персистентный бэкдор для повторного несанкционированного доступа.</li></ol><h2>FAQ / TLDR</h2><h3>Как проверить, использовал ли я скомпрометированную версию Trivy?</h3><p>Проверьте ваши workflow-файлы в .github/workflows/*.yml на наличие версий v0.69.4 для Trivy или любых версий для trivy-action от 19 марта 2026 года. Также проверьте логи CI/CD на подозрительную активность: исходящие запросы к неизвестным доменам, особенно к canister-контейнерам на ICP.</p><h3>Что делать, если я обнаружил компрометацию?</h3><p>Немедленно ротируйте все секреты, которые передавались в workflow, отдельное внимание уделите GITHUB_TOKEN и NPM_TOKEN. Проверьте npm-пакеты на заражение CanisterWorm с помощью Socket.dev или Snyk. Проведите аудит всех публикаций в реестры за период с февраля по март 2026 года.</p><h3>Почему атака на сканер уязвимостей особенно опасна?</h3><p>Инструменты безопасности работают с максимальными привилегиями в инфраструктуре. Они имеют доступ к коду, секретам и конфиденциальным данным. Компрометация инструмента безопасности даёт злоумышленнику всё то, что этот инструмент защищает — секреты CI/CD, код и доступ к инфраструктуре.</p><h3>Как защититься от атак на зависимости в будущем?</h3><p>Используйте SHA-хеши вместо тегов для закрепления версий зависимостей. <br /><br />Применяйте принцип минимальных привилегий для всех токенов в CI/CD.<br /><br />Настройте регулярную ротацию секретов. <br /><br />Мониторьте исходящий трафик из CI/CD на предмет аномалий. <br /><br />Проводите регулярный аудит зависимостей и их источников.</p><p>Материал подготовлен по открытым данным.</p><p><b>Основные источники:</b> CrowdStrike, StepSecurity, Socket.dev, Ars Technica, Apache Foundation, Aikido Security, The Hacker News, NVD (CVE-2026-28353), GitHub Discussion #10265, Chainguard.</p>]]></content:encoded>
    </item>
    <item>
      <title>Заглянуть под капот ИИ-агентов: новый инструмент раскрывает «магию» Claude Code</title>
      <link>https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag</link>
      <comments>https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Неопознанный программист]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag</guid>
      <description><![CDATA[<p>Появился Coding Agent Explorer: инструмент раскрывает, как Claude Code читает файлы, вызывает инструменты и тратит токены при разработке</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/zaglyanut-pod-kapot-ii-agentov--novyj-instrument-raskryvaet--mag">Заглянуть под капот ИИ-агентов: новый инструмент раскрывает «магию» Claude Code</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Промпты]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 19 Feb 2026 11:05:51 GMT</pubDate>
      <content:encoded><![CDATA[<p>ИИ-агенты любят создавать ощущение магии. Например, вы даете задачу — «добавь авторизацию через JWT». Затем минуту смотрите на мигающий курсор, после чего внезапно появляются изменения в семи файлах, новые тесты и коммит. Что происходило все это время — остается за кадром.</p><p>Шведский разработчик Торе Нестениус решил <a href="https://nestenius.se/ai/introducing-the-coding-agent-explorer-net/">сорвать</a> занавес. Он <a href="https://github.com/tndata/CodingAgentExplorer" rel="nofollow">выпустил</a> Coding Agent Explorer — открытый прокси-сервер, который в реальном времени показывает все общение между агентом и API Anthropic.</p><p>Сейчас поддерживается только Claude Code, но уже в таком виде инструмент дает неожиданно глубокое понимание того, как работает агентная разработка.</p><h2>Что именно он показывает</h2><p>Explorer перехватывает HTTP-запросы и визуализирует:</p><ul><li>системные промпты (часто намного длиннее, чем кажется);</li><li>последовательность вызовов инструментов (Read, Grep, Write, Bash);</li><li>шаги «размышления» агента;</li><li>распределение задач между моделями (например, Haiku для рутинных операций и Sonnet/Opus для сложной логики);</li><li>статистику токенов, включая кэш (cache_creation_tokens и cache_read_tokens).</li></ul><p>По сути, инструмент можно воспринимать как «рентген для агентной разработки». Видно, какие файлы агент читает, как ищет паттерны в коде, почему он внезапно запускает тесты и сколько это стоит в токенах.</p><p>В интерфейсе два режима. HTTP Inspector — сухая таблица со всеми JSON-телами, временем ответа и расходом токенов. Conversation View — более «человеческий» режим, где процесс выглядит как диалог: шаги планирования, проверки гипотез, исправления ошибок.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-02-19/a137b978-5b64-416e-a3a5-d4302b1937b7.webp" alt="" /></figure><h2>Зачем это нужно</h2><p>Изначально инструмент задумывался как учебный — автор использует его на воркшопах по агентной разработке. Но практическая ценность оказалась шире.</p><p>Когда агент «зависает», теперь можно увидеть, что он на самом деле делает: перебирает файлы, пересобирает контекст или тратит половину лимита токенов на анализ README.</p><p>А уже это помогает оптимизировать промпты и понимать реальную стоимость задач. В итоге ИИ перестает быть черным ящиком.</p><h2>Безопасность и ограничения</h2><p>Explorer работает только локально (localhost). API-ключи автоматически маскируются в интерфейсе.</p><p>Данные не сохраняются — все хранится в памяти и ограничено примерно тысячей запросов. Никаких внешних сервисов и баз данных.</p>]]></content:encoded>
    </item>
    <item>
      <title>В VS Code нашли дыру, дающую бесплатный доступ к платным ИИ-агентам</title>
      <link>https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen</link>
      <comments>https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen</guid>
      <description><![CDATA[<p>В VS Code нашли дыру в Copilot: обход биллинга дает бесплатный доступ к платным ИИ-агентам через subagent-режим</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-vs-code-nawli-dyru--dayushhuyu-besplatnyj-dostup-k-platnym-ii-agen">В VS Code нашли дыру, дающую бесплатный доступ к платным ИИ-агентам</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 04 Feb 2026 11:30:16 GMT</pubDate>
      <content:encoded><![CDATA[<p>В VS Code обнаружили уязвимость, которая позволяет получать практически неограниченный доступ к платным ИИ-моделям. При этом «премиум-запросы» не списываются.</p><p>Об этом <a href="https://github.com/microsoft/vscode/issues/292452">сообщил</a> пользователь GitHub под ником Angry-Orangutan, опубликовав подробный баг-репорт в публичном репозитории Microsoft.</p><p>Проблема затрагивает новый режим agent / subagent в Copilot и связана не с безопасностью в классическом смысле, а с биллингом. Тем не менее, эффект от нее вполне материальный: дорогие модели вроде Claude Opus можно использовать бесплатно и сколько угодно долго.</p><h2>Как работает обход биллинга</h2><p>Механизм уязвимости строится на нескольких допущениях в архитектуре Copilot.</p><p>Во-первых, стоимость запроса рассчитывается только по первой модели, которая принимает сообщение. Во-вторых, запуск подагентов (subagents) и вызовы инструментов не учитываются как отдельные платные операции.</p><p>В результате пользователь может начать чат с «бесплатной» моделью, например GPT-5 Mini, а затем внутри нее создать подагента, явно указав для него уже премиум-модель.</p><p>Дальше все просто: бесплатная модель делегирует работу подагенту, а тот выполняет задачи с помощью Opus или другого дорогого ИИ — без списания лимитов. По словам автора отчета, таким способом он запускал сотни подагентов и часами обрабатывал файлы, потратив всего несколько платных кредитов.</p><h2>Реакция Microsoft</h2><p>Интересно, что изначально исследователь пытался передать проблему через MSRC — стандартный канал ответственного раскрытия уязвимостей. Однако там ответили, что «обход биллинга не относится к сфере безопасности» и предложили оформить баг публично.</p><p>В итоге issue действительно появилась в открытом репозитории VS Code, но довольно быстро была закрыта со статусом «not planned». Это означает, что компания не обещает что-либо исправить и уж тем более не комментирует сроки.</p><p>Это решение вызвало волну иронии в обсуждении: пользователи отметили, что Microsoft фактически оставила инструкцию по бесплатному использованию платных моделей в открытом доступе.</p><h2>Почему это важно</h2><p>Формально речь идет не о взломе, а о логической ошибке в расчете стоимости запросов. Но на практике уязвимость подрывает саму модель монетизации Copilot и агентных функций VS Code.</p>]]></content:encoded>
    </item>
    <item>
      <title>Линус Торвальдс впервые описал, что будет с Linux без него</title>
      <link>https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego</link>
      <comments>https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego</guid>
      <description><![CDATA[<p>Линус Торвальдс впервые описал план преемственности Linux на случай своего ухода и коллективное управление ядром проекта</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/linus-torvalds-vpervye-opisal--chto-budet-s-linux-bez-nego">Линус Торвальдс впервые описал, что будет с Linux без него</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 28 Jan 2026 09:42:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В репозитории ядра Linux появился <a href="https://github.com/torvalds/linux/commit/102606402f4f5943266160e263c450fdfe4dd981#diff-6c81210e8795b03502471e1435cac0763110f72b823038bd0033eb617c15ab8d" rel="nofollow">документ</a>, которого раньше не существовало.</p><p>Линус Торвальдс закоммитил файл Project continuity — формальный план действий на случай, если он больше не сможет выполнять роль главного мейнтейнера проекта.</p><p>Переживать не стоит — пока что речи о скором уходе или передаче власти «наследнику» не идет. Документ скорее фиксирует то, как сообщество должно действовать в кризисной ситуации — внезапной и без предварительной подготовки.</p><p>Ранее подобные вопросы в Linux решались негласно и на уровне доверия, но теперь процесс впервые описан письменно.</p><h2>Почему это вообще понадобилось</h2><p>Linux — распределенный проект с сотнями мейнтейнеров, но финальная точка принятия решений по-прежнему сходится в одном месте: в основном репозитории ядра.</p><p>Исторически эту роль выполняет сам Торвальдс. Именно он принимает изменения в mainline и определяет, что считается «официальным» Linux.</p><p>В коммите напрямую упоминается релиз 4.19 в 2018 году — момент, когда Торвальдс временно отошел от проекта.</p><p>Тогда стало очевидно, что даже при развитой системе мейнтейнеров отсутствие одного человека создает управленческую неопределенность. Новый документ — попытка эту неопределенность устранить.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-01-28/02bf2609-9870-459d-87b3-614f41f79c2c.webp" alt="" /></figure><h2>Как выглядит план преемственности</h2><p>Если кратко, Linux не переходит под контроль одного нового лидера автоматически. Вместо этого запускается процесс коллективного управления.</p><p>Организатор последнего Linux Maintainers Summit обязан в течение 72 часов собрать обсуждение с участниками саммита и Technical Advisory Board (TAB) Linux Foundation.</p><p>Эта группа рассматривает варианты дальнейшего управления репозиторием: временные или постоянные, индивидуальные или коллегиальные.</p><p>Ключевая цель формулируется прямо в тексте — сохранить долгосрочное здоровье проекта и сообщества, а не просто «назначить замену».</p><p>Если саммит давно не проводился, состав участников определяет TAB. Через две недели после встречи, сообщество получает публичное разъяснение дальнейших шагов через официальную рассылку kernel.org.</p>]]></content:encoded>
    </item>
    <item>
      <title>В Кремниевой долине сотрудников начали заменять на Mac mini с установленным ИИ-ботом</title>
      <link>https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us</link>
      <comments>https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us</guid>
      <description><![CDATA[<p>В Кремниевой долине стартапы заменяют сотрудников на Mac mini с ИИ-ботом Clawdbot, который работает 24/7 и берет на себя рутину</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-kremnievoj-doline-sotrudnikov-nachali-zamenyat-na-mac-mini-s-us">В Кремниевой долине сотрудников начали заменять на Mac mini с установленным ИИ-ботом</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Стартапы]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Notion]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 26 Jan 2026 06:50:10 GMT</pubDate>
      <content:encoded><![CDATA[<p>В Кремниевой долине появился новый мем, который стремительно перестает быть шуткой.</p><p>Стартапы начали скупать Mac mini и использовать их не как персональные компьютеры, а как круглосуточных цифровых сотрудников. На этих машинах крутится <a href="https://github.com/clawdbot/clawdbot" rel="nofollow">Clawdbot</a> — ИИ-ассистент, который берет на себя рутину и работает без выходных.</p><h2>Mac mini как «железный сотрудник»</h2><p>Компактный компьютер от Apple неожиданно оказался идеальным форматом для ИИ-работника.</p><p>Он тихий, энергоэффективный и может быть включен 24/7. В результате Mac mini стали использовать как отдельные рабочие узлы: один — для коммуникаций, другой — для автоматизации задач, третий — для интеграций с сервисами.</p><p>В некоторых офисах уже собирают целые стойки из Mac mini. Каждый такой «миник» выполняет строго определенную функцию, а в сумме они заменяют несколько операционных ролей внутри команды.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-01-26/c44147c4-409d-4d1c-abe1-4c97a19ec164.webp" alt="" /></figure><h2>Во главе угла — Clawdbot</h2><p>В сети Clawdbot частенько сравнивают с ассистентом Тони Старка — Джарвисом. Причин тому несколько. Так, это не просто чат с нейросетью, а полноценный помощник, который умеет работать с приложениями, файлами и сервисами так, как это делал бы человек.</p><p>Он пишет и отвечает на сообщения в мессенджерах, управляет файлами на компьютере, автоматизирует повторяющиеся действия и взаимодействует с популярными сервисами вроде Gmail, Notion или GitHub.</p><p>При этом бот запоминает контекст, учитывает предыдущие действия и постепенно подстраивается под стиль работы конкретной команды.</p><p>Ключевой момент — Clawdbot живет локально, на отдельной машине. Да, это не облачный ассистент, принадлежащий какой-то крупной компании.</p><h2>Почему стартапы выбирают именно такой формат</h2><p>Использование Mac mini вместо облачных серверов или виртуальных рабочих столов оказалось неожиданно практичным. Машины легко масштабировать, они не требуют сложной инфраструктуры и обходятся дешевле в долгосрочной перспективе. Один раз купил, настроил и получил «сотрудника», который всегда на месте.</p>]]></content:encoded>
    </item>
    <item>
      <title>Фальшивый сайт Microsoft Activation Scripts заразил Windows трояном</title>
      <link>https://tproger.ru/news/falwivyj-sajt-microsoft-activation-scripts-zarazil-windows-troyanom</link>
      <comments>https://tproger.ru/news/falwivyj-sajt-microsoft-activation-scripts-zarazil-windows-troyanom?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/falwivyj-sajt-microsoft-activation-scripts-zarazil-windows-troyanom</guid>
      <description><![CDATA[<p>Хакеры заразили Windows через поддельный сайт Microsoft Activation Scripts: из-за одной буквы пользователи запускали PowerShell и устанавливали троян Cosmali Loader</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/falwivyj-sajt-microsoft-activation-scripts-zarazil-windows-troyanom">Фальшивый сайт Microsoft Activation Scripts заразил Windows трояном</a>»</p>]]></description>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 25 Dec 2025 04:39:35 GMT</pubDate>
      <content:encoded><![CDATA[<p>Исследователи <a href="https://www.bleepingcomputer.com/news/security/fake-mas-windows-activation-domain-used-to-spread-powershell-malware/">выяснили</a>, что хакеры зарегистрировали поддельный домен, маскирующийся под официальный сайт <b>Microsoft Activation Scripts (MAS)</b>.</p><p>Далее его использовали для <b>распространения вредоносных PowerShell-скриптов</b>. В результате на компьютеры с Windows устанавливался <b>троян Cosmali Loader</b>.</p><p>Инцидент стал заметен после того, как пользователи MAS начали массово жаловаться на Reddit — на их компьютерах появлялись всплывающие уведомления о заражении.</p><h2>Одна буква и система скомпрометирована</h2><p>Атакующие зарегистрировали домен get.activate[.]win, который визуально почти не отличается от легитимного get.activated.win. Разница — всего в одной букве <i>«d»</i>.</p><p>Этого оказалось достаточно, чтобы часть пользователей <b>вручную ввела неверный адрес</b> и запустила вредоносный код.</p><p>После выполнения команды, в системе загружался Cosmali Loader — <b>открытый вредоносный загрузчик</b>, который затем устанавливал дополнительные компоненты.</p><p>По данным исследователей, среди полезной нагрузки были <b>криптомайнеры</b> и <b>XWorm RAT</b> — троян удаленного доступа, позволяющий полностью контролировать зараженный компьютер.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-12-25/2fd3fcd0-22a2-4044-80a8-5c82ce5999b8.jpeg" alt="" /></figure><h2>Странные предупреждения и «доброжелательный взлом»</h2><p>Интересная деталь инцидента — сами предупреждения о заражении. Они выглядели как пугающие pop-up сообщения <b>с советом переустановить Windows и проверить диспетчер задач на подозрительные PowerShell-процессы</b>.</p><p>По мнению специалистов, эти уведомления мог отправить не сам злоумышленник, а исследователь, получивший доступ к панели управления вредоносным ПО.</p><h2>Что такое MAS и почему это риск</h2><p>Microsoft Activation Scripts — это open-source набор PowerShell-скриптов, размещенный на GitHub. Он используется <b>для активации Windows и Office с помощью HWID, эмуляции KMS и других обходных методов</b>.</p><p>Microsoft считает MAS пиратским инструментом, т.к он позволяет активировать продукты без покупки лицензии.</p>]]></content:encoded>
    </item>
    <item>
      <title>Вышла PatchworkOS — минималистичная ОС, где «все — файл» даже больше, чем в UNIX</title>
      <link>https://tproger.ru/news/vywla-patchworkos---minimalistichnaya-os--gde--vse---fajl--dazhe-bolwe--chem-v-unix</link>
      <comments>https://tproger.ru/news/vywla-patchworkos---minimalistichnaya-os--gde--vse---fajl--dazhe-bolwe--chem-v-unix?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/vywla-patchworkos---minimalistichnaya-os--gde--vse---fajl--dazhe-bolwe--chem-v-unix</guid>
      <description><![CDATA[<p>PatchworkOS — экспериментальная минималистичная ОС, где процессы, события и ядро представлены как файлы. Проект исследует радикальное развитие идеи «все — файл» в духе UNIX</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/vywla-patchworkos---minimalistichnaya-os--gde--vse---fajl--dazhe-bolwe--chem-v-unix">Вышла PatchworkOS — минималистичная ОС, где «все — файл» даже больше, чем в UNIX</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[unix]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 22 Dec 2025 07:05:33 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчик Кай Норберг <a href="https://github.com/KaiNorberg/PatchworkOS">представил</a> <b>PatchworkOS</b> — минималистичную операционную систему, построенную вокруг принципа <b>«все есть файл»</b>.</p><p>Но если в UNIX это скорее философия с оговорками, то в PatchworkOS идея <b>доведена почти до абсолюта</b>. Здесь файлами считаются не только данные, но и процессы, события, таймеры и даже взаимодействие с ядром.</p><p>Проект носит исследовательский характер и не претендует на роль универсальной ОС для повседневного использования.</p><h2>Как работает «все — файл» в PatchworkOS</h2><p>В PatchworkOS файловая система — это главный интерфейс ко всему, что происходит в системе.</p><p>Процессы представлены <b>в виде каталогов</b>, их состояние — <b>в виде файлов</b>, а управление ими сводится к обычным <b>операциям чтения</b> и <b>записи</b>.</p><p>Например, чтобы отправить сигнал процессу или изменить его параметры, не нужен отдельный системный вызов. Достаточно записать нужное значение в соответствующий файл. Аналогичным образом работают таймеры, события и даже планировщик задач.</p><p>Сам автор проекта описывает PatchworkOS как <b>систему, где файловая и процессная модели слиты воедино, а граница между «данными» и «поведением» намеренно размыта</b>.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-12-22/bbeeffe1-d861-4ee2-9d98-1f0a680c6381.jpeg" alt="" /></figure><h2>Минимум абстракций и максимум прозрачности</h2><p>PatchworkOS написана с упором на <b>простоту и читаемость</b>. В системе нет привычного набора пользовательских утилит, сложных демонов или развитой экосистемы.</p><p>Зато есть понятная структура, которую можно изучать, модифицировать и расширять. ОС запускается в эмуляторе и ориентирована в первую очередь на разработчиков, студентов и энтузиастов, которым интересно устройство операционных систем на низком уровне.</p><p>Норберг отдельно отмечает, что его операционка — это <b>не Linux-дистрибутив</b> и <b>не попытка конкурировать с существующими ОС</b>.</p><h2>Ограничения и честные предупреждения</h2><p>Автор прямо говорит о лимитах своего проекта. PatchworkOS не поддерживает многопользовательский режим, не рассчитана на безопасность в привычном смысле и не оптимизирована для производительности.</p><p>Многие механизмы реализованы намеренно наивно — ради наглядности, а не скорости. Именно поэтому проект сопровождается подробной документацией, объясняющей, почему система устроена так, а не иначе.</p>]]></content:encoded>
    </item>
  </channel>
</rss>