Granular scope permissions inherit from parents
What does this MR do and why?
Granular scope permissions for namespaces inherit permissions from parent namespaces. The resulting permissions are a union of all permissions defined in the entire namespace hierarchy.
While there is no conclusion yet on whether standalone (non-inheriting) namespace permissions should be possible in addition to inheriting namespace permissions, this MR implements inheritance.
References
Issue: #571516
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"."namespace_id" IN(103, 97);
Query plan
Postgresql.ai: https://console.postgres.ai/shared/0d2b05f2-b3cc-46c1-ae88-7e07ba37bc8c
HashAggregate (cost=8.76..10.01 rows=100 width=32) (actual time=0.109..0.111 rows=1 loops=1)
Group Key: jsonb_array_elements_text(granular_scopes.permissions)
Buffers: shared hit=12
I/O Timings: read=0.000 write=0.000
-> ProjectSet (cost=0.29..8.51 rows=100 width=32) (actual time=0.100..0.104 rows=1 loops=1)
Buffers: shared hit=12
I/O Timings: read=0.000 write=0.000
-> Nested Loop (cost=0.29..8.01 rows=1 width=32) (actual time=0.078..0.080 rows=1 loops=1)
Buffers: shared hit=12
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.052..0.054 rows=1 loops=1)
Index Cond: (personal_access_token_granular_scopes.personal_access_token_id = 63)
Buffers: shared hit=6
I/O Timings: read=0.000 write=0.000
-> Index Scan using idx_granular_scopes_on_namespace_id on public.granular_scopes (cost=0.14..4.82 rows=2 width=40) (actual time=0.022..0.022 rows=1 loops=1)
Index Cond: (granular_scopes.namespace_id = ANY ('{103,97}'::bigint[]))
Buffers: shared hit=6
I/O Timings: read=0.000 write=0.000
Settings: effective_cache_size = '472585MB', seq_page_cost = '4', work_mem = '100MB', random_page_cost = '1.5', 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