Вебинар: Использование статических анализаторов кода при разработке безопасного ПО - 19.12
Вы пользуетесь GitHub, пишете код и делаете прочие веселые штуки. Для повышения качества своей работы и оптимизации своего времени используете статический анализатор. И вот вам приходит идея - а почему бы не смотреть на ошибки, которые выдал анализатор, прямо в GitHub? Да и еще, чтобы это красиво выглядело. Что же делать в этом случае? Ответ очень простой. Ваш выбор – SARIF. О том что это такое, как это настроить, и будет рассказано в данной статье. Приятного чтения.
SARIF (Static Analysis Results Interchange Format) – это формат обмена результатами статического анализа на основе JSON для вывода инструментов статического анализа. То есть нам достаточно получить отчет анализатора в этом формате, и далее мы можем его использовать в тех продуктах, которые поддерживают данный формат - например, на GitHub или в Visual Studio Code.
Этот формат появился из-за того, что в мире инструментов статического анализа каждый создавал свой собственный выходной формат. Однако, даже если отчёты разных анализаторов представлены в одном и том же формате (например, JSON), структура самих отчетов может кардинально отличаться друг от друга. Поэтому один общий стандарт был лишь вопросом времени.
Данный формат (SARIF) быстро развивается, и его начинают использовать все чаще и чаще. Однако на данный момент у него есть небольшой недостаток. Иногда он меняет свою структуру, и приходится немного корректировать код, чтобы SARIF файл проходил валидацию. Однако это мелочи по сравнению с тем, какую пользу он несёт. В теории, в идеальном мире, достаточно получить отчет в этом формате и далее его можно открыть в любой программе\системе, которая работает с результатами статического анализа. Ну красота же!
Чтобы GitHub начал анализировать SARIF файлы, сначала необходимо настроить репозиторий. При настройке мы пользовались вот этой инструкцией.
Итак, открываем свой репозиторий и нажимаем на "Security".
Находим по центру "Code scanning alerts" и нажимаем справа на кнопку "Set up code scanning".
Далее нажимаем на "Set up this workflow".
Теперь даем имя для yml файла (например upload-sarif.yml) и пишем следующее содержимое:
name: "Upload SARIF"
# Run workflow each time code is pushed to your repository and on a schedule.
# The scheduled workflow runs every at 00:00 on Sunday UTC time.
on:
push:
schedule:
- cron: '0 0 * * 0'
jobs:
build:
runs-on: ubuntu-latest
steps:
# This step checks out a copy of your repository.
- name: Checkout repository
uses: actions/checkout@v2
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v1
with:
# Path to SARIF file relative to the root of the repository
sarif_file: results.sarif
Выглядеть это должно следующим образом:
Теперь нажимаем "Start commit", пишем какое-то сообщение (например "Create upload-sarif.yml") и коммитим.
Отлично, мы настроили репозиторий! Можно приступать к получению SARIF файла.
Как вы поняли, SARIF – унифицированный стандарт, и получить его можно с помощью разных статических анализаторов и инструментов. В этой статье мы будем использовать PVS-Studio и PlogConverter. Обо всем об этом – далее.
Чтобы получить SARIF файл, сначала нам необходимо проверить проект с помощью статического анализатора. Поэтому в настроенный выше репозиторий мы добавили небольшой тестовый С++ проект с одним файлом для демонстрации. Ибо что мы будет проверять-то в самом деле? :) Вот содержимое файла:
#include <iostream>
void f(unsigned int ch)
{
unsigned int chx = -1;
if (ch >= 0x0fff0)
{
if ( !((ch >= 0x0FF10) && (ch <= 0x0FF19))
|| ((ch >= 0x0FF21) && (ch <= 0x0FF3A))
|| ((ch >= 0x0FF41) && (ch <= 0x0FF5A)))
{
ch = chx;
}
}
}
int main()
{
std::cout << "error" << std::endl;
}
Кстати, синтетический пример с ошибкой имеет реальный прототип, описанный в статье "Как PVS-Studio оказался внимательнее, чем три с половиной программиста".
Как уже было упомянуто выше, проверка будет осуществляться с помощью статического анализатора PVS-Studio. А именно - с помощью консольной утилиты "PVS-Studio_Cmd.exe". Данная утилита позволяет производить анализ C++, C# MSBuild-проектов на Windows. По умолчанию найти ее можно по пути "C:\Program Files (x86)\PVS-Studio". Подробнее о данной утилите Вы можете почитать здесь.
Если у вас нет лицензии для проверки, то не отчаивайтесь. Кликнув сюда, вы перейдёте на сайт анализатора, где сможете скачать его, а также получить триальную лицензию.
Собственно, приступаем к анализу. Чтобы его произвести достаточно выполнить вот эту команду:
PVS-Studio_Cmd.exe -t "D:\Use_SARIF_Example\BestProjectCpp.sln" \
-o "D:\Use_SARIF_Example\results.plog" -e "D:\Use_SARIF_Example\"
Рассмотрим строку запуска немного подробнее. Флаг "-t" является обязательным. Он позволяет указать объект для проверки (sln или csproj/vcxproj файл). Флаг "-o" отвечает за путь до файла, в который будут записаны результаты анализа. Флаг "-e" - корневая часть пути, которую PVS-Studio будет использовать при генерации относительных путей в предупреждениях. Нужно это потому, что отчет будет обрабатываться в облаке.
Отлично, теперь нужно преобразовать plog файл в SARIF файл. Для этого воспользуемся утилитой PlogConverter.
Преобразование мы будем выполнять с помощью утилиты PlogConverter, поэтому пару слов о ней. PlogConverter – это утилита с открытым исходным кодом, предназначенная для преобразования отчетов анализатора PVS-Studio из одного формата в другой. Более подробно утилита описана в документации.
Итак, нам необходимо найти PlogConverter.exe на компьютере. Эта утилита устанавливается вместе с PVS-Studio и располагается рядом с "PVS-Studio_Cmd.exe". Переходим туда, открываем консоль и пишем следующую команду:
PlogConverter.exe "D:\Use_SARIF_Example\results.plog" \
-o "D:\Use_SARIF_Example" -t sarif -n results
Вот и все. Теперь можно заливать этот файл и смотреть результаты анализа.
Чтобы проверить, что мы все сделали правильно, быстренько загрузим наш SARIF файл руками и посмотрим результаты анализа. Для этого переходим в репозиторий и нажимаем "Add file -> Upload files".
Далее добавляем SARIF файл и ждем, пока он обработается. Если хочется посмотреть, как там проходит обработка, то необходимо нажать на "Actions" и далее выбрать работающую задачу.
Как только все будет готово, заходим во вкладку "Security". В ней выбираем слева "Code scanning alerts -> PVS-Studio".
Справа у нас и будут сообщения анализатора. Откроем какое-нибудь предупреждение:
Мы видим:
Пришло время посмотреть, как это все может работать на практике. Предлагаю рассмотреть сценарий, когда человек скачает репозиторий, выполнит какую-то работу и с помощью описанных выше команд, создаст SARIF файл и зальет изменения в отдельную ветку. В итоге такой сценарий позволит нам смотреть не только, какие файлы изменил пользователь, но и какие ошибки он допустил. Поэтому скачиваем репозиторий и делаем изменения в файле с C++ кодом:
#include <iostream>
void f(unsigned int ch)
{
unsigned int chx = -1;
if (ch >= 0x0fff0)
{
if (!((ch >= 0x0FF10) && (ch <= 0x0FF19))
|| ((ch >= 0x0FF21) && (ch <= 0x0FF3A))
|| ((ch >= 0x0FF41) && (ch <= 0x0FF5A)))
{
ch = chx;
}
}
}
int ComputeProjectionMatrixFOV(float fov)
{
float yScale = 1.0 / tan((3.141592538 / 180.0) * fov / 2);
return yScale;
}
int main()
{
std::cout << "error" << std::endl;
}
Далее проверяем файл, сохраняем отчет, получаем SARIF файл (заменяя им уже лежащий в скаченном репозитории) и делаем коммит в отдельную ветку. Все, пользователь сделал свое дело. Теперь черед смотреть ошибки.
Заходим в репозиторий. Далее "Security" -> "Code scanning alerts" -> "PVS-Studio" и справа в "Branch" выбираем нужную ветку. Смотрим результаты:
Как вы видите, сообщения об ошибках в ветке хранятся отдельно. Согласитесь, это достаточно удобно. При желании можно, например, создать bat файл, который будет запускать анализатор, конвертировать отчет в SARIF и заменять существующий SARIF файл.
Итак, вы остались один на один с отчетом. Что доступно в вашем распоряжении? Первое, на что нужно обратить внимание, — это то, что все ошибки разделены на две группы. Это "Open" и "Closed". "Open" — это активные ошибки, которые мы не обработали. "Closed" – это ошибки, которые мы исправили или пометили как ложные.
Второе — это фильтры по статусам ошибок (закрытые, отрытые и все такое).
Еще есть фильтры по характеристикам ошибок. Например, можно отсортировать по номеру ошибки.
Также GitHub позволяет нам помечать сообщения как "false positive", "used in tests", и мое любимое "won't fix" :). Чтобы пометить сообщение, необходимо его выбрать (слева от сообщения есть checkbox) и справа вверху нажать на "Dismiss".
Сообщения, которые вы так разметите, не будут попадать в графу открытых ошибок при следующей загрузке SARIF файла.
Если у нас появилась необходимость вернуть сообщения в "Open", то это очень легко сделать. Для этого выбираем "Closed", далее выбираем то, что хотим вернуть, и нажимаем справа "Reopen".
Также обратите внимание, что если загрузить новый лог, то он перезаписывает текущие открытые ошибки. Если ошибки, которые были в "Open", не встретились в новом логе, то они попадают в "Closed". Поэтому рекомендуем использовать SARIF только для анализа всего проекта. Если вам требуется проанализировать только pull request, то для этого у нас есть ряд статей на эту тему. Например, вот эта. Использовать же SARIF для анализа pull request будет не очень удобно.
Конечно же нет, вы вообще не зависите от языка. Все, что вам нужно – это инструмент статического анализа, который сможет проанализировать ваш код и создать SARIF файл. Например, используемый в этой статье PVS-Studio умеет анализировать C++, C#, Java. Поэтому давайте еще попробуем проверить код на C#, потому что это лучший язык в мире один из авторов статьи его любит. Для примера быстренько проделываем все то же самое, о чем говорилось в статье, но уже для C# проекта. Вот содержимое файла, который был проанализирован:
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestSarif
{
class Program
{
static void Main()
{
var result = Formula42(3, 5);
}
static int Formula42(int? coefficientA, int? coefficientB)
{
var data = new List<int>();
if (coefficientA != null)
data.Add(Formula42(coefficientA.Value));
else if (coefficientB != null)
data.Add(Formula42(coefficientA.Value));
return data.SingleOrDefault();
}
static private int Formula42(int coefficient)
{
return coefficient;
}
}
}
Вот результат:
Ну и посмотрим на саму ошибку.
Подводя итог, хочется сказать, что SARIF — это удобный формат, который позволяет просматривать результаты анализа. Да и настройка использования SARIF быстрая и простая. Например, в VS Code это вообще делается в пару кликов. Кстати, если вам будет интересно, как это сделать, то напишите об этом в комментариях. Да и вообще, если у вас есть какие-то пожелания по темам статьи, то напишите об этом.
Так что пробуйте и пользуйтесь. Спасибо за внимание.
0