CODEOWNERS を使用して pull リクエストの承認を管理する

このガイドでは、プルリクエスト(PR)の承認要件を柔軟に制御できる CODEOWNERS 機能の構造、構文、実装について説明します。

はじめに

Secure Source Manager の CODEOWNERS 機能は、コードベース内のファイルを使用してファイルレベルの承認者を設定します。特定のファイルに特定のオーナーを割り当て、承認者の独立したセットを定義できるため、他のブランチルールよりもきめ細かい制御が可能です。

CODEOWNERS 機能には次の機能があります。

  • ファイル、ディレクトリ、ブランチの pull リクエストを承認できるユーザーを定義します。
  • 異なるコードオーナーのセットを構成して、異なるブランチを保護します。
  • ファイルの変更が指定されたオーナーによって確認されるようにします。

コードオーナー レビューを有効にする

CODEOWNERS ルールを有効にして適用するには、ブランチ保護管理者がリポジトリ設定のブランチルールを [プルリクエストでコードオーナーのレビューを必須にする] に更新する必要があります。このオプションは、ブランチルールの設定で選択します。この設定が off の場合、システムはターゲット ブランチへのマージで CODEOWNERS ファイルを無視します。このオプションを選択すると、コードオーナーがプルリクエストを確認して承認するまで、システムはブランチへのプッシュとマージをブロックします。

CODEOWNERS ファイルの場所と優先順位

Secure Source Manager は、CODEOWNERS ファイルの定義に次の 2 つのオプションをサポートしています。

  1. ネストされたファイル: .securesourcemanager ディレクトリ以外の任意のディレクトリにある CODEOWNERS ファイル。ネストされた CODEOWNERS ファイルは、独自のディレクトリ(サブディレクトリを含む)にのみ影響します。その中のファイルパスは、CODEOWNERS ファイルが配置されているディレクトリの相対パスで指定する必要があります。これは、ほとんどのユースケースで推奨される方法です。

  2. 単一の専用ファイル: Secure Source Manager の CODEOWNERS ファイルを他のツール(.gitlab/CODEOWNERS など)で使用される他の CODEOWNERS ファイルと区別する必要がある場合は、リポジトリ ルートの .securesourcemanager/CODEOWNERS にある単一のファイルを使用できます。このファイルが存在する場合、Secure Source Manager は、同じブランチにある他のすべての CODEOWNERS ファイル(ネストされたファイルを含む)を無視します。.securesourcemanager ディレクトリはリポジトリのルートでのみ認識されます。

Pull Request と承認の操作

pull リクエストが作成されたとき、またはそのソースブランチが新しいコミットで更新されたとき、システムはベースブランチ(マージ先のブランチ)の CODEOWNERS ファイルのみを使用して承認要件を決定します。システムは、その検証のプッシュコード内の CODEOWNERS ファイルに対する変更を無視します。

CODEOWNERS の構文と構造

CODEOWNERS ファイルは、コメント、ルール行、セクション マーカーで構成されます。コメントは # で始まり、システムによって無視されます。

罫線の形式

ルール行の標準形式は次のとおりです。

[BRANCH_GLOB] PATH_GLOB [OWNERS...]

ここで

  • BRANCH_GLOB: ルールが適用されるブランチを指定するオプションの glob パターン。ブランチ グロブを指定しない場合、ルールは CODEOWNERS ファイルがチェックインされるすべてのブランチに適用されます(ブランチ ルールで CODEOWNERS が有効になっている場合)。次に例を示します。

    • mainmain ブランチのみに一致します。
    • dev-*dev- で始まるブランチに一致します。
    • *-glob-glob で終わるブランチと一致します。
    • my-*-globmy-feat-glob などのブランチと一致します。
  • PATH_GLOB: ルールを適用するファイルパスを指定する必須の glob パターン。Secure Source Manager の構文は、gitignore パターンに基づいています。

    • パターンに / が含まれていない場合、または / が末尾の文字としてのみ含まれている場合、そのパターンは任意のディレクトリで一致する glob です。
      • *.js は、任意の場所にある JavaScript ファイルに一致します。
      • build/ は、build という名前のディレクトリに一致します。
    • パターンに / が末尾以外に含まれている場合、CODEOWNERS ファイルの場所を基準とした相対パスとして扱われます。
      • docs/* は、CODEOWNERS ファイルを基準とした docs/ の下のファイルに一致します。
      • /*.js は、CODEOWNERS ファイルと同じディレクトリにある JavaScript ファイルと一致しますが、ネストされた JavaScript ファイルとは一致しません。
    • / で終わるパターンは、ディレクトリとそのコンテンツにのみ再帰的に一致します。たとえば、build-*/build-app/build-tool/ などのディレクトリに一致します。
    • .securesourcemanager/CODEOWNERS を使用する場合、パスはリポジトリのルートからの相対パスになります。
  • OWNERS: オーナーのメールアドレスのリスト(省略可)。スペースで区切ります。省略した場合、このルールはパス除外として機能します。

ブランチ固有の所有権

ルール行の先頭にあるオプションの BRANCH_GLOB フィールドを使用すると、ブランチ固有のコード所有者制御を実装できます。

  • ルールの先頭に BRANCH_GLOB を指定しない場合、ルールはすべてのブランチに適用されます。
  • システムは、現在のブランチと一致しないブランチ グロブを含む行を無視します。

構文の基本

  • フィールドの解釈: フィールドはスペースで区切られます。
    • @ を含むフィールドは、所有者のメールアドレスとして識別されます。
    • @ のないフィールドがオーナーのメールアドレスの前に 1 つある場合は、PATH_GLOB として扱われます。たとえば、*.js user@example.com では、*.jsPATH_GLOB です。
    • @ のない 2 つのフィールドがオーナーのメールアドレスの前に付いている場合、1 つ目は BRANCH_GLOB、2 つ目は PATH_GLOB です。たとえば、main *.js user@example.com では、mainBRANCH_GLOB で、*.jsPATH_GLOB です。
    • オーナーが指定されていない場合も、同じロジックが適用されます。1 つのフィールドは PATH_GLOB、2 つのフィールドは BRANCH_GLOB PATH_GLOB になります。
  • glob スタイルの構文: Secure Source Manager は、パス式に標準の glob スタイル(.gitignore スタイル)の構文を使用します。
  • ワイルドカード文字の詳細:
    • ** は、/ を含む任意の文字列に一致します。
    • * は、/ 以外の任意の文字列に一致します。
    • ? は、/ を除く任意の 1 文字に一致します。
  • 大文字と小文字の区別: CODEOWNERS ファイルでは大文字と小文字が区別されます。
  • オーナーの識別: システムはメールアドレスでオーナーを識別します。@ 文字はオーナー フィールドを区別します。
  • 所有者のメールアドレスでは、spacebackslash のみをエスケープする必要があります。
  • 予約文字: 次の文字はシステムで予約されています。ブランチ式とパス式では、[] @*?\{}! をバックスラッシュでエスケープ(\)する必要があります。
  • ** がスラッシュ以外の文字と混在している場合、システムはそれを通常のワイルドカードとして扱います。たとえば、/**/*.py は任意の深さの Python ファイルと一致し、/**.py/*.py として扱われ、ルート ディレクトリ内のファイルのみと一致します。

複数の承認セットのセクション

[Section] を使用すると、ルールが独立した必須の承認にグループ化されます。これは、セキュリティ チームや QA チームなど、異なるチームからのレビューを要求する場合に便利です。

  • セクション定義: [Section Name] 形式の行を使用します(自然言語の名前を使用します)。
  • 承認数: セクションには、1 以外の承認数を指定するオプションの接尾辞 [<approverCount>] を含めることができます。0 のカウントは、オプションのオーナーを示します。たとえば、この機能を使用して、特定のファイルの専門家を情報提供目的で表示できます。この場合、専門家のレビューは必要ありません。
  • セクションの終了: セクションは、次のセクションが始まるまですべてのルールに適用されます。
  • セクション化されていないルール: [Section] 定義の前に表示されるルールは、単一の統合セクションとして扱われ、デフォルトで 1 つの承認が必要になります。
  • 統合: 大文字と小文字を区別しない名前が同じセクションは、複数のネストされた CODEOWNERS ファイルにまたがっていても、標準の優先順位ルールに従って、単一の統合セクションとして扱われます。

パスの除外

以前のより広範な句から特定のパスを除外するには、パスのオーナーをゼロに設定します。オーナーなしでルールを定義すると、以前のルールで設定されたパスのオーナーが削除され、パスにオーナーの承認は不要になります。

ディレクトリ一致は、末尾が / であるか、最後の部分にワイルドカードが含まれていない場合にのみ機能します。

たとえば、*.py は非表示ディレクトリ .py/ と一致しませんが、*.py/ は一致します。

競合の解決と優先順位

.securesourcemanager/CODEOWNERS ファイルが存在する場合、他のすべての CODEOWNERS ファイルは無視されます。同じセクションの 2 つの異なる行でパスが一致した場合、最後の行のみが適用されます。行が異なるセクションにある場合は、両方が適用されます。

システムは、ネストされたファイルに位置ベースの優先順位ルールを使用します。

  • ネストが深い(よりローカルな)CODEOWNERS ファイルのルールは、ネストが浅いファイルのルールよりも優先されます。
  • ルート ディレクトリの CODEOWNERS ファイルは常に優先度が最も低くなります。

CODEOWNERS ファイルの例

CODEOWNERS 構文を示す 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

他のソースコード マネージャーとの互換性

Secure Source Manager は、他のソースコード マネージャーと互換性のある使い慣れた構文を提供します。Secure Source Manager の CODEOWNERS 構文は、GitHub の CODEOWNERS 構文と互換性があり、[Section Name][2] などのセクション別の承認数を含む GitLab の CODEOWNERS 構文と部分的に互換性があります。

Secure Source Manager の CODEOWNERS の実装では、パス否定の GitLab !path 構文はサポートされていません。Secure Source Manager のパスの否定については、パスの除外をご覧ください。Secure Source Manager は、セクション ヘッダーのデフォルトの所有者([Section Name] @owner1 @owner2 など)もサポートしていません。

検証とエラー処理

CODEOWNERS ファイルを表示すると、UI にステータスと行レベルの警告または情報(このブランチと一致しない行など)が表示されます。ハイライト表示された行番号または行にカーソルを合わせると、詳細が表示されます。

適用

送信前ガードは、コードオーナー ブランチルールを有効にしたブランチで構文エラー チェックを適用します。これにより、破損した CODEOWNERS ファイルを誤ってチェックインすることを防ぐことができます。

構文エラー処理

送信前チェックは、[Require Code Owner Review on Pull Requests] が有効になっているブランチでのみ実行されます。構文的に無効な CODEOWNERS ファイルがブランチに commit され、そのブランチで後でコードオーナーのレビューが有効になった場合、システムはエラーを適切に処理します。

  • セクション定義、ルール行、コメント形式に解析できない行は無視されます。
  • 承認数が負の値の場合、システムは 0 として扱います。
  • システムは引き続き、有効な行を通常どおり解析して適用します。

次のステップ