Pular para o conteúdo
Produtos Como trabalhamos Blog Conversar

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.

CheckO que verificaBloqueia quando
LintEstilo e erros simples de código, sem nenhum aviso tolerado.Qualquer erro ou aviso.
TiposA checagem de tipos da linguagem.Qualquer erro.
TestesTestes unitários e de integração, com um banco que nasce e morre com o job.Qualquer falha.
SegredosO histórico de commits do PR, atrás de chave, token ou senha.Qualquer achado.
Análise estáticaPadrões inseguros no código, como injeção e uso perigoso de API.Achado de severidade "erro".
DependênciasVulnerabilidades conhecidas nas bibliotecas do arquivo que trava as versões.Crítica ou alta, com correção disponível.
ImagemO 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 deployAs 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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.

  1. Proteja a branch principal com PR, aprovação e lista de exceções vazia, inclusive para administrador.
  2. Crie o check agregador, que reprova job falho, cancelado ou pulado, e aponte a proteção só para ele.
  3. Para cada check que só avisa, decida se ele passa a bloquear, se vira transição com data ou se sai.
  4. Comece por segredos, testes e dependências com correção, que são os de critério mais claro.
  5. Ponha os workflows sob dono de código e o token do GitHub em só leitura por padrão.
  6. Fixe as actions por SHA e ligue a política que exige isso.
  7. 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

  1. Strategies for the Integration of Software Supply Chain Security in DevSecOps CI/CD Pipelines (NIST SP 800-204D) · NIST ·
  2. GitHub Actions – Updating the default GITHUB_TOKEN permissions to read-only · GitHub Changelog ·
  3. Keeping secrets out of public repositories · GitHub Blog ·
  4. tj-actions changed-files through 45.0.7 allows remote attackers to discover secrets by reading actions logs (CVE-2025-30066) · GitHub Advisory Database ·
  5. GitHub Actions policy now supports blocking and SHA pinning actions · GitHub Changelog ·

Leia também

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.