Gerenciar aprovações de solicitação de envio com CODEOWNERS

Este guia descreve a estrutura, a sintaxe e a implementação do recurso CODEOWNERS, que permite controlar de maneira flexível os requisitos de aprovação de solicitação de pull (PR, na sigla em inglês).

Introdução

O recurso CODEOWNERS do Secure Source Manager usa arquivos na sua base de código para definir aprovadores no nível do arquivo. Isso oferece um controle mais refinado do que outras regras de ramificação, porque você pode atribuir proprietários específicos a arquivos específicos e definir conjuntos independentes de aprovadores.

O recurso CODEOWNERS oferece os seguintes recursos:

  • Defina os usuários que podem aprovar solicitações de pull para arquivos, diretórios e ramificações.
  • Configure diferentes conjuntos de proprietários de código para proteger ramificações diferentes.
  • Verifique se as mudanças nos arquivos são analisadas pelos proprietários designados.

Ativar a revisão do proprietário do código

Para ativar e aplicar as regras CODEOWNERS, os administradores de proteção de ramificação precisam atualizar as regras de ramificação nas configurações do repositório para Exigir revisão do proprietário do código em solicitações de pull. Selecione essa opção nas configurações de regra de ramificação. Se essa configuração estiver desativada, o sistema vai ignorar os arquivos CODEOWNERS nas fusões com a ramificação de destino. Se você selecionar essa opção, o sistema vai bloquear pushes e mesclagens na ramificação até que os proprietários do código analisem e aprovem as solicitações de envio.

Local e precedência do arquivo CODEOWNERS

O Secure Source Manager oferece duas opções para definir arquivos CODEOWNERS:

  1. Arquivos aninhados: arquivos CODEOWNERS em qualquer diretório, exceto o diretório .securesourcemanager. Os arquivos CODEOWNERS aninhados afetam apenas o próprio diretório (incluindo subdiretórios), e os caminhos de arquivo neles precisam ser especificados em relação ao diretório em que o arquivo CODEOWNERS está localizado. Essa é a abordagem recomendada para a maioria dos casos de uso.

  2. Arquivo dedicado único: se você precisar distinguir o arquivo CODEOWNERS do Secure Source Manager de outros arquivos CODEOWNERS usados por outras ferramentas (por exemplo, .gitlab/CODEOWNERS), use um único arquivo localizado em .securesourcemanager/CODEOWNERS na raiz do repositório. Se esse arquivo existir, o Secure Source Manager vai ignorar todos os outros arquivos CODEOWNERS na mesma ramificação, incluindo os aninhados. O diretório .securesourcemanager só é reconhecido na raiz do repositório.

Interação com solicitações de envio e aprovações

Quando uma solicitação de envio é criada ou quando a ramificação de origem é atualizada com novos commits, o sistema usa apenas arquivos CODEOWNERS da ramificação de base (aquela em que você está fazendo o merge) para determinar os requisitos de aprovação. O sistema ignora as mudanças nos arquivos CODEOWNERS no código de envio para essa verificação.

Sintaxe e estrutura de CODEOWNERS

Um arquivo CODEOWNERS consiste em comentários, linhas de regra e marcadores de seção. Os comentários começam com # e são ignorados pelo sistema.

Formato da linha de regra

O formato padrão de uma linha de regra é:

[BRANCH_GLOB] PATH_GLOB [OWNERS...]

Em que:

  • BRANCH_GLOB: um padrão glob opcional que especifica a quais ramificações a regra se aplica. Se você não especificar um glob de ramificação, a regra será aplicada a qualquer ramificação em que o arquivo CODEOWNERS for verificado (se a ramificação tiver CODEOWNERS ativado nas regras dela). Exemplo:

    • main corresponde apenas à ramificação main.
    • dev-* corresponde a ramificações que começam com dev-.
    • *-glob corresponde a ramificações que terminam com -glob.
    • my-*-glob corresponde a ramificações como my-feat-glob.
  • PATH_GLOB: um padrão glob obrigatório que especifica a quais caminhos de arquivo a regra se aplica. A sintaxe do Secure Source Manager é baseada em padrões gitignore.

    • Se um padrão não contiver / ou contiver apenas / como um caractere final, ele será um glob que corresponde a qualquer diretório.
      • *.js corresponde a arquivos JavaScript em qualquer lugar.
      • build/ corresponde a diretórios chamados build em qualquer lugar.
    • Se um padrão contiver / em qualquer lugar que não seja o final, ele será tratado como um caminho relativo ao local do arquivo CODEOWNERS.
      • docs/* corresponde a arquivos em docs/ em relação ao arquivo CODEOWNERS.
      • /*.js corresponde a arquivos JavaScript no mesmo diretório do arquivo CODEOWNERS, mas não a arquivos JavaScript aninhados.
    • Um padrão que termina em / corresponde apenas a diretórios e ao conteúdo deles de forma recursiva. Por exemplo, build-*/ corresponde a diretórios como build-app/ e build-tool/ em qualquer lugar.
    • Se você estiver usando .securesourcemanager/CODEOWNERS, os caminhos serão relativos à raiz do repositório.
  • OWNERS: uma lista opcional de endereços de e-mail de proprietários, separados por espaços. Se omitida, essa regra vai funcionar como uma exclusão de caminho.

Propriedade específica da ramificação

O campo BRANCH_GLOB opcional no início de uma linha de regra permite implementar controles de proprietário do código específicos da ramificação.

  • Se você não especificar um BRANCH_GLOB no início da regra, ela será aplicada a todas as ramificações.
  • O sistema ignora qualquer linha com um glob de ramificação que não corresponda à ramificação atual.

Fundamentos da sintaxe

  • Interpretação de campos: os campos são separados por espaços.
    • Os campos que contêm @ são identificados como endereços de e-mail do proprietário.
    • Se um campo sem @ preceder os endereços de e-mail do proprietário, ele será tratado como PATH_GLOB. Por exemplo, em *.js user@example.com, *.js é o PATH_GLOB.
    • Se dois campos sem @ precederem os endereços de e-mail do proprietário, o primeiro será BRANCH_GLOB e o segundo será PATH_GLOB. Por exemplo, em main *.js user@example.com, main é BRANCH_GLOB e *.js é PATH_GLOB.
    • A mesma lógica se aplica se nenhum proprietário for especificado: um campo é PATH_GLOB e dois campos são BRANCH_GLOB PATH_GLOB.
  • Sintaxe no estilo glob: o Secure Source Manager usa a sintaxe padrão no estilo glob (.gitignore) para expressões de caminho.
  • Detalhes do caractere curinga:
    • ** corresponde a qualquer sequência de caracteres, incluindo /.
    • * corresponde a qualquer sequência de caracteres, exceto /.
    • ? corresponde a qualquer caractere único, exceto /.
  • Diferenciação de maiúsculas e minúsculas: os arquivos CODEOWNERS diferenciam maiúsculas de minúsculas.
  • Identificação do proprietário: o sistema identifica os proprietários pelo endereço de e-mail. O caractere @ distingue os campos do proprietário.
  • Nos endereços de e-mail do proprietário, apenas space e backslash precisam de escape.
  • Caracteres reservados: o sistema reserva os seguintes caracteres. É necessário usar a barra invertida de escape (\) em expressões de ramificação e caminho: [, ], , @, *, ?, \, {, } e !.
  • Se ** for misturado com caracteres que não sejam barras, o sistema vai tratá-lo como um curinga comum. Por exemplo, /**/*.py corresponde a qualquer arquivo Python de qualquer profundidade, /**.py é tratado como /*.py e corresponde apenas a arquivos no diretório raiz.

Seções para vários conjuntos de aprovação

Usar [Section] linhas agrupa regras em aprovações independentes obrigatórias. Isso é útil para exigir revisões de equipes distintas, como segurança ou controle de qualidade.

  • Definição de seção: use uma linha no formato [Section Name] (use qualquer nome de linguagem natural).
  • Contagem de aprovações: uma seção pode incluir um sufixo opcional [<approverCount>] para especificar uma contagem de aprovações diferente de 1. Uma contagem de 0 significa proprietários opcionais. Por exemplo, você pode usar isso para mostrar especialistas em arquivos específicos para fins informativos sem exigir uma revisão.
  • Encerramento da seção: uma seção se aplica a todas as regras a seguir até o início da próxima seção.
  • Regras sem seção: o sistema trata as regras que aparecem antes de qualquer definição de [Section] como uma única seção unificada, exigindo uma aprovação por padrão.
  • Consolidação: o sistema trata seções com o mesmo nome sem diferenciação de maiúsculas e minúsculas, mesmo em vários arquivos CODEOWNERS aninhados, como uma única seção unificada, seguindo as regras de precedência padrão.

Exclusão de caminho

Para excluir caminhos específicos de uma cláusula mais ampla anterior, defina zero proprietários para o caminho. Se você definir uma regra sem proprietários, o sistema vai remover todos os proprietários desse caminho definidos por regras anteriores, e o caminho não vai exigir aprovações de proprietários.

As correspondências de diretório só funcionam se terminarem em / ou não tiverem caracteres curinga na parte final.

Por exemplo, *.py não corresponde a um diretório oculto .py/, mas *.py/ sim.

Resolução de conflitos e precedência

Se um arquivo .securesourcemanager/CODEOWNERS existir, todos os outros arquivos CODEOWNERS serão ignorados. Se um caminho for correspondido por duas linhas diferentes na mesma seção, apenas a última linha será aplicada. Se as linhas estiverem em seções diferentes, as duas serão aplicadas.

O sistema usa uma regra de precedência baseada em local para arquivos aninhados:

  • As regras em um arquivo CODEOWNERS aninhado mais profundamente (mais local) substituem as regras correspondentes em um arquivo mais superficial.
  • O arquivo do diretório raiz CODEOWNERS sempre tem a menor precedência.

Exemplo de arquivo CODEOWNERS

A seguir, um exemplo de arquivo CODEOWNERS, demonstrando a sintaxe CODEOWNERS:

# Un-sectioned rules; 1 approve required from any of owners of last matching line.
# Format: [BRANCH_GLOB] PATH_GLOB [OWNERS...]

# Make repo-admin the owner of all files of the current branch.
*   repo-admin@example.com      # No slash prefix; matches in sub-dirs too.
/**/* repo-admin@example.com      # Slash-prefix equivalent of prior line.

# Match all py files (including sub-dirs). Note repo-admin must be re-added.
*.py  repo-admin@example.com python-owner@example.com

# With repo-admin not included here, repo-admin no longer owns README.
/README.md readme-owner@example.com

/scratchpad.txt             # Can also override a path to have zero owners (path exclusion).

# Branch-specific syntax.
# Note that since un-sectioned rules are independent of sectioned rules,
# the above [Section] rules will still apply to this branch if they
# aren't modified to add e.g. `main ` as a prefix.
dev-* *             # Remove all owners reqs on dev branches.
dev-* /experimental/ exp-owner@example.com   # dev-specific owners.

# Make repo admin own all CODEOWNERS files, regardless of any prior rules.
CODEOWNERS repo-admin@example.com

# Section; 1 approval required *in addition* to owners outside this section.
[Security Team]
/secure-directory/ security-expert@example.com security-reviewer@example.com
/**/*secure\ me* security-expert@example.com security-reviewer@example.com

# Section w/ req approval count of 2 instead of 1.
[Doc Team][2]
/docs doc-expert@example.com doc-reviewer@example.com
*.md doc-expert@example.com doc-reviewer@example.com

Compatibilidade com outros gerenciadores de código-fonte

O Secure Source Manager oferece uma sintaxe familiar e portátil com outros gerenciadores de código-fonte. A sintaxe do Secure Source Manager CODEOWNERS é compatível com a sintaxe do GitHub CODEOWNERS e parcialmente compatível com a sintaxe do GitLab CODEOWNERS, incluindo contagens de aprovação seccional, como [Section Name][2].

A implementação do Secure Source Manager de CODEOWNERS não é compatível com a sintaxe !path do GitLab para negação de caminho. Para informações sobre a negação de caminhos no Secure Source Manager, consulte Exclusão de caminhos. O Secure Source Manager também não é compatível com proprietários padrão em cabeçalhos de seção, como [Section Name] @owner1 @owner2.

Validação e tratamento de erros

Ao visualizar um arquivo CODEOWNERS, a UI mostra o status dele e avisos ou informações no nível da linha (por exemplo, linhas que não correspondem a esta ramificação). Passe o cursor sobre os números ou linhas destacados para ver mais detalhes.

Aplicação

Uma proteção de pré-envio força a verificação de erros de sintaxe em qualquer ramificação em que você ativa a regra de ramificação dos proprietários do código. Isso evita que você faça check-in acidentalmente de arquivos CODEOWNERS corrompidos.

Tratamento de erros de sintaxe

As verificações de pré-envio só são executadas em ramificações em que a opção Exigir revisão do proprietário do código em solicitações de pull está ativada. Se um arquivo CODEOWNERS sintaticamente inválido for confirmado em uma ramificação e a revisão do proprietário do código for ativada posteriormente para essa ramificação, o sistema vai processar os erros de maneira adequada:

  • O sistema ignora linhas que não podem ser analisadas em uma definição de seção, linha de regra ou formato de comentário.
  • Se uma contagem de aprovações for negativa, o sistema a tratará como zero.
  • O sistema continua analisando e aplicando todas as linhas válidas normalmente.

A seguir