Skip to content

Commit

Permalink
Add: Extend GitHub API for code scanning default setup
Browse files Browse the repository at this point in the history
Implement the code scanning default setup API of GitHub.
  • Loading branch information
bjoernricks committed Oct 19, 2023
1 parent 15b6df4 commit 4607a2e
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 1 deletion.
97 changes: 96 additions & 1 deletion pontos/github/api/code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later

from typing import AsyncIterator, Optional, Union
from typing import AsyncIterator, Iterable, Optional, Union

from pontos.github.api.client import GitHubAsyncREST
from pontos.github.models.base import SortOrder
Expand All @@ -12,8 +12,12 @@
Analysis,
CodeQLDatabase,
CodeScanningAlert,
DefaultSetup,
DefaultSetupState,
DismissedReason,
Instance,
Language,
QuerySuite,
Severity,
)
from pontos.helper import enum_or_value
Expand Down Expand Up @@ -535,3 +539,94 @@ async def codeql_database(
response = await self._client.get(api)
response.raise_for_status()
return CodeQLDatabase.from_dict(response.json())

async def default_setup(
self,
repo: str,
) -> DefaultSetup:
"""
Gets a code scanning default setup configuration
https://docs.github.com/en/rest/code-scanning/code-scanning#get-a-code-scanning-default-setup-configuration
Args:
repo: GitHub repository (owner/name)
Raises:
HTTPStatusError: A httpx.HTTPStatusError is raised if the request
failed.
Returns:
Code scanning default setup
Example:
.. code-block:: python
from pontos.github.api import GitHubAsyncRESTApi
async with GitHubAsyncRESTApi(token) as api:
setup = await api.code_scanning.default_setup(
"org/repo"
)
print(setup)
"""

api = f"/repos/{repo}/code-scanning/default-setup"
response = await self._client.get(api)
response.raise_for_status()
return DefaultSetup.from_dict(response.json())

async def update_default_setup(
self,
repo: str,
state: Union[str, DefaultSetupState],
query_suite: Union[str, QuerySuite],
languages: Iterable[Union[str, Language]],
) -> dict[str, str]:
"""
Updates a code scanning default setup configuration
https://docs.github.com/en/rest/code-scanning/code-scanning#update-a-code-scanning-default-setup-configuration
Args:
repo: GitHub repository (owner/name)
state: Whether code scanning default setup has been configured or
not
query_suite: CodeQL query suite to be used
languages: CodeQL languages to be analyzed
Raises:
HTTPStatusError: A httpx.HTTPStatusError is raised if the request
failed.
Returns:
See the GitHub documentation for the response object
Example:
.. code-block:: python
from pontos.github.api import GitHubAsyncRESTApi
from pontos.github.models.code_scanning import (
DefaultSetupState,
Language,
QuerySuite,
)
async with GitHubAsyncRESTApi(token) as api:
await api.code_scanning.update_default_setup(
"org/repo",
state=DefaultSetupState.CONFIGURED,
query_suite=QuerySuite.EXTENDED,
languages=[Language.PYTHON, Language.JAVASCRIPT]
)
"""

api = f"/repos/{repo}/code-scanning/code-scanning/default-setup"
data = {
"state": enum_or_value(state),
"query_suite": enum_or_value(query_suite),
"languages": [enum_or_value(value) for value in languages],
}
response = await self._client.patch(api, data=data)
response.raise_for_status()
return response.json()
55 changes: 55 additions & 0 deletions pontos/github/models/code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,58 @@ class CodeQLDatabase(GitHubModel):
updated_at: datetime
url: str
commit_oid: Optional[str] = None


class DefaultSetupState(Enum):
"""
State of a default setup
"""

CONFIGURED = "configured"
NOT_CONFIGURED = "not-configured"


class Language(Enum):
"""
Analyzed Language
"""

C_CPP = "c-cpp"
CSHARP = "csharp"
GO = "go"
JAVA_KOTLIN = "java-kotlin"
JAVASCRIPT_TYPESCRIPT = "javascript-typescript"
JAVASCRIPT = "javascript"
PYTHON = "python"
RUBY = "ruby"
TYPESCRIPT = "typescript"
SWIFT = "swift"


class QuerySuite(Enum):
"""
Used code scanning query suite
"""

DEFAULT = "default"
EXTENDED = "extended"


@dataclass
class DefaultSetup(GitHubModel):
"""
Code scanning default setup configuration
Attributes:
state: Code scanning default setup has been configured or not
languages: Languages to be analyzed
query_suite: CodeQL query suite to be used
updated_at: Timestamp of latest configuration update
schedule: The frequency of the periodic analysis
"""

state: DefaultSetupState
languages: list[Language]
query_suite: QuerySuite
updated_at: Optional[datetime] = None
schedule: Optional[str] = None
57 changes: 57 additions & 0 deletions tests/github/api/test_code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
from pontos.github.models.code_scanning import (
AlertSort,
AlertState,
DefaultSetupState,
DismissedReason,
Language,
QuerySuite,
Severity,
)
from tests import AsyncIteratorMock, aiter, anext
Expand Down Expand Up @@ -1194,3 +1197,57 @@ async def test_codeql_database(self):
)

self.assertEqual(alert.id, 1)

async def test_default_setup(self):
response = create_response()
response.json.return_value = {
"state": "configured",
"languages": ["ruby", "python"],
"query_suite": "default",
"updated_at": "2023-01-19T11:21:34Z",
"schedule": "weekly",
}
self.client.get.return_value = response

setup = await self.api.default_setup(
"foo/bar",
)

self.client.get.assert_awaited_once_with(
"/repos/foo/bar/code-scanning/default-setup",
)

self.assertEqual(setup.state, DefaultSetupState.CONFIGURED)

async def test_update_default_setup(self):
response = create_response()
response.json.return_value = {
"run_id": 42,
"run_url": "https://api.github.com/repos/octoorg/octocat/actions/runs/42",
}
self.client.patch.return_value = response

resp = await self.api.update_default_setup(
"foo/bar",
state=DefaultSetupState.CONFIGURED,
query_suite=QuerySuite.EXTENDED,
languages=[Language.GO],
)

self.client.patch.assert_awaited_once_with(
"/repos/foo/bar/code-scanning/code-scanning/default-setup",
data={
"state": "configured",
"query_suite": "extended",
"languages": ["go"],
},
)

self.assertEqual(
resp["run_id"],
42,
)
self.assertEqual(
resp["run_url"],
"https://api.github.com/repos/octoorg/octocat/actions/runs/42",
)
26 changes: 26 additions & 0 deletions tests/github/models/test_code_scanning.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
Analysis,
CodeQLDatabase,
CodeScanningAlert,
DefaultSetup,
DefaultSetupState,
Instance,
Language,
Location,
QuerySuite,
Rule,
Severity,
Tool,
Expand Down Expand Up @@ -401,3 +405,25 @@ def test_from_dict(self):
"https://api.github.com/repos/octocat/Hello-World/code-scanning/codeql/databases/java",
)
self.assertEqual(db.commit_oid, "12345678901234567000")


class DefaultSetupTestCase(unittest.TestCase):
def test_from_dict(self):
setup = DefaultSetup.from_dict(
{
"state": "configured",
"languages": ["ruby", "python"],
"query_suite": "default",
"updated_at": "2023-01-19T11:21:34Z",
"schedule": "weekly",
}
)

self.assertEqual(setup.state, DefaultSetupState.CONFIGURED)
self.assertEqual(setup.languages, [Language.RUBY, Language.PYTHON])
self.assertEqual(setup.query_suite, QuerySuite.DEFAULT)
self.assertEqual(
setup.updated_at,
datetime(2023, 1, 19, 11, 21, 34, tzinfo=timezone.utc),
)
self.assertEqual(setup.schedule, "weekly")

0 comments on commit 4607a2e

Please sign in to comment.