Add group transfer event handler to security scan profile
What does this MR do and why?
Adds a group transfer handler for security scan profiles. The new worker schedules a worker based on the previous state of the group based on the decision made here.
Changelog: added
EE: true
How to set up and validate locally
Actions:
Create a scan profile
profile = Security::ScanProfile.create!(
namespace_id: <group_id>,
scan_type: :secret_detection,
name: 'Test profile',
description: 'Test profile for secret detection',
gitlab_recommended: false
)
Attach scan profile to a project
Security::ScanProfileProject.create!(
security_scan_profile_id: profile.id,
project_id: <project_id>
)
Verify project-profile associations
<project>.security_scan_profiles
Verify scan profile exists
Security::ScanProfile.find(<profile_id>)
Validation steps:
Setup
- Select a root group
rg. - Create a scan profile for
rg. - Create (or select) a nested subgroup
gunderrg. - Create (or select) a project
p1underg. - Attach the scan profile to
p1.
Test 1: Move subgroup within same root namespace
- Move group
gto a different group nested underrg(same root namespace). - Verify the connection between the scan profile and
p1remains.
Test 2: Move subgroup to different root namespace
- Move group
gto a different root namespace. - Verify the connection between the scan profile and
p1is deleted.
Test 3: Move root group to be nested group
- Create (or select) a project
p2underrg. - Attach the scan profile to
p2. - Move
rgto be nested under a different root group. - Verify both the scan profile and all project connections are deleted.
Query plans
Note - These tables are new and empty. All queries will return 0 rows.
clean_old_namespace_connections_service - delete all
Raw sql
DELETE FROM "security_scan_profiles_projects"
WHERE ("security_scan_profiles_projects"."id") IN (
SELECT
"security_scan_profiles_projects"."id"
FROM
"security_scan_profiles_projects"
INNER JOIN "security_scan_profiles" ON "security_scan_profiles"."id" = "security_scan_profiles_projects"."security_scan_profile_id"
WHERE
"security_scan_profiles_projects"."project_id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
AND "security_scan_profiles"."namespace_id" != 9970)
Query plan
See full plan here ModifyTable on public.security_scan_profiles_projects (cost=0.04..0.06 rows=0 width=0) (actual time=0.006..0.007 rows=0 loops=1)
-> Nested Loop Semi Join (cost=0.04..0.06 rows=1 width=18) (actual time=0.005..0.006 rows=0 loops=1)
-> Seq Scan on public.security_scan_profiles_projects (cost=0.00..0.00 rows=1 width=14) (actual time=0.005..0.006 rows=0 loops=1)
-> Nested Loop (cost=0.04..0.05 rows=1 width=20) (actual time=0.000..0.000 rows=0 loops=0)
-> Seq Scan on public.security_scan_profiles_projects security_scan_profiles_projects_1 (cost=0.04..0.04 rows=1 width=22) (actual time=0.000..0.000 rows=0 loops=0)
Filter: (security_scan_profiles_projects_1.project_id = ANY ('{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}'::bigint[]))
Rows Removed by Filter: 0
-> Seq Scan on public.security_scan_profiles (cost=0.00..0.00 rows=1 width=14) (actual time=0.000..0.000 rows=0 loops=0)
Filter: (security_scan_profiles.namespace_id <> 9970)
Rows Removed by Filter: 0
Settings: random_page_cost = '1.5', work_mem = '100MB', jit = 'off', seq_page_cost = '4', effective_cache_size = '338688MB'
delete_scan_profile_service - scan_profile.destroy
Raw sql
DELETE FROM "security_scan_profiles" WHERE "security_scan_profiles"."id" = 1
Query plan
See full plan here ModifyTable on public.security_scan_profiles (cost=0.00..0.00 rows=0 width=0) (actual time=0.004..0.005 rows=0 loops=1)
-> Seq Scan on public.security_scan_profiles (cost=0.00..0.00 rows=1 width=6) (actual time=0.004..0.004 rows=0 loops=1)
Filter: (security_scan_profiles.id = 1)
Rows Removed by Filter: 0
Settings: work_mem = '100MB', jit = 'off', seq_page_cost = '4', effective_cache_size = '338688MB', random_page_cost = '1.5'
delete_scan_profile_service - delete_all
Raw sql
DELETE FROM "security_scan_profiles_projects" WHERE "security_scan_profiles_projects"."id" IN (100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110)
Query plan
See full plan here ModifyTable on public.security_scan_profiles_projects (cost=0.03..0.03 rows=0 width=0) (actual time=0.002..0.003 rows=0 loops=1)
-> Seq Scan on public.security_scan_profiles_projects (cost=0.03..0.03 rows=1 width=6) (actual time=0.002..0.002 rows=0 loops=1)
Filter: (security_scan_profiles_projects.id = ANY ('{100,101,102,103,104,105,106,107,108,109,110}'::bigint[]))
Rows Removed by Filter: 0
Settings: effective_cache_size = '338688MB', random_page_cost = '1.5', work_mem = '100MB', jit = 'off', seq_page_cost = '4'
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to [Backend] Handle project and group transfer events (#581533) • Gal Katz • 18.8
Edited by Gal Katz