commit d80689c7dee7996c3232b2d09bd4e9ec9e2657b6 Author: Wolfgang Hottgenroth Date: Tue Apr 1 17:59:34 2025 +0200 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39af63c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +ENV +defs/ +*/.venv/ +__pycache__/ + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..34d3895 --- /dev/null +++ b/readme.md @@ -0,0 +1,95 @@ +# Python Client Packages for the DependencyTrack and DefectDojo API + +## Download the OpenAPI definitions + +``` +curl https://dtrack-api.hottis.de/api/openapi.json \ + > dependencytrack-openapi.json +curl https://defectdojo.hottis.de/api/v2/oa3/schema/?format=json \ + > defectdojo-openapi.json +``` + + +## Naive Generation of the Client Package for DefectDojo + +``` +docker run \ + -it \ + --rm \ + -v $PWD:/work \ + -u $UID \ + openapitools/openapi-generator-cli:v7.12.0 \ + generate \ + -i /work/defectdojo-openapi.json \ + -g python \ + -o /work/defectdojo-client \ + --package-name defectdojo_api +``` + +## Naive Generation of the Client Package for DependencyTrack + +``` +docker run \ + -it \ + --rm \ + -v $PWD:/work \ + -u $UID openapitools/openapi-generator-cli:v7.12.0 \ + generate \ + -i /work/dependencytrack-openapi.json \ + -g python \ + -o /work/dependencytrack-client \ + --package-name dependencytrack_api +``` + +## Fixed Generation of the Client Package for DependencyTrack + +In the OpenAPI definition of DependencyTrack a regex is used which is not understood by Python's +default regex implement `re`, which in turn is hardwired in the openapi-generator provided code. +So, it is necessary to adjust the template for code generation to use the extended regex module +`regex` instead of the default one. + +For this purpose, the template must be exported: + +``` +docker run \ + --rm \ + -v $PWD:/work \ + openapitools/openapi-generator-cli:v7.12.0 \ + author \ + template \ + -g python \ + -o /work/dependencytrack-custom-templates +``` + +Now within `dependencytrack-custom-templates` the both files `model_anyof.mustache` and `model_generic.mustache` must be fixed. +Replace + +``` +import re +``` + +at the tops of the files by + +``` +import regex as re +``` + +Now run the generator using the adjusted template: + +``` +docker run \ + -it \ + --rm \ + -v $PWD:/work \ + -u $UID \ + openapitools/openapi-generator-cli:v7.12.0 \ + generate \ + -i /work/dependencytrack-openapi.json \ + -g python \ + -o /work/dependencytrack-client \ + --package-name dependencytrack_api \ + -t /work/dependencytrack-custom-templates +``` + +Make sure to install the module `regex` in the environment the client shall run in. + diff --git a/snippets/requirements.txt b/snippets/requirements.txt new file mode 100644 index 0000000..b65648b --- /dev/null +++ b/snippets/requirements.txt @@ -0,0 +1 @@ +regex==2024.11.6 diff --git a/snippets/test01.py b/snippets/test01.py new file mode 100644 index 0000000..5bf34e2 --- /dev/null +++ b/snippets/test01.py @@ -0,0 +1,27 @@ +import os +import defectdojo_api +from defectdojo_api.rest import ApiException +from pprint import pprint + +configuration = defectdojo_api.Configuration( + host = os.environ["DEFECTDOJO_URL"] +) + +configuration.api_key['tokenAuth'] = os.environ["DEFECTDOJO_TOKEN"] +configuration.api_key_prefix['tokenAuth'] = 'Token' + +with defectdojo_api.ApiClient(configuration) as api_client: + api_instance = defectdojo_api.AnnouncementsApi(api_client) + announcement_request = defectdojo_api.AnnouncementRequest( + message='Hallo' + ) + + try: + api_response = api_instance.announcements_create(announcement_request=announcement_request) + print(f"{api_response=}") + except ApiException as e: + print(f"{e=}, {str(e)}") + + + + diff --git a/snippets/test02.py b/snippets/test02.py new file mode 100644 index 0000000..a0cfa4b --- /dev/null +++ b/snippets/test02.py @@ -0,0 +1,126 @@ +import os + +import defectdojo_api +from defectdojo_api.rest import ApiException as DefectDojoApiException +import datetime +from dateutil.relativedelta import relativedelta + +import dependencytrack_api +from dependencytrack_api.rest import ApiException as DependencyTrackApiException + +try: + DTRACK_API_URL = os.environ["DTRACK_API_URL"] + DTRACK_TOKEN = os.environ["DTRACK_TOKEN"] + DEFECTDOJO_URL = os.environ["DEFECTDOJO_URL"] + DEFECTDOJO_TOKEN = os.environ["DEFECTDOJO_TOKEN"] +except KeyError as e: + raise Exception(f"Env variable {e} is shall be set") + + + +defectdojo_configuration = defectdojo_api.Configuration( + host = DEFECTDOJO_URL +) +defectdojo_configuration.api_key['tokenAuth'] = DEFECTDOJO_TOKEN +defectdojo_configuration.api_key_prefix['tokenAuth'] = 'Token' + +dependencytrack_configuration = dependencytrack_api.Configuration( + host = f"{DTRACK_API_URL}/api" +) +dependencytrack_configuration.debug = False +dependencytrack_configuration.api_key['ApiKeyAuth'] = DTRACK_TOKEN + +with defectdojo_api.ApiClient(defectdojo_configuration) as defectdojo_api_client: + try: + print("Create product in DefectDojo") + products_api_instance = defectdojo_api.ProductsApi(defectdojo_api_client) + product_request = defectdojo_api.ProductRequest( + name="Test Product", + description="Just a product for test the API", + prod_type=1 + ) + product_response = products_api_instance.products_create(product_request=product_request) + print(f"{product_response=}") + print("Done.") + print("") + + product_id = product_response.id + print(f"{product_id=}") + + print("Create engagement in DefectDojo") + engagements_api_instance = defectdojo_api.EngagementsApi(defectdojo_api_client) + start_time = datetime.date.today() + end_time = start_time + relativedelta(years=10) + engagement_request = defectdojo_api.EngagementRequest( + name="Test Engagement 01", + target_start=start_time, + target_end=end_time, + status="In Progress", + product=product_id + ) + engagement_response = engagements_api_instance.engagements_create(engagement_request=engagement_request) + print(f"{engagement_response=}") + print("Done.") + print("") + + engagement_id = engagement_response.id + print(f"{engagement_id=}") + except DefectDojoApiException as e: + print(f"DefectDojoApiException: {e=}, {str(e)}") + +with dependencytrack_api.ApiClient(dependencytrack_configuration) as dependencytrack_api_client: + try: + print("Create project in DependencyTrack") + project_api_instance = dependencytrack_api.ProjectApi(dependencytrack_api_client) + project = dependencytrack_api.Project( + name="TestProject", + uuid="", + last_bom_import=0 + ) + project_response = project_api_instance.create_project(project=project) + print(f"{project_response=}") + print("Done.") + print("") + + project_uuid = project_response.uuid + print(f"{project_uuid=}") + + print("Create project property in DependencyTrack") + project_property_api_instance = dependencytrack_api.ProjectPropertyApi(dependencytrack_api_client) + property = dependencytrack_api.ProjectProperty( + group_name="integrations", + property_name="defectdojo.engagementId", + property_value=str(engagement_id), + property_type="STRING" + ) + property_response = project_property_api_instance.create_property1(project_uuid, project_property=property) + print(f"{property_response=}") + print("Done.") + print("") + + print("Create project property in DependencyTrack") + property = dependencytrack_api.ProjectProperty( + group_name="integrations", + property_name="defectdojo.doNotReactivate", + property_value="true", + property_type="BOOLEAN" + ) + property_response = project_property_api_instance.create_property1(project_uuid, project_property=property) + print(f"{property_response=}") + print("Done.") + print("") + + print("Create project property in DependencyTrack") + property = dependencytrack_api.ProjectProperty( + group_name="integrations", + property_name="defectdojo.reimport", + property_value="true", + property_type="BOOLEAN" + ) + property_response = project_property_api_instance.create_property1(project_uuid, project_property=property) + print(f"{property_response=}") + print("Done.") + print("") + except DependencyTrackApiException as e: + print(f"DependencyTrackApiException: {e=}, {str(e)}") +