Приглашение через API с параметром group_names возвращает 403 для владельца группы, если он не админ

Резюме

Пользователь, не являющийся администратором, но имеющий роль владельца (owner) группы Discourse, может успешно приглашать новых участников с назначением этой группы через диалоговое окно приглашений в веб-интерфейсе. Точно такое же действие через REST API (/invites.json, API-ключ с глобальным доступом, правильный заголовок Api-Username) возвращает ошибку 403 invalid_access — но только если в теле запроса присутствуют параметры group_names/group_ids. Это происходит независимо от того, передается ли group_names в виде простой строки (например, "group_names": "my-group") или в виде массива (например, "group_names": ["my-group"]) — оба формата приводят к идентичной ошибке 403.

Критически важно, что назначение пользователю статуса Модератора не исправляет вызов API — работает только назначение полного статуса Администратора, хотя для всех остальных протестированных сценариев (веб-интерфейс, приглашение через API без привязки к группе) статуса Модератора достаточно.

Окружение

  • Версия Discourse: [указать — страница Admin → Upgrade]
  • Тип API-ключа: Глобальный доступ, Api-Username = точное имя пользователя тестового аккаунта

Шаги для воспроизведения

  1. Создайте пользователя, не являющегося ни администратором, ни модератором (<userid>), и сделайте его владельцем группы <group_name>.
  2. В веб-интерфейсе, от имени <userid>: приглашение без группы → успешно. Приглашение с назначением <group_name> → успешно.
  3. Через API, от имени <userid> (ключ с глобальным доступом, Api-Username=<userid>):
    • POST /invites.json без group_names → успешно.
    • POST /invites.json с group_names="<group_name>" (формат строки) → 403 invalid_access.
    • POST /invites.json с group_names=["<group_name>"] (формат массива) → 403 invalid_access (идентичная ошибка, протестированы оба формата).
  4. Повысьте <userid> до Модератора. Повторите вызовы API с группой из шага 3 (оба формата) → всё ещё 403 invalid_access.
  5. Повысьте <userid> до Администратора. Повторите вызовы API с группой из шага 3, с тем же ключом и теми же телами запросов → успешно.

Ожидаемое поведение

Поскольку владения группой достаточно, чтобы пользователь без специальных прав назначил эту группу при приглашении через веб-интерфейс, API — аутентифицированное как тот же самый пользователь через Api-Username — должно уважать те же права доступа. Как минимум, статус Модератора (который является персоналом) не должен вести себя так же, как пользователь без привилегий; тот факт, что Модератор получает ту же ошибку, что и пользователь без роли, а успех достигается только с полным статусом Администратора, указывает на то, что в коде API явно проверяется user.admin?, а не владение группой или даже общий статус персонала (user.staff?, который истинен для модераторов).

Фактическое поведение

API возвращает 403 для любого приглашения с привязкой к группе (в формате строки или массива), если действующий пользователь не является полным Администратором. Ни владение группой (проверено в веб-интерфейсе), ни статус Модератора/персонала (проверено прямым повышением) не являются достаточными для пути API, хотя оба этих условия достаточны для веб-интерфейса или для случая API без привязки к группе.

Вопрос команде Discourse

Требует ли код приглашения с группой через API явной проверки user.admin?, вместо проверки владения группой или user.staff?, как это делает путь веб-интерфейса / аутентифицированный через сессию? Если да, то это намеренное решение (недокументированное ограничение, специфичное для API) или это баг, при котором проверка guardian в API расходится с проверкой guardian в веб-интерфейсе для этого действия?

Готов предоставить полные логи запросов/ответов (с скрытым ключом) по запросу.