Segurança de Branches e Merge
Esta aula aborda práticas de segurança em branches e merge em Git, incluindo proteções de branches, pull requests, status checks e regras de merge. O objetivo é garantir que o código seja revisado e testado antes de ser integrado à branch principal.
Em ambientes colaborativos de desenvolvimento, a integridade do código é fundamental. Branches e merges são operações diárias que, sem controles adequados, podem introduzir vulnerabilidades ou quebras no software. Esta aula explora mecanismos de segurança que plataformas como GitHub, GitLab e Bitbucket oferecem para proteger branches críticas (como main ou master) e garantir que apenas código revisado e aprovado seja mesclado.
Proteções
Proteções de branch são regras configuradas para restringir ações em branches específicas. Elas previnem que desenvolvedores acidentalmente (ou maliciosamente) façam push direto, forcem push ou deletem a branch. Além disso, podem exigir que pull requests passem por revisões e verificações antes do merge.
Exemplos comuns de proteções incluem:
- Impedir push direto para a branch protegida.
- Exigir que pull requests sejam aprovados por um número mínimo de revisores.
- Exigir que todos os status checks sejam aprovados.
- Exigir que a branch esteja atualizada com a base (evitar merges conflitantes).
Para configurar proteções no GitHub, vá em Settings > Branches > Add rule. Lá você pode especificar o nome da branch (ex: main) e marcar as opções desejadas.
# Exemplo de regra de proteção (GitHub API)
{
"required_status_checks": {"strict": true, "contexts": ["continuous-integration"]},
"enforce_admins": true,
"required_pull_request_reviews": {"required_approving_review_count": 2},
"restrictions": null
}
PRs
Pull Requests (PRs) são a principal ferramenta para revisão de código. Um PR solicita que as alterações de uma branch sejam mescladas em outra, geralmente a branch principal. Durante o processo, outros desenvolvedores podem revisar, comentar e solicitar alterações antes do merge.
Boas práticas incluem:
- Manter PRs pequenos e focados.
- Descrever claramente o que foi alterado e por quê.
- Atribuir revisores relevantes.
- Responder a comentários e atualizar o PR conforme necessário.
Plataformas permitem exigir que PRs sejam aprovados por um ou mais revisores antes do merge, garantindo que pelo menos uma outra pessoa revisou o código.
# Exemplo de fluxo de PR
1. Criar branch feature a partir de main.
2. Fazer commits e push.
3. Abrir PR de feature para main.
4. Revisores aprovam ou solicitam alterações.
5. Após aprovação, merge.
Status checks
Status checks são verificações automatizadas que rodam contra o código do PR, como testes unitários, lint, análise de segurança, etc. Eles são integrados via serviços de CI/CD (GitHub Actions, Jenkins, CircleCI).
Se um status check falhar, o merge pode ser bloqueado (dependendo das regras de proteção). Isso garante que código que não passa nos testes não entre na branch principal.
Para configurar status checks, você precisa:
- Configurar um serviço de CI que reporte o status para o repositório (ex: GitHub Actions com
statuses). - No branch protection rule, marcar "Require status checks to pass before merging" e selecionar os contextos desejados.
# Exemplo de GitHub Action que reporta status
name: CI
on: pull_request
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm test
- uses: actions/github-script@v6
with:
script: |
github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: 'success',
context: 'continuous-integration'
})
Regras de merge
Regras de merge definem como as alterações são integradas. As opções comuns são:
- Merge commit: Cria um commit de merge que preserva o histórico da branch.
- Squash and merge: Combina todos os commits da branch em um único commit antes de merge, resultando em um histórico mais limpo.
- Rebase and merge: Rebaseia os commits da branch sobre a base, mantendo um histórico linear (sem commit de merge).
Para segurança, é importante escolher a estratégia que melhor se adapta ao fluxo de trabalho. Squash é útil para PRs com muitos commits de trabalho, enquanto rebase evita merges desnecessários. Algumas equipes preferem apenas merge commit para rastreabilidade.
Além disso, é possível exigir que a branch esteja atualizada com a base antes do merge ("Require branches to be up to date"), evitando conflitos.
# Exemplo de configuração de merge no GitHub
merge_commit: true
squash_merge: true
rebase_merge: false
Boas práticas e observações finais
Implementar proteções de branch é essencial, mas não substitui uma cultura de revisão de código. É importante equilibrar segurança com produtividade: muitas exigências podem atrasar o desenvolvimento. Recomenda-se começar com proteções básicas (impedir push direto e exigir pelo menos um revisor) e evoluir conforme necessário.
Lembre-se de que as configurações de proteção podem ser versionadas (Infrastructure as Code) usando ferramentas como Terraform ou GitHub’s branch protection API, garantindo consistência entre repositórios.
Referências
- GitHub Docs: Managing protected branches
- GitLab Docs: Protected branches
- Atlassian: Comparing Git workflows
- GitHub Docs: About pull requests
- GitHub Actions: Events that trigger workflows
Exercícios
- Qual a finalidade de uma proteção de branch? Dê um exemplo de configuração comum.
- Explique a diferença entre merge commit, squash and merge e rebase and merge.
- O que são status checks e como eles ajudam na segurança do merge?
- Como configurar uma regra de proteção que exija que a branch esteja atualizada com a base?
- Por que é importante manter PRs pequenos e focados?