Governança de IA · · 13 min de leitura
Gate que só alerta ensina o time a ignorar o vermelho
Um check de CI que só avisa vira paisagem em uma semana: o time aprende que vermelho não impede nada. Os checks que importam bloqueiam o merge. Por isso precisam ser justos: bloquear só o que tem correção no próprio PR, mandar o resto para uma fila com dono e nunca contar como aprovado um job que não rodou.
Por que alerta que não bloqueia é pior do que nenhum alerta?
Porque ele ensina. Um check que fica vermelho e deixa o merge acontecer mostra ao time, PR após PR, que vermelho não impede nada. Na primeira semana alguém lê o aviso. Na segunda, alguém comenta que "esse sempre falha". Na terceira, o vermelho virou paisagem, e o dia em que ele aponta um problema de verdade é igual a todos os outros. Sem o alerta, pelo menos ninguém se achava protegido.
É o mesmo mecanismo que discutimos no texto sobre regra escrita: uma regra que parece mecânica e não roda é pior do que nenhuma, porque cria confiança sem controle. No CI, o alerta que não bloqueia é a regra escrita em forma de ícone. Ele existe, aparece na tela, entra no relatório de conformidade e não segura nada.
Com IA no código, o problema cresce de dois jeitos. O primeiro é volume: um time que programa com assistente abre mais PRs, e maiores, com o mesmo número de pessoas para revisar, como mostramos no pilar desta série. Quem revisa passa a depender do check para saber onde olhar, e um check que grita sempre não aponta lugar nenhum. O segundo é o próprio assistente. Para um agente encarregado de "fazer a CI passar", um aviso que não impede o merge é o que é para a pessoa: algo para depois. E o caminho mais curto até o verde às vezes é afrouxar o check, acrescentando ao comando um trecho que transforma qualquer falha em sucesso.
Daí a regra: os checks que importam bloqueiam o merge. E, justamente por bloquearem, precisam ser justos. Um gate que trava o time por algo que o time não consegue corrigir provoca a mesma reação do alerta ignorado, só que mais rápido: alguém pede uma exceção, a exceção vira permanente e a proteção some.
Quais checks são obrigatórios num PR?
No nosso desenho, oito checks precisam passar antes de qualquer merge na branch principal, venha a mudança de uma pessoa ou de um assistente de IA: lint, tipos, testes, segredos, análise estática, dependências, imagem e validador de deploy. Nenhum deles é opcional, e nenhum tem exceção para administrador.
| Check | O que verifica | Bloqueia quando |
|---|---|---|
| Lint | Estilo e erros simples de código, sem nenhum aviso tolerado. | Qualquer erro ou aviso. |
| Tipos | A checagem de tipos da linguagem. | Qualquer erro. |
| Testes | Testes unitários e de integração, com um banco que nasce e morre com o job. | Qualquer falha. |
| Segredos | O histórico de commits do PR, atrás de chave, token ou senha. | Qualquer achado. |
| Análise estática | Padrões inseguros no código, como injeção e uso perigoso de API. | Achado de severidade "erro". |
| Dependências | Vulnerabilidades conhecidas nas bibliotecas do arquivo que trava as versões. | Crítica ou alta, com correção disponível. |
| Imagem | O build da imagem do contêiner, a varredura dela e da configuração, e a lista de componentes. | Crítica ou alta, com correção disponível. |
| Validador de deploy | As regras da casa para o que vai a produção. | Qualquer violação. |
O lint bloqueia aviso, não só erro: aviso tolerado é a versão pequena do alerta que não bloqueia, e com zero avisos um aviso novo é notícia. E o validador de deploy, que recusa no PR porta exposta, contêiner privilegiado e versão "latest", foi o protagonista do texto sobre o PR como único caminho.
O desenho de cada check segue um princípio que já apareceu no texto sobre como um guardrail decide: quem relata não é quem decide. A ferramenta de varredura gera o relatório inteiro, guardado mesmo quando o job falha. Um passo separado lê esse relatório e aplica a política da casa: severidade, existência de correção, exceções aprovadas. É esse passo, e não o padrão da ferramenta, que devolve verde ou vermelho. Mudar a política é um PR revisado, não um ajuste silencioso numa linha de comando.
Os oito checks protegem a branch principal por uma regra de proteção ativa, com a lista de exceções vazia, que também exige aprovação de dono de código, branch atualizada e nenhum push forçado. E um detalhe fecha uma porta que pouca gente vê: os arquivos que definem os próprios checks, os workflows, ficam sob dono de código. Um PR que afrouxa o gate precisa da aprovação de quem responde por ele, venha de uma pessoa apressada ou de um assistente que só queria o verde.
Por que a dependência vulnerável só bloqueia quando há correção?
Porque bloquear o que ninguém consegue corrigir no PR é a forma mais rápida de ensinar o time a ignorar o vermelho. Quando uma biblioteca tem uma vulnerabilidade crítica e já existe versão corrigida, o autor do PR tem uma ação possível: subir a versão. O bloqueio é justo. Quando não existe correção, não há o que fazer no PR, e bloquear é punir quem estava mexendo em outra coisa.
Imagine um time de cinco pessoas. Uma vulnerabilidade é publicada de madrugada contra uma biblioteca que o projeto usa há dois anos, e na manhã seguinte todos os PRs ficam vermelhos, inclusive o que corrige um texto na tela de login. A correção ainda não existe. Em uma hora, alguém com permissão desliga o check "só por hoje". Em uma semana, ninguém lembra que ele estava desligado.
Por isso, no nosso desenho, o gate de dependências e o de imagem bloqueiam só vulnerabilidade crítica ou alta com correção disponível. O resto não desaparece. Vai para uma fila de achados com dono, revisada toda semana na rotina de 30 minutos que o fecho da série vai detalhar. Para cada item, o dono escolhe um de três caminhos: mitigar de outro jeito, trocar a dependência ou aceitar o risco por escrito, com motivo e data de validade. A aceitação é um arquivo de exceções no repositório, alterado por PR, e a exceção vence sozinha na data marcada.
Para a vulnerabilidade nova numa dependência que nenhum PR tocou, existe uma auditoria semanal de todos os repositórios, que avisa o dono e não é obrigatória no merge, de propósito: vulnerabilidade nova trava a semana de quem responde pelo alarme, não o merge de quem mexeu em outra coisa. E a ferramenta que abre PR de atualização de versão, como o Dependabot do GitHub, faz o resto: a correção chega como um PR pequeno, que passa pelos mesmos oito checks.
O erro comum aqui não é bloquear de menos. É bloquear tudo, colher a revolta e voltar para o alerta. Um gate com um critério que o time entende, "se tem correção, corrija agora", sobrevive.
O que fazer com o teste dinâmico (DAST)?
Começar como alerta, dentro do job, contra uma cópia efêmera da aplicação, e só torná-lo obrigatório depois que ele estiver estável. É o único caso em que o desenho aceita um check que só avisa, e por um motivo preciso: é transição, com data para acabar.
O teste dinâmico ataca a aplicação rodando, como faria um visitante mal-intencionado: procura cabeçalho de segurança ausente, página de erro que vaza informação, rota sem autenticação. Para isso precisa de uma aplicação no ar, e o atalho óbvio é apontá-lo para homologação ou, pior, para produção. Isso exige que a máquina de CI alcance esses ambientes, e a máquina que roda código de qualquer PR não deve alcançar nada disso, como a série vai mostrar no texto sobre isolamento.
A saída é subir a aplicação dentro do próprio job. A imagem que acabou de ser construída sobe numa rede que só existe naquela execução, com um ambiente gerado na hora: para cada nome do modelo de configuração do projeto, um valor aleatório, que não vale nada fora dali. O teste roda, o relatório é guardado, a aplicação e a rede são destruídas. Nenhuma credencial real, nenhuma rota para fora do job.
Mesmo assim, o teste dinâmico começa só avisando. Ele tem mais falso positivo do que os outros checks e costuma pedir ajuste fino por aplicação. Se entrar bloqueando no primeiro dia, o falso positivo trava o merge e o time aprende a lição errada. Então ele roda em todo PR, os achados vão para a mesma fila semanal e, quando o ruído fica sob controle por algumas semanas seguidas, ele é promovido a obrigatório, ao lado dos oito. A diferença para o alerta que ensina a ignorar é que este tem dono, critério de promoção e data de revisão. Contra produção, a varredura é só passiva: observa, não ataca.
Que armadilhas travam tudo ou deixam tudo passar?
Três, e nenhuma aparece na tela como erro. As duas primeiras se resolvem com o mesmo conserto. A terceira pede uma mudança de atitude.
O check obrigatório com nome errado. A regra de proteção exige os checks pelo nome. Se ela pede um check chamado "build" e o job se chama "imagem", o check exigido nunca é reportado, e todo PR fica parado à espera de um resultado que não vai chegar. A reação natural é alguém abrir uma exceção para destravar o dia, e a exceção fica. O conserto é um check agregador, com nome estável, que depende de todos os jobs; a regra de proteção aponta só para ele. Renomear um job deixa de quebrar a proteção.
O job pulado contado como aprovado. No GitHub Actions, um job pulado por uma condição reporta "sucesso", e a própria documentação avisa que isso não impede o merge, mesmo quando ele é um check obrigatório. Uma condição escrita ao contrário ou um filtro de caminho que não pega o arquivo novo, e o verde é de quem não rodou. O mesmo agregador resolve: ele reprova quando qualquer job falhou, foi cancelado ou foi pulado, porque job pulado não validou nada.
A varredura de segredo que só pega depois do push. O check de segredos roda no CI, e o CI só roda depois que o commit chegou ao servidor do Git. Quando ele fica vermelho, o merge está bloqueado, mas o segredo já está no histórico remoto e em cada clone feito desde então. O check impede que o segredo chegue à branch principal; não impede que ele vaze. Por isso achado do check de segredos não se resolve apagando o commit: o segredo conta como comprometido e é trocado. A escala é pública: nas oito primeiras semanas de 2024, o GitHub detectou mais de 1 milhão de segredos vazados em repositórios públicos.
A camada que pega antes é a proteção no push, que recusa o envio quando reconhece um segredo. O GitHub anunciou em fevereiro de 2024 que ela passava a valer por padrão nos envios para repositórios públicos; em repositório privado, ela depende de um recurso pago. Sem ela, a camada anterior é a máquina de quem programa: uma verificação local antes do commit e, quando o código é escrito com assistente, o guardrail que barra o segredo antes de ele virar arquivo. O check do CI continua obrigatório. Ele é a última rede, não a primeira.
Como as Actions entram sem virar porta?
Por quatro controles: lista permitida, versão fixada pelo SHA do commit, token só de leitura por padrão e workflow de PR de fork desligado. Uma action de terceiro roda dentro do job, com o token e os segredos dele. Sem esses controles, ela é código de fora executando com a sua credencial.
O risco não é teórico. Em março de 2025, uma action de terceiros muito usada, que lista os arquivos alterados num PR, foi comprometida. Segundo o alerta publicado no banco de vulnerabilidades do GitHub, os atacantes moveram várias etiquetas de versão para um commit malicioso, que extraía segredos da memória da máquina do job e os imprimia no log do workflow. Quem referenciava a action pela etiqueta recebeu o código novo sem mudar uma linha. Etiqueta, no Git, pode ser movida; o SHA de um commit, não.
Os quatro controles respondem a isso.
- Lista permitida. Só rodam as actions da própria organização, as do GitHub e poucas de terceiros, nomeadas uma a uma. As ferramentas de varredura rodam como imagem de contêiner com versão fixa, e não como action, o que encolhe a lista.
- Fixadas por SHA. Toda action é referenciada pelo SHA completo do commit. Desde agosto de 2025, o GitHub permite que o administrador exija isso por política, e o workflow que usa action sem SHA falha. A versão nova chega por PR, com o SHA novo.
- Token só de leitura por padrão. O token que o GitHub entrega a cada job só lê o repositório; escrita vai só para o job que precisa, como o que publica a imagem depois do merge. Em fevereiro de 2023, o GitHub passou a criar organizações e repositórios novos com esse padrão; os antigos mantêm o que tinham, e vale conferir.
- PR de fork desligado. Em repositório privado, workflows disparados por PR vindo de fork ficam desligados. Código de fora não roda com os segredos de dentro.
O erro comum é tratar a action como configuração, e não como código de terceiro, com acesso a tudo o que o job acessa. O NIST, no SP 800-204D, de fevereiro de 2024, trata o próprio pipeline de CI/CD como parte da cadeia de suprimentos de software. É o enquadramento certo: a esteira que verifica o código também precisa ser verificada.
Por onde começar num time pequeno?
Pela lista do que roda hoje e do que bloqueia de verdade. Monte uma tabela com três colunas: o que bloqueia, o que só avisa e o que ninguém sabe se roda. Depois, siga esta ordem.
- Proteja a branch principal com PR, aprovação e lista de exceções vazia, inclusive para administrador.
- Crie o check agregador, que reprova job falho, cancelado ou pulado, e aponte a proteção só para ele.
- Para cada check que só avisa, decida se ele passa a bloquear, se vira transição com data ou se sai.
- Comece por segredos, testes e dependências com correção, que são os de critério mais claro.
- Ponha os workflows sob dono de código e o token do GitHub em só leitura por padrão.
- Fixe as actions por SHA e ligue a política que exige isso.
- Dê a cada fila de achados um dono e meia hora por semana.
Nada disso exige ferramenta cara. Exige decidir, para cada vermelho, se ele impede o merge. Vermelho que impede precisa ser justo. Vermelho que não impede precisa de dono e de data. O que não pode existir é o terceiro tipo: o vermelho que não impede e que ninguém lê.
Um dos oito checks merece um texto só para ele, porque o que ele procura não deveria nem chegar ao repositório. É o segredo, que costuma deixar rastro antes de chegar ao código: no terminal.
Perguntas frequentes
Bloquear o merge não deixa o time mais lento?
Deixa o merge mais lento quando há problema, e é para isso que ele existe. O que atrasa de verdade é o gate injusto, o que trava por algo sem correção ou por falso positivo frequente. Com critério claro, o vermelho vira uma tarefa com solução conhecida, resolvida no próprio PR, em vez de uma discussão sobre se dá para mergear assim mesmo.
O que fazer quando um check dá falso positivo?
Corrigir a regra, não contornar o check. A exceção entra num arquivo do repositório, por PR, com motivo e data de validade, revisada por quem é dono do check. Assim o falso positivo deixa de bloquear sem que o check deixe de valer para o resto, e a exceção vence sozinha se ninguém a renovar.
Por que não bloquear toda vulnerabilidade crítica?
Porque, sem correção publicada, não existe ação possível no PR, e bloquear ensina o time a desligar o check. Vulnerabilidade crítica ou alta com correção bloqueia. Sem correção, ela vai para uma fila semanal com dono, que decide mitigar, trocar a dependência ou aceitar o risco por escrito, com data de validade.
A varredura de segredos no CI basta?
Não. Ela roda depois do push, quando o segredo já está no servidor do Git e em cada clone. Ela impede que ele chegue à branch principal, não que vaze. Por isso achado dela conta como segredo comprometido, que precisa ser trocado. A proteção no push e a verificação na máquina de quem programa pegam antes.
O administrador pode ter exceção na proteção da branch principal?
No nosso desenho, não. Check obrigatório com exceção para administrador é alerta para o administrador, e a conta de administrador é justamente a mais valiosa para quem ataca. Uma emergência real se resolve com um PR rápido, que passa pelos mesmos checks, e não com um atalho.
Quais são os oito checks obrigatórios de um PR?
Lint, tipos, testes, segredos, análise estática, dependências, imagem e validador de deploy. Todos precisam passar antes do merge na branch principal, venha a mudança de uma pessoa ou de um assistente de IA. O teste dinâmico começa como alerta, dentro do job, e só vira obrigatório depois de estável.
Fontes
- Strategies for the Integration of Software Supply Chain Security in DevSecOps CI/CD Pipelines (NIST SP 800-204D) · NIST ·
- GitHub Actions – Updating the default GITHUB_TOKEN permissions to read-only · GitHub Changelog ·
- Keeping secrets out of public repositories · GitHub Blog ·
- tj-actions changed-files through 45.0.7 allows remote attackers to discover secrets by reading actions logs (CVE-2025-30066) · GitHub Advisory Database ·
- GitHub Actions policy now supports blocking and SHA pinning actions · GitHub Changelog ·
Leia também
- Produção nunca constrói: o PR como único caminho do código com IA
- Como um guardrail de IA decide: risco, regra e o que você pediu
- Regra escrita não é regra: por que a política de IA virou mecanismo
- Governança de IA no código: o caminho estreito até produção
Por Victor Freitas · Consultor em governança de tecnologia e IA · Franklin Freitas Consultoria
Conduz diagnósticos e implantações de governança de tecnologia e IA em pequenas e médias empresas, com experiência acumulada em provedores de internet.