Skip to main content

pre-receiveフックスクリプトの作成

pre-receiveフックスクリプトを使って、プッシュを内容に基づいて受け付けあるいは拒否するための要件を作成します。

GitHub Enterprise Server の受信前フックの例を github/platform-samples リポジトリで参照できます。

pre-receiveフックスクリプトの作成

受信前フック スクリプトは、お使いの GitHub Enterprise Server インスタンス 上の受信前フック スクリプト環境で実行されます。 受信前フック スクリプトを作成する際には、利用可能な入力、出力、終了ステータス、環境変数について考慮します。

入力 (stdin)

プッシュが発生した後で、リモート リポジトリに関して参照が更新される前に、お使いの GitHub Enterprise Server インスタンス上の git-receive-pack プロセスが受信前フック スクリプトを呼び出します。 このスクリプトの標準入力 stdin は、更新する参照ごとの行を含む文字列です。 各行には、参照の古いオブジェクト名、参照の新しいオブジェクト名、および参照の完全な名前が含まれています。

<old-value> SP <new-value> SP <ref-name> LF

この文字列は次の引数を表します。

引数説明
<old-value>参照に格納されている古いオブジェクト名。
新しい参照を作成するとき、値は 40 個のゼロです。
<new-value>参照に格納される新しいオブジェクト名。
参照を削除するとき、値は 40 個のゼロです。
<ref-name>参照の完全な名前。

git-receive-pack の詳細については、Git ドキュメントの「git-receive-pack」を参照してください。 参照の詳細については、Pro Git の「Git References」(Git の参照) を参照してください。

出力 (stdout)

スクリプトの標準出力 stdout はクライアントに返されます。 すべての echo ステートメントは、コマンド ラインまたはユーザー インターフェイスでユーザーに表示されます。

終了ステータス

受信前スクリプトの終了ステータスによって、プッシュが受け付けられるかどうかが決まります。

終了ステータスの値アクション
0プッシュは受け付けられます。
0 以外プッシュは拒否されます。

環境変数

受信前フック スクリプトの標準入力 stdin に加え、GitHub Enterprise Server によって、スクリプトの実行のために次の変数が Bash 環境で使用できるようになります。 受信前フック スクリプトの stdin の詳細については、「入力 (stdin)」を参照してください。

受信前フック スクリプトで使用できる環境変数は、スクリプトが実行するトリガーに応じて異なります。

常に使用可能かどうか

次の変数は、受信前フック環境で常に使用できます。

変数説明値の例
$GIT_DIR
インスタンス上のリモート リポジトリのパス/data/user/repositories/a/ab/
a1/b2/34/100001234/1234.git
$GIT_PUSH_OPTION_COUNT
クライアントによって --push-option で送信されたプッシュ オプションの数。 詳細については、Git ドキュメントの「git-push」を参照してください。1
$GIT_PUSH_OPTION_N
ここで N は 0 から始まる整数です。この変数にはクライアントから送信されたプッシュ オプションの文字列が含まれます。 送信された最初のオプションは GIT_PUSH_OPTION_0、送信された 2 番目のオプションは GIT_PUSH_OPTION_1 のように、順に格納されます。 プッシュ オプションの詳細については、Git ドキュメントの「git-push」を参照してください。abcd
$GIT_USER_AGENT
変更をプッシュした Git クライアントから送信されたユーザーエージェント文字列git/2.0.0
$GITHUB_REPO_NAME
更新対象のリポジトリの名前 (NAME/OWNER の形式)octo-org/hello-enterprise
$GITHUB_REPO_PUBLIC
更新対象のリポジトリがパブリックかどうかを表すブール値
  • true: リポジトリの可視性がパブリック
  • false: リポジトリの可視性がプライベートまたは内部
$GITHUB_USER_IP
プッシュを開始したクライアントの IP アドレス192.0.2.1
$GITHUB_USER_LOGIN
プッシュを開始したアカウントのユーザー名octocat

Web インターフェイスまたは API からのプッシュで使用可能

$GITHUB_VIA 変数を受信前フック環境で使用できるのは、フックをトリガーする参照更新が GitHub Enterprise Server の Web インターフェイスまたは API を介して発生するときです。 値は、参照を更新したアクションを表します。

アクション説明を見る
auto-merge deployment api
API を使用して作成されたデプロイを介したベース ブランチの自動マージデプロイ用の REST API エンドポイント
blob#save
Web インターフェイスでのファイルの内容に対する変更ファイルを編集する
branch merge api
API を使用したブランチのマージブランチとその設定用 REST API エンドポイント
branches page delete button
Web インターフェイスでのブランチの削除リポジトリ内でブランチを作成および削除する
git refs create api
API を使用した参照の作成Git リファレンス用 REST API エンドポイント
git refs delete api
API を使用した参照の削除Git リファレンス用 REST API エンドポイント
git refs update api
API を使用した参照の更新Git リファレンス用 REST API エンドポイント
git repo contents api
API を使用したファイルの内容に対する変更リポジトリ コンテンツの REST API エンドポイント
merge自動マージを使用した pull request の統合プルリクエストを自動的にマージする
merge base into head
ベース ブランチで厳密な状態チェックが必要になる際のベース ブランチのトピック ブランチの更新 (たとえば、pull request で ブランチを更新 を使用)保護されたブランチについて
pull request branch delete button
Web インターフェイスでの pull request からのトピック ブランチの削除pull request 中のブランチの削除と復元
pull request branch undo button
Web インターフェイスでの pull request からのトピック ブランチの復元pull request 中のブランチの削除と復元
pull request merge api
API を使用した pull request の統合Pull request 用 REST API エンドポイント
pull request merge button
Web インターフェイスでの pull request の統合pull request のマージ
pull request revert button
pull request を元に戻した状態Pull Request を打ち消す
releases delete button
リリースの削除リポジトリのリリースを管理する
stafftools branch restore
サイト管理者ダッシュボードでのブランチの復元Web UI からインスタンスを管理する
tag create api
API を使用したタグの作成Git タグ用 REST API エンドポイント
web branch create
Web インターフェイスを使用したブランチの作成リポジトリ内でブランチを作成および削除する

pull request のマージで使用可能

次の変数を受信前フック環境で使用できるのは、フックをトリガーするプッシュが pull request のマージによるプッシュであるときです。

変数説明値の例
$GITHUB_PULL_REQUEST_AUTHOR_LOGIN
pull request を作成したアカウントのユーザー名octocat
$GITHUB_PULL_REQUEST_HEAD
pull request のトピック ブランチの名前 (USERNAME:BRANCH 形式)octocat:fix-bug
$GITHUB_PULL_REQUEST_BASE
pull request のベース ブランチの名前 (USERNAME:BRANCH 形式)octocat:main

SSH 認証を使用したプッシュで使用可能

変数説明値の例
$GITHUB_PUBLIC_KEY_FINGERPRINT
変更をプッシュしたユーザーの公開キー フィンガープリントa1:b2:c3:d4:e5:f6:g7:h8:i9:j0:k1:l2:m3:n4:o5:p6

権限の設定と GitHub Enterprise Server への pre-receive フックのプッシュ

受信前フック スクリプトは、お使いの GitHub Enterprise Server インスタンス のリポジトリに含まれています。 サイト管理者はリポジトリの権限を考慮し、適切なユーザだけがアクセスできるようにしなければなりません。

フックは単一のリポジトリに集約することをおすすめします。 集約されたフックのリポジトリがパブリックである場合、README.md を使用してポリシーの適用を説明できます。 また、コントリビューションをプルリクエスト経由で受け付けることもできます。 しかし、pre-receiveフックはデフォルトブランチからのみ追加できます。 テストのワークフロー用には、設定を持つリポジトリのフォークを使うべきです。

  1. Mac ユーザは、スクリプトに実行権限を持たせてください。

    sudo chmod +x SCRIPT_FILE.sh
    

    Windows ユーザは、スクリプトに実行権限を持たせてください。

    git update-index --chmod=+x SCRIPT_FILE.sh
    
  2. お使いの GitHub Enterprise Server インスタンス上の受信前フック用の指定リポジトリにコミットしてプッシュします。

    git commit -m "YOUR COMMIT MESSAGE"
    git push
    
  3. GitHub Enterprise Server インスタンス上に受信前フックを作成します。

ローカルでのpre-receiveスクリプトのテスト

受信前フック スクリプトを お使いの GitHub Enterprise Server インスタンス上で作成または更新する前に、ローカルでテストできます。 その方法の 1 つは、pre-receive フックを実行できるリモートリポジトリとして働くローカルの Docker 環境を作成することです。

  1. ローカルに Docker がインストールされていることを確実にします

  2. 次を含む Dockerfile.dev というファイルを作成します。

    FROM alpine:latest
    RUN \
      apk add --no-cache git openssh bash && \
      ssh-keygen -A && \
      sed -i "s/#AuthorizedKeysFile/AuthorizedKeysFile/g" /etc/ssh/sshd_config && \
      adduser git -D -G root -h /home/git -s /bin/bash && \
      passwd -d git && \
      su git -c "mkdir /home/git/.ssh && \
      ssh-keygen -t ed25519 -f /home/git/.ssh/id_ed25519 -P '' && \
      mv /home/git/.ssh/id_ed25519.pub /home/git/.ssh/authorized_keys && \
      mkdir /home/git/test.git && \
      git --bare init /home/git/test.git"
    
    VOLUME ["/home/git/.ssh", "/home/git/test.git/hooks"]
    WORKDIR /home/git
    
    CMD ["/usr/sbin/sshd", "-D"]
    
  3. always_reject.sh という名前のテスト用の受信前スクリプトを作成します。 このスクリプト例では、全てのプッシュを拒否します。これは、リポジトリをロックする場合に役立ちます。

    #!/usr/bin/env bash
    
    echo "error: rejecting all pushes"
    exit 1
    
  4. always_reject.sh スクリプトに実行アクセス許可があることを確認します。

    chmod +x always_reject.sh
    
  5. Dockerfile.dev を含むディレクトリで、イメージをビルドします。

    $ docker build -f Dockerfile.dev -t pre-receive.dev .
    [+] Building 4.5s (8/8) FINISHED
     => [internal] load build definition from Dockerfile.dev                                                                            0.0s
     => => transferring dockerfile: 641B                                                                                                0.0s
     => [internal] load .dockerignore                                                                                                   0.0s
     => transferring context: 2B                                                                                                     0.0s
     => [internal] load metadata for docker.io/library/alpine:latest                                                                    1.9s
     => [auth] library/alpine:pull token for registry-1.docker.io                                                                       0.0s
     => [1/3] FROM docker.io/library/alpine:latest@sha256:82d1e9d7ed48a7523bdebc18cf6290bdb97b82302a8a9c27d4fe885949ea94d1              0.0s
     => => resolve docker.io/library/alpine:latest@sha256:82d1e9d7ed48a7523bdebc18cf6290bdb97b82302a8a9c27d4fe885949ea94d1              0.0s
     => => sha256:82d1e9d7ed48a7523bdebc18cf6290bdb97b82302a8a9c27d4fe885949ea94d1 1.64kB / 1.64kB                                      0.0s
     => => sha256:25fad2a32ad1f6f510e528448ae1ec69a28ef81916a004d3629874104f8a7f70 528B / 528B                                          0.0s
     => => sha256:c1aabb73d2339c5ebaa3681de2e9d9c18d57485045a4e311d9f8004bec208d67 1.47kB / 1.47kB                                      0.0s
     => [2/3] RUN   apk add --no-cache git openssh bash &&   ssh-keygen -A &&   sed -i "s/#AuthorizedKeysFile/AuthorizedKeysFile/g" /e  2.3s
     => [3/3] WORKDIR /home/git                                                                                                         0.0s
     => exporting to image                                                                                                              0.1s
     => => exporting layers                                                                                                             0.1s
     => => writing image sha256:938447846e19a4328a85883fbd1ccf5eb919d97448cc7256efebf403d8b5a196                                        0.0s
     => => naming to docker.io/library/pre-receive.dev
    
  6. 生成された SSH キーを含むデータコンテナを実行してください。

    docker run --name data pre-receive.dev /bin/true
    
  7. テスト用の受信前フック always_reject.sh をデータ コンテナーにコピーします。

    docker cp always_reject.sh data:/home/git/test.git/hooks/pre-receive
    
  8. sshd を実行してフックを実行するアプリケーション コンテナーを実行します。 返されたコンテナ ID をメモしておいてください:

    $ docker run -d -p 52311:22 --volumes-from data pre-receive.dev
    > 7f888bc700b8d23405dbcaf039e6c71d486793cad7d8ae4dd184f4a47000bc58
    
  9. 生成された SSH キーをデータコンテナからローカルマシンにコピーしてください:

    docker cp data:/home/git/.ssh/id_ed25519 .
    
  10. テスト リポジトリのリモートを変更し、Docker コンテナー内の test.git リポジトリにプッシュします。 この例では git@github.com:octocat/Hello-World.git を使用しますが、必要に応じてリポジトリを使用できます。 この例ではローカルマシン (127.0.0.1) がポート 52311 をバインドしているものとしていますが、docker がリモートマシンで動作しているなら異なる IP アドレスを使うことができます。

    $ git clone git@github.com:octocat/Hello-World.git
    $ cd Hello-World
    $ git remote add test git@127.0.0.1:test.git
    $ GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 52311 -i ../id_ed25519" git push -u test master
    > Warning: Permanently added '[127.0.0.1]:52311' (ECDSA) to the list of known hosts.
    > Counting objects: 7, done.
    > Delta compression using up to 4 threads.
    > Compressing objects: 100% (3/3), done.
    > Writing objects: 100% (7/7), 700 bytes | 0 bytes/s, done.
    > Total 7 (delta 0), reused 7 (delta 0)
    > remote: error: rejecting all pushes
    > To git@127.0.0.1:test.git
    >  ! [remote rejected] master -> master (pre-receive hook declined)
    > error: failed to push some refs to 'git@192.168.99.100:test.git'
    

    pre-receive フックの実行後にプッシュが拒否され、スクリプトからの出力がエコーされていることに注意してください。

参考資料