Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 13563] ファイルの概要

コミット

commit e1077420807882bd52fd4857100a199b9afc5909
Author: Adam Langley <agl@golang.org>
Date:   Fri Aug 3 13:28:05 2012 -0400

    crypto/tls: remove flakey tests
    
    This removes some (non-short only) tests that involved connections to
    the outside world and thus were flakey. This does remove some test
    coverage of the root fetchers on non-Windows platforms, but the right
    place for that is crypto/x509.
    
    R=golang-dev, krautz, rsc
    CC=golang-dev
    https://golang.org/cl/6455085

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/e1077420807882bd52fd4857100a199b9afc5909

元コミット内容

crypto/tls: remove flakey tests

このコミットは、外部の世界への接続を伴うため不安定(flakey)であった一部のテスト(testing.Short()モードでは実行されないテスト)を削除します。これにより、Windows以外のプラットフォームにおけるルートフェッチャーのテストカバレッジが一部失われますが、そのテストはcrypto/x509パッケージで行われるべきであると判断されました。

変更の背景

このコミットの主な背景は、Go言語のcrypto/tlsパッケージ内のテストが「flakey」、すなわち不安定であったことです。不安定なテストとは、コードの変更がないにもかかわらず、実行するたびに成功したり失敗したりするテストを指します。このようなテストは、CI/CDパイプラインの信頼性を損ない、開発者が実際のバグとテストの不安定性を区別することを困難にします。

コミットメッセージによると、これらのテストが不安定であった理由は「外部の世界への接続を伴う」ためです。具体的には、google.comgithub.comtwitter.comといった実際の外部サーバーへのTLS接続を試みていました。外部ネットワークへの依存は、以下のような要因でテストを不安定にします。

  • ネットワークの遅延や不安定性: テスト実行時のネットワークの状態(帯域幅、レイテンシ、パケットロスなど)によって、接続がタイムアウトしたり、予期せぬエラーが発生したりする可能性があります。
  • 外部サーバーの可用性: 接続先の外部サーバーが一時的にダウンしている、メンテナンス中である、またはレートリミットに達している場合、テストは失敗します。
  • 証明書の変更: 外部サーバーのTLS証明書が更新されたり、中間CA証明書が変更されたりすると、テストが期待する証明書チェーンと一致しなくなり、検証エラーが発生する可能性があります。
  • DNS解決の問題: ドメイン名の解決に失敗したり、誤ったIPアドレスが返されたりすると、接続が確立できません。

これらの要因は、テストが実行される環境やタイミングによって異なり、予測不可能な失敗を引き起こします。開発チームは、このような不安定なテストが開発プロセスに与える悪影響を考慮し、これらを削除することを決定しました。また、ルート証明書のフェッチに関するテストカバレッジはcrypto/x509パッケージで適切に行われるべきであるという判断も、この変更の重要な理由です。

前提知識の解説

1. Go言語のcrypto/tlsパッケージ

crypto/tlsパッケージは、Go言語でTLS (Transport Layer Security) プロトコルを実装するための標準ライブラリです。TLSは、インターネット上で安全な通信を提供するための暗号化プロトコルであり、ウェブブラウジング(HTTPS)、電子メール、VPNなど、多くのアプリケーションで利用されています。このパッケージは、TLSクライアントとサーバーの実装、証明書の検証、鍵交換、暗号化などの機能を提供します。

2. crypto/x509パッケージ

crypto/x509パッケージは、X.509証明書とPKIX (Public Key Infrastructure for X.509) 関連の機能を提供します。X.509証明書は、公開鍵の所有者を識別し、その公開鍵が正当なものであることを証明するために使用されます。このパッケージは、証明書のパース、検証、証明書署名要求 (CSR) の生成、証明書プール(信頼されたルート証明書の集合)の管理などを行います。TLS接続において、サーバーから提示された証明書が信頼できるものであるかを検証する際に、このパッケージが重要な役割を果たします。

3. ルート証明書と証明書チェーン

TLS接続では、サーバーは自身の公開鍵証明書をクライアントに提示します。この証明書は、通常、信頼された認証局 (CA) によって署名されています。CAはさらに上位のCAによって署名され、最終的には自己署名された「ルート認証局」の証明書にたどり着きます。この階層構造を「証明書チェーン」と呼びます。 クライアントは、自身のシステムに事前にインストールされている信頼されたルート証明書のリスト(ルート証明書バンドル)を使用して、サーバーから提示された証明書チェーンを検証します。チェーンの各証明書が正しく署名されており、最終的に信頼されたルート証明書にたどり着けば、そのサーバーの身元は信頼できると判断されます。

4. testing.Short()

Go言語のtestingパッケージには、テストの実行時間を制御するためのtesting.Short()関数があります。これは、go test -shortコマンドでテストを実行した場合にtrueを返します。開発者は、この関数を使って、時間がかかるテスト(例: ネットワークアクセス、ファイルI/O、計算量の多い処理を伴うテスト)をshortモードではスキップし、開発中の高速なフィードバックループを維持することができます。このコミットで削除されたテストは、testing.Short()falseの場合(つまり、フルテスト実行時)にのみ実行されるように設計されていました。

5. Flakey Tests (不安定なテスト)

Flakey testsとは、同じコードベースに対して同じテストを複数回実行したときに、結果が成功と失敗の間でランダムに変動するテストのことです。これは、テストが外部の非決定的な要因(ネットワークの状態、データベースのロック、システム時刻、並行処理のタイミングなど)に依存している場合に発生しやすいです。Flakey testsは、CI/CDパイプラインの信頼性を低下させ、開発者が実際のバグとテストの不安定性を区別することを困難にするため、ソフトウェア開発において大きな問題となります。

技術的詳細

このコミットは、src/pkg/crypto/tls/root_test.goファイルを完全に削除することで、crypto/tlsパッケージから不安定なテストを除去しています。削除されたテストは、Goの標準ライブラリが提供するTLSクライアント機能を使用して、実際の外部ドメイン(google.com, github.com, twitter.com)へのTLS接続を確立し、その接続が成功するかどうかを検証していました。

具体的には、以下の2つのテスト関数が削除されました。

  1. TestOSCertBundles: このテストは、オペレーティングシステムが提供するルート証明書バンドルを使用して、指定されたTLSサーバーへの接続が成功するかどうかを検証していました。Dial("tcp", addr+":443", &Config{ServerName: addr})を呼び出し、TLSハンドシェイクと証明書検証を試みていました。 このテストが不安定であった主な理由は、前述の通り、外部ネットワークの不安定性、外部サーバーの可用性、および証明書の変更に直接依存していたためです。テストが実行されるたびに、これらの外部要因が異なる結果をもたらす可能性がありました。

  2. TestCertHostnameVerifyWindows: このテストは、Windowsプラットフォームに特化しており、ServerNameに意図的に誤ったホスト名(example.com)を設定してTLS接続を試み、証明書のホスト名検証が失敗することを確認していました。期待されるエラータイプはx509.HostnameErrorでした。 このテストも外部サーバーへの接続を伴うため、TestOSCertBundlesと同様の理由で不安定になる可能性がありました。また、Windows固有の証明書ストアの挙動に依存していたため、環境による差異も不安定さの一因となったかもしれません。

コミットメッセージでは、「This does remove some test coverage of the root fetchers on non-Windows platforms, but the right place for that is crypto/x509.」と述べられています。これは、crypto/tlsパッケージがOSのルート証明書バンドルを利用して証明書を検証する機能(ルートフェッチャー)に関するテストカバレッジが一部失われることを認めています。しかし、この機能のテストは、より低レベルで証明書のパースと検証を扱うcrypto/x509パッケージで行われるべきであるという設計上の判断が示されています。

crypto/x509パッケージは、証明書チェーンの構築と検証、ホスト名検証など、TLS接続のセキュリティ基盤となるX.509証明書関連のロジックを直接扱います。したがって、ルート証明書のフェッチや検証に関するテストは、外部ネットワークに依存しない形で、crypto/x509パッケージ内でモックやスタブを用いてより制御された環境で実施されるべきであるという方針転換が示唆されています。これにより、テストの信頼性が向上し、開発者はテスト結果をより信頼できるようになります。

コアとなるコードの変更箇所

削除されたファイル: src/pkg/crypto/tls/root_test.go 変更行数: 61行の削除

このコミットは、src/pkg/crypto/tls/root_test.goファイルを完全に削除しています。

コアとなるコードの解説

削除されたroot_test.goファイルには、主に以下の2つのテスト関数が含まれていました。

  1. TestOSCertBundles(t *testing.T): このテストは、Goのcrypto/tlsパッケージがOSのルート証明書バンドルを正しく利用して、既知のTLSサーバー(google.com, github.com, twitter.com)への接続を確立できるかを検証していました。 テストはtesting.Short()モードではスキップされ、フルテスト実行時にのみ実行されました。 各サーバーに対してtls.Dial("tcp", addr+":443", &tls.Config{ServerName: addr})を呼び出し、接続が成功するかどうかを確認していました。エラーが発生した場合はt.Errorfで報告していました。

    // 削除されたコードの抜粋
    var tlsServers = []string{
        "google.com",
        "github.com",
        "twitter.com",
    }
    
    func TestOSCertBundles(t *testing.T) {
        if testing.Short() {
            t.Logf("skipping certificate tests in short mode")
            return
        }
    
        for _, addr := range tlsServers {
            conn, err := Dial("tcp", addr+":443", &Config{ServerName: addr})
            if err != nil {
                t.Errorf("unable to verify %v: %v", addr, err)
                continue
            }
            err = conn.Close()
            if err != nil {
                t.Error(err)
            }
        }
    }
    
  2. TestCertHostnameVerifyWindows(t *testing.T): このテストはWindowsプラットフォームに限定されており、runtime.GOOS != "windows"でチェックされていました。 これもtesting.Short()モードではスキップされました。 テストの目的は、tls.ConfigServerNameフィールドに意図的に間違ったホスト名(example.com)を設定した場合に、TLS接続がホスト名検証エラーで失敗することを確認することでした。期待されるエラータイプはx509.HostnameErrorでした。

    // 削除されたコードの抜粋
    func TestCertHostnameVerifyWindows(t *testing.T) {
        if runtime.GOOS != "windows" {
            return
        }
    
        if testing.Short() {
            t.Logf("skipping certificate tests in short mode")
            return
        }
    
        for _, addr := range tlsServers { // 同じtlsServersリストを使用
            cfg := &Config{ServerName: "example.com"} // 意図的に間違ったServerName
            conn, err := Dial("tcp", addr+":443", cfg)
            if err == nil { // 成功してはいけない
                conn.Close()
                t.Errorf("should fail to verify for example.com: %v", addr)
                continue
            }
            _, ok := err.(x509.HostnameError) // x509.HostnameErrorが期待される
            if !ok {
                t.Errorf("error type mismatch, got: %v", err)
            }
        }
    }
    

これらのテストは、実際のネットワーク接続と外部サーバーの証明書に依存していたため、ネットワークの不安定性、外部サーバーのダウンタイム、証明書の変更などによって、予測不能な失敗(flakey)を引き起こしていました。Goチームは、このような外部依存性を持つテストは、より制御された環境で、かつ適切なパッケージ(この場合はcrypto/x509)で実施されるべきであるという判断を下し、これらのテストを削除しました。これにより、crypto/tlsパッケージのテストスイートの信頼性が向上し、CI/CDパイプラインの安定化に貢献します。

関連リンク

参考にした情報源リンク