27

I have a flutter web app and for accessing the database I have hardcoded an APIKey in a secrets.dart file, And this works perfectly fine. I have added this file to .gitignore in order to prevent it from pushing it to version control. But when it comes to deploying the app using GitHub actions The script fails because it doesn't detect the secrets file.

I did look at the docs on Encrypted secrets from Github which basically allows storing the secrets.But it seems like those secrets are only accessible in the yml file.

I would like to know how can I use this secret in my app so that my script runs successfully and deploys the app. Here is my folder structure

lib/
  services/
     database.dart /// this file uses the APIkey from secrets.dart
  secrets.dart /// contains the APIkey

One way to solve this issue I can think of is to use a .env file but I am not much familiar with How to add the secret keys in .env file through the CI script. I believe that would also solve my problem.

Heres my CI script

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on merge
"on":
  push:
    branches:
      - master
jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-java@v1
        with:
          java-version: "12.x"
      - uses: subosito/flutter-action@v1
        with:
          channel: "master"
      - run: flutter pub get
      - run: flutter pub run build_runner build --delete-conflicting-outputs
      - run: flutter build web --release
      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: "${{ secrets.GITHUB_TOKEN }}"
          firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_VOCABHUB_34C7F }}"
          channelId: live
          projectId: vocabhub-34c7f
        env:
          FIREBASE_CLI_PREVIEWS: hostingchannels

Dharman
  • 30,962
  • 25
  • 85
  • 135
Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131

2 Answers2

54

You can use your secrets.dart file while being ignored in the source control.

Here are the steps

  1. In your local machine, encode the content of your secrets.dart using the base64 command:
      base64 lib/path/to/secrets.dart
    
  2. Copy and paste the output into your GitHub secrets, name it $SECRETS_FILE_CONTENT or whatever you want.
  3. Add this CI step into your yaml script just before the flutter pub get step.
      # other stuff ...
      - run: echo $SECRETS_FILE_CONTENT | base64 -d > lib/path/to/secrets.dart
        env:
          SECRETS_FILE_CONTENT: ${{ secrets.SECRETS_FILE_CONTENT }}
      - run: flutter pub get
      - run: flutter pub run build_runner build --delete-conflicting-outputs
      - run: flutter build web --release
      # other stuff ...
    

To add the secret in the GitHub user interface, follow these steps:

Click on the repository's Settings tab, click on Secrets, click "New repository secret", DO NOT USE "environment secrets" because it does not work

Fill in the name of the variable e.g. SECRETS_FILE_CONTENT and its value e.g. the base-64 encoded file contents

Your secret should appear in the lower "repository secrets" half of the UI, it should NOT appear in the "Environment secrets" as those do not work with a simple ${{ secrets.name_of_variable }}.

The SECRETS_FILE_CONTENT variable name should now appear in the second box at the bottom

To provide more context, here's what the "actions" file, e.g. .github/workflows/ci.yml in your repository, should look like:

name: CI

on:
  push:
    branches: [ main, dev ]
  pull_request:
    branches: [ main ]

  # Allows to run this workflow manually from the Actions tab
  workflow_dispatch:
  
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Decode base64 secrets
        run: echo $SECRETS_FILE_CONTENTS | base64 -d > lib/path/to/secrets.dart
        env:
          SECRETS_FILE_CONTENTS: ${{ secrets.SECRETS_FILE_CONTENTS }}
      # … put your steps here
        run: flutter pub get

Edit

This is also the same process when hiding google-services.json when people work with firebase. Or with signing keys (key.jks or key.keystore).

Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131
xamantra
  • 930
  • 7
  • 10
  • Dang! that seems to be working. Can you please explain what this step is doing ```run: echo $SECRETS_FILE_CONTENT | base64 -d > lib/utils/secrets.dart``` is it creating a file with the content? – Mahesh Jamdade Jun 17 '21 at 01:32
  • Yes. That line will decode and write the output into the file path specified. – xamantra Jun 17 '21 at 05:52
  • Thank you so much this is one of the simplest and the most secure solutions (AFAIK) I have ever seen, I am not sure why no one mentioned this. Anyways I would like to offer you a bounty for this great answer, I will be waiting for two more days. – Mahesh Jamdade Jun 18 '21 at 04:06
  • congratulations on the bounty – Mahesh Jamdade Jun 22 '21 at 02:52
  • OH GOD. so many hours debugging this. Thanks! – motobói Feb 13 '22 at 02:22
  • Thanks! I had to use the following command : $SECRETS_FILE_CONTENT | base64 -di > lib/utils/secrets.dart Otherwise, base64 -d failed. The return message was : invalid input. – Ghislain Viguier Feb 13 '22 at 15:22
  • I wrote a blog post describing this approach https://medium.com/flutter-community/managing-secrets-in-an-open-sourced-flutter-web-app-8c2219ed72b9 – Mahesh Jamdade Apr 05 '22 at 15:55
  • silly question: why do you even need to base64 encode it? it doesn't really add anything in terms of security right? – Pjotr Gainullin Jan 12 '23 at 03:16
  • @PjotrGainullin it's not for security. If you directly paste a dart code or any string with special characters and formatting (like any code), Github Action will not accept it. And the environment runner itself will throw invalid string format errors or something like that. – xamantra Jan 12 '23 at 05:34
  • @PjotrGainullin base64 is like a very simple 1 line string avoiding any string formatting errors and allowing it to be accepted globally. – xamantra Jan 12 '23 at 05:35
  • WTF! I assigned it to "Environment Secrets" and don't know why it can't be accessed from a github action. Thanks a lot. – Athachai Jan 18 '23 at 10:55
  • Actually you can read secrets from `Environment Secrets` you just need to define the desired environment name within the job where you read them, with `environment` keyword like this `jobs: publish: environment: env_name` – Holy semicolon Mar 03 '23 at 17:41
30

if you're using Environment Secrets rather than Repository Secrets, you should define what environment will u use, check this out

jobs:
  build:
    environment: **ENVIRONMENT NAME HERE**

    steps:
      - name: blah blah
        run: echo blah blah

UPDATE (2022-08-09)


jobs:
    build:
    ...
    environment: Foo
    steps:
        - uses : actions/checkout@v3
        - name : Run some customized action
          env :
            a : ${{ secrets.Bar }}
            b : $ Mona  
            c : ${{ secrets.Lisa }}
          run : |
            echo $a 
            echo $b
            echo $c

There were a lots of updates since i answered, so to summary, There is 3 secrets in github now

  1. Environments Secrets
  2. Actions Secrets (Repository Secrets)
  3. Dependabot Secrets

Dependabot is out of this range.

Environments Secrets is

Settings -> Environments -> New Environments -> Environment Secrets

Actions Secrets is

Settings -> Secrets -> Actions -> Repository Secrets

so if i want to access environment secret value logically,

we need to know 2 arbitrary variable. Environment Name and Environment Secret Name like EnvironmentName.EnviromentSecretName.EnvironmentSecretValue

As i wroted, Foo is EnvironmentName

and

Bar is EnvironmentSecretName

and

Mona is constant

and

Lisa is Actions(Repository) Secret Name

so that if we set Environment Secret as "Mark" and Repository Secret as "Twain"

the console out will be

Mark

Mona

Twain

Additionally, Github will redact the secret value like "***" consider https://zellwk.com/blog/debug-github-actions-secret/ uri to debug it

Implermine
  • 323
  • 3
  • 8