Skip to content

Commit

Permalink
Add: Extend GitHub API for code scanning CodeQL database
Browse files Browse the repository at this point in the history
Add the GitHub API for their CodeQL based scanning.
  • Loading branch information
bjoernricks committed Oct 19, 2023
1 parent 9993a95 commit 15b6df4
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 0 deletions.
80 changes: 80 additions & 0 deletions pontos/github/api/code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
AlertSort,
AlertState,
Analysis,
CodeQLDatabase,
CodeScanningAlert,
DismissedReason,
Instance,
Expand Down Expand Up @@ -455,3 +456,82 @@ async def delete_analysis(
response = await self._client.delete(api)
response.raise_for_status()
return response.json()

async def codeql_databases(
self,
repo: str,
) -> AsyncIterator[CodeQLDatabase]:
"""
List the CodeQL databases that are available in a repository.
https://docs.github.com/en/rest/code-scanning/code-scanning#list-codeql-databases-for-a-repository
Args:
repo: GitHub repository (owner/name)
Raises:
HTTPStatusError: A httpx.HTTPStatusError is raised if the request
failed.
Returns:
An async iterator yielding the code scanning codeql database
information
Example:
.. code-block:: python
from pontos.github.api import GitHubAsyncRESTApi
async with GitHubAsyncRESTApi(token) as api:
async for database in api.code_scanning.codeql_databases(
"org/repo"
):
print(database)
"""

api = f"/repos/{repo}/code-scanning/codeql/databases"
params = {"per_page": "100"}

async for response in self._client.get_all(api, params=params):
response.raise_for_status()

for alert in response.json():
yield CodeQLDatabase.from_dict(alert)

async def codeql_database(
self,
repo: str,
language: str,
) -> CodeQLDatabase:
"""
Get a CodeQL database for a language in a repository
https://docs.github.com/en/rest/code-scanning/code-scanning#get-a-codeql-database-for-a-repository
Args:
repo: GitHub repository (owner/name)
language: The language of the CodeQL database
Raises:
HTTPStatusError: A httpx.HTTPStatusError is raised if the request
failed.
Returns:
Code scanning CodeQL database information
Example:
.. code-block:: python
from pontos.github.api import GitHubAsyncRESTApi
async with GitHubAsyncRESTApi(token) as api:
db = await api.code_scanning.codeql_database(
"org/repo", "java"
)
print(db)
"""

api = f"/repos/{repo}/code-scanning/codeql/databases/{language}"
response = await self._client.get(api)
response.raise_for_status()
return CodeQLDatabase.from_dict(response.json())
32 changes: 32 additions & 0 deletions pontos/github/models/code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,35 @@ class Analysis(GitHubModel):
tool: Tool
deletable: bool
warning: str


@dataclass
class CodeQLDatabase(GitHubModel):
"""
A CodeQL database
Attributes:
id: The ID of the CodeQL database
name: The name of the CodeQL database
language: The language of the CodeQL database
uploader: A GitHub user
content_type: The MIME type of the CodeQL database file
size: The size of the CodeQL database file in bytes
created_at: The date and time at which the CodeQL database was created
updated_at: The date and time at which the CodeQL database was last
updated
url: The URL at which to download the CodeQL database
commit_oid: The commit SHA of the repository at the time the CodeQL
database was created
"""

id: int
name: str
language: str
uploader: User
content_type: str
size: int
created_at: datetime
updated_at: datetime
url: str
commit_oid: Optional[str] = None
131 changes: 131 additions & 0 deletions tests/github/api/test_code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -1063,3 +1063,134 @@ async def test_delete_analysis(self):
resp["confirm_delete_url"],
"https://api.github.com/repos/octocat/hello-world/code-scanning/analyses/41?confirm_delete",
)

async def test_codeql_databases(self):
response = create_response()
response.json.return_value = [
{
"id": 1,
"name": "database.zip",
"language": "java",
"uploader": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": False,
},
"content_type": "application/zip",
"size": 1024,
"created_at": "2022-09-12T12:14:32Z",
"updated_at": "2022-09-12T12:14:32Z",
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
"commit_oid": 12345678901234567000,
},
{
"id": 2,
"name": "database.zip",
"language": "ruby",
"uploader": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": False,
},
"content_type": "application/zip",
"size": 1024,
"created_at": "2022-09-12T12:14:32Z",
"updated_at": "2022-09-12T12:14:32Z",
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/ruby",
"commit_oid": 23456789012345680000,
},
]

self.client.get_all.return_value = AsyncIteratorMock([response])

async_it = aiter(self.api.codeql_databases("foo/bar"))
db = await anext(async_it)
self.assertEqual(db.id, 1)
alert = await anext(async_it)
self.assertEqual(alert.id, 2)

with self.assertRaises(StopAsyncIteration):
await anext(async_it)

self.client.get_all.assert_called_once_with(
"/repos/foo/bar/code-scanning/codeql/databases",
params={
"per_page": "100",
},
)

async def test_codeql_database(self):
response = create_response()
response.json.return_value = {
"id": 1,
"name": "database.zip",
"language": "java",
"uploader": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": False,
},
"content_type": "application/zip",
"size": 1024,
"created_at": "2022-09-12T12:14:32Z",
"updated_at": "2022-09-12T12:14:32Z",
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
"commit_oid": 12345678901234567000,
}
self.client.get.return_value = response

alert = await self.api.codeql_database(
"foo/bar",
"java",
)

self.client.get.assert_awaited_once_with(
"/repos/foo/bar/code-scanning/codeql/databases/java",
)

self.assertEqual(alert.id, 1)
58 changes: 58 additions & 0 deletions tests/github/models/test_code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pontos.github.models.code_scanning import (
AlertState,
Analysis,
CodeQLDatabase,
CodeScanningAlert,
Instance,
Location,
Expand Down Expand Up @@ -343,3 +344,60 @@ def test_from_dict(self):
self.assertEqual(analysis.tool.version, "2.4.0")
self.assertIsNone(analysis.tool.guid)
self.assertTrue(analysis.deletable)


class CodeQLDatabaseTestCase(unittest.TestCase):
def test_from_dict(self):
db = CodeQLDatabase.from_dict(
{
"id": 1,
"name": "database.zip",
"language": "java",
"uploader": {
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": False,
},
"content_type": "application/zip",
"size": 1024,
"created_at": "2022-09-12T12:14:32Z",
"updated_at": "2022-09-12T12:14:32Z",
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
"commit_oid": "12345678901234567000",
}
)

self.assertEqual(db.id, 1)
self.assertEqual(db.name, "database.zip")
self.assertEqual(db.language, "java")
self.assertEqual(db.uploader.id, 1)
self.assertEqual(db.content_type, "application/zip")
self.assertEqual(db.size, 1024)
self.assertEqual(
db.created_at,
datetime(2022, 9, 12, 12, 14, 32, tzinfo=timezone.utc),
)
self.assertEqual(
db.updated_at,
datetime(2022, 9, 12, 12, 14, 32, tzinfo=timezone.utc),
)
self.assertEqual(
db.url,
"https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
)
self.assertEqual(db.commit_oid, "12345678901234567000")

0 comments on commit 15b6df4

Please sign in to comment.