Skip to main content

Поддержка SARIF для проверки кода

Чтобы отобразить результаты стороннего средства статического анализа в вашем репозитории в GitHub, необходимо хранить результаты в файле SARIF, поддерживающем конкретное подмножество схемы JSON SARIF 2.1.0 для code scanning. Если вы используете подсистему статического анализа CodeQL, результаты будут автоматически отображаться в репозитории на сайте GitHub.

Code scanning доступно во всех открытых репозиториях на GitHub.com. Code scanning также доступно в частных репозиториях, принадлежащих организациям, которые используют GitHub Enterprise Cloud и имеют лицензию на GitHub Advanced Security. Дополнительные сведения см. в разделе Сведения о GitHub Advanced Security.

Сведения о поддержке SARIF

SARIF (Static Analysis Results Interchange Format) — это стандарт OASIS, определяющий формат выходного файла. Стандарт SARIF упрощает совместное использование результатов средств статического анализа. Code scanning поддерживает подмножество схемы JSON для SARIF 2.1.0.

Чтобы передать файл SARIF из сторонней подсистемы статического анализа кода, необходимо убедиться, что отправленные файлы используют SARIF версии 2.1.0. GitHub анализирует файл SARIF и отображает оповещения, используя результаты из репозитория в рамках работы с code scanning. Дополнительные сведения см. в статье Передача файла SARIF в GitHub. Дополнительные сведения о схеме JSON для SARIF 2.1.0 см. в документации по sarif-schema-2.1.0.json.

Если вы используете GitHub Actions с CodeQL analysis workflow или CodeQL CLI, результаты code scanning будут автоматически использовать поддерживаемую часть SARIF 2.1.0. Дополнительные сведения см. в разделах Настройка code scanning для репозитория или Установка CodeQL CLI в системе CI.

Можно передать несколько файлов SARIF для одной и той же фиксации и отобразить данные из каждого файла в виде результатов code scanning. При передаче нескольких файлов SARIF для фиксации необходимо указать категорию для каждого анализа. Способ указания категории зависит от метода анализа:

  • Используя CodeQL CLI напрямую, при создании файлов SARIF передайте аргумент --sarif-category для команды codeql database analyze. Дополнительные сведения см. в разделе Настройка CodeQL CLI в системе CI.
  • Используя GitHub Actions с codeql-action/analyze, категория задается автоматически из имени рабочего процесса и любых переменных матрицы (обычно это language). Ее можно переопределить, указав входные данные category для действия, что полезно при анализе разных разделов монорепозитория в одном рабочем процессе.
  • Используя GitHub Actions для передачи результатов из других средств статического анализа, вам необходимо указать входные данные category, если вы передаете несколько файлов результатов для одного и того же средства в одном рабочем процессе. Дополнительные сведения см. в разделе Передача анализа code scanning с помощью GitHub Actions.
  • Если вы не используете ни один из этих подходов, то вам необходимо указать уникальный runAutomationDetails.id в каждом файле SARIF для передачи. Дополнительные сведения об этом свойстве см. далее в разделе Объект runAutomationDetails.

При передаче второго файла SARIF для фиксации с той же категорией и из того же средства более ранние результаты перезаписываются. Однако при попытке передать несколько файлов SARIF для одного и того же средства и категории в одном запуске рабочего процесса GitHub Actions будет определена неправильная настройка и выполнение завершится ошибкой.

Для вывода оповещений GitHub использует свойства в файле SARIF. Например, shortDescription и fullDescription отображаются в верхней части оповещения code scanning. location позволяет GitHub отображать заметки в файле кода. Дополнительные сведения см. в статье Управление оповещениями code scanning для репозитория.

Если вы не знакомы с SARIF и хотите узнать больше, ознакомьтесь репозиторием SARIF tutorials корпорации Майкрософт.

Предоставление данных для отслеживания оповещений code scanning в разных запусках

При каждой отправке результатов новой проверки кода эти результаты обрабатываются, а в репозиторий добавляются предупреждения. Чтобы предотвратить дублирование оповещений для одной и той же проблемы, code scanning использует отпечатки, позволяющие сопоставлять результаты различных запусков. Поэтому оповещения появляются только один раз в последнем запуске выбранной ветви. Это позволяет сопоставлять оповещения с правильной строкой кода при редактировании файлов. Для ruleID результата должен быть одинаковым в разных анализах.

Отчеты о согласованных пути к файлам

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

Включение данных для создания отпечатков пальцев

GitHub использует свойство partialFingerprints в стандарте OASIS, чтобы определить логическую идентичность двух результатов. Дополнительные сведения см. в записи свойства partialFingerprints в документации по OASIS.

Файлы SARIF, созданные CodeQL analysis workflow, или с помощью CodeQL CLI, включают данные отпечатков пальцев. Если вы отправили файл SARIF с помощью действия upload-sarif, но эти данные отсутствуют, GitHub пытается заполнить поле partialFingerprints из исходных файлов. Дополнительные сведения об отправке результатов см. в статье Передача файла SARIF в GitHub.

Если вы отправляете файл SARIF без данных отпечатков с помощью конечной точки API /code-scanning/sarifs, оповещения code scanning будут обрабатываться и отображаться, но пользователи могут видеть повторяющиеся оповещения. Чтобы избежать появления повторяющихся оповещений, следует вычислить данные отпечатка и заполнить свойство partialFingerprints перед отправкой файла SARIF. Вы можете найти скрипт, в котором действие upload-sarif использует полезную отправную точку: https://github.com/github/codeql-action/blob/main/src/fingerprints.ts. Дополнительные сведения об API см. в разделе Передача анализа в виде данных SARIF.

Общие сведения о правилах и результатах

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

  • Правила — это массив объектов reportingDescriptor, включенных в объект toolComponent. Здесь хранятся сведения о правилах, выполняемых во время анализа. Информация в этих объектах должна изменяться редко, обычно при обновлении средства.

  • Результаты хранятся в виде ряда объектов result в results в объекте run. Каждый объект result содержит сведения об одном оповещении в базе кода. В объекте results можно ссылаться на правило, которое обнаружило оповещение.

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

Указание корневого каталога для исходных файлов

Code scanning интерпретирует результаты, сообщаемые с относительными путями, как относительно корня проанализированного репозитория. Если результат содержит абсолютный URI, URI преобразуется в относительный URI. Затем относительный URI можно сопоставить с файлом, зафиксированным в репозитории.

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

  • checkout_path входные данные для github/codeql-action/analyze действия
  • checkout_uri параметр для конечной точки API отправки SARIF. Дополнительные сведения см. в разделе "Code scanning" в документации по REST API.
  • invocation.workingDirectory.uri свойство в ФАЙЛЕ SARIF

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

Например, SARIF-файл отправляется с помощью корневого file:///github/workspaceкаталога источника .

# Conversion of absolute URIs to relative URIs for location artifacts

file:///github/workspace/src/main.go -> src/main.go
file:///tmp/go-build/tmp.go          -> file:///tmp/go-build/tmp.go

Файл успешно отправлен, так как оба абсолютных URI используют ту же схему URI, что и корень источника.

Проверка файла SARIF

Вы можете проверить совместимость файла SARIF с code scanning, протестировав его в соответствии с правилами приема данных GitHub. Дополнительные сведения см. на странице проверяющего элемента управления SARIF Microsoft.

Примечания.

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

  • Максимальный размер файла SARIF в архиве gzip, поддерживаемый для каждой передачи, — 10 МБ. Любые отправки свыше этого ограничения будут отклонены. Если файл SARIF слишком большой, так как он содержит слишком много результатов, необходимо обновить конфигурацию, чтобы сосредоточиться на результатах для наиболее важных правил или запросов.

Поддерживаемые свойства выходного файла SARIF

При использовании подсистемы анализа кода, отличной от CodeQL, можно проверить поддерживаемые свойства SARIF, чтобы оптимизировать способ отображения результатов анализа в GitHub.

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

Любой допустимый выходной файл SARIF 2.1.0 можно отправить, но code scanning будет использовать только указанные ниже поддерживаемые свойства.

Объект sarifLog.

ИмяОписание
$schemaОбязательный. Универсальный код ресурса (URI) схемы JSON для SARIF версии 2.1.0. Например, https://json.schemastore.org/sarif-2.1.0.json.
versionОбязательный. Code scanning поддерживает только SARIF версии 2.1.0.
runs[]Обязательный. Файл SARIF содержит массив из одного или нескольких запусков. Каждый запуск представляет собой один запуск средства анализа. Дополнительные сведения о run см. в разделе Объект run.

Объект run.

Code scanning использует объект run для фильтрации результатов по средству и предоставлению сведений об источнике результата. Объект run содержит объект компонента средства tool.driver, содержащий сведения о средстве, которое создало результаты. Каждый объект run может содержать только результаты для одного средства анализа.

ИмяОписание
tool.driverОбязательный. Объект toolComponent, описывающий средство анализа. Дополнительные сведения см. в разделе Объект toolComponent.
tool.extensions[]Необязательный элемент. Массив объектов toolComponent, представляющих все подключаемые модули или расширения, используемые средством во время анализа. Дополнительные сведения см. в разделе Объект toolComponent.
invocation.workingDirectory.uriНеобязательный элемент. Это поле используется только в том случае, если checkout_uri (только API отправки SARIF) или checkout_path (только GitHub Actions не предоставляется. Значение используется для преобразования абсолютных URI, используемых в объектах, в physicalLocation относительные URI. Дополнительные сведения см. в разделе Указание корневого каталога для исходных файлов.
results[]Обязательный. Результаты средства анализа. Code scanning отображает результаты в GitHub. Дополнительные сведения см. в разделе Объект result.

Объект toolComponent.

ИмяОписание
nameОбязательный. Имя средства анализа. Code scanning отображает имя в GitHub, чтобы можно было фильтровать результаты по средству.
versionНеобязательный элемент. Версия средства анализа. Code scanning использует номер версии для отслеживания изменения результатов вследствие изменения версии средства, а не изменения анализируемого кода. Если файл SARIF содержит поле semanticVersion, code scanning не использует version.
semanticVersionНеобязательный элемент. Версия средства анализа, заданная форматом Семантического версионирования 2.0. Code scanning использует номер версии для отслеживания изменения результатов вследствие изменения версии средства, а не изменения анализируемого кода. Если файл SARIF содержит поле semanticVersion, code scanning не использует version. Дополнительные сведения см. на сайте по Семантическому версионированию 2.0.0 в документации.
rules[]Обязательный. Массив объектов reportingDescriptor, представляющих правила. Средство анализа использует правила для поиска проблем в анализируемом коде. Дополнительные сведения см. в разделе Объект reportingDescriptor.

Объект reportingDescriptor.

Здесь хранятся сведения о правилах, выполняемых во время анализа. Информация в этих объектах должна изменяться редко, обычно при обновлении средства. Дополнительные сведения см. в разделе Общие сведения о правилах и результатах выше.

ИмяОписание
idОбязательный. Уникальный идентификатор правила. id ссылается на другие части файла SARIF, а code scanning может его использовать для отображения URL-адресов в GitHub.
nameНеобязательный элемент. Имя правила. Code scanning отображает имя, чтобы можно было фильтровать результаты по правилу в GitHub.
shortDescription.textОбязательный. Краткое описание правила. Code scanning отображает краткое описание в GitHub рядом с соответствующими результатами.
fullDescription.textОбязательный. Описание правила. Code scanning отображает полное описание в GitHub рядом с соответствующими результатами. Максимальное количество знаков — 1000.
defaultConfiguration.levelНеобязательный элемент. Уровень серьезности правила по умолчанию. Code scanning использует уровни серьезности, чтобы помочь вам понять, насколько важен результат для данного правила. Это значение можно переопределить атрибутом level в объекте result. Дополнительные сведения см. в разделе Объект result. Значение по умолчанию: warning.
help.textОбязательный. Документация по правилу с использованием текстового формата. Code scanning отображает эту справочную документацию рядом с соответствующими результатами.
help.markdownРекомендуется. Документация по правилу с использованием формата Markdown. Code scanning отображает эту справочную документацию рядом с соответствующими результатами. Если объект help.markdown доступен, то отображается вместо help.text.
properties.tags[]Необязательный элемент. Массив строк. Code scanning использует tags, чтобы можно было фильтровать результаты в GitHub. Например, можно отфильтровать все результаты с тегом security.
properties.precisionРекомендуется. Строка, показывающая, как часто результаты, указанные этим правилом, являются истинными. Например, если правило имеет известный высокий ложноположительный коэффициент, то точность должна быть low. Code scanning упорядочивает результаты по точности в GitHub, чтобы сначала отображались результаты с наивысшим level и наибольшей precision. Это может быть very-high, high, medium или low.
properties.problem.severityРекомендуется. Строка, указывающая уровень серьезности любых оповещений, созданных запросом, не связанным с безопасностью. Со свойством properties.precision определяет, отображаются ли результаты по умолчанию в GitHub так, чтобы сначала отображались результаты с наивысшим значением problem.severity и наибольшей precision. Это может быть error, warning или recommendation.
properties.security-severityРекомендуется. Строка, представляющая оценку, указывающую уровень серьезности (в диапазоне от 0,0 до 10,0) для запросов безопасности (@tags содержит security). Со свойством properties.precision определяет, отображаются ли результаты по умолчанию в GitHub так, чтобы сначала отображались результаты с наивысшим значением security-severity и наибольшей precision. Code scanning преобразует числовые оценки следующим образом: больше 9,0 — critical, от 7,0 до 8,9 — high, от 4,0 до 6,9 — medium и 3,9 или меньше — low.

Объект result.

Каждый объект result содержит сведения об одном оповещении в базе кода. В объекте results можно ссылаться на правило, которое обнаружило оповещение. Дополнительные сведения см. в разделе Общие сведения о правилах и результатах выше.

Примечания.

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

  • Максимальный размер файла SARIF в архиве gzip, поддерживаемый для каждой передачи, — 10 МБ. Любые отправки свыше этого ограничения будут отклонены. Если файл SARIF слишком большой, так как он содержит слишком много результатов, необходимо обновить конфигурацию, чтобы сосредоточиться на результатах для наиболее важных правил или запросов.

ИмяОписание
ruleIdНеобязательный элемент. Уникальный идентификатор правила (reportingDescriptor.id). Дополнительные сведения см. в разделе Объект reportingDescriptor. Code scanning использует идентификатор правила, чтобы фильтровать результаты по правилу в GitHub.
ruleIndexНеобязательный элемент. Индекс связанного правила (объект reportingDescriptor) в массиве rules компонента средства. Дополнительные сведения см. в разделе Объект run. Допустимый диапазон для этого свойства от 0 до 2^63 – 1.
ruleНеобязательный элемент. Ссылка, используемая для поиска правила (дескриптора отчетности) для этого результата. Дополнительные сведения см. в разделе Объект reportingDescriptor.
levelНеобязательный элемент. Серьезность результата. Этот уровень переопределяет серьезность по умолчанию, определенную правилом. Code scanning использует уровень, чтобы фильтровать результаты по серьезности в GitHub.
message.textОбязательный. Сообщение, которое описывает результат. Code scanning отображает текст сообщения в качестве заголовка результата. Если видимое пространство ограничено, отображается только первое предложение сообщения.
locations[]Обязательный. Набор расположений, в которых был обнаружен результат ( не более 10). Следует включить только одно расположение, если проблему не получается исправить только внесением изменений в каждом указанном расположении. Примечание. Для отображения результата требуется по крайней мере одно расположение для code scanning. Code scanning будет использовать это свойство, чтобы определить, какой файл добавлять в заметки к результату. Используется только первое значение этого массива. Все остальные значения не учитываются.
partialFingerprintsОбязательный. Набор строк, используемых для отслеживания уникального идентификатора результата. Code scanning использует partialFingerprints, чтобы точно определить, какие результаты одинаковые в фиксациях и ветвях. Code scanning попытается использовать partialFingerprints, если они существуют. Если вы отправляете сторонние файлы SARIF с помощью upload-action, то для вас действие создаст partialFingerprints (если их нет в файле SARIF). Дополнительные сведения см. в разделе Предоставление данных для отслеживания оповещений сканирования кода во время выполнения. Примечание. Code scanning использует только primaryLocationLineHash.
codeFlows[].threadFlows[].locations[]Необязательный элемент. Массив объектов location для объекта threadFlow, который описывает ход выполнения программы через поток выполнения. Объект codeFlow описывает шаблон выполнения кода для обнаружения результата. Если потоки кода предоставлены, code scanning развернет потоки кода в GitHub для соответствующего результата. Дополнительные сведения см. в разделе Объект location.
relatedLocations[]Набор расположений, относящихся к этому результату. Code scanning будет ссылаться на связанные расположения при их внедрении в результирующее сообщение. Дополнительные сведения см. в разделе Объект location.

Объект location.

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

ИмяОписание
location.idНеобязательный элемент. Уникальный идентификатор, отличающий это расположение от всех остальных расположений в одном объекте результата. Допустимый диапазон для этого свойства от 0 до 2^63 – 1.
location.physicalLocationОбязательный. Идентифицирует артефакт и регион. Более подробную информацию см. в разделе physicalLocation.
location.message.textНеобязательный элемент. Сообщение, соответствующее расположению.

Объект physicalLocation.

ИмяОписание
artifactLocation.uriОбязательный. Универсальный код ресурса (URI), указывающий расположение артефакта, обычно это файл в репозитории или созданный во время сборки. Для достижения наилучших результатов рекомендуется использовать относительный путь из корня анализируемого репозитория GitHub. Например, src/main.js. Дополнительные сведения об URI артефактов см. в разделе Указание корневого каталога для исходных файлов.
region.startLineОбязательный. Номер строки первого символа в регионе.
region.startColumnОбязательный. Номер столбца первого символа в регионе.
region.endLineОбязательный. Номер строки последнего символа в регионе.
region.endColumnОбязательный. Номер столбца символа, следующего за концом региона.

Объект runAutomationDetails.

Объект runAutomationDetails содержит сведения, указывающие идентификатор выполнения.

Примечание. runAutomationDetails является объектом SARIF версии 2.1.0. Если вы используете CodeQL CLI, можно указать используемую версию SARIF. Эквивалентным объектом для runAutomationDetails является <run>.automationId для SARIF версии 1 и <run>.automationLogicalId для SARIF версии 2.

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

Использование объекта runAutomationDetails не является обязательным.

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

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

id интерпретируется как category/run-id. Если id содержит косую черту (/), то вся строка является run_id, а category будет пустой. В противном случае category является все, что находится в строке до последней косой черты, а все, что после нее — run_id.

idкатегорияrun_id
my-analysis/tool1/2021-02-01my-analysis/tool12021-02-01
my-analysis/tool1/my-analysis/tool1нет run-id
my-analysis for tool1нет категорииmy-analysis for tool1
  • Выполнение с id для my-analysis/tool1/2021-02-01 относится к категории my-analysis/tool1. Предположительно, это запуск от 2 февраля 2021 г.
  • Выполнение с id для my-analysis/tool1/ относится к категории my-analysis/tool1, но не отличается от других выполнений в этой категории.
  • Выполнение, id которого является my-analysis for tool1, имеет уникальный идентификатор, но не может быть выводимым для принадлежности к какой-либо категории.

Дополнительные сведения об объекте runAutomationDetails и поле id см. в разделе Объект runAutomationDetails в документации по OASIS.

Обратите внимание, что остальные поддерживаемые поля не учитываются.

Примеры выходных файлов SARIF

В этих примерах выходных файлов SARIF отображаются поддерживаемые свойства и примеры значений.

Пример с минимальными обязательными свойствами

Этот выходной файл SARIF содержит примеры значений для отображения минимальных обязательных свойств для результатов code scanning для нормальной работы. Если удалить какие-либо свойства, опустить значения или использовать пустую строку, эти данные не будут отображаться правильно или синхронизироваться с GitHub.

{
  "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "Tool Name",
          "rules": [
            {
              "id": "R01"
                      ...
              "properties" : {
                 "id" : "java/unsafe-deserialization",
                 "kind" : "path-problem",
                 "name" : "...",
                 "problem.severity" : "error",
                 "security-severity" : "9.8",
               }
            }
          ]
        }
      },
      "results": [
        {
          "ruleId": "R01",
          "message": {
            "text": "Result text. This result does not have a rule associated."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "fileURI"
                },
                "region": {
                  "startLine": 2,
                  "startColumn": 7,
                  "endColumn": 10
                }
              }
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "39fa2ee980eb94b0:1"
          }
        }
      ]
    }
  ]
}

Пример, показывающий все поддерживаемые свойства SARIF

Этот выходной файл SARIF содержит примеры значений для отображения всех поддерживаемых свойств SARIF для code scanning.

{
  "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "Tool Name",
          "semanticVersion": "2.0.0",
          "rules": [
            {
              "id": "3f292041e51d22005ce48f39df3585d44ce1b0ad",
              "name": "js/unused-local-variable",
              "shortDescription": {
                "text": "Unused variable, import, function or class"
              },
              "fullDescription": {
                "text": "Unused variables, imports, functions or classes may be a symptom of a bug and should be examined carefully."
              },
              "defaultConfiguration": {
                "level": "note"
              },
              "properties": {
                "tags": [
                  "maintainability"
                ],
                "precision": "very-high"
              }
            },
            {
              "id": "d5b664aefd5ca4b21b52fdc1d744d7d6ab6886d0",
              "name": "js/inconsistent-use-of-new",
              "shortDescription": {
                "text": "Inconsistent use of 'new'"
              },
              "fullDescription": {
                "text": "If a function is intended to be a constructor, it should always be invoked with 'new'. Otherwise, it should always be invoked as a normal function, that is, without 'new'."
              },
              "properties": {
                "tags": [
                  "reliability",
                  "correctness",
                  "language-features"
                ],
                "precision": "very-high"
              }
            },
            {
              "id": "R01"
            }
          ]
        }
      },
      "automationDetails": {
        "id": "my-category/"
      },
      "results": [
        {
          "ruleId": "3f292041e51d22005ce48f39df3585d44ce1b0ad",
          "ruleIndex": 0,
          "message": {
            "text": "Unused variable foo."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "main.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 2,
                  "startColumn": 7,
                  "endColumn": 10
                }
              }
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "39fa2ee980eb94b0:1",
            "primaryLocationStartColumnFingerprint": "4"
          }
        },
        {
          "ruleId": "d5b664aefd5ca4b21b52fdc1d744d7d6ab6886d0",
          "ruleIndex": 1,
          "message": {
            "text": "Function resolvingPromise is sometimes invoked as a constructor (for example [here](1)), and sometimes as a normal function (for example [here](2))."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "src/promises.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 2
                }
              }
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "5061c3315a741b7d:1",
            "primaryLocationStartColumnFingerprint": "7"
          },
          "relatedLocations": [
            {
              "id": 1,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "src/ParseObject.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 2281,
                  "startColumn": 33,
                  "endColumn": 55
                }
              },
              "message": {
                "text": "here"
              }
            },
            {
              "id": 2,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "src/LiveQueryClient.js",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 166
                }
              },
              "message": {
                "text": "here"
              }
            }
          ]
        },
        {
          "ruleId": "R01",
          "message": {
            "text": "Specifying both [ruleIndex](1) and [ruleID](2) might lead to inconsistencies."
          },
          "level": "error",
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "full.sarif",
                  "uriBaseId": "%SRCROOT%"
                },
                "region": {
                  "startLine": 54,
                  "startColumn": 10,
                  "endLine": 55,
                  "endColumn": 25
                }
              }
            }
          ],
          "relatedLocations": [
            {
              "id": 1,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "full.sarif"
                },
                "region": {
                  "startLine": 81,
                  "startColumn": 10,
                  "endColumn": 18
                }
              },
              "message": {
                "text": "here"
              }
            },
            {
              "id": 2,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "full.sarif"
                },
                "region": {
                  "startLine": 82,
                  "startColumn": 10,
                  "endColumn": 21
                }
              },
              "message": {
                "text": "here"
              }
            }
          ],
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "physicalLocation": {
                          "region": {
                            "startLine": 11,
                            "endLine": 29,
                            "startColumn": 10,
                            "endColumn": 18
                          },
                          "artifactLocation": {
                            "uriBaseId": "%SRCROOT%",
                            "uri": "full.sarif"
                          }
                        },
                        "message": {
                          "text": "Rule has index 0"
                        }
                      }
                    },
                    {
                      "location": {
                        "physicalLocation": {
                          "region": {
                            "endColumn": 47,
                            "startColumn": 12,
                            "startLine": 12
                          },
                          "artifactLocation": {
                            "uriBaseId": "%SRCROOT%",
                            "uri": "full.sarif"
                          }
                        }
                      }
                    }
                  ]
                }
              ]
            }
          ],
          "partialFingerprints": {
            "primaryLocationLineHash": "ABC:2"
          }
        }
      ],
      "columnKind": "utf16CodeUnits"
    }
  ]
}