Support all member namespaces for granular scopes
What does this MR do and why?
Support creating tokens with granular scopes for all groups and projects a user is a member of.
References
Issue: [BE] Support dynamic boundary for all groups an... (#571519)
Query
Rails
user = User.human.last
project = user.projects.first
token = user.personal_access_tokens.last
token.permitted_for_boundary?(Authz::Boundary.for(project), :create_issue)
Raw SQL
SELECT DISTINCT
jsonb_array_elements_text(permissions)
FROM
"granular_scopes"
INNER JOIN "personal_access_token_granular_scopes" ON "granular_scopes"."id" = "personal_access_token_granular_scopes"."granular_scope_id"
WHERE
"personal_access_token_granular_scopes"."personal_access_token_id" = 63
AND("granular_scopes"."all_membership_namespaces" = FALSE
AND "granular_scopes"."namespace_id" IN(90, 89)
OR "granular_scopes"."all_membership_namespaces" = TRUE)
Query plan
Postgresql.ai: https://console.postgres.ai/shared/6a697a92-d5e0-4029-b594-9d7b5ebf2191
HashAggregate (cost=7.23..8.48 rows=100 width=32) (actual time=0.073..0.074 rows=2 loops=1)
Group Key: jsonb_array_elements_text(granular_scopes.permissions)
Buffers: shared hit=7
I/O Timings: read=0.000 write=0.000
-> ProjectSet (cost=0.29..6.98 rows=100 width=32) (actual time=0.067..0.069 rows=2 loops=1)
Buffers: shared hit=7
I/O Timings: read=0.000 write=0.000
-> Nested Loop (cost=0.29..6.47 rows=1 width=32) (actual time=0.048..0.049 rows=1 loops=1)
Buffers: shared hit=7
I/O Timings: read=0.000 write=0.000
-> Index Scan using idx_pat_granular_scopes_on_pat_id on public.personal_access_token_granular_scopes (cost=0.14..3.16 rows=1 width=8) (actual time=0.041..0.042 rows=1 loops=1)
Index Cond: (personal_access_token_granular_scopes.personal_access_token_id = 63)
Buffers: shared hit=5
I/O Timings: read=0.000 write=0.000
-> Index Scan using granular_scopes_pkey on public.granular_scopes (cost=0.14..3.16 rows=1 width=40) (actual time=0.005..0.005 rows=1 loops=1)
Index Cond: (granular_scopes.id = personal_access_token_granular_scopes.granular_scope_id)
Filter: (((NOT granular_scopes.all_membership_namespaces) AND (granular_scopes.namespace_id = ANY ('{90,89}'::bigint[]))) OR granular_scopes.all_membership_namespaces)
Rows Removed by Filter: 0
Buffers: shared hit=2
I/O Timings: read=0.000 write=0.000
Settings: work_mem = '100MB', random_page_cost = '1.5', seq_page_cost = '4', effective_cache_size = '472585MB', jit = 'off'
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.
Edited by Alex Buijs