From 63754ec39769f80be18cdff2488ce6bc08e76bfd Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:48:19 +0100 Subject: [PATCH] Ruff: Add and fix FBT002 (+ merge all FBT rules) --- dojo/api_v2/serializers.py | 4 +-- dojo/components/sql_group_concat.py | 2 +- dojo/decorators.py | 2 +- dojo/endpoint/views.py | 4 +-- dojo/engagement/views.py | 2 +- dojo/filters.py | 2 +- dojo/finding/helper.py | 6 ++--- dojo/finding/views.py | 4 +-- dojo/forms.py | 2 +- dojo/jira_link/helper.py | 8 +++--- dojo/middleware.py | 2 +- dojo/models.py | 6 ++--- dojo/product/views.py | 2 +- dojo/remote_user.py | 2 +- dojo/reports/views.py | 2 +- dojo/reports/widgets.py | 2 +- dojo/risk_acceptance/helper.py | 4 +-- dojo/search/views.py | 2 +- dojo/survey/views.py | 2 +- dojo/templatetags/display_tags.py | 10 ++++---- dojo/templatetags/event_tags.py | 4 +-- dojo/templatetags/navigation_tags.py | 2 +- dojo/tools/blackduck_component_risk/parser.py | 2 +- dojo/tools/qualys_webapp/parser.py | 16 ++++++------ dojo/utils.py | 9 ++++--- dojo/views.py | 4 +-- ruff.toml | 2 +- tests/base_test_class.py | 6 ++--- tests/close_old_findings_dedupe_test.py | 2 +- tests/close_old_findings_test.py | 2 +- tests/dedupe_test.py | 2 +- tests/finding_test.py | 2 +- tests/product_test.py | 2 +- unittests/dojo_test_case.py | 25 ++++++++++--------- unittests/test_apiv2_scan_import_options.py | 2 +- unittests/test_deduplication_logic.py | 6 ++--- unittests/test_endpoint_meta_import.py | 2 +- unittests/test_import_reimport.py | 4 +-- unittests/test_jira_config_engagement.py | 18 ++++++------- unittests/test_jira_config_engagement_epic.py | 2 +- unittests/test_product_grading.py | 4 +-- unittests/test_rest_framework.py | 2 +- unittests/test_tags.py | 2 +- unittests/test_user_validators.py | 1 + unittests/tools/test_asff_parser.py | 2 +- 45 files changed, 100 insertions(+), 95 deletions(-) diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py index 5cdc2db4d8..a18463dba3 100644 --- a/dojo/api_v2/serializers.py +++ b/dojo/api_v2/serializers.py @@ -2357,7 +2357,7 @@ def process_auto_create_create_context( # Raise an explicit drf exception here raise ValidationError(str(e)) - def save(self, push_to_jira=False): + def save(self, *, push_to_jira=False): # Go through the validate method data = self.validated_data # Extract the data from the form @@ -2499,7 +2499,7 @@ def process_scan( except ValueError as ve: raise Exception(ve) - def save(self, push_to_jira=False): + def save(self, *, push_to_jira=False): # Go through the validate method data = self.validated_data # Extract the data from the form diff --git a/dojo/components/sql_group_concat.py b/dojo/components/sql_group_concat.py index 3b08bb4cc5..9d936a0f70 100644 --- a/dojo/components/sql_group_concat.py +++ b/dojo/components/sql_group_concat.py @@ -6,7 +6,7 @@ class Sql_GroupConcat(Aggregate): allow_distinct = True def __init__( - self, expression, separator, distinct=False, ordering=None, **extra, + self, expression, separator, *, distinct=False, ordering=None, **extra, ): self.separator = separator super().__init__( diff --git a/dojo/decorators.py b/dojo/decorators.py index 8f356b0f62..4ede4f41b8 100644 --- a/dojo/decorators.py +++ b/dojo/decorators.py @@ -144,7 +144,7 @@ def get_parameter_froms_args_kwargs(args, kwargs, parameter): return model_or_id -def dojo_ratelimit(key="ip", rate=None, method=UNSAFE, block=False): +def dojo_ratelimit(key="ip", rate=None, method=UNSAFE, *, block=False): def decorator(fn): @wraps(fn) def _wrapped(request, *args, **kw): diff --git a/dojo/endpoint/views.py b/dojo/endpoint/views.py index bf85092a12..0cf5717be2 100644 --- a/dojo/endpoint/views.py +++ b/dojo/endpoint/views.py @@ -38,7 +38,7 @@ logger = logging.getLogger(__name__) -def process_endpoints_view(request, host_view=False, vulnerable=False): +def process_endpoints_view(request, *, host_view=False, vulnerable=False): if vulnerable: endpoints = Endpoint.objects.filter( @@ -116,7 +116,7 @@ def vulnerable_endpoint_hosts(request): return process_endpoints_view(request, host_view=True, vulnerable=True) -def process_endpoint_view(request, eid, host_view=False): +def process_endpoint_view(request, eid, *, host_view=False): endpoint = get_object_or_404(Endpoint, id=eid) if host_view: diff --git a/dojo/engagement/views.py b/dojo/engagement/views.py index 70ff8a7b16..8cb08f53a7 100644 --- a/dojo/engagement/views.py +++ b/dojo/engagement/views.py @@ -1248,7 +1248,7 @@ def edit_risk_acceptance(request, eid, raid): # will only be called by view_risk_acceptance and edit_risk_acceptance -def view_edit_risk_acceptance(request, eid, raid, edit_mode=False): +def view_edit_risk_acceptance(request, eid, raid, *, edit_mode=False): risk_acceptance = get_object_or_404(Risk_Acceptance, pk=raid) eng = get_object_or_404(Engagement, pk=eid) diff --git a/dojo/filters.py b/dojo/filters.py index 6a1228865b..e0e92107aa 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -363,7 +363,7 @@ def get_tags_label_from_model(model): return "Tags (Unknown)" -def get_finding_filterset_fields(metrics=False, similar=False, filter_string_matching=False): +def get_finding_filterset_fields(*, metrics=False, similar=False, filter_string_matching=False): fields = [] if similar: diff --git a/dojo/finding/helper.py b/dojo/finding/helper.py index 66badd594d..13ae9a7544 100644 --- a/dojo/finding/helper.py +++ b/dojo/finding/helper.py @@ -304,7 +304,7 @@ def group_findings_by(finds, finding_group_by_option): return affected_groups, grouped, skipped, groups_created -def add_findings_to_auto_group(name, findings, group_by, create_finding_groups_for_all_findings=True, **kwargs): +def add_findings_to_auto_group(name, findings, group_by, *, create_finding_groups_for_all_findings=True, **kwargs): if name is not None and findings is not None and len(findings) > 0: creator = get_current_user() if not creator: @@ -349,8 +349,8 @@ def add_findings_to_auto_group(name, findings, group_by, create_finding_groups_f @dojo_async_task @app.task @dojo_model_from_id -def post_process_finding_save(finding, dedupe_option=True, rules_option=True, product_grading_option=True, - issue_updater_option=True, push_to_jira=False, user=None, *args, **kwargs): +def post_process_finding_save(finding, dedupe_option=True, rules_option=True, product_grading_option=True, # noqa: FBT002 + issue_updater_option=True, push_to_jira=False, user=None, *args, **kwargs): # noqa: FBT002 - this is bit hard to fix nice have this universally fixed system_settings = System_Settings.objects.get() diff --git a/dojo/finding/views.py b/dojo/finding/views.py index ec25352a90..2e9fed2e2d 100644 --- a/dojo/finding/views.py +++ b/dojo/finding/views.py @@ -130,7 +130,7 @@ logger = logging.getLogger(__name__) -def prefetch_for_findings(findings, prefetch_type="all", exclude_untouched=True): +def prefetch_for_findings(findings, prefetch_type="all", *, exclude_untouched=True): prefetched_findings = findings if isinstance( findings, QuerySet, @@ -2242,7 +2242,7 @@ def export_templates_to_json(request): return HttpResponse(leads_as_json, content_type="json") -def apply_cwe_mitigation(apply_to_findings, template, update=True): +def apply_cwe_mitigation(apply_to_findings, template, *, update=True): count = 0 if apply_to_findings and template.template_match and template.cwe is not None: # Update active, verified findings with the CWE template diff --git a/dojo/forms.py b/dojo/forms.py index 334a958e93..57b9c5aa7b 100644 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -155,7 +155,7 @@ class MonthYearWidget(Widget): month_field = "%s_month" year_field = "%s_year" - def __init__(self, attrs=None, years=None, required=True): + def __init__(self, attrs=None, years=None, *, required=True): # years is an optional list/tuple of years to use in the # "year" select box. self.attrs = attrs or {} diff --git a/dojo/jira_link/helper.py b/dojo/jira_link/helper.py index 308331987a..25a0929016 100644 --- a/dojo/jira_link/helper.py +++ b/dojo/jira_link/helper.py @@ -178,7 +178,7 @@ def can_be_pushed_to_jira(obj, form=None): # use_inheritance=True means get jira_project config from product if engagement itself has none -def get_jira_project(obj, use_inheritance=True): +def get_jira_project(obj, *, use_inheritance=True): if not is_jira_enabled(): return None @@ -673,7 +673,7 @@ def push_to_jira(obj, *args, **kwargs): return None -def add_issues_to_epic(jira, obj, epic_id, issue_keys, ignore_epics=True): +def add_issues_to_epic(jira, obj, epic_id, issue_keys, *, ignore_epics=True): try: return jira.add_issues_to_epic(epic_id=epic_id, issue_keys=issue_keys, ignore_epics=ignore_epics) except JIRAError as e: @@ -1070,7 +1070,7 @@ def issue_from_jira_is_active(issue_from_jira): return issue_from_jira.fields.resolution == "None" -def push_status_to_jira(obj, jira_instance, jira, issue, save=False): +def push_status_to_jira(obj, jira_instance, jira, issue, *, save=False): status_list = obj.status() issue_closed = False # check RESOLVED_STATUS first to avoid corner cases with findings that are Inactive, but verified @@ -1384,7 +1384,7 @@ def jira_get_issue(jira_project, issue_key): @app.task @dojo_model_from_id(model=Notes, parameter=1) @dojo_model_from_id -def add_comment(obj, note, force_push=False, **kwargs): +def add_comment(obj, note, *, force_push=False, **kwargs): if not is_jira_configured_and_enabled(obj): return False diff --git a/dojo/middleware.py b/dojo/middleware.py index 239a2d92f4..6c75cb5c1a 100644 --- a/dojo/middleware.py +++ b/dojo/middleware.py @@ -121,7 +121,7 @@ def get_from_db(self, *args, **kwargs): return System_Settings() return from_db - def get(self, no_cache=False, *args, **kwargs): + def get(self, no_cache=False, *args, **kwargs): # noqa: FBT002 - this is bit hard to fix nice have this universally fixed if no_cache: # logger.debug('no_cache specified or cached value found, loading system settings from db') return self.get_from_db(*args, **kwargs) diff --git a/dojo/models.py b/dojo/models.py index 99074a9cf3..61e63273f7 100644 --- a/dojo/models.py +++ b/dojo/models.py @@ -135,7 +135,7 @@ class UniqueUploadNameProvider: the filename extension will be dropped. """ - def __init__(self, directory=None, keep_basename=False, keep_ext=True): + def __init__(self, directory=None, *, keep_basename=False, keep_ext=True): self.directory = directory self.keep_basename = keep_basename self.keep_ext = keep_ext @@ -2625,8 +2625,8 @@ class Meta: def __str__(self): return self.title - def save(self, dedupe_option=True, rules_option=True, product_grading_option=True, - issue_updater_option=True, push_to_jira=False, user=None, *args, **kwargs): + def save(self, dedupe_option=True, rules_option=True, product_grading_option=True, # noqa: FBT002 + issue_updater_option=True, push_to_jira=False, user=None, *args, **kwargs): # noqa: FBT002 - this is bit hard to fix nice have this universally fixed from dojo.finding import helper as finding_helper diff --git a/dojo/product/views.py b/dojo/product/views.py index 654169363d..db58f59c9e 100644 --- a/dojo/product/views.py +++ b/dojo/product/views.py @@ -1044,7 +1044,7 @@ def delete_product(request, pid): @user_is_authorized(Product, Permissions.Engagement_Add, "pid") -def new_eng_for_app(request, pid, cicd=False): +def new_eng_for_app(request, pid, *, cicd=False): jira_project_form = None jira_epic_form = None diff --git a/dojo/remote_user.py b/dojo/remote_user.py index a60fe52c89..2362a05ad3 100644 --- a/dojo/remote_user.py +++ b/dojo/remote_user.py @@ -50,7 +50,7 @@ class PersistentRemoteUserMiddleware(RemoteUserMiddleware): class RemoteUserBackend(OriginalRemoteUserBackend): - def configure_user(self, request, user, created=True): + def configure_user(self, request, user, *, created=True): changed = False if settings.AUTH_REMOTEUSER_EMAIL_HEADER and \ diff --git a/dojo/reports/views.py b/dojo/reports/views.py index 061476efe1..1438033edb 100644 --- a/dojo/reports/views.py +++ b/dojo/reports/views.py @@ -328,7 +328,7 @@ def product_endpoint_report(request, pid): }) -def generate_report(request, obj, host_view=False): +def generate_report(request, obj, *, host_view=False): user = Dojo_User.objects.get(id=request.user.id) product_type = None product = None diff --git a/dojo/reports/widgets.py b/dojo/reports/widgets.py index 7439a4bb8f..b4ebdee387 100644 --- a/dojo/reports/widgets.py +++ b/dojo/reports/widgets.py @@ -363,7 +363,7 @@ def get_option_form(self): return mark_safe(html) -def report_widget_factory(json_data=None, request=None, user=None, finding_notes=False, finding_images=False, +def report_widget_factory(json_data=None, request=None, user=None, *, finding_notes=False, finding_images=False, host=None): selected_widgets = OrderedDict() widgets = json.loads(json_data) diff --git a/dojo/risk_acceptance/helper.py b/dojo/risk_acceptance/helper.py index 00897d134c..66f18d3634 100644 --- a/dojo/risk_acceptance/helper.py +++ b/dojo/risk_acceptance/helper.py @@ -296,7 +296,7 @@ def prefetch_for_expiration(risk_acceptances): ) -def simple_risk_accept(user: Dojo_User, finding: Finding, perform_save=True) -> None: +def simple_risk_accept(user: Dojo_User, finding: Finding, *, perform_save=True) -> None: if not finding.test.engagement.product.enable_simple_risk_acceptance: raise PermissionDenied @@ -319,7 +319,7 @@ def simple_risk_accept(user: Dojo_User, finding: Finding, perform_save=True) -> )) -def risk_unaccept(user: Dojo_User, finding: Finding, perform_save=True) -> None: +def risk_unaccept(user: Dojo_User, finding: Finding, *, perform_save=True) -> None: logger.debug("unaccepting finding %i:%s if it is currently risk accepted", finding.id, finding) if finding.risk_accepted: logger.debug("unaccepting finding %i:%s", finding.id, finding) diff --git a/dojo/search/views.py b/dojo/search/views.py index 07a8c0ab6f..ce3a2117a6 100644 --- a/dojo/search/views.py +++ b/dojo/search/views.py @@ -450,7 +450,7 @@ def vulnerability_id_fix(keyword): return keyword -def apply_tag_filters(qs, operators, skip_relations=False): +def apply_tag_filters(qs, operators, *, skip_relations=False): tag_filters = {"tag": ""} if qs.model == Finding: diff --git a/dojo/survey/views.py b/dojo/survey/views.py index d83803f2ef..824bbf52d4 100644 --- a/dojo/survey/views.py +++ b/dojo/survey/views.py @@ -200,7 +200,7 @@ def view_questionnaire(request, eid, sid): }) -def get_answered_questions(survey=None, read_only=False): +def get_answered_questions(survey=None, *, read_only=False): if survey is None: return None diff --git a/dojo/templatetags/display_tags.py b/dojo/templatetags/display_tags.py index 94bcf80d6e..dd21df0e7b 100644 --- a/dojo/templatetags/display_tags.py +++ b/dojo/templatetags/display_tags.py @@ -828,8 +828,8 @@ def jiraencode_component(value): @register.filter -def jira_project(obj, use_inheritance=True): - return jira_helper.get_jira_project(obj, use_inheritance) +def jira_project(obj, *, use_inheritance=True): + return jira_helper.get_jira_project(obj, use_inheritance=use_inheritance) @register.filter @@ -906,7 +906,7 @@ def class_name(value): @register.filter(needs_autoescape=True) -def jira_project_tag(product_or_engagement, autoescape=True): +def jira_project_tag(product_or_engagement, *, autoescape=True): if autoescape: esc = conditional_escape else: @@ -961,7 +961,7 @@ def full_name(user): @register.filter(needs_autoescape=True) -def import_settings_tag(test_import, autoescape=True): +def import_settings_tag(test_import, *, autoescape=True): if not test_import or not test_import.import_settings: return "" @@ -1003,7 +1003,7 @@ def esc(x): @register.filter(needs_autoescape=True) -def import_history(finding, autoescape=True): +def import_history(finding, *, autoescape=True): if not finding or not settings.TRACK_IMPORT_HISTORY: return "" diff --git a/dojo/templatetags/event_tags.py b/dojo/templatetags/event_tags.py index 237845738c..493ebf3ab2 100644 --- a/dojo/templatetags/event_tags.py +++ b/dojo/templatetags/event_tags.py @@ -14,10 +14,10 @@ def _process_field_attributes(field, attr, process): # decorate field.as_widget method with updated attributes old_as_widget = field.as_widget - def as_widget(self, widget=None, attrs=None, only_initial=False): + def as_widget(self, widget=None, attrs=None, *, only_initial=False): attrs = attrs or {} process(widget or self.field.widget, attrs, attribute, value) - return old_as_widget(widget, attrs, only_initial) + return old_as_widget(widget, attrs, only_initial=only_initial) bound_method = type(old_as_widget) try: diff --git a/dojo/templatetags/navigation_tags.py b/dojo/templatetags/navigation_tags.py index 8ea8c8531f..3da215bc88 100644 --- a/dojo/templatetags/navigation_tags.py +++ b/dojo/templatetags/navigation_tags.py @@ -69,7 +69,7 @@ def dojo_sort(request, display="Name", value="title", default=None): class PaginationNav: - def __init__(self, page_number=None, display=None, is_current=False): + def __init__(self, page_number=None, display=None, *, is_current=False): self.page_number = page_number self.is_current = is_current self.display = display or page_number or "" diff --git a/dojo/tools/blackduck_component_risk/parser.py b/dojo/tools/blackduck_component_risk/parser.py index 76db65191a..579d21f628 100644 --- a/dojo/tools/blackduck_component_risk/parser.py +++ b/dojo/tools/blackduck_component_risk/parser.py @@ -175,7 +175,7 @@ def license_description(self, component, source): desc += "**Scan:** Unable to find scan in source data." return desc - def license_mitigation(self, component, violation=True): + def license_mitigation(self, component, *, violation=True): """ Uses Component name and Component version name to display the package. :param component: Dictionary containing all components. diff --git a/dojo/tools/qualys_webapp/parser.py b/dojo/tools/qualys_webapp/parser.py index 989e5ba48c..51c62ef621 100644 --- a/dojo/tools/qualys_webapp/parser.py +++ b/dojo/tools/qualys_webapp/parser.py @@ -186,7 +186,7 @@ def get_request_response(payloads): def get_unique_vulnerabilities( - vulnerabilities, test, is_info=False, is_app_report=False, + vulnerabilities, test, *, is_info=False, is_app_report=False, ): findings = {} # Iterate through all vulnerabilites to pull necessary info @@ -250,7 +250,7 @@ def get_unique_vulnerabilities( # Traverse and retreive any information in the VULNERABILITY_LIST # section of the report. This includes all endpoints and request/response pairs def get_vulnerabilities( - vulnerabilities, test, is_info=False, is_app_report=False, + vulnerabilities, test, *, is_info=False, is_app_report=False, ): findings = {} # Iterate through all vulnerabilites to pull necessary info @@ -295,7 +295,7 @@ def get_vulnerabilities( # Retrieve information from a single glossary entry such as description, # severity, title, impact, mitigation, and CWE -def get_glossary_item(glossary, finding, is_info=False, enable_weakness=False): +def get_glossary_item(glossary, finding, *, is_info=False, enable_weakness=False): title = glossary.findtext("TITLE") if title is not None: finding.title = str(title) @@ -337,6 +337,7 @@ def get_unique_items( glossary, is_app_report, test, + *, enable_weakness=False, ): ig_qid_list = [int(ig.findtext("QID")) for ig in info_gathered] @@ -377,6 +378,7 @@ def get_items( glossary, is_app_report, test, + *, enable_weakness=False, ): ig_qid_list = [int(ig.findtext("QID")) for ig in info_gathered] @@ -410,7 +412,7 @@ def get_items( return findings -def qualys_webapp_parser(qualys_xml_file, test, unique, enable_weakness=False): +def qualys_webapp_parser(qualys_xml_file, test, unique, *, enable_weakness=False): if qualys_xml_file is None: return [] @@ -443,7 +445,7 @@ def qualys_webapp_parser(qualys_xml_file, test, unique, enable_weakness=False): glossary, is_app_report, test, - enable_weakness, + enable_weakness=enable_weakness, ).values(), ) else: @@ -454,7 +456,7 @@ def qualys_webapp_parser(qualys_xml_file, test, unique, enable_weakness=False): glossary, is_app_report, test, - enable_weakness, + enable_weakness=enable_weakness, ).values(), ) @@ -475,5 +477,5 @@ def get_findings( self, file, test, enable_weakness=QUALYS_WAS_WEAKNESS_IS_VULN, ): return qualys_webapp_parser( - file, test, QUALYS_WAS_UNIQUE_ID, enable_weakness, + file, test, QUALYS_WAS_UNIQUE_ID, enable_weakness=enable_weakness, ) diff --git a/dojo/utils.py b/dojo/utils.py index 8c2df2be84..588d975512 100644 --- a/dojo/utils.py +++ b/dojo/utils.py @@ -712,6 +712,7 @@ def findings_this_period(findings, period_type, stuff, o_stuff, a_stuff): def add_breadcrumb(parent=None, title=None, + *, top_level=True, url=None, request=None, @@ -1351,7 +1352,7 @@ def get_page_items(request, items, page_size, prefix=""): return get_page_items_and_count(request, items, page_size, prefix=prefix, do_count=False) -def get_page_items_and_count(request, items, page_size, prefix="", do_count=True): +def get_page_items_and_count(request, items, page_size, prefix="", *, do_count=True): page_param = prefix + "page" page_size_param = prefix + "page_size" @@ -1750,7 +1751,7 @@ def add_language(product, language, files=1, code=1): # Apply finding template data by matching CWE + Title or CWE -def apply_cwe_to_template(finding, override=False): +def apply_cwe_to_template(finding, *, override=False): if System_Settings.objects.get().enable_template_match or override: # Attempt to match on CWE and Title First template = Finding_Template.objects.filter( @@ -1901,7 +1902,7 @@ def sla_compute_and_notify(*args, **kwargs): import dojo.jira_link.helper as jira_helper class NotificationEntry: - def __init__(self, finding=None, jira_issue=None, do_jira_sla_comment=False): + def __init__(self, finding=None, jira_issue=None, *, do_jira_sla_comment=False): self.finding = finding self.jira_issue = jira_issue self.do_jira_sla_comment = do_jira_sla_comment @@ -2317,7 +2318,7 @@ def prod_name(obj): # Returns image locations by default (i.e. uploaded_files/09577eb1-6ccb-430b-bc82-0742d4c97a09.png) # if return_objects=True, return the FileUPload object instead of just the file location -def get_file_images(obj, return_objects=False): +def get_file_images(obj, *, return_objects=False): logger.debug("getting images for %s:%s", type(obj), obj) files = None if not obj: diff --git a/dojo/views.py b/dojo/views.py index df65be4d6b..f50784af8d 100644 --- a/dojo/views.py +++ b/dojo/views.py @@ -190,7 +190,7 @@ def manage_files(request, oid, obj_type): @login_required -def protected_serve(request, path, document_root=None, show_indexes=False): +def protected_serve(request, path, document_root=None, *, show_indexes=False): """Serve the file only after verifying the user is supposed to see the file.""" file = FileUpload.objects.get(file=path) if not file: @@ -211,7 +211,7 @@ def protected_serve(request, path, document_root=None, show_indexes=False): return generate_file_response(file) -def access_file(request, fid, oid, obj_type, url=False): +def access_file(request, fid, oid, obj_type, *, url=False): def check_file_belongs_to_object(file, object_manager, object_id): if not object_manager.filter(id=object_id).exists(): raise PermissionDenied diff --git a/ruff.toml b/ruff.toml index 12b556d5cf..662eab981c 100644 --- a/ruff.toml +++ b/ruff.toml @@ -42,7 +42,7 @@ select = [ "YTT", "ASYNC", "S1", "S2", "S5", "S7", "S311", - "FBT001", "FBT003", + "FBT", "A003", "A004", "A005", "A006", "COM", "C4", diff --git a/tests/base_test_class.py b/tests/base_test_class.py index 7fcc3a6f20..6dbae90b67 100644 --- a/tests/base_test_class.py +++ b/tests/base_test_class.py @@ -34,7 +34,7 @@ def wrapper(self, *args, **kwargs): return wrapper -def set_suite_settings(suite, jira=False, github=False, block_execution=False): +def set_suite_settings(suite, *, jira=False, github=False, block_execution=False): if jira: suite.addTest(BaseTestCase("enable_jira")) else: @@ -289,7 +289,7 @@ def element_exists_by_id(self, id): elems = self.driver.find_elements(By.ID, id) return len(elems) > 0 - def change_system_setting(self, id, enable=True): + def change_system_setting(self, id, *, enable=True): logger.info("changing system setting " + id + " enable: " + str(enable)) driver = self.driver driver.get(self.base_url + "system_settings") @@ -330,7 +330,7 @@ def disable_github(self): def enable_github(self): return self.enable_system_setting("id_enable_github") - def set_block_execution(self, block_execution=True): + def set_block_execution(self, *, block_execution=True): # we set the admin user (ourselves) to have block_execution checked # this will force dedupe to happen synchronously, among other things like notifications, rules, ... logger.info(f"setting block execution to: {block_execution}") diff --git a/tests/close_old_findings_dedupe_test.py b/tests/close_old_findings_dedupe_test.py index 007bd3279e..d953b35535 100644 --- a/tests/close_old_findings_dedupe_test.py +++ b/tests/close_old_findings_dedupe_test.py @@ -294,7 +294,7 @@ def test_check_same_product_status(self): self.check_nb_duplicates(4) -def add_close_old_tests_to_suite(suite, jira=False, github=False, block_execution=False): +def add_close_old_tests_to_suite(suite, *, jira=False, github=False, block_execution=False): suite.addTest(BaseTestCase("test_login")) set_suite_settings(suite, jira=jira, github=github, block_execution=block_execution) diff --git a/tests/close_old_findings_test.py b/tests/close_old_findings_test.py index 8e7c355c95..fa3fb27f8f 100644 --- a/tests/close_old_findings_test.py +++ b/tests/close_old_findings_test.py @@ -244,7 +244,7 @@ def test_close_same_product_tests(self): self.assertTrue(self.is_success_message_present(text="1 findings and closed 3 findings")) -def add_close_old_tests_to_suite(suite, jira=False, github=False, block_execution=False): +def add_close_old_tests_to_suite(suite, *, jira=False, github=False, block_execution=False): suite.addTest(BaseTestCase("test_login")) set_suite_settings(suite, jira=jira, github=github, block_execution=block_execution) diff --git a/tests/dedupe_test.py b/tests/dedupe_test.py index 2edc8c0328..59fd72d76f 100644 --- a/tests/dedupe_test.py +++ b/tests/dedupe_test.py @@ -507,7 +507,7 @@ def test_check_service(self): self.check_nb_duplicates(0) -def add_dedupe_tests_to_suite(suite, jira=False, github=False, block_execution=False): +def add_dedupe_tests_to_suite(suite, *, jira=False, github=False, block_execution=False): suite.addTest(BaseTestCase("test_login")) set_suite_settings(suite, jira=jira, github=github, block_execution=block_execution) diff --git a/tests/finding_test.py b/tests/finding_test.py index 4e08744c5e..80adcab577 100644 --- a/tests/finding_test.py +++ b/tests/finding_test.py @@ -506,7 +506,7 @@ def test_list_components(self): self.assertTrue(self.is_element_by_css_selector_present("table")) -def add_finding_tests_to_suite(suite, jira=False, github=False, block_execution=False): +def add_finding_tests_to_suite(suite, *, jira=False, github=False, block_execution=False): suite.addTest(BaseTestCase("test_login")) set_suite_settings(suite, jira=jira, github=github, block_execution=block_execution) diff --git a/tests/product_test.py b/tests/product_test.py index f0bdf0172d..e5839b61cb 100644 --- a/tests/product_test.py +++ b/tests/product_test.py @@ -536,7 +536,7 @@ def test_metrics_dashboard(self): driver.get(self.base_url + "metrics?date=5&view=dashboard") -def add_product_tests_to_suite(suite, jira=False, github=False, block_execution=False): +def add_product_tests_to_suite(suite, *, jira=False, github=False, block_execution=False): # Add each test and the suite to be run # success and failure is output by the test suite.addTest(BaseTestCase("test_login")) diff --git a/unittests/dojo_test_case.py b/unittests/dojo_test_case.py index d22073e273..cacebeb9da 100644 --- a/unittests/dojo_test_case.py +++ b/unittests/dojo_test_case.py @@ -69,6 +69,7 @@ def get_test_admin(self, *args, **kwargs): def system_settings( self, + *, enable_jira=False, enable_jira_web_hook=False, disable_jira_webhook_secret=False, @@ -272,7 +273,7 @@ def get_product_with_empty_jira_project_data(self, product): def get_expected_redirect_product(self, product): return f"/product/{product.id}" - def add_product_jira(self, data, expect_redirect_to=None, expect_200=False): + def add_product_jira(self, data, expect_redirect_to=None, *, expect_200=False): response = self.client.get(reverse("new_product")) # logger.debug('before: JIRA_Project last') @@ -312,7 +313,7 @@ def set_jira_push_all_issues(self, engagement_or_product): jira_project.push_all_issues = True jira_project.save() - def add_product_jira_with_data(self, data, expected_delta_jira_project_db, expect_redirect_to=None, expect_200=False): + def add_product_jira_with_data(self, data, expected_delta_jira_project_db, expect_redirect_to=None, *, expect_200=False): jira_project_count_before = self.db_jira_project_count() response = self.add_product_jira(data, expect_redirect_to=expect_redirect_to, expect_200=expect_200) @@ -321,14 +322,14 @@ def add_product_jira_with_data(self, data, expected_delta_jira_project_db, expec return response - def add_product_with_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def add_product_with_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.add_product_jira_with_data(self.get_new_product_with_jira_project_data(), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def add_product_without_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def add_product_without_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): logger.debug("adding product without jira project") return self.add_product_jira_with_data(self.get_new_product_without_jira_project_data(), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def edit_product_jira(self, product, data, expect_redirect_to=None, expect_200=False): + def edit_product_jira(self, product, data, expect_redirect_to=None, *, expect_200=False): response = self.client.get(reverse("edit_product", args=(product.id, ))) # logger.debug('before: JIRA_Project last') @@ -358,13 +359,13 @@ def edit_jira_project_for_product_with_data(self, product, data, expected_delta_ self.assertEqual(self.db_jira_project_count(), jira_project_count_before + expected_delta_jira_project_db) return response - def edit_jira_project_for_product(self, product, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def edit_jira_project_for_product(self, product, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.edit_jira_project_for_product_with_data(product, self.get_product_with_jira_project_data(product), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def edit_jira_project_for_product2(self, product, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def edit_jira_project_for_product2(self, product, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.edit_jira_project_for_product_with_data(product, self.get_product_with_jira_project_data2(product), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def empty_jira_project_for_product(self, product, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def empty_jira_project_for_product(self, product, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): logger.debug("empty jira project for product") jira_project_count_before = self.db_jira_project_count() @@ -427,7 +428,7 @@ def get_epic_issues(self, engagement): return response.get("issues", []) # Determine whether an issue is in an epic - def assert_jira_issue_in_epic(self, finding, engagement, issue_in_epic=True): + def assert_jira_issue_in_epic(self, finding, engagement, *, issue_in_epic=True): instance = jira_helper.get_jira_instance(engagement) jira = jira_helper.get_jira_connection(instance) epic_id = jira_helper.get_jira_issue_key(engagement) @@ -499,7 +500,7 @@ def get_results_by_id(self, results: list, object_id: int) -> dict | None: return item return None - def import_scan_with_params(self, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", active=True, verified=False, + def import_scan_with_params(self, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", *, active=True, verified=False, push_to_jira=None, endpoint_to_add=None, tags=None, close_old_findings=False, group_by=None, engagement_name=None, product_name=None, product_type_name=None, auto_create_context=None, expected_http_status_code=201, test_title=None, scan_date=None, service=None, forceActive=True, forceVerified=True): @@ -553,7 +554,7 @@ def import_scan_with_params(self, filename, scan_type="ZAP Scan", engagement=1, return self.import_scan(payload, expected_http_status_code) - def reimport_scan_with_params(self, test_id, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", active=True, verified=False, push_to_jira=None, + def reimport_scan_with_params(self, test_id, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", *, active=True, verified=False, push_to_jira=None, tags=None, close_old_findings=True, group_by=None, engagement_name=None, scan_date=None, product_name=None, product_type_name=None, auto_create_context=None, expected_http_status_code=201, test_title=None): with open(get_unit_tests_path() + "/" + filename, encoding="utf-8") as testfile: @@ -602,7 +603,7 @@ def reimport_scan_with_params(self, test_id, filename, scan_type="ZAP Scan", eng return self.reimport_scan(payload, expected_http_status_code=expected_http_status_code) - def endpoint_meta_import_scan_with_params(self, filename, product=1, product_name=None, + def endpoint_meta_import_scan_with_params(self, filename, product=1, product_name=None, *, create_endpoints=True, create_tags=True, create_dojo_meta=True, expected_http_status_code=201): with open(get_unit_tests_path() + "/" + filename, encoding="utf-8") as testfile: diff --git a/unittests/test_apiv2_scan_import_options.py b/unittests/test_apiv2_scan_import_options.py index 67548898b7..f7c060506c 100644 --- a/unittests/test_apiv2_scan_import_options.py +++ b/unittests/test_apiv2_scan_import_options.py @@ -31,7 +31,7 @@ def setUp(self): test.test_type = Test_Type.objects.create(name="some other test tool") test.save() - def import_zap_scan(self, upload_empty_scan=False): + def import_zap_scan(self, *, upload_empty_scan=False): with open("tests/zap_sample.xml", encoding="utf-8") as file: if upload_empty_scan: tested_file = SimpleUploadedFile("zap_sample.xml", self.EMPTY_ZAP_SCAN.encode("utf-8")) diff --git a/unittests/test_deduplication_logic.py b/unittests/test_deduplication_logic.py index 319c076131..868f69716a 100644 --- a/unittests/test_deduplication_logic.py +++ b/unittests/test_deduplication_logic.py @@ -1208,7 +1208,7 @@ def copy_with_endpoints_without_dedupe_and_reset_finding(self, id): # return saved new finding and reloaded existing finding return finding_new, finding_org - def copy_and_reset_finding_add_endpoints(self, id, static=False, dynamic=True): + def copy_and_reset_finding_add_endpoints(self, id, *, static=False, dynamic=True): finding_new, finding_org = self.copy_and_reset_finding(id=id) # remove file_path and line as we now have endpoints finding_new.file_path = None @@ -1239,7 +1239,7 @@ def copy_and_reset_engagement(self, id): # return unsaved new finding and reloaded existing finding return new, Engagement.objects.get(id=id) - def assert_finding(self, finding, not_pk=None, duplicate=False, duplicate_finding_id=None, hash_code=None, not_hash_code=None): + def assert_finding(self, finding, not_pk=None, *, duplicate=False, duplicate_finding_id=None, hash_code=None, not_hash_code=None): if hash_code: self.assertEqual(finding.hash_code, hash_code) @@ -1272,7 +1272,7 @@ def create_new_test_and_engagment_from_finding(self, finding): test_new.save() return test_new, eng_new - def enable_dedupe(self, enable=True): + def enable_dedupe(self, *, enable=True): system_settings = System_Settings.objects.get() system_settings.enable_deduplication = enable system_settings.save() diff --git a/unittests/test_endpoint_meta_import.py b/unittests/test_endpoint_meta_import.py index d159dbd4f2..e00bd9099b 100644 --- a/unittests/test_endpoint_meta_import.py +++ b/unittests/test_endpoint_meta_import.py @@ -204,7 +204,7 @@ def endpoint_meta_import_ui(self, product, payload): response = self.client_ui.post(reverse("import_endpoint_meta", args=(product, )), payload) self.assertEqual(302, response.status_code, response.content[:1000]) - def endpoint_meta_import_scan_with_params_ui(self, filename, product=1, create_endpoints=True, + def endpoint_meta_import_scan_with_params_ui(self, filename, product=1, *, create_endpoints=True, create_tags=True, create_dojo_meta=True, expected_http_status_code=201): with open(get_unit_tests_path() + "/" + filename, encoding="utf-8") as testfile: payload = { diff --git a/unittests/test_import_reimport.py b/unittests/test_import_reimport.py index 02548ccb57..ca94e2d980 100644 --- a/unittests/test_import_reimport.py +++ b/unittests/test_import_reimport.py @@ -1807,7 +1807,7 @@ def reimport_scan_ui(self, test, payload): test = Test.objects.get(id=response.url.split("/")[-1]) return {"test": test.id} - def import_scan_with_params_ui(self, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", active=True, verified=False, + def import_scan_with_params_ui(self, filename, scan_type="ZAP Scan", engagement=1, minimum_severity="Low", *, active=True, verified=False, push_to_jira=None, endpoint_to_add=None, tags=None, close_old_findings=False, scan_date=None, service=None, forceActive=False, forceVerified=False): @@ -1852,7 +1852,7 @@ def import_scan_with_params_ui(self, filename, scan_type="ZAP Scan", engagement= return self.import_scan_ui(engagement, payload) - def reimport_scan_with_params_ui(self, test_id, filename, scan_type="ZAP Scan", minimum_severity="Low", active=True, verified=False, push_to_jira=None, tags=None, close_old_findings=True, scan_date=None): + def reimport_scan_with_params_ui(self, test_id, filename, scan_type="ZAP Scan", minimum_severity="Low", *, active=True, verified=False, push_to_jira=None, tags=None, close_old_findings=True, scan_date=None): # Mimic old functionality for active/verified to avoid breaking tests activePayload = "force_to_true" if not active: diff --git a/unittests/test_jira_config_engagement.py b/unittests/test_jira_config_engagement.py index 59adb4f319..ac9424e1a8 100644 --- a/unittests/test_jira_config_engagement.py +++ b/unittests/test_jira_config_engagement.py @@ -137,7 +137,7 @@ def get_expected_redirect_engagement(self, engagement): def get_expected_redirect_edit_engagement(self, engagement): return f"/engagement/edit/{engagement.id}" - def add_engagement_jira(self, data, expect_redirect_to=None, expect_200=False): + def add_engagement_jira(self, data, expect_redirect_to=None, *, expect_200=False): response = self.client.get(reverse("new_eng_for_prod", args=(self.product_id, ))) # logger.debug('before: JIRA_Project last') @@ -170,7 +170,7 @@ def add_engagement_jira(self, data, expect_redirect_to=None, expect_200=False): return engagement - def add_engagement_jira_with_data(self, data, expected_delta_jira_project_db, expect_redirect_to=None, expect_200=False): + def add_engagement_jira_with_data(self, data, expected_delta_jira_project_db, expect_redirect_to=None, *, expect_200=False): jira_project_count_before = self.db_jira_project_count() response = self.add_engagement_jira(data, expect_redirect_to=expect_redirect_to, expect_200=expect_200) @@ -179,16 +179,16 @@ def add_engagement_jira_with_data(self, data, expected_delta_jira_project_db, ex return response - def add_engagement_with_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def add_engagement_with_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.add_engagement_jira_with_data(self.get_new_engagement_with_jira_project_data(), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def add_engagement_without_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def add_engagement_without_jira_project(self, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.add_engagement_jira_with_data(self.get_new_engagement_without_jira_project_data(), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def add_engagement_with_jira_project_and_epic_mapping(self, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def add_engagement_with_jira_project_and_epic_mapping(self, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.add_engagement_jira_with_data(self.get_new_engagement_with_jira_project_data_and_epic_mapping(), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def edit_engagement_jira(self, engagement, data, expect_redirect_to=None, expect_200=False): + def edit_engagement_jira(self, engagement, data, expect_redirect_to=None, *, expect_200=False): response = self.client.get(reverse("edit_engagement", args=(engagement.id, ))) # logger.debug('before: JIRA_Project last') @@ -217,13 +217,13 @@ def edit_jira_project_for_engagement_with_data(self, engagement, data, expected_ self.assertEqual(self.db_jira_project_count(), jira_project_count_before + expected_delta_jira_project_db) return response - def edit_jira_project_for_engagement(self, engagement, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def edit_jira_project_for_engagement(self, engagement, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.edit_jira_project_for_engagement_with_data(engagement, self.get_engagement_with_jira_project_data(engagement), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def edit_jira_project_for_engagement2(self, engagement, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def edit_jira_project_for_engagement2(self, engagement, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.edit_jira_project_for_engagement_with_data(engagement, self.get_engagement_with_jira_project_data2(engagement), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) - def empty_jira_project_for_engagement(self, engagement, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False, expect_error=False): + def empty_jira_project_for_engagement(self, engagement, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False, expect_error=False): jira_project_count_before = self.db_jira_project_count() if not expect_redirect_to and not expect_200: diff --git a/unittests/test_jira_config_engagement_epic.py b/unittests/test_jira_config_engagement_epic.py index 7b6b753416..2e208eee62 100644 --- a/unittests/test_jira_config_engagement_epic.py +++ b/unittests/test_jira_config_engagement_epic.py @@ -64,7 +64,7 @@ def get_new_engagement_with_jira_project_data_and_epic_mapping(self): "jira-epic-form-push_to_jira": "on", } - def add_engagement_with_jira_project_and_epic_mapping(self, expected_delta_jira_project_db=0, expect_redirect_to=None, expect_200=False): + def add_engagement_with_jira_project_and_epic_mapping(self, expected_delta_jira_project_db=0, expect_redirect_to=None, *, expect_200=False): return self.add_engagement_jira_with_data(self.get_new_engagement_with_jira_project_data_and_epic_mapping(), expected_delta_jira_project_db, expect_redirect_to=expect_redirect_to, expect_200=expect_200) def test_add_engagement_with_jira_project_and_epic_mapping(self): diff --git a/unittests/test_product_grading.py b/unittests/test_product_grading.py index bc1aa557d3..ad16038801 100644 --- a/unittests/test_product_grading.py +++ b/unittests/test_product_grading.py @@ -36,10 +36,10 @@ def setUp(self): def tearDown(self): self.product.delete() - def create_finding_on_test(self, severity, verified=True): + def create_finding_on_test(self, severity, *, verified=True): Finding.objects.create(title=str(uuid.uuid4()), severity=severity, verified=verified, **self.default_finding_options) - def create_single_critical_and_assert_grade(self, expected_grade, verified=False): + def create_single_critical_and_assert_grade(self, expected_grade, *, verified=False): self.assertIsNone(self.product.prod_numeric_grade) # Add a single critical finding self.create_finding_on_test(severity="Critical", verified=verified) diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index fa30780c92..5b40fd1e83 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -388,7 +388,7 @@ def check_schema(self, schema, obj): # print(vars(schema_checker)) schema_checker.check(self.schema, obj) - def check_schema_response(self, method, status_code, response, detail=False): + def check_schema_response(self, method, status_code, response, *, detail=False): detail_path = "{id}/" if detail else "" endpoints_schema = self.schema["paths"][format_url(f"/{self.endpoint_path}/{detail_path}")] schema = endpoints_schema[method]["responses"][status_code]["content"]["application/json"]["schema"] diff --git a/unittests/test_tags.py b/unittests/test_tags.py index 3f93129fa8..4f8c2cc128 100644 --- a/unittests/test_tags.py +++ b/unittests/test_tags.py @@ -257,7 +257,7 @@ def setUp(self, *args, **kwargs): def _convert_instance_tags_to_list(self, instance) -> list: return [tag.name for tag in instance.tags.all()] - def _import_and_return_objects(self, test_id=None, reimport=False, tags=None) -> dict: + def _import_and_return_objects(self, test_id=None, *, reimport=False, tags=None) -> dict: # Import some findings to create all objects engagement = self.create_engagement("Inherited Tags Engagement", self.product) if reimport: diff --git a/unittests/test_user_validators.py b/unittests/test_user_validators.py index 8044202c07..e91e93550a 100644 --- a/unittests/test_user_validators.py +++ b/unittests/test_user_validators.py @@ -27,6 +27,7 @@ def set_policy( self, minimum_password_length=0, maximum_password_length=50, + *, number_character_required=False, special_character_required=False, lowercase_character_required=False, diff --git a/unittests/tools/test_asff_parser.py b/unittests/tools/test_asff_parser.py index fe01bb06cf..b170fd010d 100644 --- a/unittests/tools/test_asff_parser.py +++ b/unittests/tools/test_asff_parser.py @@ -16,7 +16,7 @@ def load_sample_json(self, file_name): with open(sample_path(file_name), encoding="utf-8") as file: return json.load(file) - def common_check_finding(self, finding, data, index, guarddutydate=False): + def common_check_finding(self, finding, data, index, *, guarddutydate=False): parser = AsffParser() resource_arns = parser.get_item_resource_arns(data[index]) resource_arn_strings = ", ".join(resource_arns)