Saltar para o conteudo
Avanet

Consultar o Data Lake do Sophos Fusion com a Search GraphQL API

A Search GraphQL API v1 permite pesquisar o Data Lake histórico do Sophos Fusion a partir de uma aplicação própria com QL. O processo é assíncrono: iniciar a pesquisa, guardar a sua Search-URN, verificar a conclusão e o resultado da execução e, depois, ler todas as páginas de resultados. COMPLETE, por si só, não significa que todas as partes da pesquisa tenham sido bem-sucedidas.

A API está publicada desde 12 de outubro de 2026. Complementa as API existentes e não exige uma transição imediata da XDR Query API, que continua disponível. Também não substitui Live Endpoint Search (LES): o LES consulta endpoints ligados com SQL do tipo osquery. A distinção entre Classic Live Discover, Data Lake Search e LES ajuda a escolher o percurso de dados correto.

Antes do primeiro pedido

São necessários um tenant com os dados históricos pretendidos, API Credentials adequadas, o UUID único do tenant e um cliente HTTP capaz de enviar pedidos POST JSON e guardar respostas completas. Para o exemplo, o tenant deve conter eventos de processos. Sem esses dados, uma pesquisa tecnicamente bem-sucedida pode ficar vazia.

Gerir credenciais API em segurança explica a identidade de máquina, o fluxo OAuth com client_credentials, a associação ao tenant e a rotação. Um identificador de parceiro ou organização não é um UUID de tenant. Com vários tenants, selecionar o destino através de uma correspondência aprovada e inequívoca, não apenas pelo nome apresentado.

A função mínima exata e os direitos de acesso necessários para o cliente Search concreto têm de ser esclarecidos antes da autorização para produção. O nome de uma função genérica de principal de serviço não confirma uma permissão Search. Em caso de recusa, não atribuir Super Admin por precaução.

Antes de iniciar, definir a questão de investigação, o período e os campos necessários. Os dados de processos podem conter nomes de utilizador, caminhos e linhas de comando confidenciais. As consultas e exportações devem permanecer num ambiente aprovado com direitos de acesso e conservação definidos. Tokens e Client Secret não podem aparecer nos registos de pedidos, em tickets ou em ficheiros de exemplo guardados. As linhas completas dos resultados também não devem ser registadas sem controlo.

Utilizar o host de destino específico da API

As operações seguintes partilham o mesmo contrato de pedido:

POST https://api.taegis.sophos.com/graphql
Authorization: Bearer <access-token>
X-Tenant-ID: <tenant-uuid>
X-GraphQL-Schema: default
Content-Type: application/json

No cliente HTTP, substituir <access-token> pelo token de acesso OAuth atual e <tenant-uuid> pelo UUID verificado. O URL e os cabeçalhos são iguais para cada corpo JSON seguinte. Os exemplos são modelos de pedidos, não testes de tenant executados aqui nem saídas de sucesso registadas.

O host REST regional de apiHosts.dataRegion não é o host de destino deste contrato Search. Inversamente, não alterar globalmente os clientes REST existentes para o host GraphQL. Este nome de host também não garante o local de armazenamento nem a residência dos dados; esclarecer esses requisitos segundo as disposições contratuais e do tenant aplicáveis.

Iniciar e acompanhar inequivocamente uma pesquisa

Criar uma nova execução com createSearch

O modelo seguinte pesquisa eventos de processos da última hora e limita os campos de evento selecionados. -1h é uma janela temporal relativa para uma primeira verificação funcional; numa comparação posterior com outro cliente, definir limites temporais explícitos idênticos.

{
  "operationName": "CreateSearch",
  "query": "mutation CreateSearch($input: CreateSearchInput) { createSearch(input: $input) { urn status } }",
  "variables": {
    "input": {
      "text": "from process where earliest = -1h | fields host_id, commandline, image_path"
    }
  }
}

Antes de enviar, verificar tenant, período e âmbito dos dados. createSearch cria e inicia uma nova execução de pesquisa, mas não altera a configuração de proteção dos endpoints. A execução pode gerar trabalho no serviço e resultados sensíveis. Um erro do cliente não deve, por isso, iniciar automaticamente uma série ilimitada de novas pesquisas.

Após o pedido, avaliar primeiro o estado HTTP e o array GraphQL errors de nível superior. HTTP 200 também pode conter erros GraphQL. Guardar data.createSearch.urn apenas depois desta verificação. Utilizar a URN devolvida sem alterações para consultar estado e resultados; não decompor nem reconstruir o seu formato. O estado inicial pode variar.

Para cada execução, o cliente regista pelo menos UUID do tenant, texto da consulta, referência temporal, Search-URN e hora de início. Uma Search-URN identifica a execução completa. Uma Partition-URN identifica uma subtarefa e um Event Resource Name um evento individual. Estes identificadores não são intercambiáveis.

Reutilizar pesquisas existentes de forma deliberada

Se for permitido utilizar uma pesquisa adequada já em curso ou concluída, getOrCreateSearch é uma alternativa:

{
  "operationName": "GetOrCreateSearch",
  "query": "mutation GetOrCreateSearch($input: CreateSearchInput) { getOrCreateSearch(input: $input) { urn status } }",
  "variables": {
    "input": {
      "text": "from process where earliest = -1h | fields host_id, commandline, image_path"
    }
  }
}

Aqui, obter a URN de data.getOrCreateSearch.urn. A correspondência considera os dados de entrada e compara as consultas pela representação estruturada canónica, não apenas por texto idêntico. A reutilização não garante resultados recentes e o cliente não a pode apresentar como uma nova execução. Se a tarefa exigir uma nova execução, utilizar deliberadamente createSearch.

Se um timeout fizer perder a resposta após createSearch, a pesquisa pode continuar em execução. Uma repetição cega pode criar outra execução. Registar este estado como «criação incerta» e decidir a retoma segundo os requisitos de reutilização e atualidade previamente definidos. getOrCreateSearch não prova retroativamente que foi encontrada precisamente a execução perdida.

Verificar conclusão, falhas parciais e expiração

Consultar o estado com a Search-URN guardada. Substituir <search-urn> exclusivamente pelo valor efetivamente devolvido:

{
  "operationName": "SearchDiagnostics",
  "query": "query SearchDiagnostics($urn: URN!) { search(urn: $urn) { urn status errors expireTime outcome { success errors { urn errors } } searchPartitions { urn schemaType status errors } } }",
  "variables": {
    "urn": "<search-urn>"
  }
}

Enquanto status for QUEUED ou IN_PROGRESS, o cliente aguarda entre consultas. outcome.success: UNKNOWN é esperado antes da conclusão. Um intervalo de consulta de, por exemplo, cinco segundos é uma possível decisão do cliente, não um limite garantido do serviço. Cada pedido também precisa de um timeout, e o processo completo de um prazo adequado à carga. Ultrapassado esse prazo, a execução continua por esclarecer; parar a consulta local não cancela a pesquisa no servidor.

Com status: COMPLETE, avaliar separadamente outcome.success:

ValorSignificado
ALLTodas as partições foram bem-sucedidas.
PARTIALApenas algumas partições foram bem-sucedidas.
NONENenhuma partição foi bem-sucedida.

Para PARTIAL, definir antes da utilização em produção se e para que fins são aceitáveis resultados parciais. Um relatório de investigação completo não pode assumi-los silenciosamente como conclusão global. Com NONE, não existe um âmbito pesquisado com sucesso que permita declarar ausência de ameaça. outcome.errors associa mensagens às partições; searchPartitions fornece esquema, estado e erros. Mesmo numa execução bem-sucedida, errors ao nível da pesquisa ou da partição pode conter avisos.

Utilizar também expireTime para verificar o plano de obtenção posterior: ler os resultados necessários até esse momento e, se forem precisos durante mais tempo, guardá-los num sistema próprio aprovado. Guardar uma URN ou um cursor não prolonga a disponibilidade. Não se deduz aqui uma TTL fixa de um único exemplo.

Ler todas as páginas de resultados

Após a conclusão e a avaliação do resultado da execução, pedir a primeira página sem cursor nas variáveis:

{
  "operationName": "SearchResults",
  "query": "query SearchResults($urn: URN!, $limit: Int, $cursor: String) { searchResults(urn: $urn, limit: $limit, cursor: $cursor) { fields { name baseType originSchemaTypes } values totals { total { value } subtotals { schemaType value } } nextCursor } }",
  "variables": {
    "urn": "<search-urn>",
    "limit": 2
  }
}

limit: 2 facilita verificar a sequência de páginas no piloto. Limita as linhas por página, não o número total de correspondências. Para produção, escolher o tamanho de página adequado ao processamento, sem daí deduzir um máximo documentado ou um limite global de resultados.

Após cada obtenção, verificar estado HTTP, GraphQL errors e caminho de resposta esperado. Só depois processar a página. Mesmo após COMPLETE, a obtenção pode ainda demorar; um timeout de leitura não prova uma falha da pesquisa. Repetir erros transitórios de leitura com backoff limitado, utilizando a mesma Search-URN e o mesmo cursor. O consumidor tem de impedir que uma página relida seja adicionada duas vezes à exportação.

Se data.searchResults.nextCursor contiver um valor, copiá-lo sem alterações para as variáveis do mesmo pedido SearchResults:

{
  "urn": "<search-urn>",
  "limit": 2,
  "cursor": "<next-cursor>"
}

Este é apenas o conteúdo substituto da secção variables, não um corpo GraphQL completo. <next-cursor> provém da página imediatamente anterior processada com sucesso. Cada cursor permanece ligado à Search-URN que o forneceu. Não interpretar, alterar ou transferir para outra execução. Continuar até nextCursor ser null ou estar ausente. Tratar um cursor repetido ou o prazo do cliente ultrapassado como erro de obtenção, não como conclusão bem-sucedida.

Distinguir valores, metadados e totais

values contém objetos JSON de linha, não uma lista de colunas SQL nem uma cadeia additionalColumns codificada em JSON como no formato de resultados LES. As entradas podem conter objetos e listas aninhados. fields descreve os nomes e tipos de campos disponíveis; uma entrada de metadados não garante um valor preenchido em cada linha. Tratar tanto campos ausentes como null explícito, sem os equiparar genericamente a uma cadeia vazia ou a zero correspondências.

baseType serve para interpretar os valores. Por exemplo, TIMESTAMP_SECONDS distingue segundos de TIMESTAMP_MILLISECONDS e TIMESTAMP_MICROSECONDS; TIMESTAMP_ISO_8601 indica uma cadeia ISO-8601. Processar tipos de lista e mapa como coleções, não como um único escalar. expireTime também é um carimbo temporal ISO-8601. Os metadados podem nomear campos aninhados com notação por pontos, como process_file_hash.md5. O parser não pode, por isso, assumir que cada nome desse tipo é uma chave plana no objeto de linha.

As indicações opcionais totals.total e totals.subtotals referem-se, respetivamente, ao conjunto completo de resultados e aos seus esquemas, não ao comprimento da lista values atual. Para uma obtenção completa, processar todas as páginas e comparar as linhas recolhidas com os totais disponíveis. A ausência de totais não justifica inventar um número; continuam a ser necessários o fim dos cursores e a documentação do âmbito obtido. Nem uma paginação completa torna um resultado PARTIAL totalmente bem-sucedido.

Preservar a projeção QL e o enriquecimento

No exemplo, | fields host_id, commandline, image_path limita os campos de evento da consulta QL. O conjunto de seleção GraphQL determina, por sua vez, se são incluídas secções de resposta como fields, totals ou nextCursor. values é um escalar JSON: os campos individuais das linhas não podem ser selecionados por um conjunto de seleção GraphQL aninhado.

O enriquecimento acrescenta informação derivada. hostname e enrichSummary não podem aparecer diretamente em | fields. Preservar host_id para resolver o nome do host. Mesmo assim, não se garante um nome resolúvel. Os campos de entrada de enrichSummary dependem do evento; uma projeção mais restrita pode encurtar o resumo. Antes de reduzir, comparar eventos representativos com os enriquecimentos de que o consumidor necessita.

Uma projeção pode reduzir a resposta. Não demonstra custos de análise inferiores nem execução mais rápida. Omitir as secções de resposta desnecessárias não pode, sobretudo, implicar perder nextCursor e, assim, a possibilidade de obter todos os resultados.

Comparar um cliente XDR Query existente de forma controlada

A transição de SQL histórico para Search-QL não é uma substituição de URL nem uma tradução mecânica de SQL. Inventariar primeiro consultas existentes, campos necessários e relatórios subsequentes. A distinção geral das API XDR continua relevante, separadamente, para Cases, Detections e outros processos.

Para cada consulta histórica, comparar nesta ordem:

  1. Registar a questão funcional e as fontes necessárias. As tabelas SQL não justificam correspondência direta com esquemas QL homónimos; verificar cada esquema e nome de campo.
  2. Definir limites explícitos earliest e latest idênticos nas duas pesquisas e documentar a referência temporal. Duas consultas sucessivas de «última hora» não constituem uma comparação rigorosa de igualdade.
  3. Verificar comparações de cadeias, distinção entre maiúsculas e minúsculas e expressões regulares. QL não suporta joins SQL; joins e colunas derivadas exigem um processo funcional redesenhado. Não efetuar a transição sem uma equivalência esclarecida.
  4. Verificar primeiro a consulta QL interativamente em Security Operations > Data Lake Search. Executar depois a pesquisa API com as mesmas condições funcionais.
  5. Comparar registos representativos, campos obrigatórios, tipos, carimbos temporais e enriquecimento, não apenas contagens. Ambos os clientes têm de ler integralmente os respetivos resultados.
  6. Adaptar o novo consumidor a values/fields, Search-URN e cursores. Não mapear cegamente os antigos estados REST finished e succeeded para um único campo de estado GraphQL: COMPLETE e outcome.success continuam a ser verificações separadas.

Antes da transição, também têm de funcionar a política de falhas parciais, as repetições limitadas, a criação incerta, a expiração e a conservação de exportações. O piloto de tenant aprovado regista consulta, janela temporal, campos necessários e todas as páginas, mas nenhum segredo. Uma pesquisa vazia só é devidamente interpretada após verificar fonte, período, filtros, resultado da execução e resultados lidos integralmente; não é uma declaração geral de ausência de ameaça.

Até à aceitação, o cliente XDR Query existente mantém-se como percurso operacional acordado. Se o novo processo falhar, parar a transição ou devolver a aplicação ao cliente anteriormente preservado. Isto não elimina dados já exportados nem corrige lacunas de prova surgidas. Uma nova pesquisa posterior pode diferir da primeira devido a referências temporais diferentes ou a dados já indisponíveis.

Delimitar os erros de forma dirigida

  • Pedido recusado: Verificar URL, X-GraphQL-Schema: default, corpo JSON, token Bearer válido e UUID correto do tenant. Esclarecer separadamente autenticação e autorização específica da operação; não procurar uma região por tentativa e erro. Excluir segredos dos diagnósticos.
  • HTTP 200, mas sem data utilizável: Ler errors de nível superior. Verificar consulta, tipos de variáveis e campos pedidos antes de processar dados subsequentes.
  • COMPLETE com PARTIAL ou NONE: Avaliar outcome.errors, erros de pesquisa e searchPartitions afetadas. Tratar a exportação como incompleta ou retê-la segundo a regra de resultados parciais previamente aprovada; não confundir com zero correspondências.
  • Sem nome de host ou resumo mais curto: Verificar projeção e tipo de evento. Preservar host_id para resolver o nome do host; não substituir entradas de enriquecimento em falta por hostname ou enrichSummary em | fields.
  • A obtenção bloqueia ou termina cedo demais: Verificar timeout do pedido, prazo global, URN inalterada, última página processada com sucesso e associação do cursor. Um limit pequeno não é um limite global de resultados.
  • Uma URN guardada deixa de devolver resultados mais tarde: Verificar expireTime e dados já guardados. Nem URN nem cursor é um arquivo permanente. Se for necessária nova execução, documentá-la como nova e não como restauro do resultado original.

A API continua a evoluir. Limitar o cliente às operações documentadas createSearch, getOrCreateSearch, search e searchResults e aos campos suportados. Campos adicionais obtidos por introspeção não constituem autorização automática de implementação.