Changes for Introducing services to handle service accounts at project level
What does this MR do and why?
Service level changes for https://gitlab.com/gitlab-org/gitlab/-/work_items/585509
Changes included in MR as
- Create Service account for project
- Update Service account for project
- Delete service account for project
- Create personal access token for service account which belongs to a project
- Revoke personal access token for service account while belongs to a project
How to test
Prerequisite -
Create users with role - group owner admin and project owner and project maintainer in your local gdk setup
create service
@org = Organization.first
result = Namespaces::ServiceAccounts::CreateService.new(
@admin,
{ organization_id: @org.id, project_id: @project.id }
).execute
Test invalid scenarios like
puts "\n--- 1e: Invalid project_id should fail ---"
result = Namespaces::ServiceAccounts::CreateService.new(
@admin,
{ organization_id: @org.id, project_id: 999999999 }
).execute
Update service
result = Namespaces::ServiceAccounts::CreateService.new(
@admin, { organization_id: @org.id, project_id: @project.id }
).execute
@project_sa = result.payload[:user]
result = Namespaces::ServiceAccounts::UpdateService.new(
<current_user>,
@project_sa,
{ project_id: @project.id, name: new_name }
).execute
Delete service
sa_user = Namespaces::ServiceAccounts::CreateService.new(
admin,
{ organization_id: org.id, project_id: project.id }
).execute
result = Namespaces::ServiceAccounts::DeleteService.new(@developer, sa).execute
Test creating pat and revoking pat using this script
result = PersonalAccessTokens::CreateService.new(
current_user: @admin,
target_user: @project_sa,
organization_id: @org.id,
params: {
name: "Test PAT #{Time.current.to_i}",
scopes: [:api, :read_api],
expires_at: 30.days.from_now,
project: @project # Key: passing project for project-level SA
}
).execute
pat = result.payload[:personal_access_token]
result = PersonalAccessTokens::RevokeService.new(
@admin,
token: pat,
project: @project,
source: :self
).execute
Qurey plan for added logic to check subscription in case of Project provisioned service level account
This is an expensive query but as suggested we will not execute it since the feature flag is already enabled in Production. So Service account creation is unlimited for Premium as well as trial namespace as of now.
https://console.postgres.ai/gitlab/gitlab-production-main/sessions/47523/commands/143674
Aggregate (cost=107652.28..107652.29 rows=1 width=8) (actual time=11206.577..11215.281 rows=1 loops=1)
Buffers: shared hit=31217 read=29183 dirtied=1701
WAL: records=1859 fpi=1701 bytes=13423175
I/O Timings: read=20083.678 write=0.000
-> Gather (cost=107652.06..107652.27 rows=2 width=8) (actual time=11201.505..11215.268 rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=31217 read=29183 dirtied=1701
WAL: records=1859 fpi=1701 bytes=13423175
I/O Timings: read=20083.678 write=0.000
-> Aggregate (cost=106652.06..106652.07 rows=1 width=8) (actual time=11194.888..11194.890 rows=1 loops=3)
Buffers: shared hit=31217 read=29183 dirtied=1701
WAL: records=1859 fpi=1701 bytes=13423175
I/O Timings: read=20083.678 write=0.000
-> Nested Loop (cost=206.53..106645.25 rows=2725 width=0) (actual time=11194.884..11194.886 rows=0 loops=3)
Buffers: shared hit=31217 read=29183 dirtied=1701
WAL: records=1859 fpi=1701 bytes=13423175
I/O Timings: read=20083.678 write=0.000
-> Parallel Bitmap Heap Scan on public.users (cost=194.96..24118.85 rows=5699 width=4) (actual time=64.024..6525.199 rows=3118 loops=3)
Filter: (NOT users.composite_identity_enforced)
Rows Removed by Filter: 1402
Buffers: shared hit=3 read=13356 dirtied=679
WAL: records=728 fpi=679 bytes=5201044
I/O Timings: read=6518.779 write=0.000
-> Bitmap Index Scan using index_users_on_user_type_and_id (cost=0.00..191.55 rows=13681 width=0) (actual time=67.873..67.873 rows=13662 loops=1)
Index Cond: (users.user_type = 13)
Buffers: shared hit=3 read=69
I/O Timings: read=62.952 write=0.000
-> Index Scan using index_user_details_on_user_id on public.user_details (cost=11.56..14.48 rows=1 width=8) (actual time=1.493..1.493 rows=0 loops=9354)
Index Cond: (user_details.user_id = users.id)
Filter: ((user_details.provisioned_by_group_id = ANY ('{1,34,22}'::bigint[])) OR (hashed SubPlan 1))
Rows Removed by Filter: 1
Buffers: shared hit=31214 read=15827 dirtied=1022
WAL: records=1131 fpi=1022 bytes=8222131
I/O Timings: read=13564.899 write=0.000
SubPlan 1
-> Index Only Scan using index_projects_on_namespace_id_and_id on public.projects (cost=0.56..10.76 rows=97 width=4) (actual time=3.256..25.938 rows=69 loops=3)
Index Cond: (projects.namespace_id = ANY ('{1,34,22}'::integer[]))
Heap Fetches: 0
Buffers: shared hit=201 read=41
I/O Timings: read=26.350 write=0.000
Settings: work_mem = '100MB', effective_cache_size = '472585MB', jit = 'off', random_page_cost = '1.5', seq_page_cost = '4'
Edited by Smriti Garg