devsecops-engine-tools 1.33.0__py3-none-any.whl → 1.34.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of devsecops-engine-tools might be problematic. Click here for more details.
- devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py +5 -20
- devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/__init__.py +0 -0
- devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/client/__init__.py +0 -0
- devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/client/auth_client.py +12 -0
- devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/jwt/__init__.py +0 -0
- devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/jwt/jwt_object.py +64 -0
- devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/jwt/jwt_tool.py +153 -0
- devsecops_engine_tools/engine_utilities/sonarqube/src/domain/model/gateways/sonar_gateway.py +4 -2
- devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py +8 -4
- devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/driven_adapters/sonarqube/sonarqube_report.py +37 -30
- devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/entry_points/entry_point_report_sonar.py +12 -3
- devsecops_engine_tools/engine_utilities/utils/utils.py +14 -0
- devsecops_engine_tools/version.py +1 -1
- {devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/METADATA +1 -1
- {devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/RECORD +18 -12
- {devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/WHEEL +0 -0
- {devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/entry_points.txt +0 -0
- {devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/top_level.txt +0 -0
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py
CHANGED
|
@@ -18,6 +18,7 @@ from devsecops_engine_tools.engine_utilities.defect_dojo import (
|
|
|
18
18
|
from devsecops_engine_tools.engine_core.src.domain.model.exclusions import Exclusions
|
|
19
19
|
from devsecops_engine_tools.engine_core.src.domain.model.report import Report
|
|
20
20
|
from devsecops_engine_tools.engine_utilities.utils.session_manager import SessionManager
|
|
21
|
+
from devsecops_engine_tools.engine_utilities.utils.utils import Utils
|
|
21
22
|
from devsecops_engine_tools.engine_core.src.domain.model.customs_exceptions import (
|
|
22
23
|
ExceptionVulnerabilityManagement,
|
|
23
24
|
ExceptionFindingsExcepted,
|
|
@@ -28,13 +29,11 @@ from devsecops_engine_tools.engine_core.src.infrastructure.helpers.util import (
|
|
|
28
29
|
format_date,
|
|
29
30
|
)
|
|
30
31
|
from functools import partial
|
|
31
|
-
|
|
32
32
|
from devsecops_engine_tools.engine_utilities.utils.logger_info import MyLogger
|
|
33
33
|
from devsecops_engine_tools.engine_utilities import settings
|
|
34
34
|
from devsecops_engine_tools.engine_utilities.defect_dojo.domain.serializers.import_scan import (
|
|
35
35
|
ImportScanSerializer,
|
|
36
36
|
)
|
|
37
|
-
import time
|
|
38
37
|
import concurrent.futures
|
|
39
38
|
|
|
40
39
|
logger = MyLogger.__call__(**settings.SETTING_LOGGER).get_logger()
|
|
@@ -113,7 +112,7 @@ class DefectDojoPlatform(VulnerabilityManagementGateway):
|
|
|
113
112
|
def request_func():
|
|
114
113
|
return DefectDojo.send_import_scan(request)
|
|
115
114
|
|
|
116
|
-
response =
|
|
115
|
+
response = Utils().retries_requests(
|
|
117
116
|
request_func,
|
|
118
117
|
vulnerability_management.config_tool["VULNERABILITY_MANAGER"][
|
|
119
118
|
"DEFECT_DOJO"
|
|
@@ -166,7 +165,7 @@ class DefectDojoPlatform(VulnerabilityManagementGateway):
|
|
|
166
165
|
else None
|
|
167
166
|
)
|
|
168
167
|
|
|
169
|
-
return
|
|
168
|
+
return Utils().retries_requests(request_func, dd_max_retries, retry_delay=5)
|
|
170
169
|
|
|
171
170
|
except Exception as ex:
|
|
172
171
|
raise ExceptionVulnerabilityManagement(
|
|
@@ -555,7 +554,7 @@ class DefectDojoPlatform(VulnerabilityManagementGateway):
|
|
|
555
554
|
session=session_manager, service=service, **query_params
|
|
556
555
|
).results
|
|
557
556
|
|
|
558
|
-
return
|
|
557
|
+
return Utils().retries_requests(request_func, max_retries, retry_delay=5)
|
|
559
558
|
|
|
560
559
|
def _get_finding_exclusion(self, session_manager, max_retries, query_params):
|
|
561
560
|
def request_func():
|
|
@@ -563,21 +562,7 @@ class DefectDojoPlatform(VulnerabilityManagementGateway):
|
|
|
563
562
|
session=session_manager, **query_params
|
|
564
563
|
).results
|
|
565
564
|
|
|
566
|
-
return
|
|
567
|
-
|
|
568
|
-
def _retries_requests(self, request_func, max_retries, retry_delay):
|
|
569
|
-
for attempt in range(max_retries):
|
|
570
|
-
try:
|
|
571
|
-
return request_func()
|
|
572
|
-
except Exception as e:
|
|
573
|
-
logger.error(f"Error making the request: {e}")
|
|
574
|
-
if attempt < max_retries - 1:
|
|
575
|
-
logger.warning(f"Retry in {retry_delay} seconds...")
|
|
576
|
-
time.sleep(retry_delay)
|
|
577
|
-
else:
|
|
578
|
-
logger.error("Maximum number of retries reached, aborting.")
|
|
579
|
-
raise e
|
|
580
|
-
|
|
565
|
+
return Utils().retries_requests(request_func, max_retries, retry_delay=5)
|
|
581
566
|
|
|
582
567
|
def _date_reason_based(self, finding, date_fn, reason, tool, **kwargs):
|
|
583
568
|
def get_vuln_id(finding, tool):
|
|
File without changes
|
|
File without changes
|
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/client/auth_client.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from devsecops_engine_tools.engine_dast.src.domain.model.gateways.authentication_gateway import (
|
|
2
|
+
AuthenticationGateway,
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AuthClientCredential(AuthenticationGateway):
|
|
7
|
+
def __init__(self, security_auth: dict):
|
|
8
|
+
self.client_id: str = security_auth.get("client_id")
|
|
9
|
+
self.client_secrets: str = security_auth.get("client_secret")
|
|
10
|
+
|
|
11
|
+
def get_credentials(self):
|
|
12
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from time import (
|
|
2
|
+
time
|
|
3
|
+
)
|
|
4
|
+
from secrets import (
|
|
5
|
+
token_hex
|
|
6
|
+
)
|
|
7
|
+
from authlib.jose import (
|
|
8
|
+
jwt
|
|
9
|
+
)
|
|
10
|
+
from devsecops_engine_tools.engine_dast.src.domain.model.gateways.authentication_gateway import (
|
|
11
|
+
AuthenticationGateway,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class JwtObject(AuthenticationGateway):
|
|
16
|
+
def __init__(self, security_auth: dict):
|
|
17
|
+
self.type = "jwt"
|
|
18
|
+
self.private_key: str = security_auth.get("jwt_private_key")
|
|
19
|
+
self.algorithm: str = security_auth.get("jwt_algorithm")
|
|
20
|
+
self.iss: str = security_auth.get("jwt_iss")
|
|
21
|
+
self.sum: str = security_auth.get("jwt_sum")
|
|
22
|
+
self.aud: str = security_auth.get("jwt_aud")
|
|
23
|
+
self.iat: float = time()
|
|
24
|
+
self.exp: float = self.iat + 60 * 60
|
|
25
|
+
self.nonce = token_hex(10)
|
|
26
|
+
self.payload: dict = {}
|
|
27
|
+
self.header: dict = {}
|
|
28
|
+
self.jwt_token: str = ""
|
|
29
|
+
self.header_name: str = security_auth.get("jwt_header_name")
|
|
30
|
+
self.init_header()
|
|
31
|
+
self.init_payload()
|
|
32
|
+
|
|
33
|
+
def init_header(self) -> None:
|
|
34
|
+
self.header: dict = {"alg": self.algorithm}
|
|
35
|
+
|
|
36
|
+
def init_payload(self) -> dict:
|
|
37
|
+
self.payload: dict = {
|
|
38
|
+
"iss": self.iss,
|
|
39
|
+
"sum": self.sum,
|
|
40
|
+
"aud": self.aud,
|
|
41
|
+
"exp": self.exp,
|
|
42
|
+
"iat": self.iat,
|
|
43
|
+
"nonce": self.nonce,
|
|
44
|
+
}
|
|
45
|
+
return self.payload
|
|
46
|
+
|
|
47
|
+
def get_credentials(self) -> tuple:
|
|
48
|
+
"""
|
|
49
|
+
Generates JWT using a file with the configuration
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
|
|
53
|
+
tuple: header and jwt
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
self.private_key = (
|
|
57
|
+
self.private_key.replace(" ", "\n")
|
|
58
|
+
.replace("-----BEGIN\nPRIVATE\nKEY-----", "-----BEGIN PRIVATE KEY-----")
|
|
59
|
+
.replace("-----END\nPRIVATE\nKEY-----", "-----END PRIVATE KEY-----")
|
|
60
|
+
)
|
|
61
|
+
self.jwt_token = jwt.encode(self.header, self.payload, self.private_key).decode(
|
|
62
|
+
"utf-8"
|
|
63
|
+
)
|
|
64
|
+
return self.header_name, self.jwt_token
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
List
|
|
3
|
+
)
|
|
4
|
+
from datetime import (
|
|
5
|
+
datetime,
|
|
6
|
+
)
|
|
7
|
+
import jwt
|
|
8
|
+
from devsecops_engine_tools.engine_core.src.domain.model.finding import (
|
|
9
|
+
Category,
|
|
10
|
+
Finding,
|
|
11
|
+
)
|
|
12
|
+
from devsecops_engine_tools.engine_dast.src.domain.model.gateways.tool_gateway import (
|
|
13
|
+
ToolGateway,
|
|
14
|
+
)
|
|
15
|
+
from devsecops_engine_tools.engine_dast.src.domain.model.api_operation import (
|
|
16
|
+
ApiOperation
|
|
17
|
+
)
|
|
18
|
+
from devsecops_engine_tools.engine_dast.src.infrastructure.helpers.file_generator_tool import (
|
|
19
|
+
generate_file_from_tool,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class JwtTool(ToolGateway):
|
|
23
|
+
|
|
24
|
+
def __init__(self, target_config):
|
|
25
|
+
self.TOOL = "JWT"
|
|
26
|
+
self.BAD_JWT_ALG = ["none", "ES256", "ES384", "ES512"]
|
|
27
|
+
self.BAD_JWS_ALG = ["none", "ES256", "ES384", "ES512"]
|
|
28
|
+
self.GOOD_JWE_ALG = ["dir", "RSA-OAEP", "RSA-OAEP-256"]
|
|
29
|
+
self.GOOD_JWE_ENC = ["A256GCM"]
|
|
30
|
+
self.target_config = target_config
|
|
31
|
+
|
|
32
|
+
def verify_jwt_alg(self, token):
|
|
33
|
+
"Evaluate JSON Web token's algorithm"
|
|
34
|
+
|
|
35
|
+
map_id = "JWT_ALGORITHM"
|
|
36
|
+
alg = jwt.get_unverified_header(token)["alg"]
|
|
37
|
+
|
|
38
|
+
if alg in self.BAD_JWT_ALG: #Is vulnerable
|
|
39
|
+
return {
|
|
40
|
+
"map_id": map_id,
|
|
41
|
+
"description": "msg"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
def verify_jws_alg(self, token):
|
|
45
|
+
"""Evaluate JSON Web signature's algorithm"""
|
|
46
|
+
|
|
47
|
+
map_id = "JWS_ALGORITHM"
|
|
48
|
+
alg = jwt.get_unverified_header(token)["alg"]
|
|
49
|
+
|
|
50
|
+
if alg in self.BAD_JWS_ALG:#Is vulnerable
|
|
51
|
+
return {
|
|
52
|
+
"map_id": map_id,
|
|
53
|
+
"description": "msg"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
def verify_jwe(self, token):
|
|
57
|
+
"""Evaluate JSON Web encryption's algorithm"""
|
|
58
|
+
|
|
59
|
+
map_id = "JWE_ALGORITHM"
|
|
60
|
+
msg = ""
|
|
61
|
+
enc = jwt.get_unverified_header(token)["enc"]
|
|
62
|
+
alg = jwt.get_unverified_header(token)["alg"]
|
|
63
|
+
|
|
64
|
+
if enc in self.GOOD_JWE_ENC:
|
|
65
|
+
if alg in self.GOOD_JWE_ALG:# Is not vulnerable
|
|
66
|
+
return
|
|
67
|
+
else:
|
|
68
|
+
msg = "Algorithm: " + alg
|
|
69
|
+
else:
|
|
70
|
+
msg = "Encryption: " + enc
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
"map_id": map_id,
|
|
74
|
+
"description": msg
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
def check_token(self, token, jwt_details, config_tool):
|
|
78
|
+
"Validates JWT, JWS or JWE"
|
|
79
|
+
|
|
80
|
+
hed = jwt.get_unverified_header(token)
|
|
81
|
+
|
|
82
|
+
if "enc" in hed.keys():
|
|
83
|
+
result = self.verify_jwe(token)
|
|
84
|
+
elif "typ" in hed.keys():
|
|
85
|
+
result = self.verify_jwt_alg(token)
|
|
86
|
+
else:
|
|
87
|
+
result = self.verify_jws_alg(token)
|
|
88
|
+
|
|
89
|
+
if result:
|
|
90
|
+
mapped_result = {
|
|
91
|
+
"check_id": config_tool["RULES"][result["map_id"]]["checkID"],
|
|
92
|
+
"cvss": config_tool["RULES"][result["map_id"]]["cvss"],
|
|
93
|
+
"matched-at": jwt_details["path"],
|
|
94
|
+
"description": result["msg"],
|
|
95
|
+
"severity": config_tool["RULES"][result["map_id"]]["severity"],
|
|
96
|
+
"remediation": result["remediation"]
|
|
97
|
+
}
|
|
98
|
+
return mapped_result
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
def configure_tool(self, target_data):
|
|
102
|
+
"""Method for group all operations that uses JWT"""
|
|
103
|
+
jwt_list: List[ApiOperation] = []
|
|
104
|
+
for operation in target_data.operations:
|
|
105
|
+
if operation.authentication_gateway.type.lower() == "jwt":
|
|
106
|
+
jwt_list.append(operation)
|
|
107
|
+
return jwt_list
|
|
108
|
+
|
|
109
|
+
def execute(self, jwt_config: List[ApiOperation], config_tool):
|
|
110
|
+
result_scans = []
|
|
111
|
+
if len(jwt_config) > 0:
|
|
112
|
+
for jwt_operation in jwt_config:
|
|
113
|
+
jwt_operation.authenticate()
|
|
114
|
+
result = self.check_token(token=jwt_operation.credentials[1],
|
|
115
|
+
jwt_details=jwt_operation.data["operation"],
|
|
116
|
+
config_tool=config_tool)
|
|
117
|
+
if result:
|
|
118
|
+
result_scans.append(result)
|
|
119
|
+
return result_scans
|
|
120
|
+
|
|
121
|
+
def get_list_finding(
|
|
122
|
+
self,
|
|
123
|
+
result_scan_list: "List[dict]"
|
|
124
|
+
) -> "List[Finding]":
|
|
125
|
+
list_open_findings = []
|
|
126
|
+
if len(result_scan_list) > 0:
|
|
127
|
+
for scan in result_scan_list:
|
|
128
|
+
finding_open = Finding(
|
|
129
|
+
id=scan.get("check-id"),
|
|
130
|
+
cvss=scan.get("cvss"),
|
|
131
|
+
where=scan.get("matched-at"),
|
|
132
|
+
description=scan.get("description"),
|
|
133
|
+
severity=scan.get("severity").lower(),
|
|
134
|
+
identification_date=datetime.now().strftime("%d%m%Y"),
|
|
135
|
+
module="engine_dast",
|
|
136
|
+
category=Category("vulnerability"),
|
|
137
|
+
requirements=scan.get("remediation"),
|
|
138
|
+
tool="jwt",
|
|
139
|
+
published_date_cve=scan.get("published-cve")
|
|
140
|
+
)
|
|
141
|
+
list_open_findings.append(finding_open)
|
|
142
|
+
return list_open_findings
|
|
143
|
+
|
|
144
|
+
def run_tool(self, target_data, config_tool):
|
|
145
|
+
jwt_config = self.configure_tool(target_data)
|
|
146
|
+
result_scans = self.execute(jwt_config, config_tool)
|
|
147
|
+
if result_scans:
|
|
148
|
+
finding_list = self.get_list_finding(result_scans)
|
|
149
|
+
path_file_results = generate_file_from_tool(
|
|
150
|
+
self.TOOL, result_scans, config_tool
|
|
151
|
+
)
|
|
152
|
+
return finding_list, path_file_results
|
|
153
|
+
return []
|
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/model/gateways/sonar_gateway.py
CHANGED
|
@@ -39,7 +39,8 @@ class SonarGateway(metaclass=ABCMeta):
|
|
|
39
39
|
sonar_token: str,
|
|
40
40
|
endpoint: str,
|
|
41
41
|
data: dict,
|
|
42
|
-
finding_type: str
|
|
42
|
+
finding_type: str,
|
|
43
|
+
sonar_max_retry: int
|
|
43
44
|
):
|
|
44
45
|
"use API to change vulnerabilities state in sonar"
|
|
45
46
|
|
|
@@ -50,7 +51,8 @@ class SonarGateway(metaclass=ABCMeta):
|
|
|
50
51
|
sonar_token: str,
|
|
51
52
|
endpoint: str,
|
|
52
53
|
params: dict,
|
|
53
|
-
finding_type: str
|
|
54
|
+
finding_type: str,
|
|
55
|
+
sonar_max_retry: int
|
|
54
56
|
):
|
|
55
57
|
"use API to get project findings in sonar"
|
|
56
58
|
|
|
@@ -127,7 +127,8 @@ class ReportSonar:
|
|
|
127
127
|
"s": "CREATION_DATE",
|
|
128
128
|
"asc": "false"
|
|
129
129
|
},
|
|
130
|
-
"issues"
|
|
130
|
+
"issues",
|
|
131
|
+
report_config_tool["MAX_RETRIES_QUERY_SONAR"]
|
|
131
132
|
)
|
|
132
133
|
sonar_hotspots = self.sonar_gateway.get_findings(
|
|
133
134
|
args["sonar_url"],
|
|
@@ -138,7 +139,8 @@ class ReportSonar:
|
|
|
138
139
|
"ps": 100,
|
|
139
140
|
"p": 1,
|
|
140
141
|
},
|
|
141
|
-
"hotspots"
|
|
142
|
+
"hotspots",
|
|
143
|
+
report_config_tool["MAX_RETRIES_QUERY_SONAR"]
|
|
142
144
|
)
|
|
143
145
|
|
|
144
146
|
sonar_findings = sonar_vulnerabilities + sonar_hotspots
|
|
@@ -164,7 +166,8 @@ class ReportSonar:
|
|
|
164
166
|
"issue": related_sonar_finding["key"],
|
|
165
167
|
"transition": status
|
|
166
168
|
},
|
|
167
|
-
"issue"
|
|
169
|
+
"issue",
|
|
170
|
+
report_config_tool["MAX_RETRIES_QUERY_SONAR"]
|
|
168
171
|
)
|
|
169
172
|
else:
|
|
170
173
|
resolution = None
|
|
@@ -185,7 +188,8 @@ class ReportSonar:
|
|
|
185
188
|
secret["token_sonar"],
|
|
186
189
|
"/api/hotspots/change_status",
|
|
187
190
|
data,
|
|
188
|
-
"hotspot"
|
|
191
|
+
"hotspot",
|
|
192
|
+
report_config_tool["MAX_RETRIES_QUERY_SONAR"]
|
|
189
193
|
)
|
|
190
194
|
|
|
191
195
|
except Exception as e:
|
|
@@ -61,47 +61,54 @@ class SonarAdapter(SonarGateway):
|
|
|
61
61
|
def filter_by_sonarqube_tag(self, findings):
|
|
62
62
|
return [finding for finding in findings if "sonarqube" in finding.tags]
|
|
63
63
|
|
|
64
|
-
def change_finding_status(self, sonar_url, sonar_token, endpoint, data, finding_type):
|
|
64
|
+
def change_finding_status(self, sonar_url, sonar_token, endpoint, data, finding_type, sonar_max_retry):
|
|
65
65
|
try:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
def request_func():
|
|
67
|
+
response = requests.post(
|
|
68
|
+
f"{sonar_url}{endpoint}",
|
|
69
|
+
headers={
|
|
70
|
+
"Authorization": f"Basic {Utils().encode_token_to_base64(sonar_token)}"
|
|
71
|
+
},
|
|
72
|
+
data=data
|
|
73
|
+
)
|
|
74
|
+
response.raise_for_status()
|
|
75
|
+
|
|
76
|
+
if finding_type == "issue":
|
|
77
|
+
info = data["transition"]
|
|
78
|
+
else:
|
|
79
|
+
resolution_info = ""
|
|
80
|
+
if data.get("resolution"): resolution_info = f" ({data['resolution']})"
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
info = data["transition"]
|
|
77
|
-
else:
|
|
78
|
-
resolution_info = ""
|
|
79
|
-
if data.get("resolution"): resolution_info = f" ({data['resolution']})"
|
|
82
|
+
info = f"{data['status']}{resolution_info}"
|
|
80
83
|
|
|
81
|
-
|
|
84
|
+
print(f"The state of the {finding_type} {data[finding_type]} was changed to {info}.")
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
Utils().retries_requests(request_func, sonar_max_retry, retry_delay=5)
|
|
87
|
+
|
|
84
88
|
except Exception as e:
|
|
85
89
|
logger.warning(f"Unable to change the status of {finding_type} {data[finding_type]}. Error: {e}")
|
|
86
90
|
pass
|
|
87
91
|
|
|
88
|
-
def get_findings(self, sonar_url, sonar_token, endpoint, params, finding_type):
|
|
92
|
+
def get_findings(self, sonar_url, sonar_token, endpoint, params, finding_type, sonar_max_retry):
|
|
89
93
|
findings = []
|
|
90
94
|
try:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
def request_func():
|
|
96
|
+
while True:
|
|
97
|
+
response = requests.get(
|
|
98
|
+
f"{sonar_url}{endpoint}",
|
|
99
|
+
headers={
|
|
100
|
+
"Authorization": f"Basic {Utils().encode_token_to_base64(sonar_token)}"
|
|
101
|
+
},
|
|
102
|
+
params=params
|
|
103
|
+
)
|
|
104
|
+
response.raise_for_status()
|
|
105
|
+
data = response.json()
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
findings.extend(data[finding_type])
|
|
108
|
+
if len(data[finding_type]) < params["ps"]: break
|
|
109
|
+
params["p"] = params["p"] + 1
|
|
110
|
+
|
|
111
|
+
Utils().retries_requests(request_func, sonar_max_retry, 5)
|
|
105
112
|
|
|
106
113
|
return findings
|
|
107
114
|
except Exception as e:
|
|
@@ -26,19 +26,28 @@ def init_report_sonar(
|
|
|
26
26
|
args["remote_config_repo"], "/engine_core/ConfigTool.json", args["remote_config_branch"]
|
|
27
27
|
)
|
|
28
28
|
report_config_tool = devops_platform_gateway.get_remote_config(
|
|
29
|
-
args["remote_config_repo"], "/report_sonar/ConfigTool.json"
|
|
29
|
+
args["remote_config_repo"], "/report_sonar/ConfigTool.json", args["remote_config_branch"]
|
|
30
30
|
)
|
|
31
|
+
excluded_pipelines = devops_platform_gateway.get_remote_config(
|
|
32
|
+
args["remote_config_repo"], "/report_sonar/Exclusions.json", args["remote_config_branch"]
|
|
33
|
+
)
|
|
34
|
+
|
|
31
35
|
Printers.print_logo_tool(config_tool["BANNER"])
|
|
32
36
|
|
|
33
37
|
pipeline_name = devops_platform_gateway.get_variable("pipeline_name")
|
|
34
38
|
branch = devops_platform_gateway.get_variable("branch_tag")
|
|
39
|
+
|
|
35
40
|
is_valid_pipeline = not re.match(
|
|
36
|
-
report_config_tool["IGNORE_SEARCH_PATTERN"],
|
|
37
|
-
|
|
41
|
+
report_config_tool["IGNORE_SEARCH_PATTERN"],
|
|
42
|
+
pipeline_name,
|
|
43
|
+
re.IGNORECASE
|
|
44
|
+
) and pipeline_name not in excluded_pipelines
|
|
45
|
+
|
|
38
46
|
is_valid_branch = any(
|
|
39
47
|
target_branch in str(branch)
|
|
40
48
|
for target_branch in report_config_tool["TARGET_BRANCHES"]
|
|
41
49
|
)
|
|
50
|
+
|
|
42
51
|
is_enabled = config_tool["REPORT_SONAR"]["ENABLED"]
|
|
43
52
|
|
|
44
53
|
if is_enabled and is_valid_pipeline and is_valid_branch:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import zipfile
|
|
2
2
|
import tarfile
|
|
3
3
|
import platform
|
|
4
|
+
import time
|
|
4
5
|
from devsecops_engine_tools.engine_utilities.github.infrastructure.github_api import (
|
|
5
6
|
GithubApi,
|
|
6
7
|
)
|
|
@@ -141,3 +142,16 @@ class Utils:
|
|
|
141
142
|
)
|
|
142
143
|
|
|
143
144
|
return set_threshold(match_pattern) if match_pattern else threshold
|
|
145
|
+
|
|
146
|
+
def retries_requests(self, request_func, max_retries, retry_delay):
|
|
147
|
+
for attempt in range(max_retries):
|
|
148
|
+
try:
|
|
149
|
+
return request_func()
|
|
150
|
+
except Exception as e:
|
|
151
|
+
logger.error(f"Error making the request: {e}")
|
|
152
|
+
if attempt < max_retries - 1:
|
|
153
|
+
logger.warning(f"Retry in {retry_delay} seconds...")
|
|
154
|
+
time.sleep(retry_delay)
|
|
155
|
+
else:
|
|
156
|
+
logger.error("Maximum number of retries reached, aborting.")
|
|
157
|
+
raise e
|
|
@@ -1 +1 @@
|
|
|
1
|
-
version = '1.
|
|
1
|
+
version = '1.34.0'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
devsecops_engine_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
devsecops_engine_tools/version.py,sha256=
|
|
2
|
+
devsecops_engine_tools/version.py,sha256=GX9p1uQ5pMzl5fxTcEjUuh508LFzTFrl8YQ3typxofg,19
|
|
3
3
|
devsecops_engine_tools/engine_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
devsecops_engine_tools/engine_core/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
devsecops_engine_tools/engine_core/src/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -38,7 +38,7 @@ devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/aws/secret
|
|
|
38
38
|
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
39
|
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/azure_devops.py,sha256=buCBJ6kAg-5b_7P-gWzem6NEMbk5lK9Hx0Zuf-BQfXQ,5090
|
|
40
40
|
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
|
-
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py,sha256=
|
|
41
|
+
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py,sha256=ma6TTlrXnUqGJ6DXM7PQzgZyoTK6Wd-tvMXLITpOvaA,27330
|
|
42
42
|
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
43
|
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/github_actions.py,sha256=KCg6tTDncasrRZbB20QiLZNE6TKYkfgQ9zP0wPd3xe0,3925
|
|
44
44
|
devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/printer_pretty_table/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -72,6 +72,12 @@ devsecops_engine_tools/engine_dast/src/domain/usecases/__init__.py,sha256=47DEQp
|
|
|
72
72
|
devsecops_engine_tools/engine_dast/src/domain/usecases/dast_scan.py,sha256=9zQhA8d9McGWNT2ZdvjmjWCIPN3UpST7RWve2QvyHu4,4693
|
|
73
73
|
devsecops_engine_tools/engine_dast/src/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
74
|
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
|
+
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
+
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
|
+
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/http/client/auth_client.py,sha256=aeEB5-TKH1jow8KwxSpucpgoGrxotJ7jeY2Jliwr20o,407
|
|
78
|
+
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/jwt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
79
|
+
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/jwt/jwt_object.py,sha256=p0_rDDjdsyAa_ar-HgZE_SQE-beua0oK3KBnwj8EmPo,1998
|
|
80
|
+
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/jwt/jwt_tool.py,sha256=9Yh7lOd6lsHcvl8exgWW7N8qTP55w-Znl0kid7IlKrM,5431
|
|
75
81
|
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/nuclei/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
82
|
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/nuclei/nuclei_config.py,sha256=TxjdA5_KDmn-RqZQsPkrrqyjd9zPMweKH37pwnxSV8Q,3090
|
|
77
83
|
devsecops_engine_tools/engine_dast/src/infrastructure/driven_adapters/nuclei/nuclei_deserealizer.py,sha256=qqoBMXr350ItzabSU6a_fD2-9kB6pAmtWioFP5AvCIE,1346
|
|
@@ -319,15 +325,15 @@ devsecops_engine_tools/engine_utilities/sonarqube/src/applications/runner_report
|
|
|
319
325
|
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
320
326
|
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
321
327
|
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/model/gateways/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
322
|
-
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/model/gateways/sonar_gateway.py,sha256=
|
|
328
|
+
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/model/gateways/sonar_gateway.py,sha256=mgycD3bzC_BYv7qT0tMLAro9hyNOvi4gJRzceYNF0t8,1339
|
|
323
329
|
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
324
|
-
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py,sha256=
|
|
330
|
+
devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py,sha256=DnJowGn2mI2JvYjFTyrcZ6MOj2RrHk1xJt-kLWu0Z1k,9493
|
|
325
331
|
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
326
332
|
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/driven_adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
327
333
|
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/driven_adapters/sonarqube/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
328
|
-
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/driven_adapters/sonarqube/sonarqube_report.py,sha256=
|
|
334
|
+
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/driven_adapters/sonarqube/sonarqube_report.py,sha256=BpCLMgFQjytZc1HfZ5hXqX44E8T0JhLpAaNOVq5pFjo,4909
|
|
329
335
|
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/entry_points/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
330
|
-
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/entry_points/entry_point_report_sonar.py,sha256=
|
|
336
|
+
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/entry_points/entry_point_report_sonar.py,sha256=cAPH9-jjnAvF_hH5_UOSG2pndycAxJgpN9e6K8Aufso,2603
|
|
331
337
|
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
332
338
|
devsecops_engine_tools/engine_utilities/sonarqube/src/infrastructure/helpers/utils.py,sha256=SGOWrkzQrvOt9bRhhSfgiMzj1695e1W0B9ox9C1ihQI,294
|
|
333
339
|
devsecops_engine_tools/engine_utilities/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -340,9 +346,9 @@ devsecops_engine_tools/engine_utilities/utils/logger_info.py,sha256=4Mz8Bwlm9Mku
|
|
|
340
346
|
devsecops_engine_tools/engine_utilities/utils/name_conversion.py,sha256=ADJrRGaxYSDe0ZRh6VHRf53H4sXPcb-vNP_i81PUn3I,307
|
|
341
347
|
devsecops_engine_tools/engine_utilities/utils/printers.py,sha256=amYAr9YQfYgR6jK9a2l26z3oovFPQ3FAKmhq6BKhEBA,623
|
|
342
348
|
devsecops_engine_tools/engine_utilities/utils/session_manager.py,sha256=Z0fdhB3r-dxU0nGSD9zW_B4r2Qol1rUnUCkhFR0U-HQ,487
|
|
343
|
-
devsecops_engine_tools/engine_utilities/utils/utils.py,sha256=
|
|
344
|
-
devsecops_engine_tools-1.
|
|
345
|
-
devsecops_engine_tools-1.
|
|
346
|
-
devsecops_engine_tools-1.
|
|
347
|
-
devsecops_engine_tools-1.
|
|
348
|
-
devsecops_engine_tools-1.
|
|
349
|
+
devsecops_engine_tools/engine_utilities/utils/utils.py,sha256=XFap4yOK7ItLWsqbwDhvLd7NpDhs7i-UGJAMD6jjd7w,6687
|
|
350
|
+
devsecops_engine_tools-1.34.0.dist-info/METADATA,sha256=kKt7j0H8HxuPAFBVW5lCEgGPWUwKW0Ep1OkUqrJqyG4,11592
|
|
351
|
+
devsecops_engine_tools-1.34.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
|
352
|
+
devsecops_engine_tools-1.34.0.dist-info/entry_points.txt,sha256=MHCTFFs9bdNKo6YcWCcBW2_8X6yTisgLOlmVx-V8Rxc,276
|
|
353
|
+
devsecops_engine_tools-1.34.0.dist-info/top_level.txt,sha256=ge6y0X_xBAU1aG3EMWFtl9djbVyg5BxuSp2r2Lg6EQU,23
|
|
354
|
+
devsecops_engine_tools-1.34.0.dist-info/RECORD,,
|
|
File without changes
|
{devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{devsecops_engine_tools-1.33.0.dist-info → devsecops_engine_tools-1.34.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|