Skip to content

Commit 0dab65d

Browse files
authored
Fix sonar-audit bugs (#1412)
* Fixes #1410 * Align requests error on ERROR * Fixes #1411 * Remove crlf in error log * Add logging on objects search * Speedup QP loading
1 parent 418054e commit 0dab65d

File tree

7 files changed

+36
-10
lines changed

7 files changed

+36
-10
lines changed

cli/findings_export.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ def __get_component_findings(queue: Queue[tuple[object, ConfigSettings]], write_
324324
try:
325325
findings_list = component.get_issues(filters=new_params)
326326
except (ConnectionError, RequestException) as e:
327-
log.critical("%s while exporting issues of %s, skipped", util.error_msg(e), str(component))
327+
log.error("%s while exporting issues of %s, skipped", util.error_msg(e), str(component))
328328
findings_list = {}
329329
else:
330330
log.debug("Status = %s, Types = %s, Resol = %s, Sev = %s", str(i_statuses), str(i_types), str(i_resols), str(i_sevs))

sonar/permissions/permission_templates.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def to_json(self, export_settings: types.ConfigSettings = None) -> types.ObjectJ
180180
return utilities.remove_nones(utilities.filter_export(json_data, _IMPORTABLE_PROPERTIES, export_settings.get("FULL_EXPORT", False)))
181181

182182
def _audit_pattern(self, audit_settings: types.ConfigSettings) -> list[pb.Problem]:
183-
log.debug("Auditing %s projectKeyPattern ('%s')", str(self.project_key_pattern))
183+
log.debug("Auditing %s projectKeyPattern ('%s')", str(self), str(self.project_key_pattern))
184184
if not self.project_key_pattern or self.project_key_pattern == "":
185185
if not (self.is_applications_default() or self.is_portfolios_default() or self.is_projects_default()):
186186
return [pb.Problem(get_rule(RuleId.TEMPLATE_WITH_NO_PATTERN), self, str(self))]

sonar/qualityprofiles.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ def rules(self) -> dict[str, rules.Rule]:
242242
if self._rules is not None:
243243
# Assume nobody changed QP during execution
244244
return self._rules
245-
self._rules = rules.search(self.endpoint, activation="true", qprofile=self.key, s="key", languages=self.language)
245+
rule_key_list = rules.search_keys(self.endpoint, activation="true", qprofile=self.key, s="key", languages=self.language)
246+
self._rules = {k: rules.get_object(self.endpoint, k) for k in rule_key_list}
246247
return self._rules
247248

248249
def activate_rule(self, rule_key: str, severity: str = None, **params) -> bool:
@@ -534,10 +535,10 @@ def audit(endpoint: pf.Platform, audit_settings: types.ConfigSettings = None) ->
534535
:rtype: list[Problem]
535536
"""
536537
log.info("--- Auditing quality profiles ---")
537-
get_list(endpoint=endpoint)
538+
rules.get_list(endpoint=endpoint)
538539
problems = []
539540
langs = {}
540-
for qp in search(endpoint).values():
541+
for qp in search(endpoint=endpoint).values():
541542
problems += qp.audit(audit_settings)
542543
langs[qp.language] = langs.get(qp.language, 0) + 1
543544
for lang, nb_qp in langs.items():

sonar/rules.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,27 @@ def get_facet(facet: str, endpoint: platform.Platform) -> dict[str, str]:
244244

245245

246246
def search(endpoint: platform.Platform, **params) -> dict[str, Rule]:
247-
"""Searches ruless with optional filters"""
247+
"""Searches rules with optional filters"""
248248
return sq.search_objects(endpoint=endpoint, object_class=Rule, params=params, threads=4)
249249

250250

251+
def search_keys(endpoint: platform.Platform, **params) -> list[str]:
252+
"""Searches ruless with optional filters"""
253+
new_params = params.copy() if params else {}
254+
new_params["ps"] = 500
255+
new_params["p"], nbr_pages = 0, 1
256+
rule_list = []
257+
try:
258+
while new_params["p"] < nbr_pages:
259+
new_params["p"] += 1
260+
data = json.loads(endpoint.get(Rule.SEARCH_API, params=new_params).text)
261+
nbr_pages = utilities.nbr_pages(data)
262+
rule_list += [r[Rule.SEARCH_KEY_FIELD] for r in data[Rule.SEARCH_RETURN_FIELD]]
263+
except (ConnectionError, RequestException) as e:
264+
log.error("%s while getting rules", utilities.error_msg(e))
265+
return rule_list
266+
267+
251268
def count(endpoint: platform.Platform, **params) -> int:
252269
"""Count number of rules that correspond to certain filters"""
253270
return json.loads(endpoint.get(Rule.SEARCH_API, params={**params, "ps": 1}).text)["total"]

sonar/sqobject.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ def search_objects(endpoint: object, object_class: any, params: types.ApiParams,
133133
new_params["p"] = 1
134134
objects_list = {}
135135
data = json.loads(endpoint.get(api, params=new_params).text)
136+
nb_pages = utilities.nbr_pages(data)
137+
nb_objects = max(len(data[returned_field]), utilities.nbr_total_elements(data))
138+
log.info("%d %s to load", nb_objects, object_class.__name__)
136139
for obj in data[returned_field]:
137140
if object_class.__name__ in ("Portfolio", "Group", "QualityProfile", "User", "Application", "Project", "Organization"):
138141
objects_list[obj[key_field]] = object_class.load(endpoint=endpoint, data=obj)
139142
else:
140143
objects_list[obj[key_field]] = object_class(endpoint, obj[key_field], data=obj)
141-
nb_pages = utilities.nbr_pages(data)
142144
if nb_pages == 1:
143145
# If everything is returned on the 1st page, no multi-threading needed
144146
return objects_list

sonar/tasks.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import json
2525
import re
2626

27+
from requests import RequestException
28+
2729
import sonar.logging as log
2830
import sonar.sqobject as sq
2931
import sonar.platform as pf
@@ -530,8 +532,12 @@ def search(endpoint: pf.Platform, only_current: bool = False, component_key: str
530532
params["onlyCurrents"] = "true"
531533
if component_key is not None:
532534
params["component"] = component_key
533-
data = json.loads(endpoint.get("ce/activity", params=params).text)
534-
return [Task(endpoint=endpoint, task_id=t["id"], data=t) for t in data["tasks"]]
535+
try:
536+
data = json.loads(endpoint.get("ce/activity", params=params).text)
537+
return [Task(endpoint=endpoint, task_id=t["id"], data=t) for t in data["tasks"]]
538+
except (ConnectionError, RequestException) as e:
539+
log.error("%s while getting background tasks of component '%s'", util.error_msg(e), str(component_key))
540+
return []
535541

536542

537543
def search_all_last(endpoint: pf.Platform) -> list[Task]:

sonar/utilities.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def http_error_and_code(exception: requests.HTTPError) -> tuple[int, str]:
440440
response = exception.response
441441
if response.ok:
442442
return None, "No error"
443-
tool_msg = f"For request URL {response.request.url}\n"
443+
tool_msg = f"URL {response.request.url}: "
444444
code = response.status_code
445445
if code == HTTPStatus.UNAUTHORIZED:
446446
tool_msg += f"HTTP error {code} - Authentication error. Is token valid ?"

0 commit comments

Comments
 (0)