Ten days ago, Mullvad released Mullvad Browser. I was involved in its development, being part of the applications team at the Tor Project.
So, I would like to use this occasion to describe how we maintain Tor Browser and the similarities with Mullvad Browser.
Tor Browser is a fork of Firefox. However, we are a small team, and we cannot stay on pass with the rapid release channel of Mozilla.
Instead, our starting point is the extended support release, the version geared towards enterprises.
It is not an old Firefox, but a channel Mozilla actively supports for about one year. Like the rapid release, it receives monthly updates, typically only with security patches. It rarely receives new features.
This is an enormous advantage because we can quickly update Tor Browser without auditing the changes. Moreover, these few changes are unlikely to create conflicts to be manually merged and reviewed carefully.
After a new ESR major is released, the old one continues to be supported for a few months. This gives us the time to rebase, audit, and add any needed patches to the new Tor Browser major while maintaining a stable channel in the old ESR.
As I had mentioned, we are a small team, and last year, we were late, and we had to backport security patches manually for a couple of months. It was difficult because it involved backporting fixes over a year of changes, and we would prefer not to do it again.
So, we planned to start rebasing once the next ESR (115) enters the nighly phase this year: this will give us two more months to prepare the next major release, for a total of five months.
The monthly update
About a week before a release, Mozilla tags in their Mercurial infrastructure the commit they will use to build. Then, we update the Tor Browser code in a few days, but we make sure not to publish the updated binaries before Mozilla.
We do not merge Mozilla updates on top of our patches.
Instead, we continuously branch out of the last tagged commit and cherry-pick the commits from the previous branch.
All our git branches are made of Mozilla commits, followed by our commits (about 100), which we call patchset.
Therefore, we do not have a
main branch, but our default branch changes continuously. To be more precise, we create two new branches for each Firefox update: one for our release channel and one for the alpha, where new developments happen.
Of course, this procedure introduces risks of unwanted changes. However, just like all other changes, it goes through a review process. Usually, it involves another developer using git range-diff to inspect differences.
We prefer this workflow because our patchset remains compact, and we do not risk losing track of changes.
A curiosity: we do not manage a bridge between Moz’s Hg and Git. Instead, we rely on the official gecko-dev mirror. This guarantees users that we do not mess up with Firefox code outside the patchset, as commit hashes are untouched.
What does the patchset look like
Commits in Tor Browser do not have the usual meaning of changeset or fix. Usually, we have a commit for each feature or even for a group of functionalities.
Often, new changes are fixups to existing commits and are squashed during the rebases.
One of our goals is to make the browser buildable at every commit without needing the following ones. This helps in isolating bugs through bisection, should we need it.
In general, this needs care and additional maintenance from time to time. One of the last reworks was one of my first tasks at Tor between December 2021 and January 2022. The strategy we currently follow was defined by Richard, our team lead:
- Commits from the Rapid Release that are not part of the ESR yet (including commits we originally developed for Tor Browser and then upstreamed to Firefox).
- Reverts of Firefox commits we do not want at all for Tor Browser.
- Commits disabling Firefox some features we do not need (Firefox account, remote settings, synchronization, experiments, etc…).
- Other tweaks to Firefox functionalities.
- Branding and onboarding customization.
- Tor network integration.
- Tor Browser-specific functionalities (connection preferences and captive portal, onion services support, etc…).
Entering the Mullvad Browser
A few months later, Mullvad told us they wanted to create a browser with similar privacy protections to Tor Browser but without the Tor network integration.
We realized that the structure we had delined could be a solid foundation for both browsers.
In particular, we thought that the part of the patchset before the branding commit could become a shared base, and we called it Base Browser. In the following months, we to shuffled around a few commits and improved the overall patchset.
For example, the Security Level and New Identity were initially in the Torbutton submodule, added as a part of the Tor integration. However, they could benefit both browsers, so we extracted and refactored their code.
We also had to generalize our build system to build more products.
As a first approximation, Tor Browser has become Base Browser with the addition of the Tor Network and Onion Services support and the Tor branding. Mullvad Browser is Base Browser + Mullvad-specific configuration and branding.
However, Base Browser is not intended to be a product, it does not have any release, nor it ever will. It is a development tool anybody can use to create a Firefox fork, even though the final goal should be upstreaming as many patches as possible, not segmentation.
Mullvad’s sponsorship has been a fantastic opportunity for extraordinary maintenance and long-due cleaning. I am really happy we got it, and I would like to take this occasion to thank the team and all the people who contributed to this achievement.