diff --git a/src/dstack/_internal/server/services/users.py b/src/dstack/_internal/server/services/users.py index 7aaf4b9799..8504f2af75 100644 --- a/src/dstack/_internal/server/services/users.py +++ b/src/dstack/_internal/server/services/users.py @@ -44,7 +44,9 @@ async def list_users_for_user( session: AsyncSession, user: UserModel, ) -> List[User]: - return await list_all_users(session=session) + if user.global_role == GlobalRole.ADMIN: + return await list_all_users(session=session) + return [user_model_to_user(user)] async def list_all_users( diff --git a/src/tests/_internal/server/routers/test_users.py b/src/tests/_internal/server/routers/test_users.py index d192907496..df4a8f3c06 100644 --- a/src/tests/_internal/server/routers/test_users.py +++ b/src/tests/_internal/server/routers/test_users.py @@ -22,19 +22,71 @@ async def test_returns_40x_if_not_authenticated(self, test_db, client: AsyncClie @pytest.mark.asyncio @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True) - async def test_returns_users(self, test_db, session: AsyncSession, client: AsyncClient): - user = await create_user( + async def test_admins_see_all_users(self, test_db, session: AsyncSession, client: AsyncClient): + admin = await create_user( + session=session, + name="admin", + created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc), + global_role=GlobalRole.ADMIN, + ) + other_user = await create_user( + session=session, + name="other_user", + created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc), + global_role=GlobalRole.USER, + ) + response = await client.post("/api/users/list", headers=get_auth_headers(admin.token)) + assert response.status_code in [200] + assert response.json() == [ + { + "id": str(admin.id), + "username": admin.name, + "created_at": "2023-01-02T03:04:00+00:00", + "global_role": admin.global_role, + "email": None, + "active": True, + "permissions": { + "can_create_projects": True, + }, + }, + { + "id": str(other_user.id), + "username": other_user.name, + "created_at": "2023-01-02T03:04:00+00:00", + "global_role": other_user.global_role, + "email": None, + "active": True, + "permissions": { + "can_create_projects": True, + }, + }, + ] + + @pytest.mark.asyncio + @pytest.mark.parametrize("test_db", ["sqlite", "postgres"], indirect=True) + async def test_non_admins_see_only_themselves( + self, test_db, session: AsyncSession, client: AsyncClient + ): + await create_user( + session=session, + name="admin", + created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc), + global_role=GlobalRole.ADMIN, + ) + other_user = await create_user( session=session, + name="other_user", created_at=datetime(2023, 1, 2, 3, 4, tzinfo=timezone.utc), + global_role=GlobalRole.USER, ) - response = await client.post("/api/users/list", headers=get_auth_headers(user.token)) + response = await client.post("/api/users/list", headers=get_auth_headers(other_user.token)) assert response.status_code in [200] assert response.json() == [ { - "id": str(user.id), - "username": user.name, + "id": str(other_user.id), + "username": other_user.name, "created_at": "2023-01-02T03:04:00+00:00", - "global_role": user.global_role, + "global_role": other_user.global_role, "email": None, "active": True, "permissions": {