diff --git a/codeinsight_sdk/exceptions.py b/codeinsight_sdk/exceptions.py index 334cc19..455127d 100644 --- a/codeinsight_sdk/exceptions.py +++ b/codeinsight_sdk/exceptions.py @@ -1,24 +1,29 @@ - import requests import json -class GenericError(Exception): #pragma: no cover + +class GenericError(Exception): # pragma: no cover """Generic error class, catch-all for most code insight API errors.""" + pass -class NotYetImplementedError(Exception): #pragma: no cover + +class NotYetImplementedError(Exception): # pragma: no cover """Error class for API features that have not yet been implemented.""" + pass + class CodeInsightError(GenericError): """Error class for code insight API errors.""" + def __init__(self, response: requests.Response): try: resp = response.json() self.code = response.status_code - self.message = resp['Error: '] - self.arguments = resp['Arguments: '] - self.error = resp['Key: '] + self.message = resp["Error: "] + self.arguments = resp["Arguments: "] + self.error = resp["Key: "] self.add_note(f"Arguments: {self.arguments}") super().__init__("Error: %s - %s" % (self.code, self.message)) diff --git a/codeinsight_sdk/handler.py b/codeinsight_sdk/handler.py index 302ebff..62b2eb4 100644 --- a/codeinsight_sdk/handler.py +++ b/codeinsight_sdk/handler.py @@ -2,6 +2,7 @@ from typing import List + class Handler(abc.ABC): def __init__(self, client): self.client = client diff --git a/codeinsight_sdk/handlers/__init__.py b/codeinsight_sdk/handlers/__init__.py index e549db5..346c530 100644 --- a/codeinsight_sdk/handlers/__init__.py +++ b/codeinsight_sdk/handlers/__init__.py @@ -1,3 +1,3 @@ from .inventory import InventoryHandler from .project import ProjectHandler -from .report import ReportHandler \ No newline at end of file +from .report import ReportHandler diff --git a/codeinsight_sdk/handlers/report.py b/codeinsight_sdk/handlers/report.py index bb382ca..3da0b4b 100644 --- a/codeinsight_sdk/handlers/report.py +++ b/codeinsight_sdk/handlers/report.py @@ -22,7 +22,7 @@ def __init__(self, client): super().__init__(client) self.cls = Report - def get(self, id:int): + def get(self, id: int): """ Retrieves a report by its ID. @@ -35,7 +35,7 @@ def get(self, id:int): """ path = f"reports/{id}" resp = self.client.request("GET", url_part=path) - report_data = resp.json()['data'] + report_data = resp.json()["data"] report = self.cls.from_dict(report_data) return report @@ -50,6 +50,6 @@ def all(self): path = "reports" resp = self.client.request("GET", url_part=path) reports = [] - for report_data in resp.json()['data']: + for report_data in resp.json()["data"]: reports.append(self.cls.from_dict(report_data)) return reports diff --git a/codeinsight_sdk/models.py b/codeinsight_sdk/models.py index 81adf43..026013c 100644 --- a/codeinsight_sdk/models.py +++ b/codeinsight_sdk/models.py @@ -5,6 +5,7 @@ from dataclasses_json import DataClassJsonMixin, dataclass_json from typing import Any, Optional, List, Dict + @dataclass class Project(DataClassJsonMixin): id: int @@ -26,6 +27,7 @@ class Vulnerability(DataClassJsonMixin): vulnerabilityCvssV3Score: int vulnerabilityCvssV3Severity: str + @dataclass class ProjectInventoryItem(DataClassJsonMixin): itemNumber: int @@ -45,12 +47,14 @@ class ProjectInventoryItem(DataClassJsonMixin): vulnerabilitySummary: Optional[List[Dict[str, Dict]]] = None filePaths: Optional[List[str]] = None -@dataclass_json #Trying this style instead of DataClassJsonMixin + +@dataclass_json # Trying this style instead of DataClassJsonMixin @dataclass -class ProjectInventory(): +class ProjectInventory: projectId: int inventoryItems: List[ProjectInventoryItem] + @dataclass class Report(DataClassJsonMixin): id: int @@ -61,4 +65,4 @@ class Report(DataClassJsonMixin): enableProjectPicker: bool order: int createdDateTime: str - updatedDateTime: str \ No newline at end of file + updatedDateTime: str diff --git a/examples/example-1-list-projects.py b/examples/example-1-list-projects.py index f02f11d..220b35d 100644 --- a/examples/example-1-list-projects.py +++ b/examples/example-1-list-projects.py @@ -8,4 +8,3 @@ print(client.projects.all()) - diff --git a/examples/example-9-dataframe.py b/examples/example-9-dataframe.py index 6ef25f8..c3ee1c8 100644 --- a/examples/example-9-dataframe.py +++ b/examples/example-9-dataframe.py @@ -8,4 +8,4 @@ inventory = client.project_inventory.get(1) -df = pd.DataFrame(inventory.__dict__['inventoryItems']) \ No newline at end of file +df = pd.DataFrame(inventory.__dict__["inventoryItems"]) diff --git a/examples/shared.py b/examples/shared.py index b5a3277..da598ef 100644 --- a/examples/shared.py +++ b/examples/shared.py @@ -1,3 +1,2 @@ - -BASE_URL = 'https://api.revenera.com' -AUTH_TOKEN = 'test' \ No newline at end of file +BASE_URL = "https://api.revenera.com" +AUTH_TOKEN = "test" diff --git a/tests/test_client.py b/tests/test_client.py index afe4e8e..e957268 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -13,14 +13,15 @@ TEST_URL = "https://api.revenera.com" TEST_API_TOKEN = "your_api_token" + class TestCodeInsightClient: @pytest.fixture def client(self): return CodeInsightClient(TEST_URL, TEST_API_TOKEN) - + def test_client(self, client): assert client.base_url == TEST_URL - + def test_client_expertimental_disabled(self, client): assert client.experimental_enabled == False @@ -30,44 +31,54 @@ def test_endpoint_not_found(self, client): with pytest.raises(Exception): client.projects.all() + class TestProjectEndpoints: @pytest.fixture def client(self): return CodeInsightClient(TEST_URL, TEST_API_TOKEN) - + def test_create_project(self, client): project_name = "Test" with requests_mock.Mocker() as m: m.post(f"{TEST_URL}/codeinsight/api/projects", text='{"data": {"id":1}}') project_id = client.projects.create(project_name) assert project_id == 1 - + def test_get_all_projects(self, client): with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/projects", text='{"data": [{"id":1, "name":"Test"}, {"id":2, "name":"Test 2"}]}') + m.get( + f"{TEST_URL}/codeinsight/api/projects", + text='{"data": [{"id":1, "name":"Test"}, {"id":2, "name":"Test 2"}]}', + ) projects = client.projects.all() assert len(projects) > 0 def test_get_project_id(self, client): project_name = "Test" with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/project/id", text='{ "Content: ": 1 }') # Yes, the key is called 'Content: ' ... + m.get( + f"{TEST_URL}/codeinsight/api/project/id", text='{ "Content: ": 1 }' + ) # Yes, the key is called 'Content: ' ... project_id = client.projects.get_id(project_name) assert project_id == 1 - def test_get_project_id_invalid(self,client): + def test_get_project_id_invalid(self, client): project_name = "Invalid_Project" fake_response_json = """{ "Arguments: " : ["",""], "Key: ": " InvalidProjectNameParm", "Error: ": "The project name entered was not found" } """ with requests_mock.Mocker() as m: - # Note, the key names end with a colon and space '...: ' - m.get(f"{TEST_URL}/codeinsight/api/project/id", text=fake_response_json, status_code=400) + # Note, the key names end with a colon and space '...: ' + m.get( + f"{TEST_URL}/codeinsight/api/project/id", + text=fake_response_json, + status_code=400, + ) with pytest.raises(CodeInsightError): client.projects.get_id(project_name) - - def test_get_project(self,client): + + def test_get_project(self, client): project_id = 1 fake_response_json = """ { "data": { "id": 1, @@ -96,7 +107,10 @@ def test_get_project(self,client): }} """ with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/projects/{project_id}", text=fake_response_json) + m.get( + f"{TEST_URL}/codeinsight/api/projects/{project_id}", + text=fake_response_json, + ) project = client.projects.get(project_id) assert project.id == 1 assert project.name == "Test" @@ -105,7 +119,7 @@ def test_get_project(self,client): assert project.vulnerabilities["CvssV2"]["High"] == 2 assert project.vulnerabilities["CvssV2"]["Unknown"] == 4 - def test_get_project_inventory_multipage(self,client): + def test_get_project_inventory_multipage(self, client): project_id = 1 total_pages = 4 total_records = total_pages * 2 @@ -121,23 +135,32 @@ def test_get_project_inventory_multipage(self,client): ]} """ with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/project/inventory/{project_id}", - text=fake_response_json, headers=response_header) + m.get( + f"{TEST_URL}/codeinsight/api/project/inventory/{project_id}", + text=fake_response_json, + headers=response_header, + ) project_inventory = client.projects.get_inventory(project_id) assert project_inventory.projectId == project_id assert len(project_inventory.inventoryItems) == total_records - assert project_inventory.inventoryItems[0].vulnerabilities[0].vulnerabilityName == "CVE-2020-1234" - - def test_upload_codebase(self,client): + assert ( + project_inventory.inventoryItems[0].vulnerabilities[0].vulnerabilityName + == "CVE-2020-1234" + ) + + def test_upload_codebase(self, client): project_id = 1 codebase_path = "tests/resources/test_codebase.zip" with requests_mock.Mocker() as m: - m.post(f"{TEST_URL}/codeinsight/api/project/uploadProjectCodebase", text='{"data": {"id":1}}') + m.post( + f"{TEST_URL}/codeinsight/api/project/uploadProjectCodebase", + text='{"data": {"id":1}}', + ) resp = client.projects.upload_codebase(project_id, codebase_path) assert resp == 200 #### FIX THIS! #### - def test_get_project_inventory_summary(self,client): + def test_get_project_inventory_summary(self, client): project_id = 1 total_pages = 4 total_records = total_pages * 2 @@ -174,9 +197,14 @@ def test_get_project_inventory_summary(self,client): } """ with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/projects/{project_id}/inventorySummary", - text=fake_response_json, headers=response_header) - project_inventory_summary = client.projects.get_inventory_summary(project_id) + m.get( + f"{TEST_URL}/codeinsight/api/projects/{project_id}/inventorySummary", + text=fake_response_json, + headers=response_header, + ) + project_inventory_summary = client.projects.get_inventory_summary( + project_id + ) assert len(project_inventory_summary) == 8 assert project_inventory_summary[1].id == 12346 @@ -186,8 +214,8 @@ class TestReportsEndpoints: @pytest.fixture def client(self): return CodeInsightClient(TEST_URL, TEST_API_TOKEN) - - def test_get_reports_all(self,client): + + def test_get_reports_all(self, client): fake_response_json = """ { "data": [ { "id": 1, @@ -216,14 +244,13 @@ def test_get_reports_all(self,client): } """ with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/reports", - text=fake_response_json) + m.get(f"{TEST_URL}/codeinsight/api/reports", text=fake_response_json) reports = client.reports.all() assert len(reports) == 2 assert reports[1].id == 2 assert reports[1].enabled == False - def test_get_report(self,client): + def test_get_report(self, client): report_id = 1 fake_response_json = """ { "data": { @@ -240,8 +267,10 @@ def test_get_report(self,client): } """ with requests_mock.Mocker() as m: - m.get(f"{TEST_URL}/codeinsight/api/reports/{report_id}", - text=fake_response_json) + m.get( + f"{TEST_URL}/codeinsight/api/reports/{report_id}", + text=fake_response_json, + ) report = client.reports.get(1) assert report.id == 1 - assert report.enabled == True \ No newline at end of file + assert report.enabled == True diff --git a/tests/test_models.py b/tests/test_models.py index 1f94387..29e7763 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -2,29 +2,33 @@ from codeinsight_sdk.models import Project, Report + class TestProject(object): @pytest.fixture def project(self): return Project(id=1, name="Test") - + def test_project(self, project): assert project.id == 1 assert project.name == "Test" assert isinstance(project, Project) - + + class TestReport(object): @pytest.fixture def report(self): - return Report(id=1, - name="Test", - path="path/to/report", - default=True, - enabled=True, - enableProjectPicker=True, - order=1, - createdDateTime="Today", - updatedDateTime="Tomorrow") - + return Report( + id=1, + name="Test", + path="path/to/report", + default=True, + enabled=True, + enableProjectPicker=True, + order=1, + createdDateTime="Today", + updatedDateTime="Tomorrow", + ) + def test_report(self, report): assert report.id == 1 assert report.enabled == True diff --git a/tests/test_not_implemented.py b/tests/test_not_implemented.py index b00177c..33960a5 100644 --- a/tests/test_not_implemented.py +++ b/tests/test_not_implemented.py @@ -2,21 +2,21 @@ from codeinsight_sdk import CodeInsightClient -class TestNotImplemented(object): +class TestNotImplemented(object): @pytest.fixture def client(self): - return CodeInsightClient("","") + return CodeInsightClient("", "") - ## Coming soon features ## + ## Coming soon features ## def test_vulnerabilities(self, client): with pytest.raises(NotImplementedError): client.vulnerabilites() - + def test_users(self, client): with pytest.raises(NotImplementedError): client.users() - + def test_licenses(self, client): with pytest.raises(NotImplementedError): client.licenses() @@ -35,4 +35,4 @@ def test_files(self, client): def test_folders(self, client): with pytest.raises(NotImplementedError): - client.folders() \ No newline at end of file + client.folders()