Este repositório tem uma regra escrita: todo commit passa por um hook local que varre o que está prestes a entrar no git atrás de chave de API, token e senha, antes de qualquer coisa sair da máquina. Ao checar se essa regra estava mesmo valendo, para escrever este post, a resposta foi não. O hook não estava instalado. O arquivo que descreve a regra existia; a regra, na prática, não.
Duas linhas de defesa, dois trabalhos diferentes
O desenho tem duas camadas, e elas não fazem a mesma coisa:
- Local (pre-commit + gitleaks). Roda na máquina de quem está commitando, varre o diff que está prestes a virar commit e, no push, o intervalo de commits que vai sair para o servidor. É rápido, sub-segundo, e devolve arquivo e linha na hora. Existe por conveniência: pega o erro cedo, antes de qualquer round-trip com o servidor.
- Servidor (CI + branch protection). Um job de gitleaks roda a cada push e a cada PR, e a branch principal exige esse check verde para aceitar merge. Isso não depende de nada instalado na máquina de ninguém.
A diferença importa porque só uma das duas é, de fato, inegociável.
O --no-verify não é um flag só, são dois
git commit --no-verify pula os hooks de commit (pre-commit e commit-msg), o que está documentado no manual oficial do Git. git push --no-verify pula o hook de push (pre-push): mesmo nome de flag, comando diferente, hook diferente. Quem lembra de rodar os dois furou as duas pontas da camada local, sem gerar erro, sem deixar rastro: é comportamento documentado do Git, não falha de configuração.
E tem uma terceira porta, mais cirúrgica: no framework pre-commit, a variável SKIP pula um hook específico pelo id sem tocar nos demais. SKIP=gitleaks git commit -m "..." desliga só a varredura de segredo e deixa o resto do pre-commit rodando normalmente. Não precisa nem saber que --no-verify existe.
Nenhuma dessas três rotas é obscura ou exige acesso especial. São recursos padrão do Git e do pre-commit, documentados nos próprios manuais. É esse o motivo de a camada local nunca poder ser o plano de contenção.
Por que o servidor é diferente
O GitHub tem uma proteção que bloqueia o push em si quando detecta um padrão de segredo: Push Protection. No nível de usuário, ela já vem ligada por padrão e barra push de segredo para repositório público, sem custo. No nível de repositório, que é a varredura que cobre também repositório privado, depende de ligar antes o produto pago de proteção de segredo (hoje GitHub Secret Protection, antes chamado GitHub Advanced Security). Isso muda o desenho: quem trabalha com repositório privado (o caso comum em projeto de cliente) não pode simplesmente contar com a proteção automática e considerar resolvido; precisa montar o equivalente com as próprias mãos.
É para isso que serve a segunda peça: uma regra de proteção de branch com "Require status checks to pass before merging". Isso bloqueia o merge na origem, na plataforma, não num script rodando no computador de quem escreveu o código. Nenhum --no-verify, nenhum SKIP, nenhuma variável de ambiente alcança essa trava: ela não está do lado de quem poderia querer pular o hook.
O que a checagem encontrou aqui
Concretamente, o que aconteceu ao verificar este repositório: o arquivo de configuração do hook local existe, documenta as duas camadas e até explica por que uma não substitui a outra. Mas rodar o comando que confirma se o hook está instalado devolveu "módulo não encontrado", e a pasta onde o Git guarda hooks ativos só tinha os arquivos de exemplo (.sample) que vêm por padrão em qualquer repositório novo, ou seja, nenhum hook real instalado.
Ou seja: a política estava escrita, correta, bem argumentada. A execução, nesta cópia do repositório, não estava ligada. Nenhum segredo vazou por causa disso, porque a camada de servidor continua de pé, indiferente ao que acontece (ou deixa de acontecer) do lado local. Mas o exemplo é didático demais para não registrar: é exatamente o modo de falha que a própria política descreve, acontecendo na prática, num clone fresco.
A lição
Um controle de segurança que só existe dentro de um arquivo de configuração é um documento, não um controle. Ele vira controle quando alguém confere que está de fato executando: a pasta de hooks do Git tem hook real, não só exemplo; o binário que o hook chama está instalado; rodar o comando de verificação não devolve erro.
Máquina nova, clone recém-feito, container que reiniciou: qualquer um desses eventos zera a camada local silenciosamente, sem avisar ninguém, porque não existe hook para falhar. Por isso o desenho correto trata a camada local como cortesia: pega o erro de digitação na velocidade de quem está digitando, quando (e só quando) está de fato instalada. A camada que precisa funcionar sempre, para todo mundo, é a que nenhum estado de máquina local consegue desligar, a que mora no servidor, amarrada ao merge.
Quando a Mutagex desenha essa proteção para um projeto, o ponto de partida é assumir que a camada local vai falhar silenciosamente algum dia, e a esteira precisa sobreviver a isso sem depender de ninguém perceber. Foi essa mesma checagem, feita no meio da escrita deste post, que confirmou a regra na prática.