My childhood friend always said that retelling others’ secrets would give you a terrible sickness. While you can’t make your application sick, you can accidentally give away API keys, login credentials, endpoint information, etc. if you do not keep them stored safely. This article is part don’t do what we did and part here’s what you should do instead.
Originally, since my team needed to store credentials for a Mapbox API key, we all made an unchecked dart file with the same name and kept the key there. However, this turned out to be an issue later on when setting up our test suite. I thought I had everything down with our fancy new github action that would call flutter test
on every pull request. However, the tests promptly failed because of a line that looked like:
import 'package:bla/.credentials.dart';
In our local development environments flutter test
was fine. However, in the github environment, the credentials file didn’t exist! I really struggled with this for a few days and tried all kinds of things.
I tried creating the file on the fly from within a setUp()
call in the test suite. I probably didn’t get the incantation correct because this didn’t work.
I then tried to generate the credentials file from within the tests.yaml
file which is used for the github action workflow. Again, something was possibly off about how I did it because I got a new error that the import statement was unused.
Finally, I thought at work we use .env for secrets but would that work here? Spoiler alert: yes it does and it’s actually an ideal way to keep environment variables secret based on the environment (e.g. ‘development’, ‘staging’, ‘production’). So after some googling I stumbled upon the flutter_dotenv package on pub.dev.
The instructions were actually quite simple. All it consisted of is:
- adding the package to our application
- adding a .env file with secrets
- making sure the .env file is not checked into the repo (i.e. add .env to .gitignore)
- finally, generating the .env file on the fly in the
tests.yaml
file
That last bit felt extremely similar to what I had going before so you may be wondering how this is any different than what I tried in my second attempt at getting this to work. This approach differs because now I could remove that import statement and instead just import the dot_env package. Then in the code, instead of grabbing those constants from the dart file, I could use the dot_env package to access them from a global env
object.
It kinda looks like:
dotenv.env['MY_API_KEY'];
This means that now in the github environment, as long as we generate the .env file and add some dummy values in it (empty strings work fine), we don’t get any errors when running flutter test
.
I think as folks who clearly haven’t had much experience with this kind of secrecy, we took a naïve approach and it worked ok at first but it was bound to have issues later. I hope this wisdom can help others out there running into a similar issue with keeping your secrets SECRET!