Files
DeskcommCRM/sentry.server.config.ts
T
Rafael MelgaçoandClaude Opus 5 cde1ebcf37 fix(sentry): telemetria vazava token de webhook pelo canal de tracing
O beforeSend cobria erro e mensagem, e vivia TRIPLICADO verbatim nos três
runtimes. Transação, span e breadcrumb têm hooks próprios — que não existiam
em lugar nenhum. Com tracesSampleRate: 1, o canal sem sanitização era
justamente o de 100% de amostragem.

Medido com um receptor no lugar do Sentry, usando a config exata do repo: a
URL crua saía em transaction, request.url, url.full, http.url, url.path e
http.target. Quatro rotas têm credencial no path, e o token do webhook do WAHA
é a credencial ÚNICA daquela rota na instalação padrão —
WAHA_WEBHOOK_REQUIRE_SIGNATURE nasce false porque o WAHA Core não assina, e o
Caddyfile documenta que a rota por tenant continua pública apoiada em o token
ser imprevisível. A telemetria publicava esse token.

- lib/sentry/scrub.ts: ponto único com os quatro hooks. Redige o token das 4
  rotas em que ele é credencial e o VALOR da query preservando a chave. Os 134
  segmentos [id] são UUID e ficam de fora de propósito: redigir tudo cegamente
  tornaria o Sentry inútil pra depurar, que é o oposto do objetivo.
- No DSN da comunidade agora vai só ERRO: tracesSampleRate 0 e
  replaysSessionSampleRate 0. Quem aponta pro próprio Sentry recebe tudo,
  porque aí o dado não sai da infraestrutura de quem é dono dele.
- install.sh pergunta durante a instalação; em --yes sem SENTRY_DSN, desligado.
- Removidas as rotas de exemplo do assistente do Sentry: sentry-example-api era
  um GET sem auth que lançava de propósito, ou seja, qualquer um podia gerar
  evento no Sentry dos mantenedores à vontade.

Um defeito do próprio scrub só apareceu ao rodar o envelope inteiro: o Sentry
preenche request.query_string com a query CRUA, sem '?' na frente, e a primeira
versão do regex exigia o prefixo — a assinatura sobrevivia nesse campo. Tem
teste de regressão.

Relatado por @integralmarketingmx na issue #100, com diagnóstico próprio e uma
autocorreção sobre os Session Replays.

Refs #100

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C4NxbuaBH2rNizak9HkDpd
2026-08-03 12:50:27 -03:00

36 lines
1.4 KiB
TypeScript

// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
import { resolveSentryDsn, isCommunityDsn, DEFAULT_SENTRY_DSN } from "./lib/sentry/dsn";
import { sentryScrubHooks } from "./lib/sentry/scrub";
const sentryDsn = resolveSentryDsn(process.env.SENTRY_DSN);
const community = isCommunityDsn(sentryDsn);
Sentry.init({
dsn: sentryDsn,
// No Sentry da comunidade, só erro (issue #100). Ver isCommunityDsn().
tracesSampleRate: community ? 0 : 1,
enableLogs: true,
sendDefaultPii: false,
...sentryScrubHooks,
});
// Transparência de telemetria: uma linha no boot dizendo o que está ativo e como
// desligar. Evita "telemetria silenciosa" num projeto open source self-host.
if (!sentryDsn) {
console.info("[telemetria] Desligada (SENTRY_DSN=off) — nenhum erro é enviado.");
} else if (sentryDsn === DEFAULT_SENTRY_DSN) {
console.info(
"[telemetria] Relatórios de erro anonimizados ATIVOS (Sentry da comunidade). " +
"Sem rastreamento de performance nem replay de sessão. " +
"Desligue com SENTRY_DSN=off, ou envie pro seu com SENTRY_DSN=<seu-dsn>.",
);
} else {
console.info("[telemetria] Erros sendo enviados ao Sentry configurado em SENTRY_DSN.");
}