Firebase secrets in GitHub actions (Case Study)
Tags: flutter, firebase, devops, github
Published: 2020-08-04 14:21:53

### **Make sure you've:**
- Some experiences in [flutter](https://github.com/features/actions)
- Basic understanding of Git & GitHub
- Working knowledge of [setting-up a flutter app with firebase](https://firebase.google.com/docs/flutter/setup)

### **Before starting**

Let's gather some idea about [GitHub Actions](https://github.com/features/actions). GitHub Actions is a CI/CD tool for automation to build, test & deploy your projects on any platform. The idea behind this scenario is you need to create some workflows & running it in a container or, in a virtual machine. Nowadays, [flutter-action](https://github.com/marketplace/actions/flutter-action) - a third party utility is mostly used to build & test flutter applications on GitHub actions. 

### **Let's start 😎**

You might have worked with **google-services.json** during the registration of your flutter application in firebase. In most cases, developers refer it into the **.gitignore** and avoid committing the google-services.json file in GitHub due to security purpose. Avoiding to commit the JSON file is also considered to be a good practice. But doing so raises some problems too. Before diving deep, let's understand the problem through a case study.

#### Case Study

Your project manager is "Mr. X" who is very strict in terms of testing. Each branches must pass the CI/CD before merging it into the master/main branch. Your team uses **GitHub Actions** & the workflows of your project runs all the tests whenever a pull request is created. At some point, your app needs to communicate with firebase. In this situation your project needs to deal with google-services.json both in the development environment & the environment of GitHub Actions to pass the tests on each pull requests. Moreover, **you can't expose the JSON file in public.** 

![Confused Shinchan](https://media.giphy.com/media/U5DNSiHo21pvuJEXye/giphy.gif)

> Seems difficult? Let's deal with it 😎

### **Solution (Step-by-Step)**

- **tar archive:** Usually, the google-services.json is located at `android/app` directory. Next, we will be creating a tar archive of the JSON file using these options:
  * c – creates a new .tar archive file
  * v – verbosely show the .tar file progress
  * f – file name type of the archive file
- **Creating tar:** We will be naming the tar file as `services.tar`. Run the command below in your project's working directory to create the archive file: 
  * `tar cvf services.tar android/app/google-services.json`
- **.gitignore services.tar:** Add the `services.tar` file in .gitignore. Don't forget to do this !!
- **Encryption:** Before encryption, make sure you've [gnupg](https://gnupg.org/download/) installed in your system. Run the command below to encrypt the services.tar file. During encryption, it will ask for password which will be used to decrypt the encrypted file. After running the command, there will be a new file in your project's working directory named `services.tar.gpg`. The command is : 
  * `gpg -c services.tar` 
- **Secrets in GitHub:** Replace the required part with your project's repository link in the below URL & head over to it: 
  * `https://<YOUR_GITHUB_REPOSITORY_LINK>/settings/secrets/new`  
  * Or, you can find this by navigating to **Settings > Secrets > New Secret** of your repository.

- **Create secrets:** There will be two parameters required to create a secret. In the first field `name`, enter the value `FIREBASE_SECRET` & in the second field `value`, enter the password you've previously used to encrypt the tar archive file.
- **Workflow:** In your project's working directory, create a directory named as `.github`. Inside, the .github directory, create `workflows` directory. Then in the workflows directory, create a file `ci.yml`. Lastly, paste the code below in ci.yml. Assuming you have a test program test/widget_test.dart. Modify the test command at the end as your needs.
```yaml
name: CI
on: [pull_request, push]

jobs:

  build:
    name: build and test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/checkout@v1
    - uses: actions/setup-java@v1
      with:
        java-version: '12.x'
    - uses: subosito/flutter-action@v1
      with:
          channel: 'beta'
    - run: flutter pub get
    - name: Build
      run: |
        mkdir $HOME/private
        gpg --quiet --batch --yes --decrypt --passphrase="$FIREBASE_SECRET" \
        --output $HOME/private/services.tar services.tar.gpg
        tar xvf $HOME/private/services.tar
        flutter build appbundle
      env:
        FIREBASE_SECRET: ${{ secrets.FIREBASE_SECRET }}
    - name: Test
      run: flutter test test/widget_test.dart
```

#### Understanding the ci.yml

- `on: [pull_request, push]`: This workflow will work whenever someone push or, make a pull request.
- In the `steps` we are: 
  * Using required utilities.
  * Running `flutter pub get` command to install required packages defined in `pubspec.yaml`.
  * Decrypting the `services.tar.gpg` by using the password we have stored in the secrets `FIREBASE_SECRET`.
  * Building & running the tests of our application on GitHub actions.

#### **References:**
- [Automation article by flutter community](https://medium.com/flutter-community/automating-flutter-publishing-with-github-actions-firebase-app-distribution-cc80dec638de)
- [Stackoverflow solution by Bertrand Martel](https://stackoverflow.com/questions/34251441/commiting-google-services-json-to-github/42868893)

#### Last but not the least 

To err is human. If you find any mistakes here or, any sentence/word/code-snippet which can be corrected or, improved then feel free to knock me on [Twitter](https://twitter.com/_shunjid). If you find this helpful then share it to help others too.