fix(moderation): администратор инстанса тоже не может модерировать себя

Проверка иерархии пропускала все запреты для администратора инстанса, включая
запрет на модерацию себя: он мог забанить или исключить самого себя и потерять
доступ к серверу (поймано при проверке интерфейса на стенде — самобан снял
участие в «Главном сервере»).

Теперь проверка `targetID == actor.ID` выполняется до обхода иерархии, для
администратора инстанса остаются доступны любые другие цели. Регрессионный
тест: самобан и самоисключение администратора инстанса дают 403.
This commit is contained in:
2026-09-20 22:57:45 +03:00
parent 8613989b21
commit dff4a25332
2 changed files with 29 additions and 3 deletions
+5 -3
View File
@@ -974,6 +974,11 @@ func (s *Server) changeMemberRole(ctx context.Context, guildIDRaw, userIDRaw, ro
// checkMemberHierarchy запрещает действовать против владельца и участников с
// более высокими ролями (AGENT.md 6.3, 7.17).
func (s *Server) checkMemberHierarchy(ctx context.Context, guildID uint64, actor *store.User, resolved permissions.Resolved, targetID uint64) error {
// Модерировать себя нельзя никому, включая администратора инстанса: иначе
// он может случайно исключить или забанить сам себя (проверено на стенде).
if targetID == actor.ID {
return humaErrorStatus(http.StatusForbidden, "perm.denied", "you cannot moderate yourself")
}
if actor.IsInstanceAdmin {
return nil
}
@@ -989,9 +994,6 @@ func (s *Server) checkMemberHierarchy(ctx context.Context, guildID uint64, actor
if targetID == guild.OwnerID && actor.ID != guild.OwnerID {
return humaErrorStatus(http.StatusForbidden, "perm.denied", "guild owner cannot be moderated")
}
if targetID == actor.ID {
return humaErrorStatus(http.StatusForbidden, "perm.denied", "you cannot moderate yourself")
}
actorRoles, err := s.roleData(ctx, guildID, actor.ID)
if err != nil {
return err