Fix the user-uninstalled app detection in the install-new-flatpaks service

As identified in #647 (closed), the current mechanism for detecting user-initiated uninstalls of preinstalled Flatpaks is unreliable, because flatpak history goes back only as far as we have surviving journal entries.

So we create a mechanism which stores and maintains in a file (/var/lib/kde-linux/ever-installed/flatpaks) the list of the Flatpak apps that have ever been successfully preinstalled on the system. If an app appears in /usr/share/factory/var/lib/flatpak, is not installed on the system, but is present in ever-installed-flatpaks, then we infer that the user chose to uninstall it, and don't try to preinstall it.

How do we seed that list with its initial contents (i.e. the set of ever-preinstalled apps at the time that this change is released)? On a newly installed system, it's just the list of all apps in /usr/share/factory/var/lib/flatpak. On a system that existed before this change, we make a guess that all the Flatpak preinstalls added by Nov 2025 were preinstalled, but the two subsequently added (qrca and keepsecret) were not (given the fact that the install service wasn't running, see !549 (closed)). If a user did get qrca and/or keepsecret preinstalled, and chose to remove them, unfortunately they are going to reappear when this change hits. Our sense in the Matrix chat was that it wasn't worth going further to avoid this (e.g. by making a fallible guess based on whatever of flatpak history we have).

Testing this change uncovered the separate issue that attempting to sideload newly preinstalled apps from the files in /usr/share/factory/var/lib/flatpak (i.e. the directory that gets bind-mounted in the live session to make the Flatpaks available) wasn't working and can't work. The structure of this data is not the same structure as an actual Flatpak repo. The install command could only ever have worked by falling back and pulling the apps from the remote over the internet. So we (a) remove the --sideload-repo option from the code for clarity, and (b) ensure that the install service runs only after network-online.target. A consequence of (b) is that the install service will run on every boot, not just the one after update (because ConditionNeedsUpdate=|/etc will now never be true at the point the service runs). These extra runs should have very little overhead as the service simply identifies that there are no install actions to perform.

Testing done:

  • Boot the .raw image in a VM and install the system
  • Verify that (a) the initial ever-installed-flatpaks file gets written, populated with the current list of Flatpaks in the factory directory, (b) the install service runs after the network is up, and finds nothing to do.
  • Uninstall qrca (a post-Nov 2025 preinstall) and ark (a pre-Nov 2025 preinstall), and reboot.
  • Verify that nothing is reinstalled, and the logs from the install service identify that qrca and ark are user-removed preinstalls with no action required.
  • sudo rm /var/lib/kde-linux/ever-installed-flatpaks and reboot. (This simulates the behaviour when we deploy this change to an existing system.)
  • Verify that the ever-installed-flapaks file is recreated, this time without qrca and keepsecret. Verify that the install service installs qrca and not ark, and that org.kde.qrca has been appended to the ever-installed-flatpaks file.
  • Uninstall qrca and reboot.
  • Verify that this time, the service does not install qrca.

Fixes #647 (closed)

Also fixes an issue where an app would have been identified as "already installed" if its name was a substring of another app. For example if org.kde.kig was preinstalled, and then later org.kde.kigo was added as a preinstall, the service would have skipped over org.kde.kigo. Padding the app name with spaces when doing the string comparison fixes this.

Edited by Philip Grant

Merge request reports

Loading