Skip to main content

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

Убедитесь, что ваши файлы SARIF от сторонних инструментов соответствуют GitHubстандартам .

Кто может использовать эту функцию?

Code scanning доступен для следующих типов репозитория:

  • Общедоступные репозитории для GitHub.com
  • Репозитории, принадлежащие организации, на GitHub Team, GitHub Enterprise Cloud или GitHub Enterprise Server, с включённым GitHub Code Security .

GitHub может парсировать SARIF-файлы, созданные сторонними инструментами, для отображения code scanning оповещений в репозиториях. Дополнительные сведения см. в разделе О файлах SARIF для сканирования кода.

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

Если вы используете GitHub Actions с Рабочий процесс анализа CodeQL ИЛИ используете CodeQL CLI, то code scanning результаты автоматически будут использовать поддерживаемый подмножество SARIF 2.1.0.

Данные для предотвращения дублирования оповещений

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

Согласованные пути файлов

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

Генерация отпечатков пальцев

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

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

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

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

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

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

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

Расположение исходных файлов

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

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

Code scanning Также отображаются оповещения в результатах проверки pull request, когда все строки кода, определённые оповещением, существуют в дифференциаце pull request.

Для отображения в проверке запроса на вытягивание оповещение должно соответствовать всем следующим условиям:

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

Объект physicalLocation в отправленном ФАЙЛЕ SARIF определяет строки кода для оповещения. Дополнительные сведения см. в разделе physicalLocation "Объект".

Корневой адрес исходных файлов

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

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

Если указать корень источника, любое расположение артефакта, указанное с помощью абсолютного универсального кода ресурса (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, что и исходный корневой каталог.

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

Совместимость файлов

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

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

Code scanning поддерживает загрузку максимального количества записей для объектов данных в следующей таблице. Если любой из этих объектов превышает максимальное значение, то файл SARIF отклоняется. Для некоторых объектов также существует дополнительное ограничение на количество отображаемых значений. По возможности отображаются наиболее важные значения. Чтобы максимально эффективно использовать анализ, когда данные выше поддерживаемых лимитов, постарайтесь оптимизировать конфигурацию анализа (например, для CodeQL инструмента определите и отключите самые шумные запросы). Дополнительные сведения см. в разделе Результаты SARIF превышают одно или несколько ограничений.

Данные SARIFМаксимальные значенияОграничения усечения данных
Выполняется для каждого файла20нет
Результаты на выполнение25,000Будут включены только первые 5000 результатов, приоритетные по серьезности.
Правила для каждого запуска25,000нет
Расширения инструментов для каждого запуска100нет
Расположения потоков на результат10,000Будут включены только первые 1000 расположений потоков, используя приоритет.
Расположение на результат1,000Будут включены только 100 расположений.
Теги для каждого правила20Будут включены только 10 тегов.
Ограничение оповещений1 000 000нет

Для информации о других ошибках см. Устранение неполадок отправки SARIF.

Поддерживаемые свойства

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

Примечание.

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

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

объект sarifLog

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

объект run

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

ИмяОбязательныйDescription
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

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

объект reportingDescriptor

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

ИмяОбязательныйDescription
idУникальный идентификатор правила. Ссылка id используется из других частей файла SARIF и может использоваться code scanning для отображения URL на GitHub.
nameНазвание правила.
Code scanning отображает имя, позволяющее фильтровать результаты по правилу на GitHub. Ограничено 255 символами.
shortDescription.textКраткое описание правила.
Code scanning Краткое описание отображается рядом GitHub с соответствующими результатами. Ограничено 1024 символами.
fullDescription.textОписание правила.
Code scanning Полное описание GitHub отображается рядом с соответствующими результатами. Ограничено 1024 символами.
defaultConfiguration.levelУровень серьезности правила по умолчанию.
Code scanning использует уровни тяжести, чтобы понять, насколько критически важен результат для конкретного правила. По умолчанию defaultConfiguration.level задано значение warning. Однако можно переопределить уровень по умолчанию для правила, задав level атрибут в объекте, связанном result с результатом. Дополнительные сведения см. в документации по объектуresult. Допустимые значенияdefaultConfiguration.level: note``warning и error.
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 от 0.1 до 3.9 — low. Значение 0.0 или любое другое значение за пределами заданного диапазона считается отсутствием серьезности безопасности.

объект result

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

ИмяОбязательныйDescription
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

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

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

объект physicalLocation

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

объект runAutomationDetails

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

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

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

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

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

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

idcategoryrun_id
my-analysis/tool1/2022-01-02my-analysis/tool12022-01-02
my-analysis/tool1/my-analysis/tool1None
MY-анализ для Tool1NoneMY-анализ для Tool1
  • Выполнение с id для my-analysis/tool1/2021-02-01 относится к категории my-analysis/tool1.
  • Выполнение с 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"
          }
        }
      ]
    }
  ]
}

Руководство по относительному URI для производителей SARIF

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

Примечание.

Хотя это свойство не обязательно для GitHub корректного отображения code scanning результатов, при использовании относительных URI-ссылок требуется для получения действительного SARIF-вывода.

{
  "$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",
               }
            }
          ]
        }
      },
      "originalUriBaseIds": {
        "PROJECTROOT": {
         "uri": "file:///C:/Users/Mary/code/TheProject/",
           "description": {
             "text": "The root directory for all project files."
           }
        },
         "%SRCROOT%": {
           "uri": "src/",
           "uriBaseId": "PROJECTROOT",
           "description": {
             "text": "The root of the source tree."
           }
         }
      },
      "results": [
        {
          "ruleId": "R01",
          "message": {
            "text": "Result text. This result does not have a rule associated."
          },
          "locations": [
            {
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "fileURI",
                  "uriBaseId": "%SRCROOT%"
                },
                "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"
    }
  ]
}