Convite via API com parâmetro group_names retorna 403 para dono do grupo, a menos que seja admin

Resumo

Um usuário não administrador que é dono de um grupo no Discourse consegue convidar novos membros com esse grupo atribuído com sucesso através do diálogo de convite da interface web. A ação idêntica via API REST (/invites.json, chave de API com escopo Global, Api-Username correto) retorna um erro 403 invalid_access — mas apenas quando group_names/group_ids está incluído no payload. Isso ocorre independentemente de group_names ser passado como uma string simples (ex.: "group_names": "my-group") ou como um array (ex.: "group_names": ["my-group"]) — ambos os formatos produzem o mesmo erro 403.

Crucialmente, conceder ao usuário o status de Moderador não corrige a chamada da API — apenas conceder permissões de Administrador total resolve, mesmo que Moderador seja suficiente para todos os outros cenários testados (interface web, convite via API sem grupo).

Ambiente

  • Versão do Discourse: [preencher — página Admin → Upgrade]
  • Tipo de chave de API: Escopo Global, Api-Username = nome de usuário exato do usuário de teste

Passos para reproduzir

  1. Crie um usuário não administrador e não moderador (<userid>), tornando-o dono do grupo <group_name>.
  2. Na interface web, como <userid>: convidar sem grupo → sucesso. Convidar com <group_name> atribuído → sucesso.
  3. Via API, como <userid> (chave com escopo Global, Api-Username=<userid>):
    • POST /invites.json sem group_names → sucesso.
    • POST /invites.json com group_names="<group_name>" (formato string) → 403 invalid_access.
    • POST /invites.json com group_names=["<group_name>"] (formato array) → 403 invalid_access (falha idêntica, ambos os formatos testados).
  4. Promova <userid> a Moderador. Repita as chamadas da API com grupo da etapa 3 (ambos os formatos) → ainda 403 invalid_access.
  5. Promova <userid> a Administrador. Repita as chamadas da API com grupo da etapa 3, mesma chave, mesmos payloads → sucesso.

Comportamento esperado

Como a posse de um grupo é, por si só, permissão suficiente para um usuário não da equipe atribuir esse grupo ao convidar via interface web, a API — autenticada como o mesmo usuário via Api-Username — deveria respeitar a mesma permissão. No mínimo, o status de Moderador (que é da equipe) não deveria se comportar de forma idêntica a um usuário sem privilégios aqui; o fato de o Moderador falhar da mesma forma que um usuário sem cargo, e apenas o Administrador ter sucesso, sugere que o caminho do código da API verifica especificamente user.admin? em vez da posse do grupo ou mesmo do status geral de equipe (user.staff?, que é verdadeiro para moderadores).

Comportamento atual

A API retorna 403 para qualquer convite com grupo (formato de parâmetro string ou array), a menos que o usuário que executa a ação seja um Administrador total. A posse do grupo (verificado como funcional via interface web) e o status de Moderador/equipe (verificado via teste de promoção direta) são ambos insuficientes para o caminho da API, apesar de qualquer um deles ser suficiente através da interface web ou para o caso da API sem grupo.

Pergunta para a equipe do Discourse

O caminho do código de convite com grupo autenticado via API requer explicitamente user.admin?, em vez de verificar a posse do grupo ou user.staff? da mesma forma que o caminho da interface web / autenticado por sessão? Se for o caso, isso é intencional (restrição específica da API não documentada) ou é um bug onde a verificação do guardião da API diverge da verificação do guardião da web para esta ação?

Fico feliz em fornecer logs completos de requisição/resposta (chave ocultada) mediante solicitação.