Suíte de conformidade

Para: Dev — Conferido em 2026-10-18.

A suíte de conformidade é o teste de aceite do contrato da API v1. É um programa em Go que fala só HTTP com a sua operação Teste e traz um operador de referência para receber os webhooks. Verde é pré-requisito do go-live.

O que é

  • É caixa-preta: usa a superfície pública (/v1/* e /v1/sandbox/*) e um listener local para os webhooks. Não lê banco nem código do servidor.
  • Traz um operador de referência que recebe o webhook, verifica a assinatura, deduplica, faz o fetch-back e registra o crédito num livro próprio, só na memória da suíte.
  • Ela testa o Dracma, usando o operador de referência como contraparte. Ela não testa o seu conector. Para provar o seu lado, rode as Receitas por caminho contra o seu receptor e o seu livro.
  • Um caso que precisa de uma configuração que você não passou falha com "configuração ausente"; ele nunca é pulado como verde.
  • A suíte é entregue pelo Dracma no onboarding, junto com as credenciais da operação Teste.

Quando usar

  • Uma vez no onboarding, antes de pedir a operação Real, e guardando a saída como prova do go-live (Checklist de go-live).
  • De novo quando o Dracma publicar uma versão nova do contrato ou do openapi.yaml (Changelog).
  • Como teste de regressão do seu ambiente: relógio, rede até o Dracma e URL de webhook alcançável.

Como funciona

O que ela prova

Casos obrigatórios do contrato (PIX). Cada um já foi visto falhar quando a regra correspondente é quebrada.

# O que prova Caso
1 Assinatura inválida, timestamp fora da janela e nonce repetido são recusados (401 com o code certo) e nada é criado TestInvalidSignatureRejected, TestTimestampOutOfWindowRejected, TestReplayedNonceRejected, TestT1UnknownKeyAndMissingHeaders
2 Mesma chave e mesmo corpo devolvem a mesma resposta com Idempotent-Replayed: true; corpo diferente dá 409 idempotency_key_reused TestIdempotencySameResponse, TestIdempotencyDifferentBody409
3 Depósito, pay, webhook deposit.paid assinado e fetch-back coerente geram exatamente 1 crédito TestDepositPaidWebhookAndFetchBack, TestE2EP001DepositPaid
4 Webhook reentregue com o mesmo Dracma-Event-Id responde 200 sem efeito TestWebhookRedeliveredSameEventID
5 expired é terminal: pagar depois não vira paid e cancelar dá 409 TestDepositExpiration
6 Saque dentro do limite chega a approved (automático) e a paid TestWithdrawalWithinMultiplierPaid, TestE2EP002WithdrawalPaid, TestSandboxWithdrawalPayExplicit
7 Saque acima do limite vai a under_review com AUTO_MULTIPLIER_EXCEEDED TestWithdrawalAboveMultiplierUnderReview
8 review_requested: true nunca é automático TestReviewRequestedNeverAutomatic
9 Objeto de outra operação responde 404 em todas as rotas TestCrossOperationObject404, TestT4BOLA, TestDoD6CrossTenantEveryRoute
10 /sandbox/outage dá 503 repetível, e a retomada com a mesma chave não duplica TestSandboxOutageRetrySameKey

Casos adicionais:

O que prova Caso
Webhook forjado, com corpo alterado, timestamp velho ou t= divergente não credita; nem um deposit.paid válido para um depósito que a API diz pending TestT3ForgedWebhooksNoCredit
Valor divergente vai a under_review com AMOUNT_MISMATCH e não emite deposit.paid TestE2EP001AmountMismatchUnderReview
Chave PIX de e-mail passa pela consulta de titularidade do simulador TestE2EC123DictEmailKey
Máquina de estados: transição inválida dá 409 invalid_state_transition e não muda o estado TestT14StateMachine
Campo proibido no corpo (operation_id, status, decision, version, paid_amount) é recusado ou ignorado, nunca aplicado TestT9MassAssignment
Corpos hostis (SQL, número em vez de texto, notação científica, UTF-8 inválido, corpo acima de 64 KiB) dão 400 ou 413, nunca 5xx TestT13InjectionAndCoercion
A chave de integração não muda regras, webhook, chave nem IP; um pedido de regra fica pending_approval e não vigora TestT8OperatorCannotChangeControlPlane
50 saques simultâneos com a mesma chave criam 1 objeto; dois saques simultâneos não passam do limite automático TestT5ConcurrentIdempotentWithdrawals, TestT6DoubleWithdrawalRace
Digest e totais da reconciliação batem com o recalculado de forma independente TestC253ReconciliationDigestIndependent

Casos de segurança que precisam de configuração extra (flags da próxima seção): chave de Real contra Teste e o inverso, rotas /sandbox/* em Real, revogação de chave, segredo ausente de log e resposta, rastreio por trace_id, limites de taxa e cadastro de URL de webhook.

Caso de IP fora da lista

O caso TestT17IPAllowlist espera 403 ip_not_allowed para um IP fora da lista e só faz sentido se a operação de teste tiver ao menos um IP liberado. Sem IP liberado a operação aceita qualquer origem, então não passe -blocked-ip-key-id. Veja IPs do conector.

Flags

Flag Conteúdo
-dracma-url Base da API da operação Teste, incluindo /v1
-key-id e -key-secret-file Chave key_test_ da operação e o arquivo com o segredo. Nunca passe o segredo na linha de comando
-webhook-secret-file Segredos de webhook ativos, um por linha (1 ou 2 durante a rotação)
-webhook-listen Endereço do listener local do operador de referência (padrão: o endereço local da máquina, em uma porta livre)
-webhook-url URL cadastrada na operação que chega nesse listener (padrão http://<listen>/webhook)
-currency Moeda da carteira (padrão BRL)
-wait e -webhook-wait Espera máxima por uma transição (padrão 30 s) e por um webhook (padrão 90 s)
-quiesce-timeout Quanto esperar, antes dos casos, que os limites de taxa de uma rodada anterior liberem (padrão 5 min)
-key2-id e -key2-secret-file Chave de uma operação de outro tenant, para os casos de isolamento
-live-url, -live-key-id, -live-key-secret-file Operação Real, para a recusa cruzada de chaves e o 404 das rotas de sandbox
-blocked-ip-key-id, -blocked-ip-key-secret-file Chave cuja lista de IPs não inclui o IP da suíte (não se aplica hoje, veja o aviso acima)
-revoke-key-id, -revoke-key-secret-file, -revoke-cmd, -revoke-deadline Revogação de chave, com o comando de revogação e o prazo (padrão 5 min)
-log-file, -live-log-file Log JSON do servidor, para os casos de vazamento de segredo e rastreio
-recon-date Dia UTC já fechado para o caso de reconciliação (padrão: o dia fechado mais recente)
-openapi openapi.yaml de onde as rotas do caso de isolamento são enumeradas

Os arquivos de segredo ficam fora do repositório, com permissão 0400, entregues pelo seu cofre.

Exemplos

Execução do conjunto base, que só precisa da sua operação Teste e do seu receptor:

cd conformance
go test ./conformance -count=1 -v \
  -run 'TestInvalidSignature|TestTimestampOutOfWindow|TestReplayedNonce|TestT1UnknownKey|TestIdempotency|TestDeposit|TestWebhookRedelivered|TestWithdrawal|TestReviewRequested|TestSandbox|TestE2E|TestT3|TestT9|TestT13|TestT14' \
  -dracma-url="$DRACMA_BASE_URL" \
  -key-id=key_test_SUAOPERACAO \
  -key-secret-file=/caminho/seguro/segredo-chamada \
  -webhook-secret-file=/caminho/seguro/segredos-webhook \
  -webhook-listen=localhost:0 \
  -webhook-url=https://pagamentos.operador.example/dracma/webhook \
  -currency=BRL
  • O listener do operador de referência precisa ser alcançável pelo Dracma na -webhook-url cadastrada na operação. Se o Dracma não consegue chegar nele, os casos de webhook falham por tempo esgotado em -webhook-wait.
  • Para a execução completa, acrescente as flags opcionais e tire o -run. A execução completa inclui o caso de limites de taxa, que consome os baldes da chave e do IP e roda por último; ele pode deixar o IP da suíte limitado por alguns minutos. Rodadas seguidas esperam esse bloqueio passar antes de começar.
  • Há ainda os testes TestOffline*, que não precisam de servidor: eles conferem vetores de assinatura, o verificador e o operador de referência.

Erros e casos de borda

Sintoma Causa provável O que fazer
configuração ausente: -key2-id O caso exige uma segunda operação ou a operação Real, que você não passou Rode com -run no conjunto base, ou passe as flags do caso
Casos de saque caem em revisão em vez de automático As regras da operação foram mudadas (janela, horário, multiplicador) Os casos de saque assumem as regras iniciais; restaure-as ou peça a restauração ao suporte
Timeout esperando webhook A URL cadastrada não chega ao listener local, ou o relógio está desviado Confira a URL, o firewall e o NTP
429 rate_limited em sequência Duas rodadas seguidas, ou o caso de limites de taxa rodou antes Espere ou aumente -quiesce-timeout
Falhas só em segurança com -live-* A chave de Real aponta para o host errado Confira o host de Real e o prefixo key_live_

Operação Real

Passe -live-* somente com uma chave de Real quando o Dracma pedir. Os casos que usam essa chave só tentam requisições recusadas, mas a chave é de dinheiro real: guarde-a como qualquer outra credencial de produção.

Veja também