@@ -2020,6 +2020,32 @@ def filter_mitigated_on(self, queryset, name, value):
20202020 return queryset .filter (mitigated = value )
20212021
20222022
2023+ def get_finding_group_queryset_for_context (pid = None , eid = None , tid = None ):
2024+ """
2025+ Helper function to build finding group queryset based on context hierarchy.
2026+ Context priority: test > engagement > product > global
2027+
2028+ Args:
2029+ pid: Product ID (least specific)
2030+ eid: Engagement ID
2031+ tid: Test ID (most specific)
2032+
2033+ Returns:
2034+ QuerySet of Finding_Group filtered by context
2035+ """
2036+ if tid is not None :
2037+ # Most specific: filter by test
2038+ return Finding_Group .objects .filter (test_id = tid ).only ("id" , "name" )
2039+ if eid is not None :
2040+ # Filter by engagement's tests
2041+ return Finding_Group .objects .filter (test__engagement_id = eid ).only ("id" , "name" )
2042+ if pid is not None :
2043+ # Filter by product's tests
2044+ return Finding_Group .objects .filter (test__engagement__product_id = pid ).only ("id" , "name" )
2045+ # Global: return all (authorization will be applied separately)
2046+ return Finding_Group .objects .all ().only ("id" , "name" )
2047+
2048+
20232049class FindingFilterWithoutObjectLookups (FindingFilterHelper , FindingTagStringFilter ):
20242050 test__engagement__product__prod_type = NumberFilter (widget = HiddenInput ())
20252051 test__engagement__product = NumberFilter (widget = HiddenInput ())
@@ -2111,20 +2137,45 @@ class Meta:
21112137 def __init__ (self , * args , ** kwargs ):
21122138 self .user = None
21132139 self .pid = None
2140+ self .eid = None
2141+ self .tid = None
21142142 if "user" in kwargs :
21152143 self .user = kwargs .pop ("user" )
21162144
21172145 if "pid" in kwargs :
21182146 self .pid = kwargs .pop ("pid" )
2147+ if "eid" in kwargs :
2148+ self .eid = kwargs .pop ("eid" )
2149+ if "tid" in kwargs :
2150+ self .tid = kwargs .pop ("tid" )
21192151 super ().__init__ (* args , ** kwargs )
21202152 # Set some date fields
21212153 self .set_date_fields (* args , ** kwargs )
2122- # Don't show the product filter on the product finding view
2123- if self .pid :
2124- del self .form .fields ["test__engagement__product__name" ]
2125- del self .form .fields ["test__engagement__product__name_contains" ]
2126- del self .form .fields ["test__engagement__product__prod_type__name" ]
2127- del self .form .fields ["test__engagement__product__prod_type__name_contains" ]
2154+ # Don't show the product/engagement/test filter fields when in specific context
2155+ if self .tid or self .eid or self .pid :
2156+ if "test__engagement__product__name" in self .form .fields :
2157+ del self .form .fields ["test__engagement__product__name" ]
2158+ if "test__engagement__product__name_contains" in self .form .fields :
2159+ del self .form .fields ["test__engagement__product__name_contains" ]
2160+ if "test__engagement__product__prod_type__name" in self .form .fields :
2161+ del self .form .fields ["test__engagement__product__prod_type__name" ]
2162+ if "test__engagement__product__prod_type__name_contains" in self .form .fields :
2163+ del self .form .fields ["test__engagement__product__prod_type__name_contains" ]
2164+ # Also hide engagement and test fields if in test or engagement context
2165+ if self .tid :
2166+ if "test__engagement__name" in self .form .fields :
2167+ del self .form .fields ["test__engagement__name" ]
2168+ if "test__engagement__name_contains" in self .form .fields :
2169+ del self .form .fields ["test__engagement__name_contains" ]
2170+ if "test__name" in self .form .fields :
2171+ del self .form .fields ["test__name" ]
2172+ if "test__name_contains" in self .form .fields :
2173+ del self .form .fields ["test__name_contains" ]
2174+ elif self .eid :
2175+ if "test__engagement__name" in self .form .fields :
2176+ del self .form .fields ["test__engagement__name" ]
2177+ if "test__engagement__name_contains" in self .form .fields :
2178+ del self .form .fields ["test__engagement__name_contains" ]
21282179
21292180
21302181class FindingFilter (FindingFilterHelper , FindingTagFilter ):
@@ -2163,29 +2214,57 @@ class Meta:
21632214 def __init__ (self , * args , ** kwargs ):
21642215 self .user = None
21652216 self .pid = None
2217+ self .eid = None
2218+ self .tid = None
21662219 if "user" in kwargs :
21672220 self .user = kwargs .pop ("user" )
21682221
21692222 if "pid" in kwargs :
21702223 self .pid = kwargs .pop ("pid" )
2224+ if "eid" in kwargs :
2225+ self .eid = kwargs .pop ("eid" )
2226+ if "tid" in kwargs :
2227+ self .tid = kwargs .pop ("tid" )
21712228 super ().__init__ (* args , ** kwargs )
21722229 # Set some date fields
21732230 self .set_date_fields (* args , ** kwargs )
21742231 # Don't show the product filter on the product finding view
21752232 self .set_related_object_fields (* args , ** kwargs )
21762233
21772234 def set_related_object_fields (self , * args : list , ** kwargs : dict ):
2178- finding_group_query = Finding_Group .objects .all ()
2179- if self .pid is not None :
2235+ # Use helper to get contextual finding group queryset
2236+ finding_group_query = get_finding_group_queryset_for_context (
2237+ pid = self .pid ,
2238+ eid = self .eid ,
2239+ tid = self .tid ,
2240+ )
2241+
2242+ # Filter by most specific context: test > engagement > product
2243+ if self .tid is not None :
2244+ # Test context: filter finding groups by test
2245+ del self .form .fields ["test__engagement__product" ]
2246+ del self .form .fields ["test__engagement__product__prod_type" ]
2247+ del self .form .fields ["test__engagement" ]
2248+ del self .form .fields ["test" ]
2249+ elif self .eid is not None :
2250+ # Engagement context: filter finding groups by engagement
2251+ del self .form .fields ["test__engagement__product" ]
2252+ del self .form .fields ["test__engagement__product__prod_type" ]
2253+ del self .form .fields ["test__engagement" ]
2254+ # Filter tests by engagement - get_authorized_tests doesn't support engagement param
2255+ engagement = Engagement .objects .get (id = self .eid )
2256+ self .form .fields ["test" ].queryset = get_authorized_tests (Permissions .Test_View , product = engagement .product ).filter (engagement_id = self .eid ).prefetch_related ("test_type" )
2257+ elif self .pid is not None :
2258+ # Product context: filter finding groups by product
21802259 del self .form .fields ["test__engagement__product" ]
21812260 del self .form .fields ["test__engagement__product__prod_type" ]
21822261 # TODO: add authorized check to be sure
21832262 self .form .fields ["test__engagement" ].queryset = Engagement .objects .filter (
21842263 product_id = self .pid ,
21852264 ).all ()
21862265 self .form .fields ["test" ].queryset = get_authorized_tests (Permissions .Test_View , product = self .pid ).prefetch_related ("test_type" )
2187- finding_group_query = Finding_Group .objects .filter (test__engagement__product_id = self .pid )
21882266 else :
2267+ # Global context: show all authorized finding groups
21892268 self .form .fields [
21902269 "test__engagement__product__prod_type" ].queryset = get_authorized_product_types (Permissions .Product_Type_View )
21912270 self .form .fields ["test__engagement" ].queryset = get_authorized_engagements (Permissions .Engagement_View )
@@ -2194,7 +2273,7 @@ def set_related_object_fields(self, *args: list, **kwargs: dict):
21942273 if self .form .fields .get ("test__engagement__product" ):
21952274 self .form .fields ["test__engagement__product" ].queryset = get_authorized_products (Permissions .Product_View )
21962275 if self .form .fields .get ("finding_group" , None ):
2197- self .form .fields ["finding_group" ].queryset = get_authorized_finding_groups_for_queryset (Permissions .Finding_Group_View , finding_group_query )
2276+ self .form .fields ["finding_group" ].queryset = get_authorized_finding_groups_for_queryset (Permissions .Finding_Group_View , finding_group_query , user = self . user )
21982277 self .form .fields ["reporter" ].queryset = get_authorized_users (Permissions .Finding_View )
21992278 self .form .fields ["reviewers" ].queryset = self .form .fields ["reporter" ].queryset
22002279
0 commit comments