diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py index 6bc18b5115f..fe3e4c575dd 100644 --- a/dojo/api_v2/serializers.py +++ b/dojo/api_v2/serializers.py @@ -5,6 +5,7 @@ import re import time from datetime import datetime +from typing import TYPE_CHECKING import six import tagulous @@ -36,7 +37,6 @@ from dojo.finding.queries import get_authorized_findings from dojo.group.utils import get_auth_group_name from dojo.importers.auto_create_context import AutoCreateContextManager -from dojo.importers.base_importer import BaseImporter from dojo.importers.default_importer import DefaultImporter from dojo.importers.default_reimporter import DefaultReImporter from dojo.models import ( @@ -129,6 +129,9 @@ from dojo.utils import is_scan_file_too_large from dojo.validators import ImporterFileExtensionValidator, tag_validator +if TYPE_CHECKING: + from dojo.importers.base_importer import BaseImporter + logger = logging.getLogger(__name__) deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") diff --git a/dojo/engagement/views.py b/dojo/engagement/views.py index 9ecdabfdd9b..b806b60be77 100644 --- a/dojo/engagement/views.py +++ b/dojo/engagement/views.py @@ -9,6 +9,7 @@ from pathlib import Path from tempfile import NamedTemporaryFile from time import strftime +from typing import TYPE_CHECKING import pghistory from django.conf import settings @@ -71,7 +72,6 @@ TypedNoteForm, UploadThreatForm, ) -from dojo.importers.base_importer import BaseImporter from dojo.importers.default_importer import DefaultImporter from dojo.models import ( Check_List, @@ -119,6 +119,9 @@ redirect_to_return_url_or_else, ) +if TYPE_CHECKING: + from dojo.importers.base_importer import BaseImporter + logger = logging.getLogger(__name__) diff --git a/dojo/finding_group/views.py b/dojo/finding_group/views.py index 451d4dcd720..92a4aa3f0d3 100644 --- a/dojo/finding_group/views.py +++ b/dojo/finding_group/views.py @@ -1,11 +1,11 @@ import logging +from typing import TYPE_CHECKING from django.contrib import messages from django.contrib.admin.utils import NestedObjects from django.core.paginator import Page, Paginator from django.db.models import Count, Min, Q, QuerySet, Subquery from django.db.utils import DEFAULT_DB_ALIAS -from django.http import HttpRequest from django.http.response import HttpResponse, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, render from django.urls.base import reverse @@ -27,6 +27,9 @@ from dojo.product.queries import get_authorized_products from dojo.utils import Product_Tab, add_breadcrumb, get_page_items, get_setting, get_system_setting, get_words_for_field +if TYPE_CHECKING: + from django.http import HttpRequest + logger = logging.getLogger(__name__) diff --git a/dojo/group/views.py b/dojo/group/views.py index df1e6e815b2..5c220a755d4 100644 --- a/dojo/group/views.py +++ b/dojo/group/views.py @@ -1,4 +1,5 @@ import logging +from typing import TYPE_CHECKING from django.contrib import messages from django.contrib.admin.utils import NestedObjects @@ -7,7 +8,6 @@ from django.core.exceptions import PermissionDenied from django.db import DEFAULT_DB_ALIAS from django.db.models.deletion import RestrictedError -from django.db.models.query import QuerySet from django.http import HttpRequest, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse @@ -49,6 +49,9 @@ redirect_to_return_url_or_else, ) +if TYPE_CHECKING: + from django.db.models.query import QuerySet + logger = logging.getLogger(__name__) diff --git a/dojo/importers/auto_create_context.py b/dojo/importers/auto_create_context.py index 26d37ae65b0..451105e202e 100644 --- a/dojo/importers/auto_create_context.py +++ b/dojo/importers/auto_create_context.py @@ -1,10 +1,9 @@ import logging from datetime import datetime, timedelta -from typing import Any +from typing import TYPE_CHECKING, Any from crum import get_current_user from django.db import transaction -from django.http.request import QueryDict from django.utils import timezone from dojo.models import ( @@ -18,6 +17,9 @@ ) from dojo.utils import get_last_object_or_none, get_object_or_none +if TYPE_CHECKING: + from django.http.request import QueryDict + logger = logging.getLogger(__name__) deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") diff --git a/dojo/importers/base_importer.py b/dojo/importers/base_importer.py index f544d7f9552..efc48fb0624 100644 --- a/dojo/importers/base_importer.py +++ b/dojo/importers/base_importer.py @@ -1,13 +1,12 @@ import base64 import logging import time -from collections.abc import Iterable +from typing import TYPE_CHECKING from celery import chord, group from django.conf import settings from django.core.exceptions import ValidationError from django.core.files.base import ContentFile -from django.core.files.uploadedfile import TemporaryUploadedFile from django.db import IntegrityError from django.urls import reverse from django.utils.timezone import make_aware @@ -37,9 +36,15 @@ from dojo.notifications.helper import create_notification from dojo.tag_utils import bulk_add_tags_to_instances from dojo.tools.factory import get_parser -from dojo.tools.parser_test import ParserTest from dojo.utils import max_safe +if TYPE_CHECKING: + from collections.abc import Iterable + + from django.core.files.uploadedfile import TemporaryUploadedFile + + from dojo.tools.parser_test import ParserTest + logger = logging.getLogger(__name__) diff --git a/dojo/importers/default_importer.py b/dojo/importers/default_importer.py index 35fe6712387..9129968423f 100644 --- a/dojo/importers/default_importer.py +++ b/dojo/importers/default_importer.py @@ -1,7 +1,7 @@ import logging +from typing import TYPE_CHECKING from django.conf import settings -from django.core.files.uploadedfile import TemporaryUploadedFile from django.core.serializers import serialize from django.db.models.query_utils import Q from django.urls import reverse @@ -21,6 +21,9 @@ from dojo.utils import get_full_url, perform_product_grading from dojo.validators import clean_tags +if TYPE_CHECKING: + from django.core.files.uploadedfile import TemporaryUploadedFile + logger = logging.getLogger(__name__) deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") diff --git a/dojo/importers/default_reimporter.py b/dojo/importers/default_reimporter.py index 47ce8c61acd..afd493407e9 100644 --- a/dojo/importers/default_reimporter.py +++ b/dojo/importers/default_reimporter.py @@ -1,7 +1,7 @@ import logging +from typing import TYPE_CHECKING from django.conf import settings -from django.core.files.uploadedfile import TemporaryUploadedFile from django.core.serializers import serialize from django.db.models.query_utils import Q @@ -26,6 +26,9 @@ from dojo.utils import perform_product_grading from dojo.validators import clean_tags +if TYPE_CHECKING: + from django.core.files.uploadedfile import TemporaryUploadedFile + logger = logging.getLogger(__name__) deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") diff --git a/dojo/importers/options.py b/dojo/importers/options.py index 3b7c624235d..bacd8f83a13 100644 --- a/dojo/importers/options.py +++ b/dojo/importers/options.py @@ -1,9 +1,8 @@ import logging -from collections.abc import Callable from datetime import datetime from functools import wraps from pprint import pformat as pp -from typing import Any +from typing import TYPE_CHECKING, Any from django.contrib.auth.models import User from django.db.models import Model @@ -22,6 +21,9 @@ ) from dojo.utils import get_current_user, is_finding_groups_enabled +if TYPE_CHECKING: + from collections.abc import Callable + logger = logging.getLogger(__name__) diff --git a/dojo/metrics/utils.py b/dojo/metrics/utils.py index 3c7750e5130..3d7fbc49064 100644 --- a/dojo/metrics/utils.py +++ b/dojo/metrics/utils.py @@ -1,18 +1,16 @@ import logging import operator -from collections.abc import Callable from datetime import date, datetime, timedelta from enum import Enum from functools import partial -from typing import Any, NamedTuple, TypeVar +from typing import TYPE_CHECKING, Any, NamedTuple, TypeVar from dateutil.relativedelta import relativedelta from django.contrib import messages from django.db.models import Case, Count, F, IntegerField, Q, Sum, Value, When from django.db.models.functions import Coalesce, ExtractDay, Now, TruncMonth, TruncWeek from django.db.models.query import QuerySet -from django.http import HttpRequest from django.utils import timezone from django.utils.translation import gettext as _ @@ -32,6 +30,11 @@ queryset_check, ) +if TYPE_CHECKING: + from collections.abc import Callable + + from django.http import HttpRequest + logger = logging.getLogger(__name__) diff --git a/dojo/query_utils.py b/dojo/query_utils.py index b14c4bc03fd..6e7687581f4 100644 --- a/dojo/query_utils.py +++ b/dojo/query_utils.py @@ -1,5 +1,9 @@ +from typing import TYPE_CHECKING + from django.db.models import Count, IntegerField, Subquery -from django.db.models.query import QuerySet + +if TYPE_CHECKING: + from django.db.models.query import QuerySet def build_count_subquery(model_qs: QuerySet, group_field: str) -> Subquery: diff --git a/dojo/risk_acceptance/api.py b/dojo/risk_acceptance/api.py index 2fdaadf0afb..6073a3fbcee 100644 --- a/dojo/risk_acceptance/api.py +++ b/dojo/risk_acceptance/api.py @@ -1,7 +1,6 @@ from abc import ABC, abstractmethod -from typing import NamedTuple +from typing import TYPE_CHECKING, NamedTuple -from django.db.models import QuerySet from django.utils import timezone from drf_spectacular.utils import extend_schema from rest_framework import serializers, status @@ -14,6 +13,9 @@ from dojo.engagement.queries import get_authorized_engagements from dojo.models import Risk_Acceptance, User, Vulnerability_Id +if TYPE_CHECKING: + from django.db.models import QuerySet + AcceptedRisk = NamedTuple("AcceptedRisk", (("vulnerability_id", str), ("justification", str), ("accepted_by", str))) diff --git a/dojo/system_settings/views.py b/dojo/system_settings/views.py index b0bce9d52d3..ae39a0e9ec0 100644 --- a/dojo/system_settings/views.py +++ b/dojo/system_settings/views.py @@ -1,9 +1,9 @@ import logging +from typing import TYPE_CHECKING from django.conf import settings from django.contrib import messages from django.core.exceptions import PermissionDenied -from django.http import HttpRequest, HttpResponse from django.shortcuts import render from django.views import View @@ -11,6 +11,9 @@ from dojo.models import System_Settings from dojo.utils import add_breadcrumb, get_celery_worker_status +if TYPE_CHECKING: + from django.http import HttpRequest, HttpResponse + logger = logging.getLogger(__name__) diff --git a/dojo/test/views.py b/dojo/test/views.py index a05c0b3b660..3c5e597302a 100644 --- a/dojo/test/views.py +++ b/dojo/test/views.py @@ -5,6 +5,7 @@ import time from datetime import datetime, timedelta from functools import reduce +from typing import TYPE_CHECKING import pghistory from django.contrib import messages @@ -42,7 +43,6 @@ TestForm, TypedNoteForm, ) -from dojo.importers.base_importer import BaseImporter from dojo.importers.default_reimporter import DefaultReImporter from dojo.models import ( BurpRawRequestResponse, @@ -84,6 +84,9 @@ redirect_to_return_url_or_else, ) +if TYPE_CHECKING: + from dojo.importers.base_importer import BaseImporter + logger = logging.getLogger(__name__) parse_logger = logging.getLogger("dojo") deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") diff --git a/dojo/tools/appcheck_web_application_scanner/engines/appcheck.py b/dojo/tools/appcheck_web_application_scanner/engines/appcheck.py index b34931d0f8f..d6571f2b537 100644 --- a/dojo/tools/appcheck_web_application_scanner/engines/appcheck.py +++ b/dojo/tools/appcheck_web_application_scanner/engines/appcheck.py @@ -1,8 +1,11 @@ import re +from typing import TYPE_CHECKING -from dojo.models import Finding from dojo.tools.appcheck_web_application_scanner.engines.base import BaseEngineParser +if TYPE_CHECKING: + from dojo.models import Finding + class AppCheckScanningEngineParser(BaseEngineParser): diff --git a/dojo/tools/appcheck_web_application_scanner/engines/nmap.py b/dojo/tools/appcheck_web_application_scanner/engines/nmap.py index 3fba10e455d..7ba99c715cd 100644 --- a/dojo/tools/appcheck_web_application_scanner/engines/nmap.py +++ b/dojo/tools/appcheck_web_application_scanner/engines/nmap.py @@ -1,8 +1,10 @@ -from typing import Any +from typing import TYPE_CHECKING, Any -from dojo.models import Endpoint from dojo.tools.appcheck_web_application_scanner.engines.base import BaseEngineParser +if TYPE_CHECKING: + from dojo.models import Endpoint + class NmapScanningEngineParser(BaseEngineParser): diff --git a/dojo/tools/blackduck/importer.py b/dojo/tools/blackduck/importer.py index 7273770c6ec..b38dd3c3545 100644 --- a/dojo/tools/blackduck/importer.py +++ b/dojo/tools/blackduck/importer.py @@ -4,11 +4,14 @@ import zipfile from abc import ABC, abstractmethod from collections import defaultdict -from collections.abc import Iterable -from pathlib import Path +from typing import TYPE_CHECKING from .model import BlackduckFinding +if TYPE_CHECKING: + from collections.abc import Iterable + from pathlib import Path + class Importer(ABC): @abstractmethod diff --git a/dojo/tools/blackduck_binary_analysis/importer.py b/dojo/tools/blackduck_binary_analysis/importer.py index 3e737fb4dd0..573a64c1d19 100644 --- a/dojo/tools/blackduck_binary_analysis/importer.py +++ b/dojo/tools/blackduck_binary_analysis/importer.py @@ -2,11 +2,14 @@ import io from abc import ABC, abstractmethod from collections import defaultdict -from collections.abc import Iterable from pathlib import Path +from typing import TYPE_CHECKING from .model import BlackduckBinaryAnalysisFinding +if TYPE_CHECKING: + from collections.abc import Iterable + class Importer(ABC): @abstractmethod diff --git a/dojo/tools/blackduck_component_risk/importer.py b/dojo/tools/blackduck_component_risk/importer.py index 56f04f73eb0..8da1a86eae9 100644 --- a/dojo/tools/blackduck_component_risk/importer.py +++ b/dojo/tools/blackduck_component_risk/importer.py @@ -2,7 +2,10 @@ import io import logging import zipfile -from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path logger = logging.getLogger(__name__) diff --git a/dojo/tools/fortify/fpr_parser.py b/dojo/tools/fortify/fpr_parser.py index f3fb961e02f..943d837052a 100644 --- a/dojo/tools/fortify/fpr_parser.py +++ b/dojo/tools/fortify/fpr_parser.py @@ -1,13 +1,16 @@ import logging import re import zipfile -from xml.etree.ElementTree import Element +from typing import TYPE_CHECKING from defusedxml import ElementTree from dojo.models import Finding, Test from dojo.tools.fortify.fortify_data import DescriptionData, RuleData, SnippetData, VulnerabilityData +if TYPE_CHECKING: + from xml.etree.ElementTree import Element + logger = logging.getLogger(__name__) diff --git a/dojo/tools/h1/parser.py b/dojo/tools/h1/parser.py index 288cf897c61..28b1a5ef566 100644 --- a/dojo/tools/h1/parser.py +++ b/dojo/tools/h1/parser.py @@ -4,16 +4,18 @@ import json from contextlib import suppress from datetime import datetime -from typing import ClassVar +from typing import TYPE_CHECKING, ClassVar import cvss.parser from cvss.cvss3 import CVSS3 from dateutil import parser as date_parser -from django.core.files.uploadedfile import TemporaryUploadedFile from django.utils import timezone from dojo.models import Finding, Test +if TYPE_CHECKING: + from django.core.files.uploadedfile import TemporaryUploadedFile + __author__ = "Kirill Gotsman" diff --git a/dojo/tools/openvas/parser_v2/csv_parser.py b/dojo/tools/openvas/parser_v2/csv_parser.py index 23a8cd9d5ca..b73302899b6 100644 --- a/dojo/tools/openvas/parser_v2/csv_parser.py +++ b/dojo/tools/openvas/parser_v2/csv_parser.py @@ -1,10 +1,10 @@ import csv import io import logging +from typing import TYPE_CHECKING from dateutil.parser import parse as parse_date -from dojo.models import Finding from dojo.tools.openvas.parser_v2.common import ( OpenVASFindingAuxData, cleanup_openvas_text, @@ -14,6 +14,9 @@ setup_finding, ) +if TYPE_CHECKING: + from dojo.models import Finding + logger = logging.getLogger(__name__) diff --git a/dojo/tools/openvas/parser_v2/xml_parser.py b/dojo/tools/openvas/parser_v2/xml_parser.py index 60facc087bf..95991208c75 100644 --- a/dojo/tools/openvas/parser_v2/xml_parser.py +++ b/dojo/tools/openvas/parser_v2/xml_parser.py @@ -1,10 +1,10 @@ import contextlib import logging +from typing import TYPE_CHECKING from xml.dom import NamespaceErr from defusedxml import ElementTree -from dojo.models import Finding from dojo.tools.openvas.parser_v2.common import ( OpenVASFindingAuxData, cleanup_openvas_text, @@ -15,6 +15,9 @@ ) from dojo.utils import parse_cvss_data +if TYPE_CHECKING: + from dojo.models import Finding + logger = logging.getLogger(__name__) diff --git a/dojo/tools/reversinglabs_spectraassure/parser.py b/dojo/tools/reversinglabs_spectraassure/parser.py index f9ec605fe8b..ed9b1675777 100644 --- a/dojo/tools/reversinglabs_spectraassure/parser.py +++ b/dojo/tools/reversinglabs_spectraassure/parser.py @@ -1,11 +1,13 @@ # noqa: RUF100 import hashlib import logging -from typing import Any +from typing import TYPE_CHECKING, Any from dojo.models import Finding from dojo.tools.reversinglabs_spectraassure.rlJsonInfo import RlJsonInfo -from dojo.tools.reversinglabs_spectraassure.rlJsonInfo.cve_info_node import CveInfoNode + +if TYPE_CHECKING: + from dojo.tools.reversinglabs_spectraassure.rlJsonInfo.cve_info_node import CveInfoNode logger = logging.getLogger(__name__) diff --git a/dojo/tools/reversinglabs_spectraassure/rlJsonInfo/cve_info_node.py b/dojo/tools/reversinglabs_spectraassure/rlJsonInfo/cve_info_node.py index 8bab3428a94..14d431711b6 100644 --- a/dojo/tools/reversinglabs_spectraassure/rlJsonInfo/cve_info_node.py +++ b/dojo/tools/reversinglabs_spectraassure/rlJsonInfo/cve_info_node.py @@ -1,5 +1,8 @@ -import datetime import logging +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import datetime logger = logging.getLogger(__name__) diff --git a/dojo/tools/whitehat_sentinel/parser.py b/dojo/tools/whitehat_sentinel/parser.py index 651dba4f7dd..1a55a43ddcc 100644 --- a/dojo/tools/whitehat_sentinel/parser.py +++ b/dojo/tools/whitehat_sentinel/parser.py @@ -173,7 +173,7 @@ def __remove_paragraph_tags(self, html_string): def _convert_attack_vectors_to_endpoints( self, attack_vectors: list[dict], - ) -> list["Endpoint"]: + ) -> list[Endpoint]: """ Takes a list of Attack Vectors dictionaries from the WhiteHat vuln API and converts them to Defect Dojo Endpoints diff --git a/dojo/utils.py b/dojo/utils.py index 33e99846b81..c5e023cab8e 100644 --- a/dojo/utils.py +++ b/dojo/utils.py @@ -10,11 +10,11 @@ import re import time from calendar import monthrange -from collections.abc import Callable from datetime import date, datetime, timedelta from functools import cached_property from math import pi, sqrt from pathlib import Path +from typing import TYPE_CHECKING import bleach import crum @@ -77,6 +77,9 @@ ) from dojo.notifications.helper import create_notification +if TYPE_CHECKING: + from collections.abc import Callable + logger = logging.getLogger(__name__) deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") WEEKDAY_FRIDAY = 4 # date.weekday() starts with 0 @@ -246,7 +249,7 @@ def match_finding_to_existing_findings(finding, product=None, engagement=None, t return None -def count_findings(findings: QuerySet) -> tuple[dict["Product", list[int]], dict[str, int]]: +def count_findings(findings: QuerySet) -> tuple[dict[Product, list[int]], dict[str, int]]: agg = ( findings.values(prod_id=F("test__engagement__product_id")) .annotate( diff --git a/dojo/validators.py b/dojo/validators.py index 4c7c4f29d24..37ac71e64a9 100644 --- a/dojo/validators.py +++ b/dojo/validators.py @@ -1,6 +1,6 @@ import logging import re -from collections.abc import Callable +from typing import TYPE_CHECKING import cvss from cvss import CVSS2, CVSS3, CVSS4 @@ -8,6 +8,9 @@ from django.core.exceptions import ValidationError from django.core.validators import FileExtensionValidator +if TYPE_CHECKING: + from collections.abc import Callable + logger = logging.getLogger(__name__) TAG_PATTERN = re.compile(r'[ ,\'"]') # Matches spaces, commas, single quotes, double quotes diff --git a/ruff.toml b/ruff.toml index 942bd47a00a..de7d84e4034 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,5 @@ -# Always generate Python 3.13-compatible code. -target-version = "py313" +# Always generate Python 3.14-compatible code. +target-version = "py314" # Same as Black. line-length = 120