Skip to content

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

Merge request reports

Loading