テスト駆動で学ぶ Firestore セキュリティルール【CI 編】
IT技術

CI 環境におけるセキュリティルールの自動テスト

これまで、「テスト駆動で学ぶ Firestore セキュリティルール」をテーマに、実例を交えてセキュリティルールの仕様や利用可能な関数について解説してきました。
せっかく作成したテストであれば、「GitHub Actions」や「CircleCI」などの CI 環境で自動テストに活用したいところです。
今回は、ここまでの記事とは少し雰囲気をかえて、CI 環境でのセキュリティルールの自動テストについて解説していきます。
これまでの記事については、以下の記事を参照してください。
データ検証編はこちら
「データ検証編」では、リクエストデータ、データベース上のデータの参照などについて解説
データ比較編はこちら
「データ比較編」では、データの比較や型チェックなどについて解説
カスタム関数編はこちら
「カスタム関数編」では、「比較編」で作成したルールをもとに、カスタム関数の使い方を解説
対象読者
本記事では、以下のいずれかの CI ツールを利用している、または利用予定の読者を想定しています。
- GitHub Actions
 - CircleCI
 - GitLab CI/CD
 
※ GitHub Actions については、GitHub アカウントをお持ちであれば、本記事で紹介する設定ファイルの追加だけで動作確認が可能です。
注意書き
本記事では、各 CI ツール( GitHub Actions、CircleCI、GitLab CI/CD )でのセキュリティルールのテストについて、解説していきます。
各 CI ツールの基本的な使用方法や構築方法などの解説はいたしませんので、予めご了承ください。
また、CI ツールごとの解説は独立した内容となっています。
利用しない、または利用予定のない CI ツールの解説は飛ばして読み進めても問題ありません。
簡単な流れ
本記事では、以下のような流れで、「CI 環境でのセキュリティルールのテスト」について解説していきます。
- CI 環境で使用するテスト環境とテストコード、セキュリティルールを用意
 - ローカル環境でのテストの流れのおさらいと、テスト成功チェック
 - CI 環境でのテストの設定について解説
 - 人気のある3つの CI ツールにおける、セキュリティルールのテストの設定例を紹介
 - まとめ
 
前準備
まずは、CI 環境で使用する「テスト環境」と「テストコード」、「テスト対象のセキュリティルール」を用意します。
以下のリポジトリに、本記事のコードをまとめてあります。
【rightcode/firestore-security-rules-test_ci-setting】
https://github.com/rightcode/firestore-security-rules-test_ci-setting
セットアップ
以下のコマンドを実行して、テスト環境をセットアップしてください。
1git clone "https://github.com/rightcode/firestore-security-rules-test_ci-setting" sandbox
2cd sandbox
3git checkout refs/tags/test-environment「masterブランチ」に完成ソースコードを設置してあります。
本記事中で解説するソースコードを確認したい場合は、以下のコマンドで 「masterブランチ」をチェックアウトしてください。
1git checkout master※ コードの調整などにより、本記事の内容とは記述が若干異なる場合があります。
使用するテストとセキュリティルールの準備
テストコードとテスト対象となるルールは、先述のリポジトリに含まれているサンプルテストとサンプルルールを使用します。
サンプルテスト
サンプルテストの中身は、以下の通りです。
1process.env.FIRESTORE_EMULATOR_HOST = "localhost:58080";
2
3import {FirestoreTestSupporter} from "firestore-test-supporter";
4
5import * as path from "path";
6import * as firebase from "@firebase/testing";
7
8describe("サンプルテスト", () => {
9    const supporter = new FirestoreTestSupporter("my-test-project", path.join(__dirname, "firestore.rules"));
10
11    beforeEach(async () => {
12        await supporter.loadRules();
13    });
14
15    afterEach(async () => {
16        await supporter.cleanup()
17    });
18
19    describe('デフォルトで全てのアクセスを拒否', () => {
20        test('読み込み拒否', async () => {
21            const db = supporter.getFirestore();
22            const doc = db.collection('default').doc('dummy');
23            await firebase.assertFails(doc.get())
24        });
25
26        test('書き込み拒否', async () => {
27            const db = supporter.getFirestore();
28            const doc = db.collection('default').doc('dummy');
29            await firebase.assertFails(doc.set({data: 'dummy'}))
30        });
31
32        test('認証付き読み込み拒否', async () => {
33            const db = supporter.getFirestoreWithAuth();
34            const doc = db.collection('default').doc('dummy');
35            await firebase.assertFails(doc.get())
36        });
37
38        test('認証付き書き込み拒否', async () => {
39            const db = supporter.getFirestoreWithAuth();
40            const doc = db.collection('default').doc('dummy');
41            await firebase.assertFails(doc.set({data: 'dummy'}))
42        });
43    });
44});サンプルテストは、全てのアクセスの拒否を確認する内容のテストになっています。
サンプルルール
サンプルルールの中身は、以下の通りです。
1rules_version = '2';
2service cloud.firestore {
3  match /databases/{database}/documents {
4    allow read, write: if false;
5  }
6}サンプルルールは、サンプルテストの要件を満たす、全てのアクセスを拒否するセキュリティルールとなっています。
ローカル環境でテストチェック
おおよそ、ローカル環境でのテスト実行の流れを CI 環境でのテストの設定にも適用します。
ローカル環境でテストが通ることをチェックしつつ、簡単にテスト実行の流れを確認しておきます。
npm パッケージをインストール
以下のコマンドを実行して、必要となる npm パッケージをインストールしてください。
1npm installFirebase CLI ツールをインストール
Firebase CLI ツールをインストールしていない場合は、以下のコマンドを実行してインストールしてください。
1npm install -g firebase-toolsFirestore エミュレータを起動
以下のコマンドを実行して、Firestore エミュレータを起動してください。
1firebase setup:emulators:firestore
2firebase emulators:start --only firestoreテスト実行
以下のコマンドで、テストを実行してください。
1npm run test以下のように結果が表示されれば、テストは成功です!
1 PASS  tests/sample/firestore.rules.test.ts (6.033s)
2  サンプルテスト
3    デフォルトで全てのアクセスを拒否
4      √ 読み込み拒否 (4092ms)
5      √ 書き込み拒否 (55ms)
6      √ 認証付き読み込み拒否 (45ms)
7      √ 認証付き書き込み拒否 (54ms)
8
9Test Suites: 1 passed, 1 total
10Tests:       4 passed, 4 total
11Snapshots:   0 total
12Time:        6.095s, estimated 8s
13Ran all test suites.ローカル環境でのテストの成功が確認できたので、続いて、CI 環境でのテストの設定について解説していきます。
CI 環境でのテスト設定方針
簡単な流れ
各CIツールでのテストは、おおよそ、以下の流れでコマンドを実行していきます。
- npm パッケージのインストール
 - firebase-tools のインストール
 - Firestore エミュレータをインストール
 - エミュレータをバックグラウンド起動
 - エミュレータの起動待機
 - テスト実行
 
ローカル環境でのテスト環境のセットアップ、テスト実行の流れとおおよそ同じ内容ですが、以下のような違いもあります。
- CI 環境でのテストに合わせ、firebase-tools をローカルインストールする
 - CI 用に調整したテストスクリプトを使用する
 - Firestore エミュレータの起動をバックグラウンドで行う必要がある
 
注意事項
特に留意しておきたいのが、エミュレータの起動です。
CI 環境でのテストの場合、Firestore エミュレータをバックグラウンドで起動しないと、処理がそこで停滞してしまうため、肝心のテストが実行されません。
また、エミュレータが起動するまでに少し時間がかかるため、テストの実行前にエミュレータの起動待機時間の設定が必要になります。
次の項目では、以上の点に気を付けて、本題である「CI ツール別のテスト設定例」を紹介していきたいと思います。
CI ツール別のテスト設定例
CI ツールごとの設定の解説は、独立した内容となっています。
利用しない CI ツールの解説は、飛ばして読み進めても問題ありません。
また、テストに失敗する場合は、後述の「テストに失敗する場合は」の項目をチェックしてください。
GitHub Actions の場合
「GitHub Actions」でセキュリティルールをテストする場合は、.github/workflows ディレクトリを作成して、 test.yml ファイルを追加してください。
.github/workflows/test.yml を作成したら、以下のように記述してください。
1name: test
2
3on: [push]
4
5jobs:
6  test:
7    runs-on: ubuntu-latest
8
9    strategy:
10      matrix:
11        node-version: [12.x]
12
13    steps:
14      - name: リポジトリのチェックアウト
15        uses: actions/checkout@v2
16
17      - name: Node.js ${{ matrix.node-version }} セットアップ
18        uses: actions/setup-node@v1
19        with:
20          node-version: ${{ matrix.node-version }}
21
22      - name: パッケージインストール
23        run: npm install
24
25      - name: firebase-toolsをインストール
26        run: npm install firebase-tools
27
28      - name: Firestoreエミュレータをインストール
29        run: npm run setup:emu:firestore
30
31      - name: エミュレータの起動
32        run: npm run emu:start:firestore &
33
34      - name: エミュレータの起動待機...
35        run: sleep 10
36
37      - name: テスト実行
38        run: npm run ci-test上記の設定のあと、GitHub にソースコードをプッシュすると、GitHub Actions で test ワークフローがスタートし、テストが実行されます。
結果
ワークフローの実行結果は、以下のようになります。

テスト結果は、以下の通りです。
1PASS tests/sample/firestore.rules.test.ts
2  サンプルテスト
3    デフォルトで全てのアクセスを拒否
4      ✓ 読み込み拒否 (1463ms)
5      ✓ 書き込み拒否 (149ms)
6      ✓ 認証付き読み込み拒否 (99ms)
7      ✓ 認証付き書き込み拒否 (87ms)
8
9Test Suites: 1 passed, 1 total
10Tests:       4 passed, 4 total
11Snapshots:   0 total
12Time:        4.655s
13Ran all test suites.以上で、GitHub Actions でのセキュリティルールのテストの設定は完了です。
CircleCI の場合
「CircleCI」でセキュリティルールをテストする場合は、.circleci ディレクトリを作成して、 config.yml ファイルを追加してください。
.circleci/config.yml を追加したら、以下のように記述してください。
1version: 2.1
2jobs:
3  test:
4    docker:
5      - image: circleci/node:lts-browsers
6    steps:
7      - checkout
8      - run:
9          name: パッケージインストール
10          command: npm install
11      - run:
12          name: firebase-toolsをインストール
13          command: npm install firebase-tools
14      - run:
15          name: Firestoreエミュレータをインストール
16          command: npm run setup:emu:firestore
17      - run:
18          name: エミュレータの起動 & テスト実行
19          command: npm run emu:start:firestore & sleep 10; npm run ci-test
20workflows:
21  test:
22    jobs:
23      - testconfig.yml ファイルを設定したら、CircleCI サイトでテスト対象の GitHub リポジトリをプロジェクトに追加してください。
上記の設定のあと、GitHub にソースコードをプッシュすると、CircleCI の test ワークフローがスタートし、テストが実行されます。
結果
ワークフローの実行結果は、以下のようになります。

テスト結果は、以下の通りです!
1 PASS  tests/sample/firestore.rules.test.ts
2  サンプルテスト
3    デフォルトで全てのアクセスを拒否
4      ✓ 読み込み拒否 (776ms)
5      ✓ 書き込み拒否 (111ms)
6      ✓ 認証付き読み込み拒否 (70ms)
7      ✓ 認証付き書き込み拒否 (63ms)
8
9Test Suites: 1 passed, 1 total
10Tests:       4 passed, 4 total
11Snapshots:   0 total
12Time:        3.127s
13Ran all test suites.以上で、CircleCI でのセキュリティルールのテスト設定は完了です!
GitLab CI/CD の場合
「GitLab CI/CD」でセキュリティルールをテストする場合は、クローンしたリポジトリのルートに .gitlab-ci.yml ファイルを追加してください。
.gitlab-ci.yml を追加したら、以下のように記述してください。
1stages:
2  - test
3
4test:
5  image: circleci/node:lts-browsers
6  stage: test
7  script:
8    - npm install
9    - npm install firebase-tools
10    - npm run setup:emu:firestore
11    - npm run emu:start:firestore &
12    - sleep 10
13    - npm run ci-test上記の設定のあと、GitLab にソースコードをプッシュすると、GitLab CI/CD でパイプラインがスタートして、テストが実行されます。
結果
パイプラインの実行結果は、以下のようになります。

テスト結果は、以下の通りです。
1PASS tests/sample/firestore.rules.test.ts (5.357s)
2  サンプルテスト
3    デフォルトで全てのアクセスを拒否
4      ✓ 読み込み拒否 (1456ms)
5      ✓ 書き込み拒否 (210ms)
6      ✓ 認証付き読み込み拒否 (127ms)
7      ✓ 認証付き書き込み拒否 (107ms)
8
9Test Suites: 1 passed, 1 total
10Tests:       4 passed, 4 total
11Snapshots:   0 total
12Time:        5.394s
13Ran all test suites.以上で、GitLab CI/CD でのセキュリティルールのテスト設定は完了です。
テストに失敗する場合は
一部、または全てのテストに失敗する場合は、エミュレータが待機時間内で起動していない可能性があります。
待機時間は長めに設定していますが、場合によっては、テスト開始までにエミュレータが起動しない事があります。
テストが失敗する場合は、エミュレータの起動待機時間を調整してみてください。
逆に、起動待機時間が原因のテスト失敗がないのであれば、3~5秒程度に調整しても問題ありません。
まとめ
今回は、CI 環境でのセキュリティルールのテストについて解説してみました。
今回紹介した CI ツールの中でも、GitHub Actions は、GitHub アカウントさえあれば、記事中で紹介したような設定ファイルを追加するだけで簡単にはじめることができます。
まだ CI 環境を導入していない場合は、まずは GitHub Actions からはじめてみるのがオススメです!
では、最後に、今回の内容を簡単にまとめてみたいと思います。
- どの CI 環境でも、やることはローカル環境とほぼ同じ
 - CI 環境での Firestore エミュレータの起動はバックグラウンドで
 - Firestore エミュレータの起動後に待機時間が必要
 - 一度設定してしまえば、プッシュのたびに自動リグレッションテスト!
 - まだ CI 環境を導入していないなら、まずは GitHub Actions がおすすめ!
 
こちらの記事もオススメ!
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit










