@@ -589,6 +589,11 @@ def test_api_product_endpoint_cyclonedx_sbom_action(self):
589589 def test_api_product_endpoint_manage_permissions_action (self ):
590590 url = reverse ("api_v2:product-manage-permissions" , args = [self .product1 .uuid ])
591591
592+ # Unauthenticated access is rejected with 403
593+ self .client .logout ()
594+ response = self .client .get (url )
595+ self .assertEqual (status .HTTP_403_FORBIDDEN , response .status_code )
596+
592597 # User without view_product gets 404 (object not in secured queryset)
593598 self .client .login (username = self .base_user .username , password = "secret" )
594599 response = self .client .get (url )
@@ -606,38 +611,55 @@ def test_api_product_endpoint_manage_permissions_action(self):
606611 # base_user has view_product at this point
607612 self .assertEqual (1 , len (response .data ))
608613 self .assertEqual (self .base_user .username , response .data [0 ]["username" ])
614+ self .assertEqual (self .dataspace .name , response .data [0 ]["dataspace" ])
609615 self .assertIn ("view_product" , response .data [0 ]["object_permissions" ])
610616
611- # Superuser can POST to assign permissions
612- data = {"user" : self .admin_user .username , "permissions" : ["view_product" ]}
617+ # Superuser can POST to assign multiple permissions at once
618+ data = {
619+ "user" : self .admin_user .username ,
620+ "permissions" : ["view_product" , "change_product" ],
621+ }
613622 response = self .client .post (url , data , format = "json" )
614623 self .assertEqual (status .HTTP_200_OK , response .status_code )
615624 self .assertEqual ({"status" : "permissions assigned" }, response .data )
616625 self .assertIn ("view_product" , get_perms (self .admin_user , self .product1 ))
626+ self .assertIn ("change_product" , get_perms (self .admin_user , self .product1 ))
617627
618628 # Superuser can DELETE to remove permissions
619- data = {"user" : self .admin_user .username , "permissions" : ["view_product" ]}
629+ data = {"user" : self .admin_user .username , "permissions" : ["view_product" , "change_product" ]}
620630 response = self .client .delete (url , data , content_type = "application/json" )
621631 self .assertEqual (status .HTTP_200_OK , response .status_code )
622632 self .assertEqual ({"status" : "permissions removed" }, response .data )
623633 self .assertNotIn ("view_product" , get_perms (self .admin_user , self .product1 ))
634+ self .assertNotIn ("change_product" , get_perms (self .admin_user , self .product1 ))
624635
625- # Product creator (created_by) can manage permissions
636+ # Product creator (created_by) can GET, POST, and DELETE
626637 self .product1 .created_by = self .admin_user
627638 self .product1 .save ()
628639 assign_perm ("view_product" , self .admin_user , self .product1 )
629640 self .client .login (username = self .admin_user .username , password = "secret" )
641+
642+ response = self .client .get (url )
643+ self .assertEqual (status .HTTP_200_OK , response .status_code )
644+
630645 data = {"user" : self .base_user .username , "permissions" : ["change_product" ]}
631646 response = self .client .post (url , data , format = "json" )
632647 self .assertEqual (status .HTTP_200_OK , response .status_code )
633648 self .assertIn ("change_product" , get_perms (self .base_user , self .product1 ))
634649
635- # Invalid permission codename returns 400
650+ response = self .client .delete (url , data , content_type = "application/json" )
651+ self .assertEqual (status .HTTP_200_OK , response .status_code )
652+ self .assertNotIn ("change_product" , get_perms (self .base_user , self .product1 ))
653+
654+ # Invalid permission codename on POST returns 400
636655 self .client .login (username = self .super_user .username , password = "secret" )
637656 data = {"user" : self .base_user .username , "permissions" : ["nonexistent_perm" ]}
638657 response = self .client .post (url , data , format = "json" )
639658 self .assertEqual (status .HTTP_400_BAD_REQUEST , response .status_code )
640659 self .assertIn ("errors" , response .data )
660+ # DELETE with unknown codename is a no-op (guardian remove_perm is idempotent)
661+ response = self .client .delete (url , data , content_type = "application/json" )
662+ self .assertEqual (status .HTTP_200_OK , response .status_code )
641663
642664 # Missing required fields returns 400
643665 response = self .client .post (url , {}, format = "json" )
0 commit comments