CDK で Cognito をセットアップしていたのですが、コードで書いた通りにリソースがデプロイされず、GitHub で Issues を探してみるとバグとして該当しているようでした。折角なのでバグを修正し、Contribute にチャレンジしてみました。個人的な経験上、あまり GitHub で Collaborate する機会もなく、なかなかドキドキしたので今後の備忘録として初歩的な内容ですが残しておきたいと思います。

参考にさせていただいたサイト

Contribute といっても何から始めたら良いのか、、、という状態だったので、手始めに以下を参考にさせていただきました。スライドの後半に具体的な手順も紹介されていましたので大変参考になりました。

以下は、本家リポジトリで公開されている、Contributing ガイドラインです。Contribute するにあたっては必ず一読しましょう

大まかな手順

  1. GitHub で aws-cdk を Fork
  2. 自身のアカウントのリポジトリからローカルにクローン
  3. テストコードを書く、コードを変更する
  4. テストを実行
  5. 自身の GitHub リポジトリに push
  6. 本家リポジトリにプルリクエストを送る
  7. Reviewer の方々に承認されると変更が取り込まれる

前置き(経緯)

一言で Contribute と言ってもいろいろな方法があります。機能のリクエスト(feature request)に対してだったり、ドキュメントに対してだったり、あるいはバグフィックスだったり。。。今回のケースはバグフィックスになります。

元々の経緯は、今回検証のため Cognito を CDK でセットアップしていたのですが、コードに書いた通りにリソースがデプロイされず、いろいろと調べてみた結果バグだということがわかりました(実際の issue)。AWS CDK は「好きな AWS サービス」にあげてる 1つでもあったので、折角なのでバグを修正し貢献してみようと思ったのがきっかけです。

Contribute ガイドラインの Step 1にもありますが貢献するにあたり、まずは Issues の中にすでに課題として存在していないか確認すると良いと思います。

具体的な手順

ここからは実際に行った具体的な手順を書いていきます(2022年7月時点での内容です)。

1. GitHub 本家リポジトリから Fork

aws-cdk の GitHub リポジトリを自身のアカウントに Fork します。

aws-cdk リポジトリから Fork

次の画面でもそのまま “Create fork” します。

2. ローカル環境にクローン

Fork されたリポジトリをローカル環境にクローンしていきます。
(Web 上の IDE である Gitpod を利用する方法もあるようですが、今回はローカル環境で行ってみました。)

Fork されたリポジトリをローカル環境にクローン

git clone git@github.com:msysh/aws-cdk.git

3. 環境のセットアップ

環境をセットアップしていきます。ガイドの通り進めます。

cd aws-cdk
yarn install

IDE として VS Code の利用が推奨されているので VS Code でフォルダを開いていきます。

code .

CDK 全体をビルドすると 1-2時間はかかるようですが、対象モジュールと依存するモジュールだけビルドする方法も用意されています。リポジトリレイアウトの詳細はガイドを見ていただければと思いますが、各 AWS サービスのモジュールは packages/@aws-cdk/ 以下にあり、今回は Cognito でしたので packages/@aws-cdk/aws-cognito で以下のようにすることで対象を絞ってビルドとテストを実行することができます。

cd packages/@aws-cdk/aws-cognito
../../../scripts/buildup
yarn build
yarn test

4. コードの変更の前にテストを書く

環境が整ったのでコードを変更していきたいところですが、私のバグフィックスのつもりの変更が返って思わぬバグを混入させてしまうかもしれません。なのでまず最初にテストを書いていきます。

今回の Cognito の場合のテストは aws-cdk/packages/@aws-cdk/aws-cognito/test/ 以下にあります。このディレクトリの中にはユニットテストだけでなく、スナップショットやインテグレーションテストなどのファイルも含まれています。

テストコードは読んでみるだけでも CDK のテストの書き方とか勉強になります。

周辺のテストコードを見倣ってテストを追加します。テストの中身はある設定をした時に期待される結果が得られるか評価してあげます。以下は実際に追加したテストのうちの1つです。

 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
test('ExplicitAuthFlows makes only refreshToken true when all options are false', () => {
  // GIVEN
  const stack = new Stack();
  const pool = new UserPool(stack, 'Pool');

  // WHEN
  pool.addClient('Client', {
    authFlows: {
      adminUserPassword: false,
      custom: false,
      userPassword: false,
      userSrp: false,
    },
  });

  Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPoolClient', {
    ExplicitAuthFlows: [
      'ALLOW_REFRESH_TOKEN_AUTH',
    ],
  });
});

ちなみに詳細にはあまり触れませんが authFlows で全て false に設定しているにもかかわらず、custom (ALLOW_CUSTOM_AUTH) と userSrp (ALLOW_USER_SRP_AUTH) が有効になってしまうというバグでした(期待値は ALLOW_REFRESH_TOKEN_AUTH のみ設定される)。

尚、変更内容によっては統合テストも書く必要がありますが、今回は書きませんでした。詳細はガイドのこのあたりを読んでくださいまし。

5. テストを実行してみる

テストを実行してみます。今の段階ではバグはまだ修正していないので期待通りの動作とならず、テストは失敗するはずです。

yarn build
yarn test

詳細は割愛しますが、以下のようにテストは失敗します(“1 failed”)。

    :
    :
Test Suites: 1 failed, 9 passed, 10 total
Tests:       1 failed, 206 passed, 207 total
Snapshots:   0 total
Time:        27.138 s
Ran all test suites.
Error: /workspaces/aws-cdk/node_modules/jest/bin/jest.js exited with error code 1
Tests failed. Total time (31.6s) | /workspaces/aws-cdk/node_modules/jest/bin/jest.js (31.5s)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
error Command failed with exit code 1.

6. コードを変更する

テストが書けたところで、実コードを変更していきます。今回の変更対象となるファイルは packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts でして、以下のように変更しました(GitHub Commit)。

--- a/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts
+++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts
@@ -408,7 +408,7 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
   }
 
   private configureAuthFlows(props: UserPoolClientProps): string[] | undefined {
-    if (!props.authFlows) return undefined;
+    if (!props.authFlows || Object.keys(props.authFlows).length === 0) return undefined;
 
     const authFlows: string[] = [];
     if (props.authFlows.userPassword) { authFlows.push('ALLOW_USER_PASSWORD_AUTH'); }
@@ -417,13 +417,8 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
     if (props.authFlows.userSrp) { authFlows.push('ALLOW_USER_SRP_AUTH'); }
 
     // refreshToken should always be allowed if authFlows are present
-    if (authFlows.length > 0) {
-      authFlows.push('ALLOW_REFRESH_TOKEN_AUTH');
-    }
+    authFlows.push('ALLOW_REFRESH_TOKEN_AUTH');
 
-    if (authFlows.length === 0) {
-      return undefined;
-    }
     return authFlows;
   }

7. 再びテストを実行

コードが変更できたので、テストを実行します。

yarn build
yarn test

今度は無事 Pass しました。

    :
    :
Test Suites: 10 passed, 10 total
Tests:       207 passed, 207 total
Snapshots:   0 total
Time:        25.872 s
Ran all test suites.
    :
(その後 Integratin Test が実行されます)

8. 変更内容をコミット

変更内容を自分のリポジトリにコミット、プッシュしていきます。

git add .
git commit
git push origin main

9. GitHub でプルリクエストを作成する

いよいよプルリクエストを作成していきます。まずはガイドの Step 4: Pull Requestをよく読みましょう。タイトルや説明文は conventionalcommits というルールに従う必要があるようです。

自分のリポジトリの “Contribute” から “Open pull request” をクリックしていきます。

プルリクエストの作成

ガイドに従いタイトル、説明文を入力します。バグフィックスだったので元の Issue ID も付記しておきました。
また、送信前のチェックリストがありますのでよく確認し該当箇所("[ ]")にチェック(“x”)を入れます。

プルリクエストのタイトル、説明文、チェックリスト

入力が完了したら “Create pull request” で送信します。

10. あとは承認待ち

あとは、Reviewer の方の承認を待ちます。自動で実行される承認プロセスもあるようです(以下のスクリーンショットは別の方の PR なので少し違ってたかもしれません)。

プルリクエストの承認待ち

ちなみに、

This branch is out-of-date with the base branch

と出てきており、“Update branch” ボタンが表示されてますが、押す必要はありません(押してしまい、「する必要ない」と言われてしまいました…)。

11. 無事承認

今回の変更は軽微だったからでしょうか。小1時間の間に無事承認されました 🎉
(実際のプルリクエスト

プルリクエストの承認

まとめ

AWS CDK にバグフィックスという形で Contribute した時の記録としてまとめてみました。実際にやってみて今回のように軽微な内容であれば、取り組みやすいとも感じました。今回の修正が誰かのお役に立てることを切に願うばかりですし、本記事をきっかけに Contribute していただける方が一人でも増えたら幸いです 🙇‍♂️

最後に・・・

この投稿は個人的なものであり、所属組織を代表するものではありません。ご了承ください。