All posts by mclasen

Flatpak – a look behind the portal

Flatpak allows sandboxed apps to interact with the rest of the system via portals. Portals are simply D-Bus services that are designed to be safe to expose to untrusted apps.

Principles

There are several principles that have guided the design of the existing portals.

 Keep the user in control

To achieve this, most portals  will show a dialog to let the user accept or deny the applications’ request. This is not a hard rule — in some cases, a dialog is just not practical.

Avoid yes/no questions

Direct questions about permissions tend to be dismissed without much thought, since they get in the way of the task at hand. Therefore, portals avoid this kind of question whenever possible and instead just let the user get on with the task.

For example, when an app is requesting to open a file on the host, we just present the user with a fille chooser. By selecting a file, the user implicitly grants the application access to the file. Or he can cancel the file selection and implicitly deny the applications’ request.

Don’t be annoying

Nothing is worse than having to answer the same question over and over. Portals make use of a database to record previous decisions and avoid asking repeatedly for the same thing.

Practice

The database used by portals is called the permission store. The permission store is organized in tables, with a table for each portal that needs one. It has a D-Bus api, but it is more convenient to explore it using the recently added flatpak commands:

flatpak permission-list
flatpak permission-list devices
flatpak permission-list desktop-used-apps video/webm

The first command will list all permissions in all tables, the second will show the content of the “devices” table, and the last one will show just the row for video/webm in the “desktop-used-apps” table.

There are also commands that deal with permissions on a per-application basis.

flatpak permission-show org.gnome.Epiphany
flatpak permission-reset org.gnome.Epiphany

The first command will show all the permissions that apply to the application, the second will remove all permissions for the application.

And more…

The most important table in the permission store is the “documents” table, where the documents portal stores information about host files that have been exported for applications. The documents portal makes the exported files available via a fuse filesystem at

/run/user/1000/doc

A useful subdirectory here is by-app, where the exported files are visible on a per-application bases (when setting up a sandbox, flatpak makes only this part of the document store available inside the sandbox).

It is instructive to browse this filesystem, but flatpak also has a dedicated set of commands for exploring the contents of the documents portal.

flatpak document-list
flatpak document-list org.gnome.Epiphany

The first command lists all exported files, the second shows only the files that are exported for an individual application.

flatpak document-info $HOME/example.pdf

This command shows information about a file that is exported in the document portal, such as which applications have access to it, and what they are allowed to do.

Lastly, there are document-export and document-unexport commands that allow to add or remove files from the document portal.

Summary

If you want to explore how portals work, or just need to double-check which files an app has access to, flatpak has tools that let you do so conveniently.

The Flatpak BoF at Guadec

Here is a quick summary of the Flatpak BoF that happened last week at Guadec.

1.0 approaching fast

We started by going over the list of outstanding 1.0 items. It is a very short list, and they should all be included in an upcoming 0.99.3 release.

  • Alex wants to add information about renaming to desktop files
  • Owen will hold his OCI appstream work for 1.1 at this point
  • James is interested in getting more information from snapd to portal backends, but this also does not need to block 1.0, and can be pulled into a 1.1 portals release
  • Matthias will review the open portal issues and make sure everything is in good shape for a 1.0 portal release

1.0 preparation

Alex will do a 0.99.3 release with all outstanding changes for 1.0 (Update: this release has happened by now). Matthias will work with  Allan and Bastien on the press release and other materials. Nick is very interested in having information about runtime availability, lifetime and stability easily available on the website for 1.0.

We agreed to remove the ‘beta’ label from the flathub website.

Post 1.0 plans

There was a suggestion that we should have an autostart portal. This request spawned a bigger discussion of application life-cycle control, background apps and services. We need to come up with a design for these intertwined topics before adding portals for it.

After 1.0, Alex wants to focus on tests and ci for a while. One idea in this area is to have a scriptable test app that can make portal requests.

Automatic migration on renames or EOL is on Endless’ wishlist.

Exporting repositories in local networks is a feature that Endless has, but it may end up upstream in ostree instead of flatpak.

Everybody agreed that GNOME Software should merge apps from different sources in a better way.

For runtimes, the GNOME release teams aims to have the GNOME runtime built using buildstream, on top of the freedesktop 1.8 runtime. This may or may not happen in time for GNOME 3.30.

Flatpak, making contribution easy

One vision that i’ve talked abut in the past is that moving to flatpak could make it much easier to contribute to applications.

Fast-forward 3 years, and the vision is (almost) here!

Every application on flathub has a Sources extension that you can install just like anything else from a flatpak repo:

flatpak install flathub org.seul.pingus.Sources

This extension contains a flatpak manifest which lists the exact revisions of all the sources that went into the build. This lets you reproduce the build — if you can find the manifest!

Assuming you install the sources per-user, the manifest is here (using org.seul.pingus as an example):

$HOME/.local/share/flatpak/runtime/org.seul.pingus.Sources/x86_64/stable/active/files/manifest/org.seul.pingus.json

And you can build it like this:

flatpak-builder build org.seul.pingus.json

I said the vision is almost, but not quite there. Here is why: gnome-builder also has a way to kickstart a project from a manifest:

gnome-builder --manifest org.seul.pingus.json

But sadly, this currently crashes. I filed an issue for it, and it will hopefully work very soon. Next step, flip-to-hack !

Flatpak in detail, part 3

The previous in this series looked at runtimes and filesystem organization. Here, we’ll take a look at the flatpak sandbox and explore how the world looks to a running flatpak app.

The sandbox, a view from the inside

Flatpak uses container technologies to set up a sandbox for the apps it runs. The name container brings to mind an image of a vessel with solid walls, which is a bit misleading.

In reality, a container is just a plain old process which talks directly to the kernel and other processes on the system. It is the job of the container management system, in this case flatpak, to launch the process with reduced privileges to limit the harm it can do to the rest of the system. To do this, flatpak uses the same kernel features that tools like docker use: namespaces, cgroups, seccomp.

Processes

One namespace that is used by flatpak is the pid namespace, which hides processes outside the sandbox from the sandboxed app.  If you run ps inside the sandbox, you’ll see something like this:

$ ps
PID TTY TIME CMD
1 ? 00:00:00 bwrap
2 ? 00:00:00 sh
3 ? 00:00:00 ps

One thing you’ll notice is that the app itself (the sh process, in this case) ends up with a PID of 2. Just something to keep in mind when getting your app ready for running in a sandbox: PIDs can’t be used to identify the app to the rest of the system anymore. This has caused minor problems, e.g with the _NET_WM_PID property that some window managers look at to decide about window decorations.

Filesystems

Another namespace that flatpak makes extensive use of is the mount namespace. It is used to create a customized view of the filesystem for the sandboxed app.

Running mount inside the sandbox will show you all the details, but its a bit much to show here, so we’ll just stick to the most important parts:

  • /app – this is where the apps files are mounted. It is a typical Unix filesystem with /app/share, /app/bin/, /app/lib and so on. When building an app for flatpak packaging, it typically gets configured with –prefix=/app for this reason.
  • /usr – the runtime files are placed here.
  • /run/host/ – various parts of the host filesystem that are safe to expose are mounted here, for example fonts (in /run/host/fonts) and icons (in /run/host/share/icons).
  • /usr/share/runtime/locale/ – the Locale extension of the runtime is mounted here.
  • Other extensions are mounted in their pre-determined places.
  • $HOME/.var/app/$APPID is made available to the app as well. This is the place in the home directory where flatpaked apps can store persistent data. The XDG_DATA_HOME, XDG_CONFIG_HOME and XDG_CACHE_HOME environment variables are set up to point to subdirectories in this place, and respecting these variables is a good way for an app to just work in a flatpak.

D-Bus

A common way for Linux apps to communicate with services and apps in the user session is via D-Bus, and most flatpak sandboxes allow the app to talk on the session bus (it can be turned off with a setting in the metadata). But we can’t just let the app talk to any other process on the bus, that would be a big risk. Therefore, flatpak sets up a filtering proxy that only allows the app to talk to certain names (this is again set up in the metadata).

The exception to this are portals – these are D-Bus interfaces specifically designed to be safe to expose, and apps are always allowed to talk to them. Portals offer APIs for a number of common needs, such as

  • org.freedestkop.portal.FileChooser  – Open a file
  • org.freedesktop.portal.OpenUri – Show a file in an app
  • org.freedesktop.portal.Print – Print a file
  • org.freedesktop.portal.Notification – Show a notification

Most of the time, portals will present a dialog to keep the user in control of what system access the sandboxed apps gets.

Toolkits like GTK+ can transparently use portals in some cases when they detect that the app is inside a sandbox, which greatly reduces the effort in using portals.

Metadata

But how does GTK+ find out that is being used inside a sandbox?

It looks for a file called .flatpak-info which flatpak places in the filesystem root of every sandbox. This file is not just a marker, it contains some useful information about the details of the sandbox setup, and is worth looking at. Some apps show information from here in their about dialog.

Summary

Flatpak sets up a customized sandbox for the apps it runs. It tries hard to preserve an environment that typical Linux desktop apps expect, including XDG locations and the session bus.

Trying out GTK+ 4

I was asked today if there is already a Flatpak runtime that includes GTK+ 3.94. A very natural question. GTK+ 4 and flatpak are both cool, so of course you want to try them together.

But the answer is: No, GTK+ 4 is not included in a runtime yet.

It is still a bit early for that – the master branch of the GNOME runtime includes development versions of libraries, but those are libraries that are following the GNOME release schedule, where we can expect them to have a stable release in time for GNOME 3.30 in September. That is not the case for GTK+ 4.

However, that does not mean you cannot take your first steps with GTK+ 3.94 and flatpak right now. Flatpak is a flexible system and the bundling capabilities are very well-suited for this kind of scenario.

Just add GTK+ to the list of bundled modules in your flatpak manifest:

...
 "modules": [
   {
     "name": "gtk+",
     "buildsystem": "meson",
     "builddir": true,
     "config-opts": [
       "--prefix="/app",
       "--libdir="lib",
       "-Ddemos=false",
       "-Dbuild-tests=false"
     ],
     "sources": [
       "type": "archive",
       "url": "https://download.gnome.org/sources/gtk+/3.94/gtk+-3.94.0.tar.xz"
     ]
   },
   {
     "name": "your-app",
     ...
   }
 ]
...

If you are more adventurous, you can also build the GTK+ master branch from git, to see our latest progress towards GTK+ 4 as it happens.

To see a complete example of a flatpak manifest bundling GTK+ and its dependencies, you can look at corebird.

We have the beginnings of a GTK+ 3 → 4 migration guide in the GTK+ documentation. If you give it a try, please let us know what works and what is missing.

One way to so so is to file an issue. But you also welcome to come by the GTK+ BoF at Guadec in Almeria and tell us in person.

Flatpak in detail, part 2

The first post in this series looked at runtimes and extensions. Here, we’ll look at how flatpak keeps the applications and runtimes on your system organized, with installations, repositories, branches, commits and deployments.

Installations and repositories

An installation is a place on your filesystem where flatpak can install apps and runtimes. By default, flatpak has a system-wide installation in /var/lib/flatpak, and a user installation in $HOME/.local/share/flatpak.

It is possible to define additional system-wide installations by placing a key file in /etc/flatpak/installations.d. For example, this can be used to keep apps on a portable drive.

Part of the data that flatpak keeps for each installation is a list of remotes. A remote is a reference to an ostree repository that is available somewhere on the network.

Each installation also has its own local ostree repository (for example, the system-wide installation has its repo in /var/lib/flatpak/repo). You can explore the contents of these repositories using the ostree utility;

$ ostree --repo=$HOME/.local/share/flatpak/repo/ refs
gnome-nightly:appstream/x86_64
flathub:runtime/org.freedesktop.Platform.Locale/x86_64/1.6
flathub:app/de.wolfvollprecht.UberWriter/x86_64/stable
...

Branches and versions

Similar to git, ostree organizes the data in a repository in commits, which are grouped in branches. Commits are identified by a hash and branches are identified by a name.

While ostree does not care about the format of a branch name, flatpak uses branch names of the form $KIND/$ID/$ARCH/$BRANCH to uniquely identify branches.

Here are some examples:

app/org.inkscape.Inkscape/x86_64/stable
runtime/org.gnome.Platform/x86_64/master

Most of the  time, it is clear from the context if an app or runtime is being named, and only one architecture is relevant. For this case, flatpak allows a shorthand notation for branch names omitting the $KIND and $ARCH parts: $ID//$BRANCH.

In this notation, the above examples shrink to:

org.inkscape.Inkscape//stable
org.gnome.Platform//master

Deployments

Installing an app or runtime really consists of two steps: first, flatpak caches that data in the local repo of the installation, and then it deploys it, which means it creates a check-out of the branch from the local repo. The check-outs are organized in a folder structure that reflects the branch name organization.

For example, Inkscape will be checked-out in $HOME/.local/share/flatpak/app/org.inkscape.Inkscape/x86_64/stable/$COMMIT, where $COMMIT is the hash of the commit that is being deployed.

It is possible to have multiple commits from the same branch deployed, but one of them is considered active and will be used by default. Flatpak maintains symlink in the check-out directory that points at the active commit.

It is also possible to have multiple branches of an app or runtime deployed at the same time; the directory structure of checkouts is designed to allow that. One of the branches is considered current. Flatpak maintains a symlink at the toplevel of the checkout that points at the current checkout.

Flatpak can run an app from any deployed commit, regardless whether it is active or current or not. To run a particular commit, you can use the –commit option of flatpak run.

The relevance of being active and current is that flatpak exports some data (in particular, desktop files) from the active commit of the current branch, by symlinking it into ~/.local/share/flatpak/exports,  where for example gnome-shell will find it and allow you to run the app from the overview.

Note: Even though it is perfectly ok to have multiple versions of the same app installed, running more than one at the same time will typically not work, since the different versions will claim the app ID as their unique bus name on the session bus. A way around this limitation is to explicitly give one of the versions a different ID, for example, by appending a “.nightly” suffix.

Application data

One last aspect of filesystem organization to mention here is that every app that is run with flatpak gets a some filesystem space to use for permanent storage. This space is in $HOME/.var/app/$ID, and it has subdirectories called cache, config and data. At runtime, flatpak sets the XDG_CACHE_DIR, XDG_CONFIG_HOME and XDG_DATA_HOME environment variables to point at these directores.

For example, the persistent data from the inkscape flatpak can be found in $HOME/.var/app/org.inkscape.Inkscape.

Summary

Flatpak installations may look a bit intimidating with their deep diretory tree, but they have a well-defined structure and this post hopefully helps to explain the various components.

Flatpak in detail

At this point, Flatpak is a mature system for deploying and running desktop applications. It has accumulated quite some sophistication over time, which can make it appear more complicated than it is.

In this post, I’ll try to look in depth at some of the core concepts behind Flatpak, namely runtimes and extensions.

In the beginning: bundles

At its very core, the idea behind Flatpak is to bundle applications with their dependencies, and ship them as a self-contained unit.  There are good reasons that bundling is attractive for application developers:

  • There is a much bigger chance that the app will run on an arbitrary end-user system, which may have different versions of libraries, different themes, or a different kernel
  • You are not relying on all the different update mechanisms and policies of Linux distributions
  • Distribution updates to your dependencies will not break your app behind your back
  • You can test the same code that your users run

Best of both worlds: runtimes

In the age-old debate beween bundlers and packagers, there are good arguments on both sides. The usual arguments against bundling are:

  • Code duplication. If a library gets hit by a security issue you have to fix it in all the apps that bundle it
  • Wastefulness. if every app ships an entire library stack, this blows up the required bandwidth for downloads and the required disk space for installing them

With this in mind, Flatpak early on introduced the concept of runtimes. The idea behind runtimes is that many desktop applications use a deep library stack, but it is often a similar set of libraries. Therefore, it makes sense to take these common library stacks and distribute them separately as “GNOME runtime” or “KDE runtime”, and have apps declare in their metadata which runtime they need.

It then becomes the responsibility of the flatpak tooling to assemble  the applications filesystem tree with the runtimes filesystem tree when it creates the sandbox environment that the app runs in.

To avoid conflicts, Flatpak requires that the applications filesystem tree is rooted in /app, while runtimes have a traditional /usr tree.

Splitting off runtimes preserves most of the benefits that I outlined for bundles, while greatly reducing code duplication and letting us update libraries independently of applications.

Of course, it also brings back some of the risks of modularity: updating the libraries independently carries, once again, the risk of breaking the applications that use the runtime. So the team maintaining a runtime has to be very careful to avoid introducing problematic changes or incompatibilities.

Going further: extensions

As I said, shipping runtimes separately saves a lot of bandwidth, since the runtime has to be downloaded only once for all the applications that share it. But a runtime is still a pretty massive download, and contains a lot of things that may not be useful most of the time or are just optional.

A good examples for this are translations. It is not uncommon for desktop apps to be translated in 50 locales. But the average user will only ever use a single one of these. In traditional packaging, this is sometimes addressed by breaking translations out as “lang packs” that can be installed separately.

Another example is debug information. You don’t need symbols and other debug information unless you encounter a crash and want to submit a meaningful stacktrace. In traditional packaging, this is addressed by splitting off “debuginfo” packages that can be installed when needed.

Flatpak provides a mechanism  to address these use cases.  Runtimes (and applications too) can declare extension points, which are designated locations in their filesystem tree where additional runtimes can be mounted. These additional runtimes are called extensions. When constructing a sandbox for running an app, flatpak tooling will look for matching extensions and mount them at the right place.

Flatpak is not a generic solution, but tailored towards the use case of desktop applications, and it tries to do the the right thing out of the box: flatpak-builder automatically breaks out .Locale and .Debug extensions when building apps or runtimes, and when installing things, flatpak installs the matching .Locale extension. But it goes beyond that and only installs the subset of it that is relevant for the current locale, thereby recreating the space-saving effect of lang packs.

Extensions: infinite variations

The extension mechanism is flexible enough to cover not just locales and debuginfo, but all sorts of other optional components that applications might need. To give just some examples:

  • OpenGL drivers that match the GPU
  • Other hardware-specific APIs like vaaapi
  • Media codecs
  • Widget themes

All of these can be provided as extensions. Flatpak has the smarts built-in to know whether a given OpenGL driver extension matches the hardware or whether a given theme extension matches the current desktop theme, and it will automatically install and use matching extensions.

At last: the host OS

The examples in the previous paragraph are realized as extensions because the shared objects or theme components need to match the runtime they are used with.

But some things just don’t change very much over time, and don’t need exact matching against the runtime to be used by applications. Examples in this category are fonts, icons or certificates.

Flatpak makes these components from the host OS available in the sandbox, by mounting them below /run/host/ in the sandbox, and appending /run/host/share to the XDG_DATA_DIRS environment variable.

Summary

Flatpak does a lot of hard work behind the scenes to ensure that the apps it runs find an environment that looks similar to a traditional Linux desktop, by combining the application, its runtime, optional extensions and host components.

The Flatpak documentation provides more information about working with Flatpak as an application developer.

Fedora Atomic Workstation → Team Silverblue

I have been writing a long series of posts about my experience with
Fedora Atomic Workstation, which I’ve enjoyed it quite a bit. But all good things must come to an end. So, no more Atomic Workstation for me …since we’re renaming it to Team Silverblue.

Team Silverblue logoWith this project, we want to take the Atomic Workstation as it is today, and turn into something that is not just cool for the few who know it, but useful for everybody who has a need for a Workstation.

There is still some work to be done to reach that goal. We have some ideas what is needed, but as with all open projects, those who show up to build it get a chance to shape the end product.

So, come and join us in Team Silverblue!

Fedora Atomic Workstation: Getting comfortable with GNOME Builder

Note: Fedora Atomic Workstation has recently been renamed to Team Silverblue. Learn more here.

I am still going with my attempt to use Fedora Atomic Workstation fulltime as my main  development system. As part of that, I am figuring out how to do GTK+ development on an immutable OS, using GNOME Builder.

As I’ve explained in a previous post, one thing I figured out early on is that while the flatpak support in GNOME Builder is optimized for desktop applications, you can use it for other things. In my case, that means developing GTK+.

Build Configurations

GNOME Builder knows what and how to build via its build configurations. It can have multiple such configurations for each project – the Build Preferences page has a list of them. In the flatpak case, build configurations correspond more or less 1:1 to flatpak manifests that are stored as json files in the source tree. Last time, I created one that launches the  gtk4-demo application.

Currently, creating a new build configuration means copying an existing flatpak manifest to a new file, but in  3.28, GNOME Builder will support copying build configurations directly in the Build Preferences.

Environment

Influencing GTK+ at runtime for debugging purposes is often done via environment variables, such as GTK_DEBUG for controlling the debug output. Unfortunately, setting environment variables is not the most obvious in GNOME Builders flatpak support, currently.

There is an Environment section in the Build Preferences, but it sets environment variables at build time, not in the runtime sandbox that gtk4-demo will run in. GNOME Builder currently has no UI for setting up the runtime environment. We can still do it, by manually adding –env options in the finish-args section of the flatpak manifest:

"finish-args" : [
   "--share=ipc",
   "--share=network",
   "--socket=x11",
   ...
   "--env=GTK_DEBUG=modules"
 ],

This is hardly elegant, and it has the big downside that any change to the flatpak manifest will cause GNOME Builder to rebuild the project, even if the change only affects the runtime setup, as is the case here. I hope that GNOME Builder will gain proper runtime setup UI at some point.

Terminals

But maybe it would be more natural to get a command prompt and set environment variables as usual, while launching apps from there.

GNOME Bulder can actually give you a terminal, with Ctrl-Alt-Shift-T, but it is a terminal in the build sandbox, not the runtime sandbox.

Thankfully, we can help ourselves in the same way as before: Just create another build configuration, this time using “sh” as the command – that gives us a shell inside the runtime sandbox, and we can launch test apps from there while setting environment variables.

Portals

One aspect of GTK+ that I have worked on in this new setup is module loading. I’ve switched GTK+s printing support to use a GIO extension point, and of course, I wanted to test this before pushing it.

So I was a bit surprised at first that the print dialog in gtk4-demo did not trigger my new module loading code and yet seemed to work just fine. But then I remembered that we are working in a flatpak sandbox now, so GTK+s portal support kicked in and helpfully redirected the print operation to an out-of-process print dialog.

Fedora Atomic Workstation: Theming Possible

Note: Fedora Atomic Workstation has recently been renamed to Team Silverblue. Learn more here.

Today, I decided to try out how themes work with flatpak:ed apps on an Atomic Workstation.

To change themes, I need gnome-tweaks. I already had it installed from the gnome-nightly-apps repository. Unfortunately, it didn’t work, complaining about a missing python package in the runtime. Such is life with nightly builds.

Instead, I used package layering to install a stable version of gnome-tweaks:

$ rpm-ostree install gnome-tweaks

This worked better, and …I found that there are no themes on the Atomic Workstation install, apart from the default ones (Adwaita and HighContrast). So, back to package layering once more. I installed Adapta:

$ rpm-ostree install adapta-gtk-theme

Now I could switch the theme to Adapta in gnome-tweaks:After all this preparation, I was finally ready to see how flatpak:ed apps handle the new theme. But first I wanted to update them:

$ flatpak update
Looking for updates...
Installing for user: org.gtk.Gtk3theme.Adapta/x86_64/3.22 from flathub
[####################] 1 delta parts, 2 loose fetched; 336 KiB transferred in 1 seconds
...

Neat. Flatpak detected the current GTK+ theme (by reading the gsetting), found a matching runtime extension, and automatically installed it. Flatpak has a similar automatism built-in for matching the host GL drivers and for installing some hardware-specific libraries.

Of course, I could have just manually installed the theme, but this is much more convenient. To see what themes are available on flathub, use:

$ flatpak remote-ls flathub | grep theme
org.gtk.Gtk3theme.Adapta
org.gtk.Gtk3theme.Adapta-Eta
org.gtk.Gtk3theme.Adapta-Nokto
org.gtk.Gtk3theme.Adapta-Nokto-Eta
org.gtk.Gtk3theme.Ambiance
org.gtk.Gtk3theme.Arc
org.gtk.Gtk3theme.Arc-Dark
org.gtk.Gtk3theme.Arc-Dark-solid
org.gtk.Gtk3theme.Arc-Darker
org.gtk.Gtk3theme.Arc-Darker-solid
org.gtk.Gtk3theme.Arc-solid
org.gtk.Gtk3theme.Breeze
org.gtk.Gtk3theme.Breeze-Dark
org.gtk.Gtk3theme.Communitheme
org.gtk.Gtk3theme.Greybird
org.gtk.Gtk3theme.Materia
org.gtk.Gtk3theme.Materia-dark
org.gtk.Gtk3theme.Materia-light
org.gtk.Gtk3theme.Mint-Y
org.gtk.Gtk3theme.Mint-Y-Dark
org.gtk.Gtk3theme.Mint-Y-Darker
org.gtk.Gtk3theme.Numix
org.gtk.Gtk3theme.Pop
org.gtk.Gtk3theme.Pop-light
org.gtk.Gtk3theme.elementary

And now, when I run a flatpak app, for example GNOME Characters, it comes up with the Adapta theme:

Lessons learned from this quick experiment: Nightly apps don’t always work, but flatpak can handle themes just fine.

Update: It is probably worth a brief explanation why it is necessary to install the theme twice, on the host and for Flatpak.  With Flatpak, the apps can use different runtimes, and those may contain different version of libraries like GTK+. The host system may be much more stable (think RHEL). So, for every “OS extension” (like fonts, or themes, or drivers) we have to ask ourselves  – will this work across possibly different library versions ? For fonts, the answer we found is yes, font file formats have been stable forever, and it is very unlikely that a font you have on your system will not work with any app or runtime. Therefore, we make the host system fonts available inside flatpak sandboxes – you don’t have to install them again. For themes, we were not so confident, despite GTK+ 3 being stable now, we decided that it is better to have themes match the toolkit version in each runtime.