Unwanted permissions
At Temper we’ve had cases where we were releasing our app and the Play Store gave warnings that it detected new permissions being added to our app bundle which we didn’t add ourselves. After some investigation we found out that new permissions were added to one of the dependencies that was updated.
I started exploring if I can get notified automatically with Github Actions when a dependency add a new permission in their latest release. The plan was to write a Workflow that builds an APK in two parallel jobs of your main branch and the branch of which the dependency was updated. Then find out what permissions each APK require and compare both results. To finish it off, the workflow should notify us by commenting on the pull request if any changes in permissions are detected.
The image below illustrates each step required to do so in the workflow
If a dependency silently adds a permission to their manifest and we update the dependency to that new version in a pull request, we will get a message like this:
Below I’m going to explain each job of this workflow, if you want to go ahead and check the workflow already, you can find it here
The Workflow
Let’s start with the first job in the workflow named build-develop. This job is highlighted in the image below and contains 4 steps. The following steps in this job are quite straightforward if you’re familiar with Github Actions. If you never worked with Github actions before, I wrote an introduction about it here.
1name: Check permissions23on:4 pull_request:5 paths:6 - '**/dependencies.gradle'78jobs:9 build-develop:10 runs-on: ubuntu-latest11 steps:12 - uses: actions/checkout@v213 with:14 ref: develop1516 - name: Build develop APK17 run: ./gradlew app:assembleDebug1819 - name: Get permissions20 run: $ANDROID_HOME/build-tools/29.0.3/aapt d permissions app/build/outputs/apk/debug/app-debug.apk > permissions-develop.txt2122 - name: Upload permissions file develop23 uses: actions/upload-artifact@v124 with:25 name: permissions26 path: permissions-develop.txt
- First we check out the development branch
- Then we run
./gradlew app:assembleDebug
to build a debug apk - Then we extract a list of permissions from the apk with aapt. I’ll tell more about this tool later. This list is written to permissions-develop.txt.
- In the last step
permissions-develop.txt
is uploaded to the artifacts folder. This so we can use this file in the last job of this workflow.
Every file uploaded to the artifacts folder can be shared with other jobs in the same workflow.
Extracting permissions from .apk files
Aapt is the Android Asset Packaging tool providing all sorts of tooling around .apk files. We use it in this case to extract a list of permissions that an apk requires. When running aapt
on an .apk file you’ll get the following output:
:> aapt d permissions {your_app.apk}
1package: com.example.yourpackagename2uses-permission: name='android.permission.INTERNET'3uses-permission: name='android.permission.ACCESS_NETWORK_STATE'4uses-permission: name='android.permission.ACCESS_WIFI_STATE'5uses-permission: name='android.permission.CAMERA'6uses-permission: name='android.permission.ACCESS_FINE_LOCATION'7uses-permission: name='android.permission.VIBRATE'
Running the second job in parallel
Each job defined in a workflow will run in parallel unless told otherwise. For example, the third job in this workflow waits until the first two jobs succeed. More about this in the second part of this series.
Previously I talked about the steps in the build-develop job. We want to run another job exactly like that but with minimal changes. Instead of using the development branch we will use the current branch in which a dependency has been updated.
Since we follow the same steps I’ll skip how that is being done, but you can see it implemented here
That’s it for this article. In the next one I’ll go more in depth on how to retrieve the files we just uploaded to the artifacts folder of this workflow and how to utilise the diff tool to detect any changes and post them to the Pull Request on GitHub. Read more about that in the second part here
In the meantime, follow me on twitter @DionSegijn if you have any questions