Русский
Русский
English
Статистика
Реклама

E2e

Как криптомессенджер Signal успешно противостоит прослушке со стороны властей США

16.06.2020 10:18:24 | Автор: admin


На фоне событий в США резко выросла популярность защищённого мессенджера Signal c 6000 до 26 000 скачиваний в день. В этой программе реализована стойкая криптография и сквозное шифрование, она распространяется с открытым исходным кодом и работает на известных криптографических протоколах (в отличие от проприетарного MProto).

Но теперь разработчики Signal столкнулись с новой угрозой. Правительство США пытается скомпрометировать защиту мессенджера и опять получить доступ к переписке пользователей. В 2016 году им удалось получить судебную повестку на изъятие переписки одного пользователя, но из-за сквозного шифрования там нечего было изымать.

Единственные данные, которые Signal может предоставить по запросу правительственных служб или по судебной повестке только те данные, которые она хранит о пользователе. Это:

  • дата создания аккаунта в Unix-времени;
  • дата последнего использования в Unix-времени.

И это всё. Никаких контактов, информации о группах и данных из профиля.


Досье пользователя, которое Signal предоставил по судебному запросу. Скриншот из судебных документов

Мы разработали Signal таким образом, чтобы персональные данные хранились у клиентов, а не у нас, пишут разработчики. Signal использует сквозное шифрование, так что мы никогда не имеем доступа к содержимому сообщений, которые вы отправляете. Они видны только вам и предполагаемым получателям. Однако Signal также применяет эту философию дизайна и к остальным вашим данным.

В отличие от любых других популярных мессенджеров, у Signal нет доступа к контактам, социальному графу, групповым данным, информации о состоянии в группах, имени профиля, аватару профиля, данным о местоположении, истории поиска и так далее. В коде программы отсутствуют трекеры, реклама или код для аналитики. Абсолютно вся информация зашифрована, кроме даты создания аккаунта и даты последнего использования, как показано на скриншоте.


Кадр из лекции Мокси Марлинспайка на конференции по информационной безопасности Chaos Computer Club в декабре 2019 года с демонстрацией учётных данных его личного аккаунта Signal

Поскольку мы создали Signal, чтобы полностью избежать хранения какой-либо конфиденциальной информации, я могу выйти на сцену перед тысячами людей и публично опубликовать все данные своей учётной записи, не раскрыв при этом ничего, кроме того, как давно у меня установлен Signal (с тех пор, как я последний раз поменял телефон) и последней даты, когда я его использовал (это сегодня, кстати), говорит Мокси Марлинспайк (Moxie Marlinspike), известный хакер, криптоанархист и основной разработчик программы.

Главная слабость Signal и подобных мессенджеров привязка к конкретному номеру телефона. Например, если посторонний присоединиться к некоей группе, то увидит телефонные номера всех участников этой группы. Этот приём использовала полиция Гонконга, чтобы установить личности протестующих в WhatsApp, Signal и Telegram-.

С другой стороны, остальные данные аккаунта злоумышленник не получит даже по судебному запросу.

Если вы попросите генерального директора любой другой крупной коммуникационной платформы публично опубликовать свои учётные данные со своей платформы, он этого не сделает, пишет Мокси. Я их не виню это много данных, которыми неудобно делиться с вами, но это поднимает вопрос о том, насколько комфортно делиться теми же данными с ними [властями].

Любая американская компания обязана выполнять правила американского законодательства и предъявлять данные по судебному запросу, будь то WhatsApp или Signal. Но в случае Signal ей просто нечего будет предъявить.

В некоторых странах после утечек из WhatsApp даже военных и политиков переводят на обязательное использование криптомессенджеров Signal и Wickr. Например, такие правила установлены для бойцов 82-й воздушно-десантной дивизии армии США и для коммуникации членов консервативной партии Великобритании. Так что наличие на телефоне Signal не признак подозрительной активности, а скорее признак наличия здравого смысла.

Отсутствие персональных данных во владении компании единственная стратегия, которая позволяет обеспечить безопасность этих данных, уверены создатели Signal. Соответственно, доверие к любой компании сводится не к доверию сохранности наших личных данных, а к доверию их инженерным способностям и ноу-хау для разработки программного обеспечения, которое не допустит передачи личных данных от пользователя и гарантирует, что они хранятся только у него и больше никому не доступны, включая саму компанию.

Signal это некоммерческая организация 501(с)(3), поэтому программное обеспечение было и останется свободным и бесплатным. Наша миссия заключается в повышении конфиденциальности в интернете, поэтому мы публикуем нашу технологию и делимся знаниями, чтобы побудить другие компании использовать её в своих собственных продуктах и услугах, пишет Мокси Марлинспайк. Сегодня на протоколе Signal работают некоторые другие мессенджеры, хотя и они и не реализовали строгий отказ от сбора персональной информации о пользователях и продолжают хранить на своих серверах контакты, разговоры, фотографии и прочие данные для каждого аккаунта. Например, WhatsApp тоже использует защищённый протокол Signal, однако передаёт в материнскую компанию Facebook социальный граф пользователя. То же самое относится к коммерческим компаниям Telegram FZ LLC и Telegram Messenger Inc. В случае Signal на сервер передаётся только усечённый хеш каждого телефонного номера из списка контактов. Такой хеш нельзя сбрутить напрямую, хотя и о полной секретности речи не идёт.

Конечно, существуют более защищённые и надёжные мессенджеры со сквозным шифрованием, без указания телефонного номера и других идентификаторов. Например, P2P-система прямого обмена шифрованными сообщениями Matrix с клиентским программным обеспечением типа Riot и другими клиентами.


Интерфейс клиента Riot для пиринговой криптосети Matrix

Но пока эти программы не очень дружественны к пользователям. Например, чтобы в десктопном клиенте Riot отменить отправку подтверждений о прочтении, нужно отредактировать файл конфигурации /etc/riot/config.json.

Подробнее..

Перевод Примеры грамотного применения SSH-шаблонов

17.02.2021 20:19:33 | Автор: admin


SSH-сертификаты очень мощный инструмент. Первоначально в удостоверяющем центре step-ca мы реализовали только минимальный набор функций для аутентификации по сертификатам пользователя и хоста. Затем добавили шаблоны сертификатов X.509, а ещё в августе прошлого года и SSH-шаблоны, в версии 0.15.2. Наконец, мы задокументировали эту функцию и готовы о ней рассказать.

Шаблоны для сертификатов SSH действуют аналогично шаблонам X.509: это JSON-файлы, написанные в Go text/template. Они применяются для настройки SSH-сертификатов, которые выдаёт step-ca. Давайте посмотрим, что представляют собой эти шаблоны и как их можно использовать.

По умолчанию шаблон пользовательского SSH-сертификата выглядит так:

{"type": {{ toJson .Type }},"keyId": {{ toJson .KeyID }},"principals": {{ toJson .Principals }},"extensions": {{ toJson .Extensions }},"criticalOptions": {{ toJson .CriticalOptions }}}

А вот SSH-сертификат, выданный по этому шаблону:

$ step ssh inspect id_ct-cert.pubid_ct-cert.pub:        Type: ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate        Public key: ECDSA-CERT SHA256:iczSh1XiBBE36yfJcDidgp6fqY3qWx1RtEwFfAN9jDs        Signing CA: ECDSA SHA256:MKwRQ/SDKk/pCJbbCk5bfhZACjSjv7uZXLyc5n4Wx6k        Key ID: "carl@smallstep.com"        Serial: 2831574724231262409        Valid: from 2020-11-17T16:48:11 to 2020-11-18T08:49:11        Principals:                carl                carl@smallstep.com        Critical Options: (none)        Extensions:                permit-X11-forwarding                permit-agent-forwarding                permit-port-forwarding                permit-pty                permit-user-rc

Он позволяет юзеру carl (или carl@smallstep.com) пройти аутентификацию на любом SSH-хосте, который доверяет моему SSH CA. Сертификат включает в себя некоторые основные расширения:

  • permit-x11-forwarding: Разрешает переадресацию X11 (с помощью ssh -X) для запуска удалённых программ X11 на локальном дисплее.
  • permit-agent-forwarding: Разрешает переадресацию агента (с помощью ssh -A) для пересылки ключей из локального агента SSH на удалённый хост (подробнее про агента SSH см. здесь).
  • permit-port-forwarding: Разрешает переадресацию портов (туннель) с локального на удалённый порт (ssh -L) или с удалённого на локальный (ssh -R).
  • permit-pty: Очень важное расширение. Если хотите открыть интерактивную сессию в консоли, хост должен выделить вам pty (псевдо-tty). В противном случае не предусмотрено никакой интерактивности. Например, для проверки SSH-аутентификации на GitHub можно запустить ssh -T git@github.com (-T отключает запрос на pty).
  • permit-user-rc: Запуск личного RC-файла после подключения (находится в ~/.ssh/rc на удалённом хосте).

Сертификаты пользователя и хоста поддерживают расширения и критические параметры, но OpenSSH не определяет никаких встроенных расширений или критических параметров для сертификатов хоста. Таким образом, всё самое интересное происходит именно с сертификатами пользователя, поэтому в данной статье рассмотрим только их.

Примеры шаблонов сертификатов


Внесём несколько изменений в дефолтный шаблон.

Запрещаем переадресацию агента и портов

Если пользователи подключаются к внутренним хостам через хост-бастион, то хорошо бы запретить перенаправление портов по соображениям безопасности. Вы же не хотите, чтобы юзеры перенаправили трафик с продакшн-сервера MySQL на свой localhost. Так же и переадресация агента сопряжена с риском для безопасности. Вот шаблон, который просто удаляет эти два расширения из сертификатов SSH:

{"type": {{ toJson .Type }},"keyId": {{ toJson .KeyID }},"principals": {{ toJson .Principals }},"extensions": {           "permit-x11-forwarding": "",           "permit-pty": "",           "permit-user-rc": ""  },"criticalOptions": {{ toJson .CriticalOptions }}}

Встраиваем директиву force-command

ForceCommand это серверная директива конфигурации SSHD, которая вместо интерактивного терминала запускает на хосте альтернативную команду. Но с тем же эффектом можно встроить force-command прямо в сертификат в раздел Critical Options:. Может пригодиться для служебных аккаунтов, которым необходимо выполнить только одну команду, например, запустить задание в удалённой системе.

Ограничиваем соединения по адресам

Чтобы ограничить область использования сертификата, в него можно встроить список разрешённых IP-адресов (блоков CIDR).

Вот шаблон сертификата, который использует и source-address, и force-command.

{"type": {{ toJson .Type }},"keyId": {{ toJson .KeyID }},"principals": {{ toJson .Principals }},"extensions": {{ toJson .Extensions }},"criticalOptions": {"force-command": "echo \"Hello World\"","source-address": "10.20.30.0/24,1.1.1.1/32"}}

Это нормальный пример, но здесь список IP жёстко зафиксирован и не изменяется. А нам обычно хочется использовать разные списки адресов для разных пользователей. Давайте попробуем

Вставляем разные значения для разных юзеров

Очевидно, пользователям нельзя давать право редактировать диапазон адресов. Следовательно, динамические значения должны поступать из надёжного источника.

Для этого в step-ca можно через поставщика OpenID Connect (OIDC) настроить провайдера OAuth на добавление к токену нестандартных требований (custom claim), содержащих блоки адресов CIRD, которые мы хотим добавить в сертификат этого пользователя.

Поставщик OIDC представляет собой идеальный способ выдачи SSH-сертификатов в step-ca. В статье DIY Single Sign-On for SSH я рассказывал, как настроить SSH CA, чтобы он выдавал краткосрочные SSH-сертификаты по ID-токенам от доверенного провайдера OAuth. Если step-ca настроен как доверенный клиент OAuth, он будет считывать поле email из токена ID и извлекать оттуда список участников SSH-сертификата (например, по полю carl@smallstep.com сгенерируются сертификаты для carl и carl@smallstep.com).

Но OIDC позволяет через шаблоны считать из токенов ID и другие поля. Вот где начинается настоящая магия. Таким образом, добавляем в каталог пользователей на стороне провайдера идентификации отдельное поле source_address и отражаем его в нашем ID-токене. Затем через шаблон SSH можно ввести значение из токена в сертификат. Вот шаблон:

{"type": {{ toJson .Type }},"keyId": {{ toJson .KeyID }},"principals": {{ toJson .Principals }},"extensions": {{ toJson .Extensions }},{{ if .Token.source_address }}"criticalOptions": {"source-address": "{{ .Token.source_address }}"}{{ else }}"criticalOptions": {{ toJson .CriticalOptions }}{{ end }}}

Аутентификация на GitHub по сертификату

Рассмотрим ещё один пример custom claim. С помощью GitHub Enterprise Cloud или GitHub Enterprise Server можно настроить GitHub на использование SSH-сертификатов. В частности, GitHub будет доверять вашему центру сертификации SSH. Но чтобы всё заработало, нужно создать для каждого пользователя отдельный SSH-сертификат с расширением login@github.com, в котором прописывается имя пользователя на GitHub. С помощью этого расширения сертификат аутентифицирует пользователя на GitHub Enterprise. И это здорово: один и тот же сертификат позволяет и подключиться к вашему серверу по SSH, и запушить код на GitHub.

Вот шаблон сертификата с поддержкой индивидуального расширения GitHub:

{"type": {{ toJson .Type }},"keyId": {{ toJson .KeyID }},"principals": {{ toJson .Principals }},"criticalOptions": {{ toJson .CriticalOptions }},{{ if .Token.ghu }}"extensions": {  "login@github.com": {{ toJson .Token.ghu }}}{{ else }}"extensions": {{ toJson .Extensions }}{{ end }}}

Для использования шаблона нужно добавить к токенам идентификации OIDC индивидуальное требование ghu (GitHub Username). Давайте подробно рассмотрим, как создать этот custom claim с помощью вашего провайдера OAuth.

Регистрация заявления у провайдера идентификации

Не все провайдеры идентификации поддерживают индивидуальные требования, но если поддержка всё-таки есть, то процесс довольно похож. Вот как это делается с помощью Okta:

  1. Добавьте приложение OAuth в Okta и установите доверие к нему у поставщика OIDC в step-ca, как описано в статье DIY SSO for SSH.


  2. Добавьте новое поле в каталог пользователей Okta (например, GitHub Username)
  3. Добавьте к OIDC-токену индивидуальное требование, например, с сокращённым названием ghu
  4. Теперь заполняем поле для тестового юзера и проверяем требование. В Okta есть инструмент тестирования токена ID. Или можно использовать step для проверки всего потока OAuth:

    OIDC_ENDPOINT="http://personeltest.ru/aways/[your organization].okta.com/oauth2/default/.well-known/openid-configuration"CLIENT_ID="[your OAuth client ID]"CLIENT_SECRET="[your OAuth client secret]"step oauth --oidc --provider $OIDC_ENDPOINT \    --client-id $CLIENT_ID --client-secret $CLIENT_SECRET \    --listen=":10000" --bare |step crypto jwt inspect --insecure
    

  5. Наконец, настройте step-ca для использования этого шаблона. Конфигурация поставщика должна ссылаться на файл шаблона:

    {  "provisioners": [    {      "type": "OIDC",      "name": "Okta",      "clientID": "[your OAuth client ID]",      "clientSecret": "[your OAuth client secret]",      "configurationEndpoint": "https://[your organization].okta.com/oauth2/default/.well-known/openid-configuration",      "listenAddress": ":10000",      "options": {        "ssh": {            "templateFile": "templates/certs/ssh/github.tpl"        }      }    },      ...  ]}
    

Что дальше


Мы добавили в документацию раздел о шаблонах SSH, где более подробно рассматриваются все параметры и переменные.

Если есть вопросы не стесняйтесь задавать.
Подробнее..

Пиринговые мессенджеры враг государства?

24.05.2021 12:21:25 | Автор: admin


В случае полного отключения интернета одна из главных проблем общение с товарищами и родственниками. Опыт Гонконга показывает, что для этого хорошо подходят децентрализованные P2P-мессенджеры, которые работают без интернета, используя mesh-сеть по протоколам Wi-Fi Direct, Bluetooth, Apple Multipeer Connectivity Framework, ANT+, LoRa и др.

Для эффективной коммуникации приложение нужно скачать максимальному количеству человек до начала блокады интернета. Иначе придётся искать файлы после блокады. Человек с нужными файлами станет настоящим авторитетом в офисе или в классе (как это было в Беларуси в августе 2020 года за файлами Psiphon люди реально приезжали из других микрорайонов города).

Вообще, вся история сетей wireless mesh намекает на то, что эта технология крайне не нравится правоохранительным органам.

Mesh-сети


Приложения типа FireChat создают mesh-сеть, используя Bluetooth и прямые подключения через Wi-Fi. Они обеспечивают обмен сообщениями и фотографиями в офлайне между устройствами, находящимися друг от друга на расстоянии примерно до 60 метров.

Все пользователи образуют единую сеть, которая расширяется с ростом количества устройств. На пути к получателю (получателям) сообщения передаются от одного устройства к другому.

Другими словами, вам достаточно приблизиться на 60 метров к ближайшему пользователю и вы можете отправить сообщение кому угодно. Каждый юзер нода в сети. Без интернета.

Поэтому чем больше людей пользуются приложением, тем больше сеть, и тем лучше она работает. Кстати, в этом фундаментальное отличие mesh-систем от большинства других компьютерных сетей и сетевых технологий, в том числе сетей сотовой связи.

Если какой-нибудь узел mesh-сети вдруг выйдет в интернет, то сообщения пакетом от всех пользователей уйдут получателям по всему миру.

Особенно удобно, если каналы или комнаты в мессенджере создаются автоматически и объединяют людей, которые находятся рядом с друг другом (многоквартирный дом, стадион, концертный зал).

Для передачи текстовых сообщений можно приспособить практически любую mesh-сеть, даже сеть из геометок Apple AirTag, которые вообще-то предназначены не для общения людей, а для поиска утерянных вещей. В мае 2021 года хакерам удалось расшифровать трафик AirTag и передать по сети Apple Find My произвольный текст под видом оригинальных зашифрованных сообщений с GPS-координатами. Скорость передачи составила 3байта в секунду. Задержка в сети от 1 до 60 минут.



Подобные mesh-сети есть также у Samsung (Smart Things) и Amazon (Sidewalk) на протоколе LoRa. В принципе, можно использовать эту инфраструктуру для пирингового обмена сообщениями, а также для съёма данных с устройств вне зоны доступа в интернет.

Трагедия FireСhat


FireChat проприетарное приложение от американской компании Open Garden. Эта фирма прекратила дальнейшую разработку, не открыв исходники.

Последняя версия приложения: 9.0.14 (копия на 4pda) вышла полтора года назад (примечание: доступ к сайту 4pda затруднён с территории РФ).


FireChat

Первая версия FireChat появилась в марте 2014 года под iOS, в апреле под Android. Среди сооснователей Open Garden и разработчиков программы Станислав Шалунов и Грег Хазел из компании BitTorrent, где они делали торрент-клиент uTorrent (200 млн пользователей). Там и познакомились.

Вероятно, предприниматели рассчитывали, что FireСhat станет настолько же успешным, как файлоообменные P2P-приложения. Если представить себе эту картину, то весь мир может объединиться в mesh-сеть, а интернет становится практически не нужен! Даже хостинг сайтов теоретически можно размазать в распределённой сети. Такая фантазия.

Очень быстро FireСhat приобрёл популярность в Ираке после того, как местное правительство ввело ограничения на использование интернета, а затем то же самое произошло в Гонконге, во время массовых протестов 2014 года.


Главной проблемой FireСhat во время массовых протестов в Гонконге стала безопасность. Сама архитектура открытой mesh-сети предполагает, что все пользователи приложения светятся как радиомаячки на расстоянии 60 метров, а то и больше. Так что полиции отловить их было очень просто. Наличие программы на телефоне однозначно доказывало вину. Можно предположить, что сотни или тысячи пользователей были арестованы благодаря FireСhat. К тому же, в приложении не использовалось шифрование, так что никакие сообщения не были действительно приватными.

Возможно, критика от специалистов по ИБ повлияла на решение американской компании Open Garden прекратить разработку и не публиковать исходники. Ну или ребята увидели, что всемирная популярность торрентов им не светит, а развитие программы пошло совсем не по тому пути.

Когда появился FireСhat, это была единственная программа такого рода, которая позволяла пользователям создавать mеsh-сети в офлайновом режиме (без интернета) и обмениваться сообщениями1.

Инструмент, который задумывался для общения людей, де-факто превратился в наводку для репрессий и физического насилия. Пожалуй, в этом есть какая-то трагедия.


Фото из статьи FireChat мессенджер, на котором работают протесты в Гонконге, The Guardian

Тем более обидно, если FireСhat создавали специально для Гонконга, как разработку аналогичного приложения Commotion Wireless в 2011 году профинансировал госдепартамент США в преддверии Арабской весны. Хотели как лучше, а получилось как всегда

После FireСhat фирма Open Garden торговала электронными сим-картами (eSIM), продвигала свою криптовалюту, но в последние годы про неё ничего не слышно.

Вообще, приложение FireСhat было не очень качественным. Во-первых, закрытый код. Во-вторых, для регистрации обязательно (!) был нужен доступ в интернет, хотя потом оно работало в офлайне. Короче, странная программа. Может и хорошо, что разработчики её похоронили.

Рация Zello


Близкой по логике функционирования является интернет-рация Zello, которая заблокирована в Российской Федерации в апреле 2017 года.

Радио работает по принципу уоки-токи или push-to-talk. Основное преимущество возможность слушать голосовые сообщения по громкой связи в реал-тайме, вообще не притрагиваясь к смартфону и в то же время быть на связи с большим количеством пользователей.

Хотя здесь передаётся не текст/картинки, а звук, но принцип работы такой же через mesh-сеть, без интернета. Близкие друг к другу пользователи соединяются друг с другом напрямую и передают сообщения дальше, по цепочке. Что важно, здесь используется сквозное шифрование (E2E).

В России приложение получило особую популярность среди дальнобойщиков и других автомобилистов, поскольку очень удобно (и приятно) беседовать с попутчиками, которые едут по той же трассе. Они подскажут о радаре в кустах, о ДТП на дороге и т.д. Репрессии со стороны государства начались после массовых протестов дальнобойщиков в связи с введением обязательной платы миллиардеру Игорю Ротенбергу за проезд тяжёлых грузовиков по дорогам России (система Платон). Координация протестов осуществлялась через Zello, поэтому программу решили заблокировать.

Это был первый прецедент, когда власти попытались сломать мессенджер, работающий по VPN. Понадобился целый год, чтобы заблокировать свыше 4тыс. IP-адресов из облака AWS, что не принесло успеха. Тогда РКН пошёл на шантаж компании Amazon, угрожая заблокировать 26 подсетей AWS, в сумме 13,5млн адресов.

Компания Amazon оказалась не готова к войне и отказалась предоставлять услуги Zello. Лишившийся облачной инфраструктуры сервис было легко заблокировать.

После успеха с блокировкой облачной VPN-инфраструктуры Zello, в 2018 году власти решили, что смогут успешно заблокировать такую же облачную инфраструктуру мессенджера Telegram. Но здесь нашла коса на камень: Павел Дуров инвестировал миллионы долларов в покупку всё новых и новых инстансов AWS, его брат Николай с коллегами запрограммировал систему обхода блокировок через прокси, а компании Amazon и Google выдержали блокировку своих подсетей в РФ. В итоге властям пришлось заблокировать 18 миллионов IP-адресов AWS и Google Cloud, что нарушило работу крупных ритейл-компаний, банков из топ-20, частных клиник и тысяч бизнесов в России. После двух лет выматывающей борьбы государство сдалось: руководителя Роскомнадзора уволили, Telegram разблокировали, а IP-адреса облачных сервисов удалили из чёрного списка.

Криптомессенджер Briar


Четыре года назад, в июле 2017 года, вышла первая публичная бета-версия мессенджера Briar, который работает через Tor или в офлайне, через пиринг. Его разработка продолжалась аж три года. Но продукт вышел на редкость качественный.

Это уже честный опенсорс. Приложение можно собрать из исходников (пошаговая инструкция для Android Studio). Оно доступно в каталогах приложений (например, Google Play) и отлично поддерживается: последняя версия 1.2.20 от 2апреля 2021года. Реализована стойкая криптография, сквозное шифрование.


По умолчанию мессенджер работает через интернет по протоколу Tor (луковичная маршрутизация). В этом случае программа создаёт на устройстве пользователя скрытый сервис Tor и соединяется со скрытыми сервисами Tor других людей из списка контактов. В случае отсутствия интернета она переходит на peer-to-peer коммуникации через Wi-Fi Direct, локальную сеть или Bluetooth.

Разумеется, при регистрации в криптомессенджере не требуется указывать номер телефона.

Поддерживает передачу сообщений (но не файлов), приватные группы, блоги/статусы и импорт RSS. Есть несколько полезных функций, таких как блокировка приложения (по PIN-коду).

Система относительно защищена от посторонних: добавление новых контактов производится по QR-коду с другого телефона (подразумевается физическое присутствие лица) или через обмен контактами, или по уникальной ссылке. Таким образом, в контакты не должен попасть человек, с которым никто не знаком.



Briar Project некоммерческий проект, который сейчас ведут шесть добровольцев. Код на 97,7% написан на Java (+немного Kotlin, Python и Ruby) и поставляется под GPLv3. Вскоре после первого релиза код прошёл независимый аудит безопасности от компании Cure53. Она известна своим аудитом проектов SecureDrop, Cryptocat и Dovecot. Так что Briar действительно надёжный вариант для пиринговых коммуникаций.

Единственный минус, что приложение выпущено только в версии под Android. Официальной версии для iOS нет и не будет, потому что эта платформа накладывает жёсткие ограничения на разработчиков, не позволяющие реализовать некоторые идеи P2P, и является закрытым проприетарным продуктом.

Но исходный код открыт, так что теоретически кто угодно может попробовать сделать стороннюю реализацию Briar под iOS, например.


Matrix, Riot, Element


Официальный клиент Element (бывший Riot) для относительно децентрализованной сети Matrix не поддерживает пиринговые коммуникации в офлайн-режиме и формирование mesh-сети.

В последнее время этот клиент получил некоторую известность. Сейчас количество пользователей Matrix/Element сравнимо с Briar или больше. У него есть сквозное шифрование, мосты в IRC, Slack, Telegram, Jitsi Meet и др. Но именно пиринга в офлайне нет.

См. также:


Secure Scuttlebutt p2p социальная сеть, работающая и в офлайне (есть клиент Manyverse для Android и iOS)

P. S. Кроме FireСhat, протестующие в Гонконге использовали малоизвестное мексиканское приложение Bridgefy, которое тоже умеет формировать mesh-сеть и передавать сообщения в офлайне. В октябре 2020 года приложение перешло на криптографический протокол Signal.

1 На самом деле ещё раньше были другие приложения, такие как Serval Mesh от проекта Serval Project или древний Commotion Wireless от Open Technology Initiative (с финансированием госдепа), но все эти разработки давно прекращены [вернуться]




На правах рекламы


Мощные виртуальные серверы на базе процессоров AMD EPYC для любых целей, в том числе для установки VPN.

Присоединяйтесь к нашему чату в Telegram.

Подробнее..

Внедрение E2E-тестирования с Puppeteer и Jest

18.02.2021 10:20:32 | Автор: admin

Привет, Хабр!

Хотим поделиться краткой историей о том, как мы на одном из проектов Рексофт пришли к написанию автотестов, и почему сделали акцент именно на e2e-тестах.

Речь пойдет о работе с порталом крупного федерального заказчика, работающего в сфере B2B и B2C, имеющего серьезный трафик из всех регионов. Сайт писал не Рексофт. Ресурс попал к нам на поддержку какое-то время назад. Изначально проект содержал довольно много легаси кода, тестов не было, как и документации. Требовалось сделать редизайн по новым макетам, параллельно расширяя существующую функциональность. Обычная история.

В какой-то момент мы поняли, что ручное прокликивание интерфейса стало занимать очень много времени, и решили, что пришло время для автотестов.

Перед выбором подхода к автотестам классифицировали баги по типу: их большая часть касалась именно бизнес-логики (Javascript). Багов, связанных с кроссбраузерностью или вёрсткой, было не очень много.

Итак, цель была поставлена автоматизировать проверку бизнес-логики, т.е. заполнение и отправку форм, работу слайдеров и т.д.

В качестве базового фреймворка для тестов был выбран Jest, а для имитации действий пользователя Puppeteer. Последний выбрали благодаря тому, что он поддерживается Google и имеет отличную документацию. Нам было вполне достаточно тестов в одном браузере (Chrome) (хотя, есть инструменты, позволяющие с помощью Puppeteer запускать тесты и в других браузерах, например, Firefox и IE). Playwright тогда ещё не было, а Selenium, чисто субъективно, казался более сложным в развертывании.

Далее кратко опишу преимущества и недостатки e2e-тестов.

Недостатки e2e-тестов

Относительно высокая сложность написания. Нужно обладать определёнными навыками, чтобы написать компактный и легкочитаемый e2e-тест.

Проблема закопаться. Я точно знаю, что желание проверить всё и вся, может привести к написанию огромного количества избыточных тестов. Как побороть эту проблему? Не стоит пытаться протестировать абсолютно все возможные кейсы, достаточно сосредоточиться на основных.

Низкая скорость прохождения тестов (в сравнении с юнит-тестами). Довольно много времени тратится на запуск браузера, ожидание загрузки страницы, завершения анимаций и прочее. Для ускорения прохождения тестов потребуется свести к минимуму число пользовательских действий, а также число загрузок новых страниц.

Хрупкость e2e-тестов. Что я имею ввиду? Случай, когда тест падает без видимых на то причин, а при повторном запуске успешно выполняется, или же когда к падению теста приводит незначительное изменение в верстке. С хрупкостью тестов можно бороться с помощью автоматического перезапуска теста после падения. Помогут в этом раннер jest-circus и параметр retryTimes. Это практически полностью решает проблему ложных падений тестов.

Преимущества e2e-тестов

Гарантии. С e2e-тестами вы получаете определенные гарантии того, что система в целом работает корректно. Юниты такой гарантии не дают. Разумеется, это не значит, что вы получаете 100% гарантию того, что у вас работает абсолютно всё. Но вы будете уверены, что по крайней мере протестированные сценарии точно работают.

Снижение рабочей нагрузки. Без тестов разработчик вынужден думать как бы чего не сломать. Ведь не прокликивать же весь проект после очередного коммита с правками! С тестами вы узнаете о поломке еще до того, как код будет залит на стенд.

Ускорение разработки. Благодаря снижению количества багов и устранению ручных проверок интерфейса, серьезно экономится время. Причём e2e-тесты экономят не только ваше время, но и время тестировщиков (позволяя им заводить меньше багов, меньше коммуницировать, выясняя их детали и т. д.), время аналитиков (понятные тесты отличная документация, отвечать на вопросы аналитиков вы будете намного быстрее).

Ускорение рефакторинга. При рефакторинге js, e2e-тесты не придется переписывать. Да и рефакторинг в вёрстке тоже редко приводит к их переписыванию.

Нет зависимости от кодовой базы и js-фреймворка. Вы можете написать e2e-тесты даже к легаси коду, что поможет быстрее его отрефакторить. При этом вы практически не зависите от js-фреймворка, т.к. в тестах оперируете только сущностями браузера.

Лайфхаки

1. Для ускорения написания первых тестов можно записывать действия пользователя с помощью Headless recorder или с помощью встроенных в Chrome инструментов.

2. Если требуется проверить несколько наборов данных в рамках одного кейса и руки тянутся написать for внутри теста, используйте jest-each. Эта библиотека позволит прогнать несколько наборов данных в одном кейсе, сохранив читаемость кода:

each` url | selector | expectedIsVisible ${'/page1.html?land'} | ${'.js-order-button'} | ${true} ${'/page1.html'} | ${'.js-order-button'} | ${false} ${'/page2.html?land'} | ${'.js-order-button'} | ${true} ${'/page2.html'} | ${'.js-order-button'} | ${false}`.it('Отображение кнопок заказа на странице $url', async ({ url, selector, expectedIsVisible }) => { await page.goto(`${SERVER_URL}${url}`, {   waitUntil: 'networkidle2',   timeout: 0 }); expect(await isVisible(page, selector)).toEqual(expectedIsVisible);});

3. В случае возникновения ошибок, puppeteer не всегда корректно подсвечивает строку с ошибкой. Поэтому следует проверить код перед ошибочной строкой, часто ошибка кроется именно там.

4. Puppeteer позволяет запускать браузер с различными флагами, что иногда очень полезно (chrome://flags/). Ниже пример запуска браузера с отключенным флагом SameSite by default cookies

puppeteer.launch({ headless: true, slowMo: 80, args: [   '--disable-features=SameSiteByDefaultCookies' ]});

В качестве заключения

Написание e2e-тестов занимают около 5-10% от времени написания фичи. На фиксы багов уходило сильно больше времени, так что оно того стоило. Несмотря на ряд недостатков, e2e-тесты позволяют значительно ускорить процесс разработки и обрести уверенность в том, что основная функциональность системы работает.

Разумеется, при внедрении e2e-тестов для фронтенда необходимо учитывать специфику вашего проекта. Спасибо за внимание!

Подробнее..

Cypress и его место в нашей тестовой пирамиде

18.05.2021 08:17:48 | Автор: admin

Стабильность и скорость это то, что ожидается от автотестов. В этой статье я расскажу о нашей стратегии по оптимизации тестовой пирамиды, о том, почему мы сделали выбор в пользу Cypress и какие выработали подходы к написанию тестов, а также о запуске тестов на инфраструктуре AWS.

Введение в Cypress

Если отбросить капитанское определение, что Cypress это JavaScript-фреймворк для тестирования, то важно отметить, что при работе с ним мы видим на экране браузер. Он не обязательно открыт, он может быть headless, но он есть, и он открывает особое приложение самого Cypress, которое состоит из нескольких фреймов: в одном фрейме открывается продукт, который мы тестируем, в другом фрейме запускаются тесты. Код тестов пишется на JavaScript, поэтому они могут выполняться непосредственно в браузере ведь это нативный для него язык.

Так с помощью JavaScript API производятся все манипуляции, которые делаются в тестах, то есть заполнение форм, клики и тому подобное.

Преимущества Cypress

Нет Selenium WebDriver

Очевидное отличие Cypress от тех библиотек и фреймворков, которые мы использовали раньше это отсутствие основного действующего элемента, Selenium.

Selenium WebDriver это third-party сервис на Java, который обращается к браузеру по WebDriver протоколу. Это накладывает ограничения на работу с браузером в рамках протокола. Сетевое взаимодействие также вносит свой вклад во время выполнения тестов.

Изначально Selenium был создан не специально для тестов, а как общий инструмент автоматизации для браузера. Cypress, в отличие от него, сфокусирован на решении конкретной задачи, а именно, на создании end-to-end (е2е) тестов для интерфейса web-приложений.

Все в одном

Cypress не нужно собирать из кусочков он принес все достаточно современные "батарейки" с собой:

  • Синтаксис BDD (унаследовано из Mocha): describe(), context(), it().
    А также хуки: before(), beforeEach().
    Использовать такой DSL привычно для тех, кто уже писал юнит-тесты на JavaScript.

  • Библиотека ассертов (унаследовано из Chai). Например:
    expect(name).to.not.equal("Jane") ожидание того, что элемент не существует это не то же самое, что ожидание неудачи при проверке существования элемента. Если элемента нет, то это хорошо, это не нужно перепроверять, а нужно идти дальше.
    Такую задачу должен решать тестовый фреймворк, и этого нам очень не хватало в старой самописной библиотеке, при использовании которой многое ложится на плечи разработчика теста.

  • Перехват, отслеживание (spy) и подмена (mock) запросов браузера к бэкенду.

Development experience

Главное преимущество Cypress это отличный development experience. Написать первый тест для своего проекта (неважно, на каком языке написан сам проект) можно минут за 10. Потребуется добавить одну зависимость в package.json (npm install cypress), прочитать документацию про то, куда складывать файлы (cypress/integration/login.spec.js), и написать код в 5 строчек:

describe('Login', () => {it('should log in with credentials', () => {cy.visit('/login');cy.get('[name=login_name]').type(Cypress.env('login'));cy.get('[name=passwd]').type(Cypress.env('password'));cy.get('[name=send]').click();cy.get('.main-header').should('be.visible');});});

Получаем реальный тест, который посещает страницу логина, заполняет форму, нажимает на кнопку и видит результат.

На скриншоте браузера было видно, что все шаги теста логируются. Но это не просто лог это навигация, по которой после прохождения теста можно вернуться в любую точку и увидеть, что происходило в браузере. Например, можно посмотреть снэпшоты до и после Ajax-запроса.

Приятной мелочью является то, что каждый cy.get() убеждается, что страница загрузилась, и делает несколько попыток, чтобы найти элемент. С каждым годом интерфейсы веб-приложений становятся все сложнее. Результирующий HTML формируется не на стороне сервера, а на стороне браузера. Делается это асинхронно и с использованием различных библиотек компонентов. В какой момент тот или иной элемент интерфейса появится на экране, сказать уже становится сложнее.

Одна из Best Practices говорит, что не нужно никогда писать таймаут типа "подождать 2 секунды". Абсолютно все таймауты должны ждать чего-то осязаемого, например, окончания Ajax-запроса. Можно подписаться на событие, которое случается в коде продукта. Например, когда нам через веб-сокет прилетает событие с бэкенда, то срабатывает определенный listener на фронтенде.

Вся документация Cypress и Best Practices находятся на одном сайте docs.cypress.io хотелось бы отдельно отметить высокое качество этой документации, а также мастер классов, которые команда разработки Cypress проводит и публикует в открытом доступе.

Кроме того, один из паттернов, от которых стоит отказаться это PageObject. Долгое время он считался обязательным, но для новых тестов он нам уже не понадобится.

Чуть позже мы вернемся к нашим собственным наработанным Best Practices, а сейчас хочется немного отвлечься и поговорить про тестовую пирамиду и то, ради чего мы все это делаем и какова наша цель.

Тестовая пирамида

Когда говорят про тестовую пирамиду, то обычно приводят в пример анти-паттерн "перевернутая пирамида" или "стаканчик мороженого". То есть на нижнем уровне в таком примере количество юнит тестов стремится к нулю. Лично мне этот случай кажется невероятным для зрелого проекта: ведь в этом случае разработчики должны были полность отказаться писать самые простейшие тесты откуда тогда взялись сложные е2е тесты?

Как бы то ни было, к нам это не относится у нас несколько тысяч PHPUnit-тестов с покрытием около 12% строк кода.

В то же время у нас есть еще несколько тысяч е2е-тестов с Selenium, которые проверяют все возможные конфигурации продукта, занимают кучу времени (подмножество, запускаемое на каждый коммит, мы смогли оптимизировать до 40-60 минут), имеют довольно слабый уровень доверия (с вероятностью 30-40% тесты упадут, хотя коммит не содержит причины этого падения) и покрывают около 30% строк кода.

Получается, наше положение выглядит, как песочные часы нам не хватает среднего слоя в тестировании, где интеграционные тесты проверяют компоненты системы независимо друг от друга. Это горлышко песочных часов и хочется заполнить с помощью Cypress. При этом еще хочется что-то сделать с существующими е2е тестами, чтобы "заострить" вершину пирамиды. То есть, важный акцент здесь в том, что Cypress не является заместителем старого фреймворка: мы не хотим просто взять и переписать все тесты на Cypress иначе мы так и останемся на шарике мороженого. Цель тестов по-прежнему, проверять регрессию в продукте, но проверять на другом уровне, чтобы выполняться быстрее и получать результат раньше, а также быть легче в сопровождении.

Наш подход к написанию тестов

Проект, о котором идет речь, это контрольная панель Plesk. Она предоставляет пользователям интерфейс для управления хостингом веб сайтов. Функциональность панели доступна не только через UI, но и через API и CLI, которые используются для автоматизации.

Мы начали с того, что сделали следующие предположения:

  • Тесты на Cypress относятся чисто к UI. Мы не относим сюда тесты, у которых шаги выполняются через API или CLI.

  • Мы не проводим никакой дополнительной валидации, кроме той, что выполняется средствами UI. Например, если мы проверяем создание домена, то мы не отправляем запросы для проверки Web-сервера или DNS, мы считаем тест пройденным, если в UI появилось сообщение на зеленом фоне о том, что домен создан успешно. Такой подход избавляет нас от предварительной подготовки и написания тестовых сценариев.

  • На первом этапе мы автоматизируем только позитивные сценарии. Негативные сценарии не представляют ценности для клиента, но при этом тесты для их проверки занимают драгоценное время. Так что переносим такие сценарии в нижнюю часть пирамиды они, как правило, легко проверяются юнит-тестами.

Наш опыт работы с Cypress в сочетании с официальными рекомендациями привел нас к использованию следующего набора практик:

Сбрасывать состояние продукта

Мы сбрасываем состояние продукта до исходного перед запуском каждого набора тестов (Cypress рекомендует делать это перед запуском каждого теста, но мы используем облегченный вариант). Мы создаем дамп базы данных и восстанавливаем его перед прогоном каждого набора тестов (test suite / spec). Это занимает порядка 5 секунд.

before(cy.resetInstance);//=> test_helper --reset-instance//=> cat /var/lib/psa/dumps/snapshot.sql | mysql

Такой откат к прежнему состоянию может в общем случае привести Plesk в нерабочее состояние, т.к. помимо общей базы есть еще, например, базы отдельных утилит, а также бэкапы, которые хранятся в файловой системе. Но нас это устраивает, т.к. мы используем Cypress только для тестирования UI.

Использовать фикстуры

Вместо реальных объектов в качестве пререквизитов теста мы используем фикстуры сохраненные структуры, которые содержат необходимое состояние базы данных. Например, для выполнения некоторых тестов необходимо наличие домена. Вместо создания реального домена мы воссоздаем все необходимые записи в базе данных, но не трогаем файловую систему и другие системные сервисы. Это занимает меньше секунды (для сравнения, создание полноценного домена заняло бы около 30 секунд).

cy.setupData(subscription).as('subscription');//=> test_helper --setup-data < {domains: [{ id: 1, name: "example.com" }]}

Такие объекты не будут выполнять полноценные пользовательские сценарии, но для тестирования UI их будет достаточно.

Использовать прямые URL

Мы не используем навигацию и попадаем в нужные места UI по прямым URL-ам. Мы вызываем свою специальную команду login, которая создает сессию, а затем переходим прямо на нужную страницу.

beforeEach(() => {cy.login();cy.visit('/admin/my-profile/');});

В старом фреймворке мы бы использовали PageObject для входа в главное меню, а затем переходили бы из него к нужному элементу. Здесь же этого не требуется, так как мы тестируем только необходимую страницу. Единственное дублирование это команда login, но это не выглядит проблемой.

Фронтенд без бэкенда

Иногда бывает сложно создать условия для определенного состояния, которое мы хотим протестировать. Например, для проверки доступных обновлений. Намного легче подсунуть заготовленный ответ для Ajax-запроса, чем готовить инфраструктуру для обновлений.

const lastChecked = 'Jan 29, 2021 04:42 PM';cy.intercept('POST', '/admin/home/check-for-updates', {status: 'success',lastChecked,newVersion: null,whatsNewUrl: null,}).as('checkForUpdates');cy.get('[data-name="checkForUpdates"]').click();cy.wait('@checkForUpdates');cy.get('[data-name="lastCheckedDate"]').should('contain', lastChecked);

Пока не все данные доставляются через Ajax, а фронтенд не является полноценным SPA, но мы движемся в этом направлении. И именно такой подход в тестировании фронтенда с помощью заготовленных ответов бэкенда кажется нам наиболее перспективным, так как он позволит вообще не запускать бэкенд и ускорить выполнение тестов.

Стабильность тестов

Скорее всего, когда вы начнете писать Cypress тесты, то каждый второй тест будет неожиданно становиться flaky, то есть иногда проходить, а иногда нет. Чтобы избежать такой нестабильности, мы используем следующие практики.

Дожидаться выполнения Ajax-запроса

Многие формы в нашем продукте отправляются с помощью Ajax-запросов без перехода страницы. Чтобы тест гарантированно прошел, необходимо перехватить этот запрос и дождаться его завершения. Так как в Cypress мы проверяем только то, что происходит в UI, мы дожидаемся нужного нам сообщения.

В примере ниже мы перехватываем запрос по созданию клиента, сразу после нажатия на кнопку дожидаемся выполнения запроса и только после этого проверяем сообщение о том, что клиент создан.

cy.intercept('POST', '/admin/customer/create').as('customerCreate');cy.get('[name=send]').click();cy.wait('@customerCreate');cy.get('.msg-box.msg-info').should('be.visible');

Дожидаться исчезновения индикатора загрузки

Кое-где в нашем интерфейсе фоновые операции, например, обновление списка, сопровождаются анимированным индикатором загрузки ("крутилкой"). Именно на таких страницах после окончания Ajax-запроса случается ошибка "element has been detached from the DOM" при попытке Cypress кликнуть на элементы списка. Поэтому мы добавляем после Ajax-запроса дополнительную строку, которая проверяет, что индикатор загрузки не виден.

cy.get('.ajax-loading').should('not.be.visible');

Мы надеемся, что проблема будет исправлена на стороне Cypress и нам больше не придется за этим следить.

Ajax-запросы после окончания теста

После окончания каждого теста браузер остается на последней открытой странице. Cypress сбрасывает состояние браузера (включая куки) и запускает следующий тест, где первым шагом мы сбрасываем состояние продукта (включая сессии бэкенда).

До того момента, когда следующий тест сделает первый вызов "cy.visit()", предыдущая страница остается открытой и может отправлять Ajax-запросы (например, периодическое обновление), которые будут падать из-за ошибки авторизации (куки нет, сессии нет).

В качестве workaround можно переходить на пустую страницу, чтобы браузер сбрасывал все активные Ajax-запросы. Для этого добавляем в support/index.js

afterEach(() => {cy.window().then(win => {win.location.href = 'about:blank';});});

Первые результаты

За 3 человеко-месяца (3 итерации) мы получили следующие результаты:

  • 335 тестов на Cypress (разбиты на 84 спеки)

  • Пайплайн полностью выполняется за 35-40 минут, из которых сами тесты занимают 20 минут

  • Запуск пайплайна на каждый пулл-реквест в блокирующем режиме (то есть нельзя мержить без успешного прохождения тестов)

  • Уровень доверия выше 95% (то есть вероятность flaky падения ниже 5%)

  • Покрытие интерфейса 35% (ниже расскажу подробнее)

Пайплайн для запуска тестов

За время разработки пайплайн для запуска тестов прошел несколько этапов развития. Требованием было уложиться в час, иначе ожидание мержа в пулл реквесте слишком затягивается.

Как и для большинства наших задач, пайплайн запускается в Jenkins и хранится в Jenkinsfile вместе с кодом проекта.

Линейный пайплайн

В первом заходе получился простой линейный пайплайн.

Мы запускаем Docker-контейнер с Plesk в фоновом режиме и ждем, когда он будет доступен в локальной сети. Потом запускаем другой контейнер с Cypress и кодом тестов, он подключается к Plesk и выполняет все тесты, а мы ждем его завершения (не делаем detach).

Мы запускали тесты на машине с 12 ядрами, которая используется у нас для сборки Plesk и ряда его служб. В течении рабочего дня у нас бывает до 20-30 сборок. В результате Load Average достигал 20, и многие соседние процессы "вставали". Мы добавили ограничение на количество исполняемых сборок до 3-5. Но и этого оказалось недостаточно, соседи по железу продолжали жаловаться на нагрузку.

Тогда мы унесли запуск тестов на выделенный сервер в AWS с 4 ядрами внутри VPC с доступом в нашу офисную сеть. Тем самым мы избавились от недовольных соседей, но сборки тестов так и продолжили подолгу ждать в очереди, время от времени не укладываясь в таймаут.

Пайплайн с параллельными шагами

Чтобы как-то ускорить процесс, мы решили воспользоваться Jenkins EC2 Fleet plugin, который предоставляет Jenkins slave ноду по требованию из Autoscaling Group в AWS и уничтожает неактивные ноды после некоторого простоя. Такой подход позволяет тратить деньги на аренду ресурсов только тогда, когда они необходимы.

Переход на spot-инстансы позволил нам существенно сэкономить: вместо $150 в месяц за ondemand c5.xlarge, мы стали тратить около $60 за c5.xlarge и более мощные c5.2xlarge.

А главное, мы можем делать столько одновременных запусков, сколько нам нужно.

Разворачивание новой ноды занимает порядка 2 минут. Мы сделали в пайплайне несколько шагов параллельными, чтобы за это время успеть собрать продукт и быть готовыми к его установке в Docker на новой ноде.

Однако число наших тестов росло, и время пайплайна неизбежно росло вместе с ним, так что нужно было искать новые шаги для его ускорения.

Пайплайн с параллельными тестами

В Cypress есть платная фича параллельный запуск тестов с помощью Cypress Dashboard. Но мы пошли простым и бесплатным путем перечисляем файлы с тестами при запуске контейнера, при этом первый запускает все четные файлы, второй все нечетные.

cypress run --spec $(find 'cypress/integration' -type f -name '*.js' | awk '(NR - ${RUNNER}) % ${TOTAL_RUNNERS} == 0' | tr '\n' ',')

Получилась матричная сборка, где для каждой оси (axis) запускается свой контейнер с Plesk и свой контейнер с определенным набором тестов.

В итоге мы укладываемся в приемлемые 35-40 минут для всего пайплайна, а время одной пачки тестов занимает примерно 20 минут.

В дальнейшем с увеличением количества тестов нам, очевидно, потребуется больше параллельных потоков, и мы планируем использовать Amazon ECS для запуска контейнеров, чтобы не ограничиваться EC2 инстансом.

Измерение URL coverage

В нашем проекте используется много различных языков программирования и анализ code coverage является больной темой, потому что сбор данных требует специальных билдов и объединения отчетов с нескольких конфигураций.

Для анализа тестового покрытия UI мы решили воспользоваться продуктовой аналитикой и сравнить данные, полученные от тестовых инсталляций, с данными от реальных пользователей. У нас уже был сервис, аналогичный Google Analytics, для сбора пользовательских метрик, а тестовые данные складывались отдельно и никем не использовались. Из множества метрик мы отфильтровали события о посещенных URL-ах (страницах) продукта, начали сохранять эти данные в удобном для нас виде в базу данных и составлять отчет по посещенным адресам.

По полученным данным, за счет всего автоматического и ручного тестирования внутри компании мы покрываем около 60% URL-ов, которые посещают реальные пользователи в течении месяца. Наши старые тесты покрывают около 25%, а новые тесты на Cypress уже достигли 35%.

Эта статистика помогает нам планировать дальнейшее тестирование например, более посещаемые страницы мы планируем автоматизировать в первую очередь.

Следующие шаги

Ускорить сборку Docker

Одна из проблем, над которой мы хотим поработать ускорение сборки контейнеров Docker. Как уже было сказано выше, мы создаем временный сервер в AWS (slave node) для каждой сборки Docker, и эта сборка на данный момент занимает в среднем 8 минут. Но поскольку каждый временный сервер новый, то мы совершенно не используем преимущества кэширования, а хотелось бы ими воспользоваться. Поэтому сейчас мы исследуем возможность использования BuildKit. Альтернативными решениями могут стать Kaniko или AWS CodeBuild.

Сократить количество е2е тестов

Мы хотим уменьшить количество старых е2е тестов, чтобы вершина тестовой пирамиды стала более острой. Сейчас около трети этих тестов относятся к UI. Кроме этого, тесты содержат проверки через командную строку (CLI), причем иногда логика тестов в UI и CLI дублируется.

Основная идея: перенести все UI-тесты в Cypress, а в старом фреймворке оставить только CLI-тесты с детальными проверками. Поэтому для каждого UI-теста из старого фреймворка мы делаем следующее:

  1. Заменяем UI-шаги на CLI (если это возможно).

  2. Удаляем, если уже есть аналогичный тест с CLI.

  3. Если проверка возможна только через UI уносим ее в Cypress.

Например, при создании домена проверяется то, что он резолвится, и что на нем работают определенные скрипты. Эти проверки останутся только для создания домена через CLI. А тест на UI в Cypress будет проверять только появление сообщения о создании домена.

В результате мы избавимся от дублирования тестовых сценариев, сократим нагрузку на сервера с Selenium и в перспективе совсем от них избавимся, когда тестирование UI будет делать только Cypress.

Заключение

Cypress подкупает быстрым стартом к написанию тестов и удобными средствами для отладки. При этом не стоит забывать, что скорость и стабильность тестов зависят от того, как они написаны: легковесные фикстуры и подготовленные ответы бэкенда дают большое ускорение, а сброс состояния позволяет избежать случайного влияния тестов друг на друга.

Cypress позволяет организовать как полноценные e2e тесты с прохождением пользовательских сценариев на реальном продукте, так и интеграционное тестирование отдельных компонентов фронтенда. Лучше заранее выбрать цель и договориться о правилах игры для всей команды.

Кроме того, стоит отметить, что запуск тестов потребляет довольно много ресурсов CPU, поэтому стоит заранее оценить количество параллельных запусков и спланировать масштабирование инфраструктуры.

Подробнее..

Про E2E тестирование

31.10.2020 16:04:39 | Автор: admin

В пирамиде тестирования E2E тесты занимают одну из верхних ступеней. Написав один E2E тест, можно быть уверенным в результатах работы логики приложения, проверить интеграции с другими системами и создать "контракт" для вашего приложения.

К сожалению, многие из коллег, с которыми я работал, не писали E2E тесты. Отчасти потому что с головой ушли в модульное тестирование и посчитали, что оно лучше по ряду причин, включая моду на TDD. Отчасти потому что верили, что E2E тесты сложно писать, они долго исполняются, да и с инструментарием есть проблемы.

Разберемся с этими мнениями и посмотрим на плюсы, которые предлагает E2E тестирование.

Терминология

Под E2E тестами положим вид автотестов. Эти автотесты должны покрывать все функции сервиса с точки зрения клиента. Добиваются они этого, симулируя реальное взаимодействие клиента, будь это HTTP-запрос или нажатие на кнопку в UI.

Подход модульного тестирования лучше

Написание модульных тестов, к сожалению, занимает куда больше времени, чем E2E тестов. Да, на первых порах придется разобраться как E2E тесты лучше писать, но ведь то же было верно и для модульных тестов.

Зато, в результате один E2E тест покрывает больше кода, чем один Unit-тест, хотя может занимать меньшее количество строк по сравнению с аналогичным модульным test suite.

Можно не тратить время на понимание того, как правильно мокировать зависимости, ведь ими становяться в E2E тестах внешние системы, а взаимодействие с тестируемым сервисом строится по принципу "черного ящика".

Не нужно проверять все граничные условия для отдельного метода класса. Это повышает гибкость работы с кодом, так как нет необходимости рефакторить весь test suite при малейшем изменении внутренней логики работы приложения.

Невозможно попасть в ситуацию, когда ты боишься выкинуть старый код, потому что придется пройтись по набору из 100 модульных тестов (написанных даже не тобой), которые так или иначе были завязаны на этот код.

Инструментарий и скорость прогона тестов

На сегодняшний день большинство backend-разработчиков пишут сервисы, представляющие API с помощью HTTP (возможно GraphQL) или некоторым подобием MQ. В таком случае достаточно обычного клиента HTTP, доступного в большинстве mainstream ЯП.

Frontend-разработчики пишут, в основном, для Web-платформ (браузеров) или для мобильных в виде нативных приложений. Тут ситуация немного сложнее, так как инструментарий требует более детального изучения, но не дольше любого остального инструмента, с которым Вам придется столкнуться при разработке приложений.

E2E тесты действительно требуют в среднем больше времени для прогона, нежели модульные. При этом они завязаны на скорость работы Вашей системы. Т.е. они становятся метрикой производительности отдельных операций. При необходимости, они могут просто преобразовываться в нагрузочные тесты.

Дополнительные плюсы E2E тестирования

Каждый отдельный тест покрывает реальный сценарий использования приложения и дает куда больше понимания другим разработчикам, в том числе и будущим, как именно и зачем все это работает.

По результатам работы Вы получаете "настоящий" code-coverage. Если есть код и его невозможно исполнить, выполняя клиентские запросы в реальном окружении, то, скорее всего, это лишний код. Если он проверяет граничные условия или ловит маловероятный exception, задумайтесь, возможны ли такие условия в принципе?

В целом, использование только E2E тестирования для приложения заставляет задуматься об упрощении структуры Вашей системы и улучшения документации.

E2E тесты могут использоваться как контракты API и взаимодействия с Вашим сервисом. К примеру, для backend, как только Ваш E2E тест меняется, необходимо убедиться, что frontend будет готов к таким изменениям.

Заключение

В целом, на мой взгляд, E2E тестирование предоставляет большие гарантии корректной работы системы, чем unit-тесты, большую гибкость в работе с кодом с точки зрения рефакторинга и отражает реальную суть работы приложения.

Спасибо Вам за внимание! А как Вы считаете, можно ли использовать только E2E тесты?

Подробнее..

Автоматизация тестирования в микросервисной архитектуре

07.07.2020 10:10:24 | Автор: admin

Привет, Хабр. Меня зовут Сергей Вертепов, я senior backend инженер. Это небольшая обзорная статья отом, как мы тестировали монолитное приложение Авито, и что изменилось спереходом намикросервисную архитектуру.



Тестирование в домикросервисную эпоху


Изначально приложение Авито было монолитным. Справедливости ради, монолит унас и сейчас довольно большой, но микросервисов становится всё больше и больше.



Выше схема того, как выглядит монолитное приложение. Унас есть пользователь, есть уровень представления, бизнес-уровень, уровень данных и база данных, изкоторой мы их получаем. Когда унас был большой-большой монолит, то объектом тестирования было приложение сбэкендом наPHP, фронтендом наTwig, и совсем немножко наReact.


Классическая пирамида тестирования длямонолитного приложения выглядит так:


  1. Много юнит-тестов.
  2. Чуть меньше интеграционных тестов.
  3. Ещё меньше сквозных тестов.
  4. Поверх всего непонятное количество мануальных тестов.


Расскажу, как мы пытались прийти ктакой пирамиде, и что унас было изинфраструктуры.


У нас был собственный тестовый framework наPHP сPHPUnit подкапотом. Система генерации тестовых данных унас тоже своя. Это ресурс-менеджер, который позволяет создать любой необходимый запрашиваемый ресурс длятестирования. Например, пользователя сденьгами, собъявлениями вопределённой категории наАвито, пользователя сопределённым статусом.


Система просмотра отчётов тоже самописная. Кроме неё мы написали собственный jsonwire-grid. Grid это система оркестрации селениумными нодами, она позволяет потребованию поднять селениумную ноду. Узнать подробности проGrid, как мы его разрабатывали и какие технологии использовали, можно издоклада моего коллеги Михаила Подцерковского cHeisenbug 2018года.


Также унас есть собственный selenium-maper. Мы написали собственную библиотечку, которая позволяет выполнять запросы поjsonwire-протоколу.


Наш CI-pipeline выглядел следующим образом: происходил какой-то CI Event, пусть для примера это будет пуш врепозиторий. ВCI собирался артефакт длязапуска тестов. Самописная система параллельного запуска тестов парсила артефакт и начинала запускать тесты накуче разных нод.



В качестве тестового приложения мы использовали РНР-имплементацию Selenide, полный порт сJava. Но впроцессе мы отнего отказались, потому что Selenide было тяжело поддерживать, сам он уже не развивался. Мы написали свой, более легковесный, PowerUI, вокруг которого построили и архитектуру тестовых приложений скастомными матчерами, селекторами и так далее. Этот продукт сильно упростил длянас тестирование и построение отчётов. Соответственно, дальше PowerUI черезjsonwire-grid входил вселениумную ноду и выполнял необходимые действия.


Само тестовое приложение унас дополнительно ходило вресурс-менеджер длягенерации тестовых данных, и потом уже отправляло данные внашу систему просмотра отчётов Test Report System.


В целом, втакой парадигме мы прекрасно жили. Вначале релизы большого монолитного PHP-приложения были раз вдень, потом их количество выросло дотрёх, а впоследствии и вовсе дошести. Унас было несколько тысяч Е2Е-тестов сбольшим покрытием, и они были довольно легковесными. Всреднем они выполнялись порядка минуты, заредким исключением. Тест, который проверял огромный кусок бизнес-логики мог занимать две-три минуты. Унас был минимум ручного регресса и минимум багов впродакшене.


Тестирование в микросервисной архитектуре


Со временем мы стали переходить намикросервисную архитектуру. Основные её плюсы это масштабирование, быстрота доставки фич и отказоустойчивость.


С монолитом пирамида тестирования унас не получилась. Вместо неё была мороженка тестирования. Счем это было связано? Е2Е-тесты благодаря разработанной инфраструктуре были довольно быстры и не причиняли особой боли. Поэтому мы делали основной упор наних. Мы даже могли пренебрегать юнит-тестами.



Сприходом микросервисной архитектуры такой подход перестал работать. Огромная часть бизнес-логики уехала вотдельные сервисы, их становилось всё больше. На 2020год унас порядка 2,5 тысяч разных репозиториев. Втаком случае, когда мы запускали Е2Е-тесты какой-то сервис мог, например, резко перестать отвечать. Если он отвалился, все тесты, которые ходили вэтот сервис и были блокирующими длямержа, тоже начинали падать. Соответственно, унас просто падал time tomarket, так как люди не могли мержиться из-западающих тестов. Мы были вынуждены сидеть и ждать, пока придёт оунер конкретного сервиса, разберётся, что происходит, перевыкатит его или разберется спроблемами.


После этого мы внедрили карму тестов. Это очень простой механизм. Он работает наоснове самописной системы отчётов, которая имеет всю необходимую историчность данных. Карма проверяет, что тест упал, и дальше идёт смотреть, встречается ли подобная ошибка призапуске тестов вдругих ветках. Ошибка это хэш трейса. Мы берём полный трейс, хэшируем его и сохраняем. Если мы видим, что ошибка стаким хэшем встречается ещё натрёх ветках, мы понимаем, что проблема не вветке, накоторой запущены тесты, а что она носит общий характер. Если ошибка общая и не имеет отношения кконкретной ветке, то мы позволяем вмержить эту ветку.



Да, таким образом мы маскируем проблемы, но, тем не менее, это решение сильно упростило жизнь разработчиков. Вслучае, если разработчик пропустил какой-то баг, унас остаётся процесс деплоя. Вдеплое никакая карма уже не работает, всё наручном апруве тестировщиков и разработчиков, то есть мы прямо смотрим, что и как унас происходило. Если находим проблемы, выкатка блокируется дотех пор, пока проблемы не решат и не сделают хотфикс.


Количество микросервисов растёт, а количество тестировщиков не очень. Как правило, унас наюнит один ручной тестировщик. Понятное дело, что водиночку довольно-таки тяжело полностью покрывать нужды всех разработчиков изкоманды. Всреднем это несколько фронтендеров, несколько бэкендеров, ещё автоматизаторы и так далее.


Чтобы решить эту проблему, мы стали внедрять методологию Agile Testing. Суть этой методологии состоит втом, что мы предотвращаем баги, а не ищем их. Тестирование мы обсуждаем наProduct Backlog Refinements. Мы сразу определяем, как будем тестировать какую-то фичу: достаточно ли покрыть её юнит-тестом и если юнит-теста достаточно, какой это должен быть юнит-тест. Обсуждение происходит вместе стестировщиком, который определяет, нужно ли будет дополнительно провести ручное тестирование. Как правило, юнит-теста бывает достаточно. Плюс тестировщик может подсказать ещё какие-то кейсы, а также может предоставить чеклист, наоснове которого мы напишем нужные юнит- или функциональные тесты.


Разработка унас идёт отприёмочных тестов, то есть мы всегда определяем тесты, которые будут приняты приразработке. Подробнее пропереход на Agile Testing уже рассказывала моя коллега Алёна изсоседнего юнита. Встатье она пишет овнедрении методологии напримере своей команды, но это справедливо длявсего Авито.


Но Agile Testing невозможен безShift-left тестов. Shift-left testing это методология, прикоторой мы тестируем каждый деплой и прикаждом пуше прогоняем все необходимые тесты. Выкатка без этого невозможна. Но тесты приэтом должны быть легковесными. Основная суть подхода находить дефекты наранних этапах, чтобы разработчик мог запустить необходимый тест влюбой момент, когда пишет код. Также он обеспечивает непрерывное тестирование вCI, и возможность автоматизации чего угодно.


Во время Shift-left тестов мы разбиваем большие, тяжёлые тесты накучу маленьких, чтобы они запускались и выполнялись быстрее. Мы декомпозировали наши огромные Е2Е-тесты накомпонентно-интерфейсные тесты, наюнит-, интеграционные тесты, функциональные тесты, то есть начали распределять Е2Е попирамиде. Раньше запуск тестов мог занять 2030минут и требовал танцев сбубном. Сейчас влюбом микросервисе тесты прогоняются за5-10минут, и разработчик сразу знает, сломал он что-либо или нет.


Также мы внедрили методологию контрактных тестов. Сокращение CDC-тесты значит Consumer-Driven Contract тесты. Когда мы пушим изменение кода врепозитории, специально написанный брокер собирает всю необходимую информацию потому, какие написанные CDC-тесты есть, и дальше понимает, ккакому сервису они имеют отношение.


Сами CDC-тесты пишутся настороне консьюмера сервиса. Привыкатке продюсера мы прогоняем все написанные тесты, то есть проверяем, что продюсер никак не нарушает контракт. Подробнее проэто рассказывал всвоём докладе Фрол Крючков, который как раз драйвил эту идею.


Помогли ли нам CDC-тесты? Нет, потому что появилась проблема стем, что сами консьюмеры не поддерживают свои тесты. Как результат тесты нестабильны, из-заэтого получалось, что наши продюсеры не могли вовремя выкатиться. Приходилось идти и фиксить тесты состороны консьюмеров. Плюс тесты все писали по-разному, наодну ручку мог быть десяток различных тестов, которые проверяют одно и то же. Это неудобно и долго. Поэтому отидеи CDC-тестов мы отказались.


Недавно мы внедрили PaaS. Наша архитектурная команда разработала очень удобный инструмент, благодаря которому можно быстро развернуть набойлерплейтах сервис и сразу начать его разрабатывать. Приэтом не надо думать ни обазах, ни омиграторах и прочих инфраструктурных штуках. Можно сразу начать писать код и катить миграции.



Теперь сервис-потребитель и сервис-продюсер общаются между собой через Api Gateway. Настороне Api Gateway есть валидация контрактов наоснове бриф-файлов. Бриф-файл это очень простой структурный файлик, который описывает сервисное взаимодействие. Есть бриф-файл настороне продюсера, он описывает то, как мы должны общаться сэтим сервисом. Консьюмер копипастой берёт необходимую себе ручку, необходимую структуру, затаскивает всё это всвой сервис, и генерирует наоснове этого клиенты.


Соответственно, унас идёт валидация бриф-файлов, что унас всё впорядке, что мы не ломаем никакое сетевое взаимодействие. Сейчас уже такая валидация даже будет блокировать мерж, если унас где-то нарушаются контракты. Мы как раз проверяем контракты настороне инфраструктурных штук.


Ещё мы внедрили такую штуку, как service mesh. Service mesh это когда рядом скодом сервиса поднимается sidecar, который проксирует все необходимые запросы. Запрос идет не всам сервис, его сначала получает sidecar, который прокидывает необходимые заголовки, проверяет, роутит маршруты, и передаёт запрос сервису. Cервис передаёт запрос обратно вsidecar, и так дальше поцепочке.


Про service mesh подробно можно узнать издоклада Саши Лукьянченко сDevOpsConf 2019года. Внём Саша рассказывает прото, как разрабатывал решение и как мы кнему пришли.


На основе sidecar мы внедрили OpenTracing. Это технология, которая позволяет полностью отследить запросы отсамого фронта доконечного сервиса и посмотреть, какие были отвалы, сколько шёл запрос.



Это интерфейс Jaeger UI. На скриншоте трейсинг запросов современем выполнения и маршрутом


Также с помощью service mesh мы сделали Graceful Degradation тестирование. Graceful Degradation тестирование это когда мы отключаем какой-то сервис и проверяем, как унас будет работать приложение. Мы смотрим, выдаст ли приложение какую-то ошибку или полностью крашнется. Такого развития событий мы не хотим, но так как микросервисов становится много, количество точек отказа тоже растёт. Такой вид тестирования позволяет проверить поведение всей системы приотказе одного изсервисов.



На скриншоте боевой пример содного изнаших тестов вовремя прохода. Мы отключали сервис услуг и проверяли, что выдадим пользователю читаемое сообщение.


Всё это работает благодаря service mesh утилите Netramesh. Достаточно прописать заголовок X-Route, наш sidecar перехватывает запрос досервиса и перенаправляет куда надо. Вконкретном случаем мы его перенаправляли вникуда, будто бы сервис отвалился. Мы могли сказать ему, чтобы он вернул пятисотую ошибку, либо могли сделать таймаут. Netramesh всё это умеет, единственная проблема, что здесь необходимо черезDevTools-протокол добавлять ковсем запросам необходимый заголовок.


В сухом остатке


Сейчас для тестирования в микросервисной архитектуре мы используем:


  • Карму для E2E-тестов.
  • Методологию Agile Testing.
  • PaaS c Api Gateway.
  • Service mesh, благодаря которому работают OpenTracing и Graceful Degradation тестирование.
Подробнее..

Вам не нужен end-to-end? Борьба с шифрованием в западном мире набирает обороты

21.04.2021 22:10:18 | Автор: admin

В прошлый раз мы поговорили о том, кто и где ведет наиболее активную борьбу со сквозным шифрованием. Одни из лидеров в этом процессе структуры Великобритании. Но они не одиноки в своих начинаниях, и сегодня мы обсудим опыт их коллег из других стран.

Фотография: David Clode. Источник: Unsplash.comФотография: David Clode. Источник: Unsplash.com

Вверх тормашками

Австралия в некоторой степени двигается впереди всех остальных стран. Там закон, накладывающий ограничения на работу с end-to-end, действует с 2018 года. Местные компании, владеющие мессенджерами и другими ИТ-продуктами обязаны предоставлять дешифрованные данные по запросу правоохранителей. Если такой возможности у них нет, они должны найти вариант, чтобы обеспечить доступ фактически внедрить что-то вроде бэкдора.

Помимо влияния на деятельность компаний закон распространяется и на граждан например, наделяет австралийских полицейских новыми полномочиями. Они могут потребовать от подозреваемых разблокировать личные мобильные устройства и изучить переписку. За отказ в содействии грозит уголовное наказание. Однако правоохранители говорят, преступники стали чаще сотрудничать со следствием, что позволяет быстрее раскрывать преступления.

Требования к механизму раскрытия информации все еще уточняют Министерство внутренних дел страны до сих пор обсуждает варианты реализации MITM с представителями ИТ-индустрии и пока неизвестно, когда будет утвержден какой-либо технический регламент.

Фотография: Florian Gagnepain. Источник: Unsplash.comФотография: Florian Gagnepain. Источник: Unsplash.com

В то же время эта критика со стороны правозащитных организаций и некоторых правительственных агентств не умолкает. Также в поддержку технологии шифрования высказался бывший премьер-министр Австралии и один из инициаторов антишифровального закона. Кажется, он переменил свое мнение на счет end-to-endа и заявил, что тут речь может идти и о защите инфраструктуры страны от бэкдоров в железе иностранных вендоров.

С учетом этих событий есть основания полагать, что некоторые аспекты австралийского закона, ограничивающие E2E, могут быть пересмотрены. Но неизвестно в какую сторону.

Американская неспешность

Конгресс США уже несколько месяцев рассматривает поправки для закона Об этикете в средствах коммуникации. Сейчас он снимает ответственность с медийных площадок и соцсетей за содержание материалов, размещенных пользователями. Однако авторы поправок считают, что компании злоупотребляют этим правом и делают недостаточно для борьбы с запрещённым контентом. Если изменения вступят в силу, то ИТ-бизнес должен будет проходить регулярный аудит алгоритмов и методов фильтрации контента, а также выполнять требования отдельных штатов. Одним из них может стать запрет end-to-end и установка бэкдоров.

Пока что вопрос с принятием поправок отложен, так как документ подвергается критике со стороны общественности. Так, против него выступили разработчики Signal по этой теме выходил материал на Хабре. Для этого мессенджера end-to-end шифрование основополагающая технология и новым требованиям он не сможет соответствовать.

Фотография: Adolfo Flix. Источник: Unsplash.comФотография: Adolfo Flix. Источник: Unsplash.com

Однако сенаторы подготовили еще один удар по шифрованию в конце 2020-го. Это LAED Act или Lawful Access to Encrypted Data. Согласно законопректу, ИТ-сервисы с аудиторией более миллиона пользователей должны будут по запросу предоставлять правоохранителям доступ к информации на серверах и передающейся между устройствами клиентов. Пока он находится на самых ранних этапах рассмотрения, и еще рано говорить, как активно его будут продвигать сенаторы. Но эксперты из Electronic Frontier Foundation уже предупредили законопроект потребует от владельцев сервисов установки правительственных бэкдоров.

Запрет end-to-end не панацея

Эксперты предупреждают, что запрет сквозного шифрования скорее всего не только не повысит безопасность в сети, но и приведет к обратному эффекту. Предлагаемые западными регуляторами решения и установка бэкдоров это точки уязвимости, которые способны привести к утечкам персональных данных. Нельзя гарантировать, что эксплойты навсегда останутся в руках правоохранителей известны случаи, когда они утекали в сеть.

В то же время ИТ-сообщество и специалисты по ИБ продолжают говорить о других более прозрачных методах борьбы с распространением вредоносного контента в сети. Примером может быть поиск подозрительных аккаунтов в социальных сетях по метаданным. К слову, этот метод уже использует WhatsApp и блокирует более 300 тыс. аккаунтов ежемесячно.

Какое влияние подобные инициативы окажут на социальные сети и мессенджеры на мировом уровне, можно будет пронаблюдать уже в ближайшем будущем.


Дополнительное чтение:


Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru