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:

  1. Configurar um serviço de CI que reporte o status para o repositório (ex: GitHub Actions com statuses).
  2. 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

Exercícios

  1. Qual a finalidade de uma proteção de branch? Dê um exemplo de configuração comum.
  2. ✓ Resposta: A proteção de branch impede ações indesejadas em branches críticas, como push direto ou deleção. Exemplo: exigir que pull requests sejam aprovados por pelo menos um revisor antes do merge.
  3. Explique a diferença entre merge commit, squash and merge e rebase and merge.
  4. ✓ Resposta: Merge commit cria um commit de merge que preserva o histórico completo. Squash and merge combina todos os commits da branch em um único commit, resultando em histórico linear. Rebase and merge reescreve os commits da branch sobre a base, também linear, mas mantendo os commits individuais.
  5. O que são status checks e como eles ajudam na segurança do merge?
  6. ✓ Resposta: Status checks são verificações automatizadas (testes, lint, etc.) que rodam em PRs. Se falham, o merge pode ser bloqueado, garantindo que código defeituoso não entre na branch principal.
  7. Como configurar uma regra de proteção que exija que a branch esteja atualizada com a base?
  8. ✓ Resposta: No GitHub, ao criar/editar uma regra de proteção, marque a opção "Require branches to be up to date before merging". Isso impede o merge se a branch de origem não contiver os commits mais recentes da branch base.
  9. Por que é importante manter PRs pequenos e focados?
  10. ✓ Resposta: PRs pequenos facilitam a revisão, reduzem o risco de conflitos e permitem feedback mais rápido. Além disso, são mais fáceis de reverter se necessário, aumentando a segurança do processo.