This guide will give an overview of the Apertis reference Flatpak runtimes, as well as creating, signing, and publishing your own runtimes and applications.

# Reference Runtimes

Apertis provides a reference Flatpak runtime, available in two variants:

• org.apertis.headless.Platform and org.apertis.headless.Sdk: A basic runtime with some common libraries that headless applications may use.
• org.apertis.hmi.Platform and org.apertis.hmi.Sdk: A larger runtime for graphical applications, based on the headless one.

In addition, a version of GNOME Fonts using the HMI runtime is available as a demo, under the name org.apertis.hmi.gnome_font_viewer.

In order to install the runtimes and/or demo, the Flatpak repository must first be set up:

$flatpak --user remote-add apertis https://images.apertis.org/flatpak/repo/apertis.flatpakrepo  You can then proceed with the installation: $ flatpak --user install \
org.apertis.hmi.Platform \
org.apertis.hmi.Sdk \
org.apertis.hmi.gnome_font_viewer


Finally, the demo application can be run by executing the following command:

$flatpak run org.apertis.hmi.gnome_font_viewer  # Runtime Creation The reference Apertis runtimes are built using apertis-flatdeb, which is able to create a new Flatpak runtime using packages from the Apertis distribution. ## Prerequisites apertis-flatdeb can be installed on an Apertis system via sudo apt install apertis-flatdeb. ## Layout apertis-flatdeb encourages the use of a particular filesystem layout for runtimes (the concepts of “suites” will be explained further below): • A suites/ directory, containing YAML files describing “suites”, which are essentially just the package lists that a runtime will be using. • A runtimes/ directory, containing YAML files corresponding to the runtime variants that will be built. • An apps/ directory, containing flatpak-builder manifest files for applications that can be built alongside the runtimes. All of these should be under a single main directory, which we will henceforth refer to as the working directory. ## Suites As mentioned above, suites determine the package lists that will be used for the runtime to build on. Each file inside suites is named RELEASE.yaml, where RELEASE determines the Apertis version you’re targeting. For instance, to use Apertis v2022 packages, the suite file would be suites/v2022.yaml. As for the actual content, it is highly recommended to simply reuse the [suite files used in the reference runtime], which already contain everything needed for an Apertis runtime. Simply take the same file and rename it to follow the desired Apertis version. (The files contents should not need to be changed.) Once the suite is configured, we need to generate a base chroot for flatdeb to work in. From the working directory, please execute the following command: $ flatdeb --build-area=$(pwd)/flatdeb-builddir \ --ostree-repo=$(pwd)/flatdeb-builddir/ostree-repo \
--suite=<SUITE_NAME> --arch=<TARGET_ARCHITECTURE> \
base


This will create a flatdeb-builddir subfolder containing a file named base-<SUITE_NAME>-<TARGET_ARCHITECTURE>.tar.gz containing the base rootfs needed for future operations. If you delete this file, or want to target a different Apertis version, you will have to run the above command again.

## Runtime Descriptions

The majority of the logic in creating a runtime goes in runtimes/NAME.yaml, where NAME should be the id_prefix of the runtime. This file lists out the packages that go into the runtime and the details of any special steps taken during its creation. The manifest files used to build the Apertis reference runtime are available for use as well.

The files are in the following format:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34  --- id_prefix: org.test pre_apt_script: echo pre_apt_script post_script: echo post_script add_packages: - package1 - package2 overlays: - common-overlay add-extensions: org.test.Extension: directory: share/runtime/extension no-autodownload: true platform: pre_apt_script: echo platform pre_apt_script post_script: echo platform post_script overlays: - platform-overlay sdk: add_packages: - sdk-package1 - sdk-package2 pre_apt_script: echo sdk pre_apt_script post_script: echo sdk post_script overlays: - sdk-overlay ... 

### The ID Prefix

 1  id_prefix: org.test 

id_prefix determines this runtime’s IDs. The platform will be named after the prefix followed by .Platform, and the SDK will be similar but using .Sdk. For instance, in the above example, the platform and SDK names would be org.test.Platform and org.test.Sdk, respectively.

### Running Scripts

  1 2 3 4 5 6 7 8 9 10  pre_apt_script: echo pre_apt_script post_script: echo post_script platform: pre_apt_script: echo platform pre_apt_script post_script: echo platform post_script sdk: pre_apt_script: echo sdk pre_apt_script post_script: echo sdk post_script 

pre_apt_script contains code that will be run before apt installs any of the runtime’s packages, and post_script will be run towards the end of the runtime creation process (after all packages are installed). In addition, both of these are available specifically for .Platform and .Sdk by placing them inside the platform: and sdk: maps, respectively. These scripts can be used to modify the final system layout or modify the repositories before packages are installed; in particular, this is used by the reference runtime to enable development packages in the SDK (see Enabling Development Repositories).

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16  add_packages: - package1 - package2 add_packages_multiarch: - package3 - package4 sdk: add_packages: - sdk-package1 - sdk-package2 add_packages_multiarch: - sdk-package3 - sdk-package4 

The top-level add_packages will add the packages listed inside to both the Platform and Sdk variants, and the add_packages key inside sdk: will add packages only to the SDK. add_packages_multiarch is similar but will attempt to install the packages for all architectures given, rather than just the primary architecture. For instance, given the above example:

• org.test.Platform will contain:
• package1
• package2
• package3
• package4
• org.test.Sdk will contain:
• package1
• package2
• package3
• package4
• sdk-package1
• sdk-package2
• sdk-package3
• sdk-package4

In addition, package3, package4, sdk-package3, and sdk-package4 will be installed for all the architectures explicitly given to apertis-flatdeb.

The Platform will generally contain shared libraries that applications will need at runtime, but they can also include executables the application would depend on, or even resources for making the application more useful.

SDK-specific packages will likely include development libraries and headers, the build system and compilers, and optionally additional development tools.

#### Enabling Development Repositories

The suite files that the reference runtime uses only enable the target repository by default, not the development repository. This ensures that no GPLv3+ packages end up in the base platform, but it also means one cannot install development packages into the SDK. In order to resolve this, sdk:’s pre_apt_script as mentioned above can be used to enable the development repositories for the SDK only:

 1 2 3 4 5  sdk: pre_apt_script: | set -eux sed -i 's/$$^deb.*$$/\1 development/g' /etc/apt/sources.list apt-get -y -q update 

This will enable the development repositories, then update the package lists.

### Overlays

  1 2 3 4 5 6 7 8 9 10  overlays: - common-overlay platform: overlays: - platform-overlay sdk: overlays: - sdk-overlay 

overlays takes a list of paths and copies their contents onto the runtime’s rootfs towards the end of the build process (after post_script is run), providing a simple mechanism to add custom files to the final runtime. The paths are all resolved relative to the location of the runtime file, i.e. if the above were in runtimes/org.test.yaml, the first path used would be runtimes/common-overlay. Platform- and SDK-specific overlays can be added by placing the overlays key in the platform: and sdk: maps, respectively.

Given the following filesystem tree:

runtimes/
org.test.yaml
common-overlay/
etc/
test.conf
platform-overlay/
usr/
bin/
platform-util
sdk-overlay/
usr/
bin/
sdk-util


the above YAML would add the following files to the platform:

• /etc/test.conf
• /usr/bin/platform-util

and to the SDK:

• /etc/test.conf
• /usr/bin/sdk-util

### Extending Another Runtime

Sometimes, it may be desired for one runtime to extend another; for instance, the HMI reference runtime extends the headless runtime. In order to achieve this, there is one more key that can be used at the top level: extend:. As an example, consider a new runtime org.test.extended, based on org.test. Its YAML file would contain:

 1 2  id_prefix: org.test.extended extend: org.test.yaml 

This will merge in all of org.test.yaml’s definitions, according to the following rules:

• All packages from the base are available for use.
• Any pre_apt_scripts in the base will be run before the ones in the current runtime, and any post_scripts in the base will be run after.
• Any overlays in the base will be applied before the ones in the current runtime, so that the ones in the base can be overwritten.

 1 2 3 4  add-extensions: org.test.Extension: directory: share/runtime/extension no-autodownload: true 

apertis-flatdeb also has support for adding custom extensions to the runtime. The semantics of the keys in the extension definition are identical to the Flatpak metadata file, thus please consult the flatpak-metadata man page, under the section [Extension NAME].

### Suite Requirements

The suite files used by the reference runtime have persist_font_cache: set, which requires fontconfig to be installed in the platform and SDK runtimes. If this is not the case, remove persist_font_cache: from your suite file.

## Building the Runtime

Once the runtime recipe is complete, you can build the runtimes using the following commands:

$flatdeb --build-area=$(pwd)/flatdeb-builddir \
--ostree-repo=$(pwd)/flatdeb-builddir/ostree-repo \ --suite=<SUITE_NAME> --arch=<TARGET_ARCHITECTURE> \ runtimes runtimes/<RUNTIME_NAME>.yaml  This will build both the Platform and Sdk runtimes, which will be stored in an OSTree repository under flatdeb-builddir/ostree-repo. By default, both of these will have their branch set to SUITE_NAME. If another branch is desired, it can be set by passing --runtime-branch= If building for the host’s architecture, then --arch= can be omitted. ### Multiarch Builds If the runtime should include packages from multiple architectures (e.g. an arm64 runtime supporting running armhf binaries), then those packages should be listed in the add_packages_multiarch section. In order to specify which architectures should be used, you can pass multiple architectures to --arch. For instance, given the following example: $ flatdeb ... --arch=arm64,armhf runtimes runtimes/<RUNTIME_NAME>.yaml


arm64 will be used as the architecture, but any packages in add_packages_multiarch will also have armhf variants installed.

### Partial Builds

In order to speed up a more limited build, two sets of options are available:

• Only the platform or SDK can be built by passing --platform or --sdk, respectively.
• The building of the source code and debug info extensions can be skipped using --no-collect-source-code and --no-debug-symbols, respectively. These extensions are needed for debugging, but otherwise they can take a significant amount of extra time to build.

All of these options should be placed before the runtimes command.

### Overriding Packages

One can test local changes to packages that will be installed into the runtime by passing --override-package. The format for this is:

flatdeb [...] runtimes --override-package=PACKAGE=DEB


(Note that, unlike the above options, --override-package comes after the runtimes command.)

PACKAGE specifies the name of the package to replace, and DEB is the path to the local package to use. For instance, --override-package=meson=packages/meson.deb would result in any installations of meson in the runtime using the local packages/meson.deb instead of the version in the repos.

This option cannot be used to add new packages, nor can it be used to replace dependencies, i.e. passing --override-package with a package name not directly listed in add_packages: value will do nothing.

## Application

Applications are generated from a more classic flatpak-builder manifest, the only notable points here being that:

• runtime must mention your runtime as <id_prefix>.Platform
• The same goes for sdk which should contain <id_prefix>.Sdk
• runtime-version can be unset, as apertis-flatdeb will automatically set it to be the runtime’s version (e.g. v2022).

As described in Layout, the manifest should be located under a new subfolder named apps.

The application is built by executing the following command:

$flatdeb --build-area=$(pwd)/flatdeb-builddir \
--ostree-repo=$(pwd)/flatdeb-builddir/ostree-repo \ --suite=<SUITE_NAME> --arch=<TARGET_ARCHITECTURE> \ app --app-branch=<SUITE_NAME> apps/<APP_NAME>.yaml  Once the command completes, the application will be available from the same OSTree repository already containing the runtime, under flatdeb-builddir/ostree-repo. As with runtimes, if building for the host’s architecture, then --arch= can be omitted. # Verification Starting with Apertis v2022dev2, Flatpak includes the ability to distribute application bundles verified with ed25519 signatures. This signature system relies on OSTree’s library functions. Therefore, the key generation and storage process is identical to what is described in the System updates and rollback design document. Flatpak application signatures occur on several levels: • single commits • whole repositories • single-file bundles Please note, however, that GPG signatures, the upstream default, are disabled on Apertis. It is still possible to pull from GPG-signed repositories, but those signatures won’t be verified. Similarly, it is not possible to sign flatpak applications using GPG when using Apertis. ## Creating signed flatpak applications The simplest way to create a signed flatpak is to use flatpak-builder with the --sign=<SECRETKEY> command-line argument, where <SECRETKEY> is the base64-encoded secret Ed25519 key. This ensures the OSTree commit and summary are properly signed: flatpak-builder --repo=myrepo --sign=m8/rp9I9ax2w81yujZyeXTfZlbeBjEBUPQSQKo14iHgHdrzpKYH6xvL83midrFNeMrU4QBtk4jZ+x2veQoP4oQ== build-dir org.example.sampleapplication.yaml  For more advanced usage, the same command-line option can also be used with the following flatpak commands: • flatpak build-bundle • flatpak build-commit-from • flatpak build-export • flatpak build-import-bundle • flatpak build-sign • flatpak build-update-repo These commands allow one to create Ed25519-signed commits from an unsigned repository or bundle, or to create signed bundles as explained below. Multiple occurrences of the --sign option are allowed in to order to permit multiple signatures of each object. More details about those commands are available in the Flatpak documentation. ## Publishing signed Flatpaks ### Publishing a repository When distributing several applications and their runtimes, it can be useful to publish the whole repository. #### Hosting the repository Depending on whether apertis-flatdeb or flatpak-builder is used, the repository will be stored in the folder specified by either the --ostree-repo or --repo command-line argument, respectively. In its simplest form, hosting the repository can simply be placing its contents as-is on a remote server. However, uploading the data to the server is somewhat sensitive: during the upload process, some files in the OSTree repository may be present before the files they in turn depend on. Thus, the repository may turn out to be unusable until the upload completes. In order to remedy this, a tool named ostree-push can be used, which will upload the repository files in a well-defined order to the remote server over SSH. When using ostree-push, it’s recommended to pull down the contents of the remote repository before building the runtimes or apps in question via flatdeb or flatpak-builder: $ ostree init --repo=repo
$ostree remote --repo=repo --sign-verify=ed25519=inline:<PUBLICKEY> \ --if-not-exists origin https://example.org/flatpak/repo$ ostree pull --repo=repo --depth=-1 --mirror origin <REFS>...


where <PUBLICKEY> is the base64-encoded public Ed25519 key, and <REFS> contains the references that will later be uploaded. For instance, for the runtime org.test.Platform/x86_64/v2022 and app org.test.App/x86_64/v2022pre, the following pull command would be used:

$ostree pull --repo=repo --depth=-1 --mirror origin \ runtime/org.test.Platform/x86_64/v2022 \ app/org.test.Platform/x86_64/v2022  (Note the runtime/ and app/ prefix.) After the build process is completed, the newly built items can be uploaded via the following: $ ostree-push --repo repo ssh://<USER>@<HOST>:<PORT>/<PATH> <REFS>...


where:

• <HOST> is the SSH server to connect to
• <USER> is the user to sign in as on the server
• <PORT> is the port the SSH server is running on (:<PORT> may be omitted entirely if the default port of 22 is used)
• <REFS> is identical to as mentioned previously for ostree pull

Continuing the previous example, if we now wanted push the same refs to /var/public/repo on an SSH server ssh.test.com, port 2022, logging in as the user archive, the command used would be the following:

$ostree-push --repo repo ssh://archive@ssh.test.com:2022/var/public/repo \ runtime/org.test.Platform/x86_64/v2022 \ app/org.test.Platform/x86_64/v2022  After ostree-push is run, the summary file (essentially an index file for the repository) will need to be rebuilt. This can be accomplished by running the following on the server containing the repository: $ flatpak build-update-repo --sign=<SECRETKEY> <REPO>


where <SECRETKEY> is the base64-encoded secret Ed25519 key and <REPO> is the path to the repository. One can pass --generate-static-deltas in order to make pulling from the repository faster, at the expense of taking up more storage space on the host system.

#### Making the repository publicly accessible

In order for the repository to easily be added to client systems, a .flatpakrepo file can be used.

The only difference here compared to the linked documentation is that the GPGKey=... line must be replaced with SignatureKey=<PUBLICKEY>, where <PUBLICKEY> is the base64-encoded public Ed25519 key.

Such a .flatpakrepo file could be:

[Flatpak Repo]
Title=Sample Repository
Url=https://example.org/flatpak/repo
Homepage=https://example.org/flatpak
Comment=Sample Flatpak repository signed with Ed25519
Description=This Flatpak repository provides applications signed with Ed25519
Icon=https://example.org/flatpak/icon.svg
SignatureKey=B3a86SmB+sby/N5onaxTXjK1OEAbZOI2fsdr3kKD+KE=


#### Making a single application accessible

One way to make installing a single flatpak application from a repository convenient is to use .flatpakref files. Those files include all necessary information for flatpak to be able to install and update the application.

Exactly as it is done with with .flatpakrepo files, using SignatureKey=<PUBLICKEY> instead of GPGKey=... will instruct flatpak to enable Ed25519 signature verification for this repository.

This line will instruct flatpak to add the corresponding configuration keys to the remote and perform signature verification when installing and/or updating this application.

Such a .flatpakref file could be:

[Flatpak Ref]
Name=org.example.sampleapplication
Title=Sample application from our example repo
Url=https://example.org/flatpak/repo
RuntimeRepo=https://example.org/flatpak/example.flatpakrepo
IsRuntime=false
SignatureKey=B3a86SmB+sby/N5onaxTXjK1OEAbZOI2fsdr3kKD+KE=


### Publishing a bundle

Flatpak applications can also be distributed as single-file bundles, which can be created using the flatpak build-bundle command. As previously mentioned, these bundles can be signed by adding the --sign=<SECRETKEY> option to the command invocation:

flatpak build-bundle --sign=m8/rp9I9ax2w81yujZyeXTfZlbeBjEBUPQSQKo14iHgHdrzpKYH6xvL83midrFNeMrU4QBtk4jZ+x2veQoP4oQ== myrepo example.bundle org.example.sampleapplication


However, when publishing a signed flatpak bundle, the corresponding public key has to be stored in a location easily accessible to the final user for signature verification, as the bundle file itself is signed and doesn’t provide any mean to retrieve the associated public key.

## Installing a signed flatpak

### Configuring a remote repository

If the repository publisher provides a .flatpakrepo file including the public key, then no action is needed other than running flatpak remote-add <REPONAME> <REPOFILE>.

However, if such a file is not available, one must add the --sign-verify command-line option to the flatpak remote-add command in order to provide either the public key directly, or a file containing the public key:

• --sign-verify=ed25519=inline:<PUBLICKEY> is used to directly specify the public key needed to verify this repository
• --sign-verify=ed25519=file:<PATH> can be used to point flatpak to a file containing a list of public keys (base64-encoded, one key per line), among which at least one can be used to verify signatures for this repository
flatpak remote-add example example.flatpakrepo


or

flatpak remote-add --sign-verify=ed25519=inline:B3a86SmB+sby/N5onaxTXjK1OEAbZOI2fsdr3kKD+KE= example https://example.org/flatpak/repo


Multiple --sign-verify occurrences are allowed in order to specify as many public keys as needed. This can be useful when a new signature key is being deployed, while the old one is still in use: by specifying both the old and the new key, users can make sure at least one of those will be able to verify the signatures. That way, once the old key is revoked and only the new one is used for signing the repository, the corresponding remote will keep working as expected.

This option can also be added when using the flatpak remote-modify command.

### Installing a signed application

Similarly to the process of using .flatpakrepo files, when installing a single application using a .flatpakref file including the public key, no additional action is needed. Flatpak will automatically verify Ed25519 signatures using the provided public key:

flatpak install --from example.flatpakref


When the application is installed from a previously configured repository, signature verification is also automated, as long as the corresponding public key has been imported into the remote’s configuration:

flatpak install org.example.sampleapplication


If the public key has not been previously imported into the remote’s configuration, one can also use the --sign-verify command-line option:

flatpak install --sign-verify=ed25519=inline:B3a86SmB+sby/N5onaxTXjK1OEAbZOI2fsdr3kKD+KE= org.example.sampleapplication


### Installing a signed bundle

Flatpak bundles are not installed from a repository like most flatpak applications, but from a single, optionally signed, file. As there is no repository configuration to import public keys from, the user needs to specify the relevant public keys using the --sign-verify command-line option as stated above.

flatpak install --sign-verify=ed25519=inline:B3a86SmB+sby/N5onaxTXjK1OEAbZOI2fsdr3kKD+KE= --bundle example.bundle


This option works the same way with both flatpak build-import-bundle and flatpak install commands.

# References

Flatpak reference documentation: https://docs.flatpak.org/