Branch permissions granular: protegendo paths específicos
1. Introdução à proteção granular de branches
1.1. O problema da proteção tudo-ou-nada
Em repositórios Git tradicionais, a proteção de branches opera no modelo binário: uma branch está protegida ou não. Quando ativada, todas as alterações na branch principal exigem revisão, independentemente do conteúdo. Esse modelo "tudo-ou-nada" cria riscos significativos em cenários onde paths específicos dentro do repositório são críticos — como arquivos de CI/CD, secrets de infraestrutura ou configurações de deploy.
Considere um cenário onde um desenvolvedor front-end modifica acidentalmente um arquivo .gitlab-ci.yml junto com uma correção de CSS. Sem proteção granular, essa alteração na pipeline pode passar despercebida em uma revisão focada apenas no código visual.
1.2. Path-based permissions vs. branch-level permissions tradicionais
As permissões baseadas em path diferem fundamentalmente das regras tradicionais de branch. Enquanto as regras de branch protegem a branch como um todo (exigindo pull requests, revisões ou status checks), as permissões por path permitem definir políticas específicas para diretórios ou arquivos individuais dentro da mesma branch.
# Exemplo: Proteção tradicional vs. granular
# Tradicional: Toda alteração na branch main requer 2 aprovações
# Granular: Alterações em config/ exigem aprovação do time de DevOps
# Alterações em src/ exigem aprovação do time de desenvolvimento
1.3. Casos de uso típicos
Paths que frequentemente exigem proteção granular incluem:
infra/oudeploy/: Configurações de infraestrutura e scripts de deploy.github/workflows/ou.gitlab-ci.yml: Arquivos de CI/CDsecrets/ouconfig/: Arquivos com segredos ou configurações sensíveisdatabase/migrations/: Migrações de banco de dados que podem causar downtime
2. Mecanismos nativos de proteção por path no Git
2.1. .gitattributes e git diff
O Git oferece mecanismos nativos para detectar alterações em paths específicos, embora não forneça proteção automática. O arquivo .gitattributes pode definir atributos por path, e o comando git diff permite filtrar alterações:
# Detectar alterações apenas em paths específicos
git diff --name-only main..feature-branch | grep '^infra/'
# Usar diff-filter para identificar tipos de alteração
git diff --diff-filter=M --name-only main..feature-branch | grep '\.yml$'
2.2. Hooks do lado do servidor
Hooks server-side como pre-receive e update podem implementar validações de path. Um exemplo de hook update que bloqueia alterações em paths sensíveis:
#!/bin/bash
# Hook update: Bloqueia pushes que modificam paths críticos
refname="$1"
oldrev="$2"
newrev="$3"
# Paths proibidos sem aprovação específica
PROTECTED_PATHS=("infra/" "secrets/" "config/production.yml")
for path in "${PROTECTED_PATHS[@]}"; do
if git diff --name-only $oldrev..$newrev | grep -q "^$path"; then
echo "ERRO: Alterações em $path requerem aprovação do time de infraestrutura."
exit 1
fi
done
exit 0
2.3. Limitações dos hooks
Apesar de funcionais, hooks server-side apresentam limitações significativas:
- Manutenção manual e propensa a erros
- Falta de integração visual com a interface do repositório
- Dificuldade de aplicar regras diferentes para diferentes branches
- Ausência de logs centralizados de tentativas de bypass
3. Implementação com plataformas modernas
3.1. GitHub: CODEOWNERS e regras de branch
O GitHub oferece suporte nativo a path permissions através do arquivo CODEOWNERS combinado com regras de branch:
# .github/CODEOWNERS
# Time de infraestrutura é responsável por paths específicos
infra/ @time-devops
config/deploy.yml @time-devops
.github/workflows/ @time-qa
# Time de segurança revisa alterações em secrets
secrets/ @time-seguranca
Para forçar a revisão, configure a regra de branch "Require review from Code Owners".
3.2. GitLab: Merge request approvals com regras de path
No GitLab, as regras de aprovação podem ser configuradas por path:
# Configuração no GitLab UI ou via API
# Crie uma regra de aprovação que exige:
# - 2 aprovações do grupo "devops" para alterações em infra/
# - 1 aprovação do grupo "security" para alterações em secrets/
3.3. Bitbucket: Branch permissions avançadas
O Bitbucket permite criar permissões de branch com restrições por path:
# Configuração no Bitbucket
# 1. Acesse Settings > Branch permissions
# 2. Crie uma regra para a branch main
# 3. Adicione "Path-based restrictions" para infra/ e config/
# 4. Defina grupos que podem modificar esses paths
4. Estratégia de CODEOWNERS para paths sensíveis
4.1. Sintaxe de arquivos CODEOWNERS
O arquivo CODEOWNERS segue uma sintaxe simples baseada em padrões de path:
# Padrões de path e owners correspondentes
# Cada linha define um padrão e os usuários/equipes responsáveis
# Owner padrão para todo o repositório
* @time-core
# Owner específico para diretório de documentação
docs/ @time-tech-writer
# Owner para múltiplos diretórios
infra/ config/deploy/ @time-devops
# Owner para arquivos específicos
.env.example @time-seguranca
4.2. Combinando CODEOWNERS com required reviews
Para que o CODEOWNERS seja efetivo, é necessário configurar regras de branch que exijam revisão dos code owners:
# Configuração no GitHub (via UI ou API)
# 1. Settings > Branches > Add rule
# 2. Nome da branch: main
# 3. Habilitar "Require a pull request before merging"
# 4. Habilitar "Require review from Code Owners"
# 5. Habilitar "Dismiss stale pull request approvals when new commits are pushed"
4.3. Boas práticas para CODEOWNERS
- Evitar overlaps: Quando dois padrões correspondem ao mesmo path, o último padrão no arquivo tem precedência
- Definir owners por subdiretórios: Seja específico para evitar ambiguidades
- Usar equipes em vez de usuários individuais: Facilita a manutenção quando membros mudam
5. Integração com status checks e CI/CD como gate de path
5.1. Criando status checks que analisam paths alterados
É possível criar status checks que analisam quais paths foram modificados e aplicam regras específicas:
# Exemplo de script para GitHub Actions
name: Path Security Check
on: pull_request
jobs:
check-sensitive-paths:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check for sensitive path changes
run: |
CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}..HEAD)
SENSITIVE_PATHS=("infra/" "secrets/")
for path in "${SENSITIVE_PATHS[@]}"; do
if echo "$CHANGED_FILES" | grep -q "^$path"; then
echo "Alterações detectadas em path sensível: $path"
echo "Requer aprovação do time de DevOps."
exit 1
fi
done
5.2. Workflows de CI que bloqueiam merges
Um workflow completo pode bloquear merges se paths proibidos forem modificados sem aprovação:
name: Block Sensitive Changes
on:
pull_request:
types: [opened, synchronize]
jobs:
validate-paths:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Validate changed paths
id: validate
run: |
CHANGED=$(git diff --name-only origin/main..HEAD)
echo "Arquivos alterados:"
echo "$CHANGED"
# Verificar se há alterações em paths críticos
if echo "$CHANGED" | grep -qE '^(infra/|config/production)'; then
echo "CRITICAL_PATH_CHANGED=true" >> $GITHUB_ENV
fi
- name: Notify DevOps team
if: env.CRITICAL_PATH_CHANGED == 'true'
run: |
echo "Alterações críticas detectadas. Notificando time de DevOps."
# Aqui poderia enviar notificação via Slack, email, etc.
5.3. Exemplo prático: Pipeline bloqueando alterações em infra/
# .github/workflows/infra-guard.yml
name: Infra Guard
on:
pull_request:
paths:
- 'infra/**'
- 'config/deploy/**'
jobs:
require-devops-approval:
runs-on: ubuntu-latest
steps:
- name: Check for DevOps approval label
run: |
if [[ "${{ github.event.pull_request.labels }}" != *"devops-approved"* ]]; then
echo "Este PR modifica infraestrutura. Adicione o label 'devops-approved' após revisão."
exit 1
fi
6. Políticas de merge condicionais por path
6.1. Definindo regras de merge que exigem revisores específicos
Plataformas modernas permitem criar regras de merge condicionais baseadas em paths:
# Exemplo de configuração no GitHub
# Usando branch protection rules + CODEOWNERS
# 1. Crie a regra de branch para main
# 2. Em "Require a pull request before merging", configure:
# - Required approvals: 2
# - Dismiss stale reviews: true
# - Require review from Code Owners: true
# 3. Em "Require status checks", adicione o check de path validation
6.2. Uso de required_pull_request_reviews com path patterns
# Configuração via API do GitHub
curl -X PUT \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/owner/repo/branches/main/protection \
-d '{
"required_pull_request_reviews": {
"required_approving_review_count": 2,
"require_code_owner_reviews": true
},
"required_status_checks": {
"strict": true,
"contexts": ["Path Security Check"]
}
}'
6.3. Automatizando a atribuição de revisores
É possível automatizar a atribuição de revisores baseada em paths modificados:
# Script para atribuir revisores automaticamente
# Executado como GitHub Action ou webhook
CHANGED_FILES=$(git diff --name-only origin/main..HEAD)
if echo "$CHANGED_FILES" | grep -q "^infra/"; then
ASSIGN_REVIEWERS+=("time-devops")
fi
if echo "$CHANGED_FILES" | grep -q "^secrets/"; then
ASSIGN_REVIEWERS+=("time-seguranca")
fi
# Atribuir revisores via API
for reviewer in "${ASSIGN_REVIEWERS[@]}"; do
curl -X POST \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/owner/repo/pulls/$PR_NUMBER/requested_reviewers \
-d "{\"team_reviewers\":[\"$reviewer\"]}"
done
7. Monitoramento e auditoria de permissões por path
7.1. Logs de alterações em paths protegidos
O Git fornece ferramentas poderosas para auditar alterações em paths específicos:
# Listar todos os commits que modificaram paths protegidos
git log --all --oneline -- 'infra/' 'secrets/'
# Verificar quem modificou um arquivo específico
git log --format="%h %an %ad %s" -- 'config/deploy.yml'
# Usar git blame para ver a última modificação linha a linha
git blame -L 10,20 config/deploy.yml
7.2. Ferramentas de auditoria
Para detectar bypasses ou permissões excessivas:
# Script de auditoria: detecta merges que bypassaram proteções
# Verifica pull requests mesclados sem revisão de code owners
git log --merges --format="%h %an %ad" --first-parent main
# Verificar alterações em paths protegidos que não passaram por review
# (requer integração com API da plataforma)
7.3. Revisão periódica de regras de path permissions
Estabeleça um processo de revisão periódica:
# Checklist de revisão trimestral
# 1. Verificar se novos paths críticos foram adicionados
# 2. Remover regras para paths que não são mais sensíveis
# 3. Atualizar CODEOWNERS com mudanças de equipe
# 4. Testar regras com branches de exemplo
# 5. Revisar logs de tentativas de bypass
8. Considerações finais e boas práticas
8.1. Equilíbrio entre segurança e agilidade
Proteger paths desnecessariamente pode criar gargalos no desenvolvimento. Avalie cuidadosamente quais paths realmente precisam de proteção granular. Uma boa prática é começar com paths críticos (CI/CD, secrets, configurações de produção) e expandir conforme necessário.
8.2. Documentação das regras para a equipe
Mantenha documentação clara sobre as regras de path permissions:
# Exemplo de documentação no README.md
## Path Permissions
### Paths Protegidos
- `infra/` - Requer aprovação do time de DevOps
- `secrets/` - Requer aprovação do time de Segurança
- `.github/workflows/` - Requer aprovação do time de QA
### Como Solicitar Alterações
1. Crie um pull request
2. Adicione o label correspondente ao path alterado
3. Aguarde a revisão do time responsável
8.3. Teste das políticas com branches de exemplo
Antes de aplicar regras em produção, teste em branches de exemplo:
# Fluxo de teste
# 1. Crie uma branch de teste: git checkout -b test-path-permissions
# 2. Modifique um arquivo em path protegido
# 3. Crie um pull request para main
# 4. Verifique se as regras de proteção são aplicadas corretamente
# 5. Ajuste as regras conforme necessário
# 6. Delete a branch de teste
A proteção granular de paths no Git é uma prática essencial para equipes que lidam com repositórios complexos contendo diferentes tipos de ativos. Ao implementar essas estratégias, você equilibra segurança e produtividade, garantindo que alterações críticas recebam a atenção necessária sem burocratizar o desenvolvimento de código não sensível.
Referências
- GitHub Docs: About code owners — Documentação oficial do GitHub sobre o arquivo CODEOWNERS e como configurar revisores automáticos por path.
- GitLab Docs: Merge request approvals — Guia completo sobre regras de aprovação no GitLab, incluindo aprovações baseadas em paths.
- Bitbucket Cloud: Branch permissions — Tutorial da Atlassian sobre como restringir alterações em paths específicos usando permissões de branch no Bitbucket.
- Atlassian Git Tutorial: Hooks — Guia detalhado sobre hooks do Git, incluindo exemplos de hooks server-side para validação de paths.
- GitHub Blog: Required status checks and branch protection — Artigo técnico do GitHub sobre como configurar status checks obrigatórios e proteção de branches com path filters.