GitHubでのコミットにGPG署名することを求められた場合

CodeIgniter Advent Calendar 2016 の7日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。

現在開発中のCodeIgniter4へのPull Requestでは、commitにGPG署名が求められています。

これは、ソースコードの出所を証明するためのものです。

CodeIgniter3へのPull Requestでもgitのcommit -sによる署名が求めらています。

しかし、これは所詮コミットログに名前を入力するだけのものです。コミットログに認証があるわけではなくどんな文字列も記載可能ですから、究極的には誰がそのコミットをしたのかは証明できません。

commitにGPG署名すれば、少なくとも署名したアカウントをGitHubが証明してくれます。

それでは、commitにGPG署名をする方法を説明します。

GPGのインストール

以下から、GPGをダウンロードしてインストールします。

GPG鍵の作成

ターミナルから新しいGPG鍵を作成します。

$ gpg --gen-key
gpg (GnuPG/MacGPG2) 2.0.30; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits       
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)  ←無期限を選択
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Your Name ←名前を入力
Email address: your_address@example.jp  ←メアドを入力
Comment:                              
You selected this USER-ID:
    "Your Name <your_address@example.jp>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
You need a Passphrase to protect your secret key.    ←秘密鍵のパスフレーズを入力

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy. ←マウスをぐるぐるする
gpg: key 28E5003B marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   3  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 3u
gpg: next trustdb check due at 2018-08-19
pub   4096R/28E5003B 2016-12-07
      Key fingerprint = E870 21D3 2D61 240C B80A  F3F5 D29A 30C6 28E5 003B
uid       [ultimate] Your Name <your_address@example.jp>
sub   4096R/0F7D6F53 2016-12-07

これで鍵が作成されました。

アプリ「GPG Keychain」を起動すれば、作成した鍵が表示されるはずです。

公開鍵のGitHubへの登録

公開鍵をエクスポートします。

$ gpg -a --export your_address@example.com

これで公開鍵が出力されます。

-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org

…略…
-----END PGP PUBLIC KEY BLOCK-----

GitHubへブラウザでアクセスし、右上の自分のアイコンから「Settings」を選び、「SSH and GPG keys」をクリックします。

「New GPG key」ボタンを押し、出力されたGPG公開鍵(-----BEGIN PGP PUBLIC KEY BLOCK-----から-----END PGP PUBLIC KEY BLOCK-----まで)をペーストし、追加します。

これで、GitHubにGPG公開鍵が登録されました。

Gitの設定

次に、GitにGPG公開鍵を設定します。

まず、鍵IDを確認します。

$ gpg --list-secret-keys --keyid-format LONG

以下の出力の場合、3AA5C34371567BD2が鍵 IDです。

/Users/hubot/.gnupg/secring.gpg
------------------------------------
sec   4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10]
uid                          Hubot 
ssb   4096R/42B317FD4BA89E7A 2016-03-10

その鍵をgitに設定します。

$ git config --global user.signingkey 3AA5C34371567BD2

これで、gitに公開鍵が設定されました。

CodeIgniter4リポジトリではデフォルトで署名するように設定する

GPG署名が求めらるリポジトリでは、デフォルトで署名するように設定しましょう。

$ cd CodeIgniter4/
$ git config commit.gpgsign true

署名が必要なときはGPG秘密鍵のパスフレーズの入力を求められます。

署名の仕方

デフォルトで署名する設定になっていないリポジトリの場合は、commit -Sでcommitに署名できます。

$ git commit -S

GPG秘密鍵のパスフレーズの入力を求められます。

ログの確認

--show-signatureオプションを付けると署名の情報が表示できます。

$ git log --show-signature

GitHubでの表示

GPG署名されたコミットには、以下のように「Verified」のマークが付きます。

この記事は、CodeIgniter Advent Calendar 2016 の7日目です。明日はayatoさんの「僕もget sparksしたかったよ」の予定です。

関連

Tags: github, git, gpg, codeigniter, mac

CodeIgniterのset_value()とは何か?

CodeIgniterにはset_value()というヘルパー関数があるのですが、仕様や意図が少しわかりづらいので、調査して整理しておきます。

このヘルパーの意味

3.2.0-devのユーザガイドでは、以下のように説明されています。

入力フォームやテキストエリアの値を設定します。関数の第1引数でフィールド名を指定します。 第2引数(オプション)では、フォームの初期値を指定できます。
http://codeigniter.jp/user_guide/3/helpers/form_helper.html#set_value

また、Noteとして、以下の記述があります。

フォームバリデーション (検証) をロードし このヘルパーで使われているフィールド名の検証ルールを設定している場合、 フォームバリデーション (検証) 自身の set_value() メソッドの呼び出しを行います。 それ以外の場合、この関数はフィールドの値を設定するために $_POST を参照します。

念のため、3.1.0の本家のユーザガイド http://www.codeigniter.com/userguide3/helpers/form_helper.html#set_value も見ておきましょう。

Permits you to set the value of an input form or textarea. You must supply the field name via the first parameter of the function. The second (optional) parameter allows you to set a default value for the form.

Noteも。

If you’ve loaded the Form Validation Library and have set a validation rule for the field name in use with this helper, then it will forward the call to the Form Validation Library‘s own set_value() method. Otherwise, this function looks in $_POST for the field value.

同じですね。

つまり、このヘルパーはFormからの入力値を返すもので、Form_validationクラスと関連するが、必ずしもForm_validationと一緒に使う必要があるわけではないということになります。ちょっとわかりにくいですね。

実装

具体的な実装を確認しておきましょう。

CodeIgniter 3.1.0

    function set_value($field, $default = '', $html_escape = TRUE)
    {
        $CI =& get_instance();

        $value = (isset($CI->form_validation) && is_object($CI->form_validation) && $CI->form_validation->has_rule($field))
            ? $CI->form_validation->set_value($field, $default)
            : $CI->input->post($field, FALSE);

        isset($value) OR $value = $default;
        return ($html_escape) ? html_escape($value) : $value;
    }

現在の実装は、Form_validationがロードされており、指定フィールドに対する検証ルールがあれば、Form_validation::set_value()メソッドの返り値を、そうでなければPOSTパラメータから値を取得し、最後にHTMLエスケープして(デフォルトの場合)います。

つまり、Form_validationクラスを使わなくても、このヘルパー関数はPOSTパラメータの値をエスケープして返します。

はい、ユーザガイドに書いてある通りですね。

ただし、Form_validationクラスがロードされ、検証ルールが定義されている場合は、Form_validation::run()メソッドを実行しないとset_value()は入力値を返しません。

なぜなら、Form_validation::set_value()メソッドは以下のようになっているからです。Form_validation::run()メソッドを実行しないと$this->_field_data[$field]['postdata'])の値がセットされないからです。

    public function set_value($field = '', $default = '')
    {
        if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
        {
            return $default;
        }

        // If the data is an array output them one at a time.
        //  E.g: form_input('name[]', set_value('name[]');
        if (is_array($this->_field_data[$field]['postdata']))
        {
            return array_shift($this->_field_data[$field]['postdata']);
        }

        return $this->_field_data[$field]['postdata'];
    }

CodeIgniter 2.2.6

過去のバージョンでの実装も見ておきましょう。

    function set_value($field = '', $default = '')
    {
        if (FALSE === ($OBJ =& _get_validation_object()))
        {
            if ( ! isset($_POST[$field]))
            {
                return $default;
            }

            return form_prep($_POST[$field], $field);
        }

        return form_prep($OBJ->set_value($field, $default), $field);
    }

やっていることはほぼ同じです。

CodeIgniter 1.7.3

    function set_value($field = '', $default = '')
    {
        if (FALSE === ($OBJ =& _get_validation_object()))
        {
            if ( ! isset($_POST[$field]))
            {
                return $default;
            }

            return form_prep($_POST[$field], $field);
        }

        return form_prep($OBJ->set_value($field, $default), $field);
    }

2.2と同じです。

CodeIgniter 1.6.1

なし。

いつ追加されたのか?

では、この関数はいつ追加されたのでしょうか?

27 Aug 2008に追加されています。https://github.com/bcit-ci/CodeIgniter/commit/43e0fbb650d05466cd2568b8a2cc1c38849a6b52#diff-1c29a972aad2e090993d30d846a74282R592 より。

+   function set_value($field = '', $default = '')
+   {
+       if (FALSE === ($OBJ =& _get_validation_object()))
+       {
+           if ( ! isset($_POST[$field]))
+           {
+               return $default;
+           }
+           
+           return $_POST[$field];
+       }
+       
+       return $OBJ->set_value($field, $default);
+   }

当初はHTMLエスケープしていませんでしたが、その後、エスケープ処理が追加されたようです。

まとめ

  • set_value()はFormからの入力値をビューで表示するためのヘルパー関数である
  • デフォルトでは入力値(POSTパラメータ)をエスケープして返す
  • Form_validationクラスで検証ルールを定義した場合は、Form_validation::run()を実行しないと入力値を取得できない
  • その場合は、Form_validation::set_value()の値を返す
  • Form_validationクラスをロードしていない場合は、POSTパラメータから値を取得する

参考

Tags: codeigniter