Skip to main content

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

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

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

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

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

入力 (stdin)

プッシュが発生した後で、リモート リポジトリに関して参照が更新される前に、your GitHub Enterprise Server instance上の 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 参照」を参照してください。

出力 (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 を使用した参照の作成REST API ドキュメントの「Git データベース
git refs delete api
API を使用した参照の削除REST API ドキュメントの「Git データベース
git refs update api
API を使用した参照の更新REST API ドキュメントの「Git データベース
git repo contents api
API を使用したファイルの内容に対する変更REST API ドキュメントの「ファイル コンテンツの作成または更新

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 フックのプッシュ

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

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

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

    $ sudo chmod +x SCRIPT_FILE.sh

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

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

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

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

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

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

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

    FROM gliderlabs/alpine:3.3
    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 .
    > Sending build context to Docker daemon 3.584 kB
    > Step 1 : FROM gliderlabs/alpine:3.3
    >  ---> 8944964f99f4
    > Step 2 : 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"
    >  ---> Running in e9d79ab3b92c
    > fetch http://alpine.gliderlabs.com/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
    > fetch http://alpine.gliderlabs.com/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
    ....truncated output....
    > OK: 34 MiB in 26 packages
    > ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
    > Password for git changed by root
    > Generating public/private ed25519 key pair.
    > Your identification has been saved in /home/git/.ssh/id_ed25519.
    > Your public key has been saved in /home/git/.ssh/id_ed25519.pub.
    ....truncated output....
    > Initialized empty Git repository in /home/git/test.git/
    > Successfully built dd8610c24f82
  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 main
    > Warning: Permanently added '[192.168.99.100]: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@192.168.99.100:test.git
    >  ! [remote rejected] main -> main (pre-receive hook declined)
    > error: failed to push some refs to 'git@192.168.99.100:test.git'

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

参考資料