Search API Group Access para Drupal: pesquisa e respostas de AI que mostram a cada membro só o que o Group lhe permite abrir
Uma pessoa que pertence a dois departamentos pergunta ao assistente da intranet o que a empresa tem sobre SMTP. A base de dados vetorial ordena a intranet inteira, devolve as dez passagens mais próximas, e só depois o Drupal deita fora as que ela não pode abrir. Fica com o que sobra, menos do que pediu e não o melhor que podia ter. Na página de pesquisa ao lado, o mesmo problema aparece como um total de resultados por cima de uma lista mais curta do que a página, e um pager que continua para lá do último resultado que ela pode abrir.
É o que acontece num site feito com o Group 3 assim que a pesquisa passa pelo Search API. O Group aplica o acesso alterando as queries SQL, por isso as listagens de nodes em Views respeitam-no. Uma pesquisa do Search API vai para o backend, onde o Group nunca a vê. O processor Content access que vem com o Search API indexa os node grants, e o Group 3 não usa nenhum.
O Search API Group Access fecha essa falha onde ela se abre, dentro do backend de pesquisa. É software livre, sob GPL-2.0-or-later, e a 1.0.0, publicada a 8 de novembro, é a primeira release estável. Liga-se ao Search API e ao Group, e funciona em qualquer backend que suporte condition groups e filtros IN: o backend de base de dados, e o AI Search sobre uma base de dados vetorial como o Qdrant.
O que podes construir com ele
- Uma página de pesquisa numa intranet ou extranet cujo total de resultados, facets e pager batem certo com o que cada membro vê, porque o backend só ordena e conta isso.
- Um assistente de AI que responde a partir dos teus conteúdos e só vai buscar aos grupos a que a pessoa pertence, por isso pedir dez passagens devolve dez que ela pode abrir.
- Um membro novo que encontra os documentos do grupo logo na pesquisa seguinte. Memberships, roles e permissões são lidos quando a pesquisa corre, por isso mudá-los não obriga a reindexar nada.
- Comentários encontrados por quem pode ver a entidade a que estão ligados, e reindexados quando essa entidade muda de grupos, de dono ou de estado.
- Paragraphs, ou qualquer outra entidade que o Group não relaciona, que herdam o acesso da entidade onde vivem através de um event subscriber.
- Um índice grande posto a funcionar sem interromper o serviço: indexas os valores de acesso com o filtro desligado enquanto as pesquisas continuam a funcionar, e depois ligas o filtro sem reindexar.
A mesma resposta que o Group, ou nenhuma
A regra que o módulo segue é a paridade com o Group: para a operação "view", uma pesquisa devolve um item se e só se uma entity query com verificação de acesso também o devolvesse, no que depende do Group. Permissões de outsider, insider e individuais, "any" e "own", publicado e não publicado. A suite de testes corre as duas para uma matriz de contas e compara os resultados, em Drupal 10 e 11.
Onde não consegue ser exato, erra para o lado de esconder. Um item que ainda não foi indexado com o processor não é devolvido a ninguém. Há um caso conhecido em que o Group mostraria um item e a pesquisa não: um item que pertence a dois grupos quando o insider role dá menos do que o outsider role. O módulo aceita esse falso negativo em vez de arriscar um falso positivo. Os grupos em si não estão cobertos, nem outras operações além de "view".
A cache tem o mesmo cuidado. Ligar ou desligar o processor volta a gravar as views do índice, para que uma cache de resultados nunca sirva os resultados de um membro ao seguinte.
De onde veio
Construímo-lo para a nossa própria intranet, onde um assistente responde a perguntas a partir de cerca de 270 000 itens guardados no Qdrant através do AI Search, e todas as pesquisas dele passam pelo filtro. A pessoa que menos vê da intranet pede dez passagens e recebe dez, todas de documentos que pode abrir.
O caminho até lá ensinou ao módulo duas coisas que agora faz sozinho. Os valores que têm de corresponder exatamente passam a hashes em hexadecimal simples, porque o AI Search passa todos os atributos de texto por um conversor de HTML para Markdown, que lhes escapava os underscores. E o relatório de estado assinala um índice do AI Search cujos campos de acesso não estão definidos como filterable attributes, caso em que todas as pesquisas voltariam vazias. No Qdrant, cria payload indexes para esses campos: num índice de 190 000 pontos, uma pesquisa filtrada demorava 100 a 210 ms sem eles e 2 a 16 ms com eles.
Como obter
composer require drupal/search_api_group_access
drush en search_api_group_access
Depois marca Group access no separador Processors do índice e reindexa. Requer Drupal 10.3 ou 11, Group 3.3 ou posterior e Search API 1.39 ou posterior. As releases estáveis estão cobertas pela política de security advisories do Drupal.
O README explica como pôr um índice grande a funcionar, o AI Search e o Qdrant, e os eventos. Se também precisas que os campos entity reference ofereçam só o conteúdo do grupo que está a ser editado, o Group Entity Reference Filter faz isso. E se o teu site partilha conteúdo por grupo de uma forma que o módulo ainda não cobre, diz-nos na issue queue.