Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated a number of API functionalities in Groups, Reports, Projects, Configurations and more #144

Merged
merged 7 commits into from
Sep 26, 2024
8 changes: 8 additions & 0 deletions CheckmarxPythonSDK/CxOne/Configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import json
from CheckmarxPythonSDK.CxOne.httpRequests import get_request

def get_configurations(project_id):
relative_url = f"/api/configuration/project?project-id={project_id}"

response = get_request(relative_url=relative_url)
return response.json()
21 changes: 19 additions & 2 deletions CheckmarxPythonSDK/CxOne/KeycloakAPI/ClientsAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@


def get_all_oauth_clients(realm):
relative_url = api_url + f"/{realm}/clients??first=0&max=999999&search=True"
relative_url = api_url + f"/{realm}/clients?first=0&max=999999&search=True"
response = get_request(relative_url=relative_url, is_iam=True)
return response


def get_oauth_client_by_name(realm, client_name):
relative_url = api_url + f"/{realm}/clients??first=0&max=999999&search=True"
relative_url = api_url + f"/{realm}/clients?first=0&max=999999&search=True"
response = get_request(relative_url=relative_url, is_iam=True)

for client in response.json():
Expand All @@ -20,6 +20,10 @@ def get_oauth_client_by_name(realm, client_name):

return response

def get_all_oauth_client_by_id(realm, client_id):
relative_url = api_url + f"/{realm}/clients/{client_id}"
response = get_request(relative_url=relative_url, is_iam=True)
return response

def create_oauth_client(realm, client_name):
relative_url = api_url + f"/{realm}/clients"
Expand Down Expand Up @@ -158,3 +162,16 @@ def add_group_to_oauth_client(realm, service_account_user_id, group_id):
response = put_request(relative_url=relative_url, data=put_data, is_iam=True)

return response

def generate_oauth_secret(realm, client_id):
relative_url = api_url + f"/{realm}/clients/{client_id}/client-secret"

post_data = json.dumps(
{
"realm": realm,
"client": client_id
}
)

response = post_request(relative_url=relative_url, data=post_data, is_iam=True)
return response
14 changes: 14 additions & 0 deletions CheckmarxPythonSDK/CxOne/KeycloakAPI/GroupsAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ def create_subgroup(realm, group_id, subgroup_name) -> bool:
result = True
return result

def get_subgroup_by_id(realm, group_id):
"""
Get a subgroup by group id.
Args:
realm (str):
group_id (str):

Returns:
bool
"""
relative_url = f"{api_url}/{realm}/groups/{group_id}/children?max=1000"
response = get_request(relative_url=relative_url)
subgroups = response.json()
return subgroups

def get_group_permissions(realm, group_id) -> ManagementPermissionReference:
"""
Expand Down
8 changes: 8 additions & 0 deletions CheckmarxPythonSDK/CxOne/apisecAPI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import json
from CheckmarxPythonSDK.CxOne.httpRequests import get_request

def get_scan_apisec_risk_overview(scan_id):
relative_url = f"/api/apisec/static/api/scan/{scan_id}/risks-overview"

response = get_request(relative_url=relative_url)
return response.json()
101 changes: 101 additions & 0 deletions CheckmarxPythonSDK/CxOne/projectsAPI.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# encoding: utf-8
import json
from .httpRequests import get_request, post_request, put_request, delete_request
from CheckmarxPythonSDK.utilities.compat import NO_CONTENT
from .utilities import get_url_param, type_check, list_member_type_check
Expand Down Expand Up @@ -309,3 +310,103 @@ def delete_a_project(project_id):
if response.status_code == NO_CONTENT:
is_successful = True
return is_successful

def update_project_group(project_id, groups):
"""

Args:
project_id (str):
groups (`list` of str):

Returns:
bool
"""
relative_url = f"/api/projects/{project_id}"

project = get_request(relative_url=relative_url)
project_data = project.json()
project_data['groups'] = groups

response = put_request(relative_url=relative_url, data=json.dumps(project_data))
return response

def update_primary_branch(project_id, branch_name):
"""

Args:
project_id (str):
branch_name (str): The desired branch name to be the primary branch
Returns:
HTTP 204 No Content
"""
relative_url = f"/api/projects/{project_id}"

project = get_request(relative_url=relative_url)
project_data = project.json()
project_data['mainBranch'] = branch_name

response = put_request(relative_url=relative_url, data=json.dumps(project_data))
return response

def add_project_single_tag(project_id, tag_key, tag_value):
"""

Args:
project_id (str):
tag_key (str):
tag_value (str):
Returns:
HTTP 204 No Content
"""
relative_url = f"/api/projects/{project_id}"

project = get_request(relative_url=relative_url)
project_data = project.json()
if 'tags' not in project_data:
project_data['tags'] = {}
project_data['tags'][tag_key] = tag_value

response = put_request(relative_url=relative_url, data=json.dumps(project_data))
return response

def remove_project_single_tag(project_id, tag_key):
"""

Args:
project_id (str):
tag_key (str):
tag_value (str):
Returns:
HTTP 204 No Content
"""
relative_url = f"/api/projects/{project_id}"

project = get_request(relative_url=relative_url)
project_data = project.json()
if 'tags' in project_data:
project_data['tags'].pop(tag_key)

response = put_request(relative_url=relative_url, data=json.dumps(project_data))
return response

def update_project_single_tag(project_id, tag_key, tag_value):
"""

Args:
project_id (str):
tag_key (str):
tag_value (str):
Returns:
HTTP 204 No Content
"""
relative_url = f"/api/projects/{project_id}"

project = get_request(relative_url=relative_url)
project_data = project.json()
if 'tags' in project_data:
project_data['tags'][tag_key] = tag_value

# Update the project with the new tags
response = put_request(relative_url=relative_url, data=json.dumps(project_data))
return response

103 changes: 97 additions & 6 deletions CheckmarxPythonSDK/CxOne/reportAPI.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,60 @@
import json
import requests
import time
import os
from CheckmarxPythonSDK.CxOne.httpRequests import get_request, post_request
from CheckmarxPythonSDK.utilities.httpRequests import auth_header
from CheckmarxPythonSDK.CxOne.config import config

api_url = "/api/reports"

def create_scan_report_v2(file_format, scan_engines, scan_id):
report_url = f"{api_url}/v2"

post_data = json.dumps({
"fileFormat": file_format,
"reportType": "ui",
"reportName": "improved-scan-report",
"reportFilename": "",
"sections":[
"scan-information",
"results-overview",
"scan-results",
"categories",
"resolved-results",
"vulnerability-details"
],
"entities":[
{
"entity":"scan",
"ids":[scan_id],
"tags":[]
}
],
"filters":{
"scanners":scan_engines,
"severities":["high","medium","low","information"],
"states":["to-verify","confirmed","urgent","not-exploitable","proposed-not-exploitable"],
"status":["new","recurrent"]
},
"reportType":"ui",
"emails":[]
})

response = post_request(relative_url=report_url, data=post_data)
report_json = response.json()
report_id = report_json.get("reportId")

report_status_url = f"/api/reports/{report_id}?returnUrl=true"
while True:
response = get_request(relative_url=report_status_url)
status_json = response.json()
status = status_json.get("status")

if status == "completed":
print("Report has been generated successfully!")
break
else:
print("Generating report, please wait...")
time.sleep(2)
return report_id


def create_scan_report(file_format, scan_id, project_id):
report_url = api_url
Expand Down Expand Up @@ -58,11 +105,55 @@ def get_scan_report(report_id):
relative_url = api_url + f"/{report_id}/download"

response = get_request(relative_url=relative_url)
return response.content
response_json = json.loads(response.content)
return response_json


def get_risk_scan_report(scan_id, report_type):
relative_url = f"/api/sca/risk-management/risk-reports/{scan_id}/export?format={report_type}"

response = get_request(relative_url=relative_url)
return response.content
response_json = json.loads(response.content)
return response_json

def create_sca_scan_report(scan_id):
report_url = f"/api/sca/export/requests"

data = json.dumps({
"ScanId": scan_id,
"FileFormat": "ScanReportJson",
"ExportParameters": {
"hideDevAndTestDependencies": False,
"showOnlyEffectiveLicenses": False,
"excludePackages": False,
"excludeLicenses": True,
"excludeVulnerabilities": False,
"excludePolicies": True
}
})

response = post_request(relative_url=report_url, data=(data))
response_json = response.json()
export_id = response_json['exportId']
return export_id

def get_sca_scan_report(export_id):
report_status_url = f"/api/sca/export/requests?exportId={export_id}"
while True:
response = get_request(relative_url=report_status_url)
status_json = response.json()
status = status_json.get("exportStatus")

if status == "Completed":
report_download_url = f"/api/sca/export/requests/{export_id}/download"
response = get_request(relative_url=report_download_url)
print("Report has been generated successfully!")
break
if status == "Failed":
print(f"Error: {response.content}")
break
else:
print("Generating report, please wait...")
time.sleep(2)

return response.json()
72 changes: 72 additions & 0 deletions CheckmarxPythonSDK/CxOne/scansAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,75 @@ def get_a_detailed_workflow_of_a_scan(scan_id):
info=item.get("Info"),
) for item in items or []
]

def sca_recalculate(project_id, branch):
"""

Args:
project_id (str):
branch (str):

Returns:
HTTP 201 Created
"""
relative_url = f"/api/scans/recalculate"

scan_data = json.dumps({
"project_id": f"{project_id}",
"branch": f"{branch}",
"engines":["sca"],
"config":[{"type":"sca","value":{"enableContainersScan":True}}]
})

response = post_request(relative_url=relative_url, data=(scan_data))
return response

def scan_by_repo_url(project_id, repo_url, branch, engines, tag):
"""

Args:
project_id (str):
repo_url (str):
branch (str):
engines (`list` of str): ["sast","sca", "kics", "apisec"]
tag (json): {"test-all": ""}

Returns:
HTTP 201 Created
"""

relative_url = f"/api/scans"

scan_data = {
"type": "git",
"handler": {
"repoUrl": repo_url,
"branch": branch,
# "skipSubModules": False
},
"project": {
"id": project_id,
"tags": {}
},
"config": [],
"tags": tag
}

engine_configs = {
"sast": {"incremental": "false"},
"sca": {},
"kics": {},
"apisec": {}
}

for engine in engines:
if engine in engine_configs:
scan_data["config"].append({
"type": engine,
"value": engine_configs[engine]
})
else:
print(f"Warning: Engine '{engine}' is not supported and will be ignored.")

response = post_request(relative_url=relative_url, data=json.dumps((scan_data)))
return response