Skip to content

Commit 15b6df4

Browse files
committed
Add: Extend GitHub API for code scanning CodeQL database
Add the GitHub API for their CodeQL based scanning.
1 parent 9993a95 commit 15b6df4

File tree

4 files changed

+301
-0
lines changed

4 files changed

+301
-0
lines changed

pontos/github/api/code_scanning.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
AlertSort,
1111
AlertState,
1212
Analysis,
13+
CodeQLDatabase,
1314
CodeScanningAlert,
1415
DismissedReason,
1516
Instance,
@@ -455,3 +456,82 @@ async def delete_analysis(
455456
response = await self._client.delete(api)
456457
response.raise_for_status()
457458
return response.json()
459+
460+
async def codeql_databases(
461+
self,
462+
repo: str,
463+
) -> AsyncIterator[CodeQLDatabase]:
464+
"""
465+
List the CodeQL databases that are available in a repository.
466+
467+
https://docs.github.com/en/rest/code-scanning/code-scanning#list-codeql-databases-for-a-repository
468+
469+
Args:
470+
repo: GitHub repository (owner/name)
471+
472+
Raises:
473+
HTTPStatusError: A httpx.HTTPStatusError is raised if the request
474+
failed.
475+
476+
Returns:
477+
An async iterator yielding the code scanning codeql database
478+
information
479+
480+
Example:
481+
.. code-block:: python
482+
483+
from pontos.github.api import GitHubAsyncRESTApi
484+
485+
async with GitHubAsyncRESTApi(token) as api:
486+
async for database in api.code_scanning.codeql_databases(
487+
"org/repo"
488+
):
489+
print(database)
490+
"""
491+
492+
api = f"/repos/{repo}/code-scanning/codeql/databases"
493+
params = {"per_page": "100"}
494+
495+
async for response in self._client.get_all(api, params=params):
496+
response.raise_for_status()
497+
498+
for alert in response.json():
499+
yield CodeQLDatabase.from_dict(alert)
500+
501+
async def codeql_database(
502+
self,
503+
repo: str,
504+
language: str,
505+
) -> CodeQLDatabase:
506+
"""
507+
Get a CodeQL database for a language in a repository
508+
509+
https://docs.github.com/en/rest/code-scanning/code-scanning#get-a-codeql-database-for-a-repository
510+
511+
Args:
512+
repo: GitHub repository (owner/name)
513+
language: The language of the CodeQL database
514+
515+
Raises:
516+
HTTPStatusError: A httpx.HTTPStatusError is raised if the request
517+
failed.
518+
519+
Returns:
520+
Code scanning CodeQL database information
521+
522+
Example:
523+
.. code-block:: python
524+
525+
from pontos.github.api import GitHubAsyncRESTApi
526+
527+
async with GitHubAsyncRESTApi(token) as api:
528+
db = await api.code_scanning.codeql_database(
529+
"org/repo", "java"
530+
)
531+
print(db)
532+
"""
533+
534+
api = f"/repos/{repo}/code-scanning/codeql/databases/{language}"
535+
response = await self._client.get(api)
536+
response.raise_for_status()
537+
return CodeQLDatabase.from_dict(response.json())

pontos/github/models/code_scanning.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,35 @@ class Analysis(GitHubModel):
281281
tool: Tool
282282
deletable: bool
283283
warning: str
284+
285+
286+
@dataclass
287+
class CodeQLDatabase(GitHubModel):
288+
"""
289+
A CodeQL database
290+
291+
Attributes:
292+
id: The ID of the CodeQL database
293+
name: The name of the CodeQL database
294+
language: The language of the CodeQL database
295+
uploader: A GitHub user
296+
content_type: The MIME type of the CodeQL database file
297+
size: The size of the CodeQL database file in bytes
298+
created_at: The date and time at which the CodeQL database was created
299+
updated_at: The date and time at which the CodeQL database was last
300+
updated
301+
url: The URL at which to download the CodeQL database
302+
commit_oid: The commit SHA of the repository at the time the CodeQL
303+
database was created
304+
"""
305+
306+
id: int
307+
name: str
308+
language: str
309+
uploader: User
310+
content_type: str
311+
size: int
312+
created_at: datetime
313+
updated_at: datetime
314+
url: str
315+
commit_oid: Optional[str] = None

tests/github/api/test_code_scanning.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,3 +1063,134 @@ async def test_delete_analysis(self):
10631063
resp["confirm_delete_url"],
10641064
"https://api.github.com/repos/octocat/hello-world/code-scanning/analyses/41?confirm_delete",
10651065
)
1066+
1067+
async def test_codeql_databases(self):
1068+
response = create_response()
1069+
response.json.return_value = [
1070+
{
1071+
"id": 1,
1072+
"name": "database.zip",
1073+
"language": "java",
1074+
"uploader": {
1075+
"login": "octocat",
1076+
"id": 1,
1077+
"node_id": "MDQ6VXNlcjE=",
1078+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
1079+
"gravatar_id": "",
1080+
"url": "https://api.github.com/users/octocat",
1081+
"html_url": "https://github.com/octocat",
1082+
"followers_url": "https://api.github.com/users/octocat/followers",
1083+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
1084+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
1085+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
1086+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
1087+
"organizations_url": "https://api.github.com/users/octocat/orgs",
1088+
"repos_url": "https://api.github.com/users/octocat/repos",
1089+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
1090+
"received_events_url": "https://api.github.com/users/octocat/received_events",
1091+
"type": "User",
1092+
"site_admin": False,
1093+
},
1094+
"content_type": "application/zip",
1095+
"size": 1024,
1096+
"created_at": "2022-09-12T12:14:32Z",
1097+
"updated_at": "2022-09-12T12:14:32Z",
1098+
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
1099+
"commit_oid": 12345678901234567000,
1100+
},
1101+
{
1102+
"id": 2,
1103+
"name": "database.zip",
1104+
"language": "ruby",
1105+
"uploader": {
1106+
"login": "octocat",
1107+
"id": 1,
1108+
"node_id": "MDQ6VXNlcjE=",
1109+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
1110+
"gravatar_id": "",
1111+
"url": "https://api.github.com/users/octocat",
1112+
"html_url": "https://github.com/octocat",
1113+
"followers_url": "https://api.github.com/users/octocat/followers",
1114+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
1115+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
1116+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
1117+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
1118+
"organizations_url": "https://api.github.com/users/octocat/orgs",
1119+
"repos_url": "https://api.github.com/users/octocat/repos",
1120+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
1121+
"received_events_url": "https://api.github.com/users/octocat/received_events",
1122+
"type": "User",
1123+
"site_admin": False,
1124+
},
1125+
"content_type": "application/zip",
1126+
"size": 1024,
1127+
"created_at": "2022-09-12T12:14:32Z",
1128+
"updated_at": "2022-09-12T12:14:32Z",
1129+
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/ruby",
1130+
"commit_oid": 23456789012345680000,
1131+
},
1132+
]
1133+
1134+
self.client.get_all.return_value = AsyncIteratorMock([response])
1135+
1136+
async_it = aiter(self.api.codeql_databases("foo/bar"))
1137+
db = await anext(async_it)
1138+
self.assertEqual(db.id, 1)
1139+
alert = await anext(async_it)
1140+
self.assertEqual(alert.id, 2)
1141+
1142+
with self.assertRaises(StopAsyncIteration):
1143+
await anext(async_it)
1144+
1145+
self.client.get_all.assert_called_once_with(
1146+
"/repos/foo/bar/code-scanning/codeql/databases",
1147+
params={
1148+
"per_page": "100",
1149+
},
1150+
)
1151+
1152+
async def test_codeql_database(self):
1153+
response = create_response()
1154+
response.json.return_value = {
1155+
"id": 1,
1156+
"name": "database.zip",
1157+
"language": "java",
1158+
"uploader": {
1159+
"login": "octocat",
1160+
"id": 1,
1161+
"node_id": "MDQ6VXNlcjE=",
1162+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
1163+
"gravatar_id": "",
1164+
"url": "https://api.github.com/users/octocat",
1165+
"html_url": "https://github.com/octocat",
1166+
"followers_url": "https://api.github.com/users/octocat/followers",
1167+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
1168+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
1169+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
1170+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
1171+
"organizations_url": "https://api.github.com/users/octocat/orgs",
1172+
"repos_url": "https://api.github.com/users/octocat/repos",
1173+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
1174+
"received_events_url": "https://api.github.com/users/octocat/received_events",
1175+
"type": "User",
1176+
"site_admin": False,
1177+
},
1178+
"content_type": "application/zip",
1179+
"size": 1024,
1180+
"created_at": "2022-09-12T12:14:32Z",
1181+
"updated_at": "2022-09-12T12:14:32Z",
1182+
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
1183+
"commit_oid": 12345678901234567000,
1184+
}
1185+
self.client.get.return_value = response
1186+
1187+
alert = await self.api.codeql_database(
1188+
"foo/bar",
1189+
"java",
1190+
)
1191+
1192+
self.client.get.assert_awaited_once_with(
1193+
"/repos/foo/bar/code-scanning/codeql/databases/java",
1194+
)
1195+
1196+
self.assertEqual(alert.id, 1)

tests/github/models/test_code_scanning.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pontos.github.models.code_scanning import (
1111
AlertState,
1212
Analysis,
13+
CodeQLDatabase,
1314
CodeScanningAlert,
1415
Instance,
1516
Location,
@@ -343,3 +344,60 @@ def test_from_dict(self):
343344
self.assertEqual(analysis.tool.version, "2.4.0")
344345
self.assertIsNone(analysis.tool.guid)
345346
self.assertTrue(analysis.deletable)
347+
348+
349+
class CodeQLDatabaseTestCase(unittest.TestCase):
350+
def test_from_dict(self):
351+
db = CodeQLDatabase.from_dict(
352+
{
353+
"id": 1,
354+
"name": "database.zip",
355+
"language": "java",
356+
"uploader": {
357+
"login": "octocat",
358+
"id": 1,
359+
"node_id": "MDQ6VXNlcjE=",
360+
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
361+
"gravatar_id": "",
362+
"url": "https://api.github.com/users/octocat",
363+
"html_url": "https://github.com/octocat",
364+
"followers_url": "https://api.github.com/users/octocat/followers",
365+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
366+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
367+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
368+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
369+
"organizations_url": "https://api.github.com/users/octocat/orgs",
370+
"repos_url": "https://api.github.com/users/octocat/repos",
371+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
372+
"received_events_url": "https://api.github.com/users/octocat/received_events",
373+
"type": "User",
374+
"site_admin": False,
375+
},
376+
"content_type": "application/zip",
377+
"size": 1024,
378+
"created_at": "2022-09-12T12:14:32Z",
379+
"updated_at": "2022-09-12T12:14:32Z",
380+
"url": "https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
381+
"commit_oid": "12345678901234567000",
382+
}
383+
)
384+
385+
self.assertEqual(db.id, 1)
386+
self.assertEqual(db.name, "database.zip")
387+
self.assertEqual(db.language, "java")
388+
self.assertEqual(db.uploader.id, 1)
389+
self.assertEqual(db.content_type, "application/zip")
390+
self.assertEqual(db.size, 1024)
391+
self.assertEqual(
392+
db.created_at,
393+
datetime(2022, 9, 12, 12, 14, 32, tzinfo=timezone.utc),
394+
)
395+
self.assertEqual(
396+
db.updated_at,
397+
datetime(2022, 9, 12, 12, 14, 32, tzinfo=timezone.utc),
398+
)
399+
self.assertEqual(
400+
db.url,
401+
"https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
402+
)
403+
self.assertEqual(db.commit_oid, "12345678901234567000")

0 commit comments

Comments
 (0)