Skip to content

Commit

Permalink
Refactor CodeQL CI (#3319)
Browse files Browse the repository at this point in the history
- Move CodeQL scripts to the scripts directory
- Only report error in CI if it's a CodeQL reported issue and was not dismissed
  before and is likely to be an actual error
  • Loading branch information
TianlongLiang authored Apr 16, 2024
1 parent 42199f1 commit 30426be
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/usr/bin/env bash

#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#

sudo apt update

sudo apt install -y build-essential cmake g++-multilib libgcc-11-dev lib32gcc-11-dev ccache ninja-build ccache
Expand Down
124 changes: 124 additions & 0 deletions .github/scripts/codeql_fail_on_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env python3

#
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#

import json
import sys
import os
import requests


def fetch_dismissed_alerts(repo_name, github_token):
headers = {
"Authorization": f"token {github_token}",
"Accept": "application/vnd.github.v3+json",
}
url = (
f"https://api.github.com/repos/{repo_name}/code-scanning/alerts?state=dismissed"
)
response = requests.get(url, headers=headers)
return response.json() # This assumes a successful API call


def parse_location(location):
path = location.get("physicalLocation", {}).get("artifactLocation", {}).get("uri")
start_line = location.get("physicalLocation", {}).get("region", {}).get("startLine")
column_range = (
location.get("physicalLocation", {}).get("region", {}).get("startColumn"),
location.get("physicalLocation", {}).get("region", {}).get("endColumn"),
)
return (path, start_line, column_range)


def is_dismissed(rule_id, path, start_line, column_range, dismissed_alerts):
for alert in dismissed_alerts:
alert_rule_id = alert.get("rule", {}).get("id")
alert_path = alert.get("location", {}).get("path")
alert_start_line = alert.get("location", {}).get("start_line")
alert_column_range = (
alert.get("location", {}).get("start_column"),
alert.get("location", {}).get("end_column"),
)

if (
rule_id == alert_rule_id
and path == alert_path
and start_line == alert_start_line
and column_range == alert_column_range
):
return True
return False


# Return whether SARIF file contains error-level results
def codeql_sarif_contain_error(filename, dismissed_alerts):
has_error = False

with open(filename, "r") as f:
s = json.load(f)

for run in s.get("runs", []):
rules_metadata = run["tool"]["driver"]["rules"]
if not rules_metadata:
rules_metadata = run["tool"]["extensions"][0]["rules"]

for res in run.get("results", []):
if "ruleIndex" in res:
rule_index = res["ruleIndex"]
elif "rule" in res and "index" in res["rule"]:
rule_index = res["rule"]["index"]
else:
continue

# check whether it's dismissed before
rule_id = res["ruleId"]
path, start_line, column_range = parse_location(res["locations"][0])
# the source code is from dependencies
if "_deps" in path:
continue
if is_dismissed(rule_id, path, start_line, column_range, dismissed_alerts):
print(
f"====== Finding a dismissed entry: {rule_id} at {path}:{start_line} is dismissed.======"
)
print(res)
continue

try:
rule_level = rules_metadata[rule_index]["defaultConfiguration"]["level"]
except IndexError as e:
print(e, rule_index, len(rules_metadata))
else:
if rule_level == "error":
# very likely to be an actual error
if rules_metadata[rule_index]["properties"].get("precision") in [
"high",
"very-high",
]:
# the security severity is above medium(Common Vulnerability Scoring System (CVSS) >= 4.0)
if "security-severity" in rules_metadata[rule_index][
"properties"
] and (
float(
rules_metadata[rule_index]["properties"][
"security-severity"
]
)
> 4.0
):
print("====== Finding a likely error. ======")
print(res)
has_error = True

return has_error


if __name__ == "__main__":
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")
dismissed_alerts = fetch_dismissed_alerts(GITHUB_REPOSITORY, GITHUB_TOKEN)

if codeql_sarif_contain_error(sys.argv[1], dismissed_alerts):
sys.exit(1)
7 changes: 5 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.

- run: |
./.github/workflows/codeql_buildscript.sh
./.github/scripts/codeql_buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
Expand Down Expand Up @@ -110,5 +110,8 @@ jobs:

- name: Fail if an error is found
run: |
./.github/workflows/codeql_fail_on_error.py \
./.github/scripts/codeql_fail_on_error.py \
${{ steps.step1.outputs.sarif-output }}/cpp.sarif
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
34 changes: 0 additions & 34 deletions .github/workflows/codeql_fail_on_error.py

This file was deleted.

0 comments on commit 30426be

Please sign in to comment.