<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://planet.gnome.org/</id>
  <title>Planet GNOME</title>
  <updated>2026-06-06T11:32:44+00:00</updated>
  <link href="https://planet.gnome.org/" rel="alternate"/>
  <link href="https://planet.gnome.org/atom.xml" rel="self"/>
  <generator uri="https://lkiesow.github.io/python-feedgen" version="1.0.0">python-feedgen</generator>
  <subtitle>Planet GNOME - https://planet.gnome.org/</subtitle>
  <entry>
    <id>https://blogs.gnome.org/jrb/2026/04/24/goblint-notes/</id>
    <title>Jonathan Blandford: Goblint Notes</title>
    <updated>2026-04-24T07:57:16+00:00</updated>
    <author>
      <name>Jonathan Blandford</name>
    </author>
    <content type="html">&lt;p&gt;I was excited to see Bilal’s &lt;a class="external" href="https://belmoussaoui.com/blog/23-goblin-linter/"&gt;announcement&lt;/a&gt; of goblint, and I’ve spent the past week getting Crosswords to work with it. This is a tool I’ve always wanted and I’m pretty convinced it will be a great boon for the GNOME ecosystem. I’m posting my notes in hope that more people try it out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First and most importantly, Bilal has been so great to work with. I have filed ~20 issues and feature requests and he fixed them all very quickly. In some cases, he fixed the underlying issue before I completed adding annotations to the code.&lt;/li&gt;
&lt;li&gt;Most of the issues flagged were idiomatic and stylistic, but it did find real bugs. It found a half-dozen leaks, a missing g_timeout removal, and five missing class function chain ups. One was a long-standing crasher. There’s a definite improvement in quality from adopting this tool.&lt;/li&gt;
&lt;li&gt;I’m also excited about pairing this with new GSoC interns. The types of things goblint flags are the things that students hit in particular (when they don’t write it all their code with AI). I think goblint will be even more important to our ecosystem as a teaching tool to our C codebase. It’s already effectively replaced my styleguide.&lt;/li&gt;
&lt;li&gt;In a few instances, the &lt;code&gt;use_g_autoptr&lt;/code&gt; rule outstripped static-scan’s ability to track leaks. Ultimately, I ended up annotating and removing the &lt;code&gt;g_autoptr()&lt;/code&gt; calls as I couldn’t get the two to play nicely together.&lt;/li&gt;
&lt;li&gt;Along the same lines, cairo, pango, and librsvg all lack &lt;code&gt;G_DEFINE_AUTOPTR_CLEANUP_FUNC&lt;/code&gt;. It would be really great if we could fix these core libraries. In the meantime, you can add the following to your project’s goblint.toml file:&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;"&gt;
&lt;pre style="margin: 0; line-height: 125%;"&gt;&lt;span style="color: #080; font-weight: bold;"&gt;[rules.use_g_autoptr_inline_cleanup]&lt;/span&gt;
level &lt;span style="color: #333;"&gt;=&lt;/span&gt; &lt;span style="background-color: #fff0f0;"&gt;"error"&lt;/span&gt;
ignore_types &lt;span style="color: #333;"&gt;=&lt;/span&gt; [&lt;span style="background-color: #fff0f0;"&gt;"cairo_*"&lt;/span&gt;, &lt;span style="background-color: #fff0f0;"&gt;"Pango*"&lt;/span&gt;, &lt;span style="background-color: #fff0f0;"&gt;"RsvgHandle"&lt;/span&gt;]
&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;I had some trouble getting the pipeline integrated with GNOME’s gitlab. The gitlab recipe on his page uses premium features unavailable in the self hosted version. If it’s helpful for others, here’s what I ended up using:&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;"&gt;
&lt;pre style="margin: 0; line-height: 125%;"&gt;&lt;span style="color: #070;"&gt;goblint&lt;/span&gt;:
  &lt;span style="color: #070;"&gt;stage&lt;/span&gt;: analysis
  &lt;span style="color: #070;"&gt;extends&lt;/span&gt;:
    - &lt;span style="background-color: #fff0f0;"&gt;"opensuse-container@x86_64.stable"&lt;/span&gt;
    - &lt;span style="background-color: #fff0f0;"&gt;".fdo.distribution-image@opensuse"&lt;/span&gt;
  &lt;span style="color: #070;"&gt;needs&lt;/span&gt;:
    - &lt;span style="color: #070;"&gt;job&lt;/span&gt;: opensuse-container@x86_64.stable
      &lt;span style="color: #070;"&gt;artifacts&lt;/span&gt;: false
  &lt;span style="color: #070;"&gt;before_script&lt;/span&gt;:
    - source ci/env.sh
    - cargo install --git https://github.com/bilelmoussaoui/goblint goblint
  &lt;span style="color: #070;"&gt;script&lt;/span&gt;:
    &lt;span style="color: #888;"&gt;# Goblint is fast. We run it twice: Once to generate the report,&lt;/span&gt;
    &lt;span style="color: #888;"&gt;# and a second time to display the output and triger an error&lt;/span&gt;
    - /root/.cargo/bin/goblint . --format sarif &amp;gt; goblint.sarif || true
    - /root/.cargo/bin/goblint . --format text
  &lt;span style="color: #070;"&gt;artifacts&lt;/span&gt;:
    &lt;span style="color: #070;"&gt;reports&lt;/span&gt;:
      &lt;span style="color: #070;"&gt;sast&lt;/span&gt;: goblint.sarif
    &lt;span style="color: #070;"&gt;when&lt;/span&gt;: always&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;YMMV&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/jrb/2026/04/24/goblint-notes/"/>
    <published>2026-04-24T07:57:16+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/alatiera/2026/04/27/goblins-in-your-toolchain/</id>
    <title>Jordan Petridis: Goblins in your toolchain</title>
    <updated>2026-04-27T10:05:43+00:00</updated>
    <author>
      <name>Jordan Petridis</name>
    </author>
    <content type="html">&lt;p&gt;At the start of the month, Bilal gave us all a giant gift with &lt;a class="external" href="https://belmoussaoui.com/blog/23-goblin-linter/"&gt;Goblint&lt;/a&gt;. On the first week it was already impressive. Now it’s an invaluable tool for anyone that ever interfaced with GObject, glib or GTK. It will catch leaks, bugs, or even offer to auto fix and modernize your code to the modern paradigms we use. It’s one of those things that is going to save countless hours of debugging and more importantly, prevent the issues before they even get committed. Jonathan Blandford wrote about using it two days ago, and I suggest you read the &lt;a href="https://blogs.gnome.org/jrb/2026/04/24/goblint-notes"&gt;post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Everyone is trying to use goblint, and we are all &lt;a class="external" href="https://gitlab.gnome.org/GNOME/epiphany/-/merge_requests/2079#note_2733667"&gt;stumbling&lt;/a&gt; upon the same issues integrating it into our tooling. Initially, it was only able to produce Sarif reports, which GitLab still has behind a &lt;a class="external" href="https://docs.gitlab.com/18.11/ci/yaml/artifacts_reports/#artifactsreportssarif"&gt;feature flag&lt;/a&gt;, in addition to only  be available in GitLab Enterprise Editions.&lt;/p&gt;
&lt;p&gt;I added an &lt;a class="external" href="https://github.com/bilelmoussaoui/goblint/pull/61"&gt;export&lt;/a&gt; for GitLab’s &lt;a class="external" href="https://docs.gitlab.com/ci/testing/code_quality/"&gt;Code Quality&lt;/a&gt; format which has &lt;em&gt;some&lt;/em&gt; support in the non-proprietary Community Edition we use in the GNOME and Freedesktop.org instances. Sadly, almost &lt;a class="external" href="https://docs.gitlab.com/ci/testing/code_quality/#view-code-quality-results"&gt;everything nice&lt;/a&gt; is still only available in the enterprise editions, but at least there is this little Widget in the Merge Requests page.&lt;/p&gt;
&lt;p&gt;&lt;img alt="A screenshot of the linked Merge Request showcasing the Code Quality GitLab widget." class="aligncenter wp-image-5304 size-full" height="1476" src="https://blogs.gnome.org/alatiera/files/2026/04/Screenshot-2026-04-27-at-09-48-57-Modernize-the-coebase-a-bit-324-·-Merge-requests-·-GNOME-_-gnome-initial-setup-·-GitLab.png" width="1814"/&gt;&lt;/p&gt;
&lt;p&gt;Additionally, we now have CI &lt;a class="external" href="https://gitlab.gnome.org/GNOME/citemplates/-/merge_requests/171"&gt;templates&lt;/a&gt; for Goblint. One is adding a job to the existing &lt;a class="external" href="https://gitlab.gnome.org/GNOME/citemplates#gnomeos-basic-ci"&gt;&lt;code&gt;gnomeos-basic-ci&lt;/code&gt;&lt;/a&gt; component we use everywhere. Simply go to your latest pipeline and look for &lt;a class="external" href="https://gitlab.gnome.org/GNOME/gdm/-/jobs/6470591"&gt;the job&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="external" href="https://gitlab.gnome.org/GNOME/gdm/-/jobs/6470591"&gt;&lt;img alt="A screenshot of the linked job and its output log" class="aligncenter size-full wp-image-5320" height="1630" src="https://blogs.gnome.org/alatiera/files/2026/04/Screenshot-2026-04-28-at-14-20-41-build-gnomeos-goblint-6470591-·-Jobs-·-GNOME-_-gdm-·-GitLab.png" width="2544"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The report will also show up in Merge Requests that have been updated since yesterday.  The gnomeos-basic-ci has other goodies like sanitizers, static analyzers, test coverage, etc wired out of the box, so you should give it a try if you are not using it yet.&lt;/p&gt;
&lt;p&gt;If you do but don’t want the goblint job, you can disable it easily with &lt;code&gt;inputs: goblint: "disabled"&lt;/code&gt; similar to all the other tools the component provides.&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;
&lt;pre class="sourceCode yaml"&gt;&lt;code class="sourceCode yaml"&gt;&lt;span id="cb1-1"&gt;&lt;span class="fu"&gt;include&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;  &lt;span class="kw"&gt;-&lt;/span&gt; &lt;span class="fu"&gt;project&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt; &lt;span class="st"&gt;"GNOME/citemplates"&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;    &lt;span class="fu"&gt;file&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt; &lt;span class="st"&gt;"templates/default-rules.yml"&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;  &lt;span class="kw"&gt;-&lt;/span&gt; &lt;span class="fu"&gt;component&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt; &lt;span class="st"&gt;"gitlab.gnome.org/GNOME/citemplates/gnomeos-basic-ci@26.1"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If you want only a goblint job, I’ve also added a standalone template that you can use. (Or &lt;a class="external" href="https://gitlab.gnome.org/GNOME/citemplates/-/blob/master/templates/goblint.yml"&gt;copy-paste&lt;/a&gt; from it).&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;
&lt;pre class="sourceCode yaml"&gt;&lt;code class="sourceCode yaml"&gt;&lt;span id="cb1-1"&gt;&lt;span class="fu"&gt;include&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;  &lt;span class="kw"&gt;-&lt;/span&gt; &lt;span class="fu"&gt;component&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt; &lt;span class="st"&gt;"gitlab.gnome.org/GNOME/citemplates/goblint@26.1"&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;    &lt;span class="fu"&gt;inputs&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;      &lt;span class="fu"&gt;job-stage&lt;/span&gt;&lt;span class="kw"&gt;:&lt;/span&gt; &lt;span class="st"&gt;"lint"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In order for the Code Quality report to work, you will need to have a report uploaded from your target branch, so GitLab will have something to compare the one from the merge request with. The template rules will handle that for you, but keep it in mind.&lt;/p&gt;
&lt;p&gt;At this moment all the lints are warnings so the job will never be fatal. This is why we can enabled it by default without worrying about breaking pipelines for now. You can further configure its behavior to your needs, and error out if you want to, through the &lt;a class="external" href="https://github.com/bilelmoussaoui/goblint/blob/main/CONFIG.md"&gt;&lt;code&gt;configuration&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;
&lt;div class="sourceCode" id="cb1"&gt;
&lt;pre class="sourceCode toml"&gt;&lt;code class="sourceCode toml"&gt;&lt;span id="cb1-1"&gt;&lt;span class="dt"&gt;min_glib_version&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;"2.76"&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-2"&gt;&lt;/span&gt;
&lt;span id="cb1-3"&gt;&lt;span class="kw"&gt;[rules.g_declare_semicolon]&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-4"&gt;&lt;span class="dt"&gt;level&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;"ignore"&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-5"&gt;&lt;/span&gt;
&lt;span id="cb1-6"&gt;&lt;span class="kw"&gt;[rules.untranslated_string]&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-7"&gt;&lt;span class="dt"&gt;level&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="st"&gt;"error"&lt;/span&gt;&lt;/span&gt;
&lt;span id="cb1-8"&gt;&lt;span class="dt"&gt;ignore&lt;/span&gt; &lt;span class="op"&gt;=&lt;/span&gt; &lt;span class="op"&gt;[&lt;/span&gt;&lt;span class="st"&gt;"**/test-*.c"&lt;/span&gt;&lt;span class="op"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It’s also very likely that we are going to &lt;a class="external" href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/merge_requests/4659"&gt;add&lt;/a&gt; goblint and its LSP server to the GNOME SDK Flatpak runtime, along with GNOME OS, so it will always be available for use with tools like Builder and foundry.&lt;/p&gt;
&lt;p&gt;Enjoy&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/alatiera/2026/04/27/goblins-in-your-toolchain/"/>
    <published>2026-04-27T10:05:43+00:00</published>
  </entry>
  <entry>
    <id>https://ergaster.org/til/yubikey-unlock-laptop/</id>
    <title>Thibault Martin: TIL that Yubikeys are convenient for Linux login</title>
    <updated>2026-04-28T10:00:00+00:00</updated>
    <author>
      <name>Thibault Martin</name>
    </author>
    <content type="html">&lt;p&gt;I got myself a Yubikey recently, and I wanted to use it as a nice convenience to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Grant me sudo privileges&lt;/li&gt;
&lt;li&gt;Unlock my session&lt;/li&gt;
&lt;li&gt;Decrypt my LUKS-encrypted disk&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I've only managed to do the first two, since they both rely on Linux Pluggable Authentication Modules (PAM). Luckily for me, one of PAM's modules supports U2F, the standard Yubikeys rely on.&lt;/p&gt;
&lt;p&gt;First I need to install &lt;code&gt;pam-u2f&lt;/code&gt; to add U2F support to PAM, and &lt;code&gt;pamu2fcfg&lt;/code&gt; to configure my key.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo rpm-ostree install pam-u2f pamu2fcfg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since I'm running an immutable OS I need to reboot, and then I can create the correct directory and file to dump an U2F key into it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mkdir -p ~/.config/Yubico
$ pamu2fcfg &amp;gt; ~/.config/Yubico/u2f_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I make sure to have a root session open in case I lock myself out of sudoers.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo su
#
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a different terminal, I can edit the sudoers file to add this line&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#%PAM-1.0
auth       sufficient   pam_u2f.so cue openasuser
auth       include      system-auth
account    include      system-auth
password   include      system-auth
session    optional     pam_keyinit.so revoke
session    required     pam_limits.so
session    include      system-auth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I save this file and open a new terminal. I type in &lt;code&gt;sudo vi&lt;/code&gt; and it asks me to touch my FIDO authenticator before opening vi! If I touch the Yubikey, it indeed opens vi with root privileges.&lt;/p&gt;
&lt;p&gt;Let's break down the line:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auth&lt;/code&gt; for authentication&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sufficient&lt;/code&gt; passing this authentication challenge is enough (it's not an additional factor of authentication)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pam_u2f.so&lt;/code&gt; the module we load is for U2F, the standard Yubikeys use&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cue&lt;/code&gt; print "Please touch the FIDO authenticator." when the user needs to authenticate&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openasuser&lt;/code&gt; to fetch the authentication file without root privileges&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's also possible to use it to unlock my session, but it would be a bit reckless to allow anyone with my Yubikey to log into my laptop. If my backpack gets stolen and it has both my Yubikey and my laptop, anyone can log in.&lt;/p&gt;
&lt;p&gt;It's possible to make the login screen require either my user password, or all of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Yubikey itself&lt;/li&gt;
&lt;li&gt;The PIN of the Yubikey&lt;/li&gt;
&lt;li&gt;Me to touch the Yubikey&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If someone fails more than three times to enter the correct PIN, the Yubikey will lock itself and require a PUK to be unlocked. This gives me an additional layer of security, and it's more convenient than having to type a full length passphrase.&lt;/p&gt;
&lt;p&gt;I've added the following line to &lt;code&gt;/etc/pam.d/greetd&lt;/code&gt; (the greeter I use):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#%PAM-1.0
auth       sufficient  pam_u2f.so cue openasuser pinverification=1 userpresence=1
auth       substack    system-auth
[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!warning] I can lose my Yubikey&lt;/p&gt;
&lt;p&gt;I use my Yubikey as a nice convenience to set up a weaker PIN while not compromising too much on security. I use it &lt;em&gt;instead&lt;/em&gt; of a password, no in addition to it.&lt;/p&gt;
&lt;p&gt;Since I can lose or break my Yubikey and I don't want to buy two of them, I make the U2F login &lt;code&gt;sufficient&lt;/code&gt; but not &lt;code&gt;required&lt;/code&gt;. This means I can still fallback to password authentication if I lose my Yubikey.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, DankMaterialShell uses its own lockscreen manager too. I still want to be able to fallback to password authentication if need be, so I'll configure it to accept U2F OR the password, not both.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This means that the lockscreen will call &lt;code&gt;/etc/pam.d/dankshell-u2f&lt;/code&gt; to know what to do when the screen is locked. Since this file doesn't exist, I can create it with the following content.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#%PAM-1.0
auth sufficient pam_u2f.so cue openasuser pinverification=1 userpresence=1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I need a fallback for when I don't have my Yubikey, so I also create the one for this occasion&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#%PAM-1.0
auth include system-auth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I have a consistent setup where both my login and lock screen require me to plug my key, enter its PIN and touch it, or enter my full password. When it comes to sudo, I can only touch my key without requiring an PIN.&lt;/p&gt;
&lt;p&gt;My next quest will be to use my Yubikey to unlock my LUKS-encrypted disk.&lt;/p&gt;</content>
    <link href="https://ergaster.org/til/yubikey-unlock-laptop/"/>
    <published>2026-04-28T10:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/jrb/2026/04/29/remembering-seth/</id>
    <title>Jonathan Blandford: Remembering Seth</title>
    <updated>2026-04-29T05:07:58+00:00</updated>
    <author>
      <name>Jonathan Blandford</name>
    </author>
    <content type="html">&lt;p&gt;I heard the &lt;a class="external" href="https://lwn.net/Articles/1070213/"&gt;news about Seth Nickell’s passing&lt;/a&gt; last week, and have been in a bit of a funk ever since.&lt;/p&gt;
&lt;p&gt;Seth was brilliant, iconoclastic, fearless.&lt;/p&gt;
&lt;p&gt;It’s been a long while since Seth was an active part of the GNOME Community, but his influence on the project can still be seen in its DNA if you know where to look. He arrived on the GNOME scene while still in school with hundreds of ideas on how to improve things. It was an interesting time: We had just launched GNOME 1.5 and were searching for a new path towards GNOME 2.0. The Sun usability study had been published and the community had internalized the need to change directions. Seth rolled up his sleeves and did the work needed to help light that path.&lt;/p&gt;
&lt;p&gt;Seth championed radical proposals such as instant apply, &lt;a class="external" href="https://mail.gnome.org/archives/gtk-devel-list/2001-November/msg00153.html"&gt;button ordering&lt;/a&gt;, &lt;a class="external" href="https://mail.gnome.org/archives/gtk-devel-list/2001-November/msg00666.html"&gt;message dialog fixes&lt;/a&gt;, and more. He cleaned up the control-center proposing some of the most visible changes from GNOME 1 to 2. He also did the initial designs for epiphany, pushing for a cleaner browser experience during an era of high browser complexity. He had a vision of desktops as a democratic tool, as easy and natural to use as any other tool in the human experience.&lt;/p&gt;
&lt;p&gt;As a designer, Seth was focused on trying to understand who we were designing for and making sure we were solving problems for them. While he wasn’t beyond fixing paddings / layouts, he wanted to get the &lt;strong&gt;Big Picture&lt;/strong&gt; right. He wasn’t beyond rolling up his sleeves writing code to move things forward, but was at his best as a champion and visionary, arguing for us to take &lt;a class="external" href="https://thegnomejournal.wordpress.com/2005/01/10/experimental-culture/"&gt;risks and continue to innovate&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Spending time was Seth was a hoot. He had such a flair for the dramatic. I remember…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;…the time he sold the design for what would become NetworkManager to a bunch of engineers. He got up on the stage and announced: &lt;em&gt;“We are going to make this &lt;/em&gt;[holding an ethernet cable]&lt;em&gt; as easy to use as this &lt;/em&gt;[producing a power plug]&lt;em&gt;!”&lt;/em&gt; It’s hard to describe how many steps it took to set up networking back then.&lt;/li&gt;
&lt;li&gt;…his vision of an improved messaging system — Project Yarrr. He used &lt;img alt="☠" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/2620.png" style="height: 1em;"/&gt; (U+2620) as the SVN repo name partially to see how many internal tools weren’t UTF-8 clean.&lt;/li&gt;
&lt;li&gt;…him breaking out into an operatic rendition of “&lt;a class="external" href="https://en.wikipedia.org/wiki/Tradition_(song)"&gt;Tradition&lt;/a&gt;” when  developers were pushing back on a change he was proposing.&lt;/li&gt;
&lt;li&gt;…the time he changed everyone’s background in the RH office to have crop circles over night. He showed up the next morning in a robe dressed as an old-testament prophet, beating a drum and carrying a “RHEL5 IS NIGH” sign.&lt;/li&gt;
&lt;li&gt;…hanging  printouts of hate mail he got for various design choices outside of the Mega Cube (a group activity)!&lt;/li&gt;
&lt;li&gt;And &lt;em&gt;everyone&lt;/em&gt; who was around for the &lt;strong&gt;Dark Princess Incident&lt;/strong&gt; will always remember it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Being one of the public faces of GNOME2 was hard, and he moved on. Later, he worked on OLPC and Sugar, and made his mark there. After that, he seemed to travel a lot. We lost touch, though he’d reappear every couple of years to say hi. I hope he found what he was looking for.&lt;/p&gt;
&lt;p&gt;Farewell, my friend. The world now has less color in it.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://felipeborges.pages.gitlab.gnome.org/heads-of-gnome/heads/seth.png"/&gt;&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/jrb/2026/04/29/remembering-seth/"/>
    <published>2026-04-29T05:07:58+00:00</published>
  </entry>
  <entry>
    <id>https://www.vixalien.com/blog/mise/</id>
    <title>vixalien: A love letter to mise</title>
    <updated>2026-04-30T00:00:00+00:00</updated>
    <author>
      <name>vixalien</name>
    </author>
    <content type="html">&lt;p&gt;Recently, I have been using &lt;a href="https://os.gnome.org/"&gt;GNOME OS&lt;/a&gt;, as my daily driver.&lt;/p&gt;
&lt;p&gt;After being a seasoned Linux for long, dabbling in distros like &lt;a href="https://alpinelinux.org"&gt;Alpine Linux&lt;/a&gt;, &lt;a href="https://archlinux.org"&gt;Arch Linux&lt;/a&gt;, Fedora (and even Silverblue), I tried switching to something more &lt;em&gt;opinionated&lt;/em&gt; and that "works by default" all while being hard to break.&lt;/p&gt;
&lt;p&gt;And given my existing &lt;a href="https://teams.pages.gitlab.gnome.org/Websites/people.gnome.org/#jimmac:~:text=Angelo%20Verlain%20Shema"&gt;relationship with GNOME&lt;/a&gt;, GNOME OS was a choice worth looking into.&lt;/p&gt;
&lt;p&gt;One feature of GNOME OS is that it is immutable (i.e. system files are read-only). It also doesn't ship with a package manager, so it doesn't have functionality built-in to install extra packages.&lt;/p&gt;
&lt;p&gt;You can install GUI Applications normally using &lt;a href="https://flathub.org/en"&gt;Flathub&lt;/a&gt; (and Snap/AppImage), but installing non-GUI applications like development tools or CLI packages is not built-in.&lt;/p&gt;
&lt;p&gt;There are of course several solutions you can use, such as &lt;a href="https://brew.sh/"&gt;homebrew&lt;/a&gt;, &lt;a href="https://gitlab.postmarketos.org/postmarketOS/coldbrew"&gt;coldbrew&lt;/a&gt;, but today we will focus on &lt;a href="https://mise.jdx.dev/"&gt;mise&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What is mise?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://mise.jdx.dev/"&gt;mise&lt;/a&gt; pitches itself as "One tool to manage languages, env vars, and tasks per project, reproducibly."&lt;/p&gt;
&lt;p&gt;However, I only use a fraction of it's functionality, in that I only use it to install packages.&lt;/p&gt;
&lt;h2&gt;How to install it?&lt;/h2&gt;
&lt;p&gt;The instructions are here: https://mise.jdx.dev/getting-started.html&lt;/p&gt;
&lt;p&gt;But essentially it's as easy as running this (remember to read the source of the installer first):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl https://mise.run | sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Activating mise&lt;/h2&gt;
&lt;p&gt;Then you will need to "activate" mise, which essentially makes tools installed by mise available by modifying your &lt;code&gt;$PATH&lt;/code&gt; variable&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo 'eval "$(~/.local/bin/mise activate bash --shims)"' &amp;gt;&amp;gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The instructions above are for bash, so you will need to consult the docs to get instructions for your shell.&lt;/p&gt;
&lt;p&gt;You will need to re-login for the &lt;code&gt;mise&lt;/code&gt; command to be available, or open a new shell.&lt;/p&gt;
&lt;h3&gt;A note on shims&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Feel free to skip this section, as it's just an explainer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also, note that the above command use the &lt;code&gt;--shims&lt;/code&gt; flag, which is NOT the default. It essentially means that mise will modify the &lt;code&gt;$PATH&lt;/code&gt; variable, instead of doing a weird thing where it will re-activate itself after each command you run.&lt;/p&gt;
&lt;p&gt;The non-shim way to activate mise is useful when you use mise to install different package versions across different repositories, but that sometimes breaks IDEs and is our of the scope of this blog post.&lt;/p&gt;
&lt;h2&gt;Installing packages&lt;/h2&gt;
&lt;p&gt;You can start installing your first package with &lt;code&gt;mise&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g java
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command installs &lt;code&gt;java&lt;/code&gt; globally (hence the &lt;code&gt;-g&lt;/code&gt; flag), which you can now confirm by running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ java --version
openjdk 26.0.1 2026-04-21
OpenJDK Runtime Environment (build 26.0.1+8-34)
OpenJDK 64-Bit Server VM (build 26.0.1+8-34, mixed mode, sharing)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can install much more tools, of which you can find a non-complete list here: &lt;a href="https://mise-tools.jdx.dev/"&gt;mise-tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, you can similarly install a specific major version of nodejs&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g node@22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or install the latest LTS version of node&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g node@lts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or you can be overlay specific&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g node@v25.9.0
mise use -g node@25.9.0 # this works too!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Searching&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;mise search&lt;/code&gt; to find packages.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise search typ
Tool       Description                                                                                                                            
typos      Source code spell checker. https://github.com/crate-ci/typos
typst      A new markup-based typesetting system that is powerful and easy to learn. https://github.com/typst/typst
typstyle   Beautiful and reliable typst code formatter. https://github.com/Enter-tainer/typstyle
quicktype  Generate types and converters from JSON, Schema, and GraphQL provided by https://quicktype.io. https://www.npmjs.com/package/quicktype
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Uninstalling&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;mise unuse -g node
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Updating&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;mise self-update # updating mise itself
mise up          # updating tools installed by mise
mise outdated    # checking if you have outdated tools
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Config File&lt;/h2&gt;
&lt;p&gt;Tools you install with mise globally will be saved in the file &lt;code&gt;~/.config/mise/config.toml&lt;/code&gt;, which you can commit to your dotfiles so you can have similar tools across different machines.&lt;/p&gt;
&lt;p&gt;Here's an example of my mise config file at the time of writing this blog post.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ~/.config/mise/config.toml
[tools]
bat = "latest"
btop = "latest"
bun = "latest"
caddy = "latest"
"cargo:mergiraf" = "latest"
deno = "latest"
difftastic = "latest"
doggo = "latest"
fastfetch = "latest"
fzf = "latest"
github-cli = "latest"
"github:railwayapp/railpack" = "latest"
glab = "latest"
helix = "latest"
java = "latest"
lazygit = "latest"
node = "latest"
"npm:vscode-langservers-extracted" = "latest"
oha = "latest"
pipx = "latest"
pnpm = "latest"
prettier = "latest"
rust = "latest"
scooter = "latest"
tmux = "latest"
usage = "latest"
yt-dlp = { version = "latest", rename_exe = "yt-dlp" }
zellij = "latest"
"github:patryk-ku/music-discord-rpc" = { version = "latest", asset_pattern = "music-discord-rpc" }
rclone = "latest"
mc = "latest"
go = "latest"
"go:git.sr.ht/~migadu/alps/cmd/alps" = "latest"
"npm:localtunnel" = "latest"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the tools inside the config has changed, you can run the following comand to make mise re-install packages from the config file&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise install
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Mise Backends&lt;/h2&gt;
&lt;p&gt;Mise is able to install packages from multiple sources. These sources are called "backends" by mise.&lt;/p&gt;
&lt;p&gt;When you type &lt;code&gt;mise use -g node@22&lt;/code&gt;, it will resolve &lt;code&gt;node&lt;/code&gt; against the registry and figure out that the default backend for &lt;code&gt;node&lt;/code&gt; is &lt;code&gt;core&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Core&lt;/h3&gt;
&lt;p&gt;The default backend is called &lt;code&gt;core&lt;/code&gt; and tools from this backend are usually provided from the official source.&lt;/p&gt;
&lt;p&gt;Other tools that are available from &lt;code&gt;core&lt;/code&gt; include Node.js, Ruby, Python, etc...&lt;/p&gt;
&lt;p&gt;We could also have been explicit with the backend we want to use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g core:node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find &lt;a href="https://mise.jdx.dev/core-tools.html"&gt;a list of all core packages here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Aqua&lt;/h3&gt;
&lt;p&gt;You can also install packages from the &lt;a href="https://aquaproj.github.io/"&gt;Aqua&lt;/a&gt; registry.&lt;/p&gt;
&lt;h3&gt;Language Package Managers&lt;/h3&gt;
&lt;p&gt;You can also install tools from their respective package managers. Here are a few examples&lt;/p&gt;
&lt;h4&gt;&lt;code&gt;npm&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;You can install prettier, typescript, oxlint and other JavaScript/TypeScript tools published on the npm registry. Find the tools on &lt;a href="https://www.npmjs.com/search?q=keywords:cli"&gt;npm&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g npm:prettier
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;pipx&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;You can install black, poetry and other Python tools from pypi. Find the tools on &lt;a href="https://pypi.org/"&gt;pypi&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g pipx:black
pipx:git+https://github.com/psf/black.git # from a github repo
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&lt;code&gt;cargo&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;You can install cargo packages with this backed. You need to have rust installed beforehand though, which you can do with mise&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g rust
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then install your packages&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g cargo:eza
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are more &lt;a href="https://mise.jdx.dev/dev-tools/backends/"&gt;language package manager backends&lt;/a&gt; like: &lt;code&gt;gem&lt;/code&gt;, &lt;code&gt;go&lt;/code&gt; and more.&lt;/p&gt;
&lt;h3&gt;Github&lt;/h3&gt;
&lt;p&gt;You can install packages from Github directly, as long as the project you are trying to install from uses Github releases&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mise use -g github:railwayapp/railpack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;mise will usually auto-detect which asset you want to use, but you can also specify the asset glob in &lt;code&gt;~/.config/mise/config.toml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[tools]
"github:patryk-ku/music-discord-rpc" = { version = "latest", asset_pattern = "music-discord-rpc" }
&lt;/code&gt;&lt;/pre&gt;</content>
    <link href="https://www.vixalien.com/blog/mise/"/>
    <published>2026-04-30T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/sophieh/2026/04/30/testing-library-code-in-gnome-os/</id>
    <title>Sophie Herold: Testing Library Code in GNOME OS</title>
    <updated>2026-04-30T12:58:20+00:00</updated>
    <author>
      <name>Sophie Herold</name>
    </author>
    <content type="html">&lt;p&gt;Yesterday, I wanted to debug a glycin (or Shell) issue on GNOME OS. Turns out, there is currently no documentation that works or includes all necessary steps.&lt;/p&gt;
&lt;p&gt;Here is the simplest variant if you don’t develop on GNOME OS and have an internet connection that can download 16 GB in a reasonable amount of time.&lt;/p&gt;
&lt;p&gt;First we get a toolbox image to build our code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ toolbox create gnomeos-nightly -i quay.io/gnome_infrastructure/gnome-build-meta:gnomeos-devel-nightly&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After entering the toolbox with&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ toolbox enter gnomeos-nightly&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we can clone and build our project with &lt;a class="external" href="https://gitlab.gnome.org/tchx84/sysext-utils#building-extensions"&gt;sysext-utils&lt;/a&gt; that are included in our image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ meson setup ./build --prefix /usr --libdir="lib/$(gcc -print-multiarch)"
$ sysext-build example ./build&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a &lt;code&gt;example.sysext.raw&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Now, we need a GNOME OS to test our build. We can &lt;a class="external" href="https://os.gnome.org/"&gt;download the image&lt;/a&gt; and install it in Boxes. After logging in, we can just drag and drop the &lt;code&gt;example.sysext.raw&lt;/code&gt; into the VM.&lt;/p&gt;
&lt;p&gt;Before we can install it, we need to get the development tools for our VM:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ run0 updatectl enable devel --now&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we need to restart the VM.&lt;/p&gt;
&lt;p&gt;Finally, we can test our build:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ run0 sysext-add ~/Downloads/example.sysext.raw&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding the &lt;code&gt;--persistent&lt;/code&gt; flag to this command will make the changes stay active across reboots.&lt;/p&gt;
&lt;p&gt;If the changes made it impossible to boot into the VM again, we can start the VM in “Safe mode” from the boot menu. After logging in, we can manually remove the extension:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ run0 rm /var/lib/extensions/example.raw&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy hacking!&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/sophieh/2026/04/30/testing-library-code-in-gnome-os/"/>
    <published>2026-04-30T12:58:20+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/feborges/gsoc-2026-contributors-announcement/</id>
    <title>Felipe Borges: Let’s Welcome Our Google Summer of Code 2026 Contributors!</title>
    <updated>2026-04-30T21:05:07+00:00</updated>
    <author>
      <name>Felipe Borges</name>
    </author>
    <content type="html">&lt;p&gt;GNOME is once again participating in &lt;a class="external" href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;. This year, we have 6 contributors working on adding Debug Adapter Protocol support to GJS, incorporating vocab-style puzzles into GNOME Crosswords, creating a native GTK4/Rust rewrite of the Pitivi timeline ruler, porting gitg to GTK4, implementing app uninstallation in the GNOME Shell app grid, and enabling recovery from GPU resets.&lt;/p&gt;
&lt;p&gt;As we onboard the contributors, we will be adding them to &lt;a class="external" href="https://planet.gnome.org/"&gt;Planet GNOME&lt;/a&gt;, where you can get to know them better and follow their project updates.&lt;/p&gt;
&lt;p&gt;GSoC is a great opportunity to welcome new people into our project. Please help them get started and make them feel at home in our community!&lt;/p&gt;
&lt;p&gt;Special thanks to our community mentors, who are donating their time and energy to help welcome and guide our new contributors: Philip Chimento, Jonathan Blandford, Yatin, Alex Băluț, Alberto Fanjul,  Adrian Vovk, Jonas Ådahl, and Robert Mader.&lt;/p&gt;
&lt;p&gt;For more information, visit &lt;a class="external" href="https://summerofcode.withgoogle.com/programs/2026/organizations/gnome-foundation"&gt;https://summerofcode.withgoogle.com/programs/2026/organizations/gnome-foundation&lt;/a&gt;&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/feborges/gsoc-2026-contributors-announcement/"/>
    <published>2026-04-30T21:05:07+00:00</published>
  </entry>
  <entry>
    <id>https://www.dragonsreach.it/2026/05/01/selinux-mcs-challenges-gitlab-runners/</id>
    <title>Andrea Veri: SELinux MCS challenges with GitLab Runners</title>
    <updated>2026-05-02T01:00:00+00:00</updated>
    <author>
      <name>Andrea Veri</name>
    </author>
    <content type="html">&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#the-mcs-problem"&gt;The MCS problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#the-test-script"&gt;The test script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#gitlabs-official-suggestion-and-why-it-falls-short"&gt;GitLab’s official suggestion and why it falls short&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#how-gnome-currently-handles-this"&gt;How GNOME currently handles this&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#exploring-libkrun"&gt;Exploring libkrun&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#firecracker-and-the-custom-executor-path"&gt;Firecracker and the custom executor path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.dragonsreach.it/categories/planet-gnome/index.xml#what-comes-next"&gt;What comes next&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;GNOME’s GitLab runners use Podman as the container runtime with SELinux in Enforcing mode on Fedora. The GitLab Runner Docker/Podman executor spawns multiple containers per job: a &lt;strong&gt;helper&lt;/strong&gt; container that clones the repository and handles artifacts, and a &lt;strong&gt;build&lt;/strong&gt; container that runs the actual CI script. Both containers need to share a &lt;code&gt;/builds&lt;/code&gt; volume — and this is where SELinux’s &lt;strong&gt;Multi-Category Security (MCS)&lt;/strong&gt; becomes a problem.&lt;/p&gt;
&lt;h2 id="the-mcs-problem"&gt;The MCS problem&lt;/h2&gt;
&lt;p&gt;An SELinux label has four fields: &lt;code&gt;user:role:type:level&lt;/code&gt;. For containers the interesting part is the &lt;strong&gt;level&lt;/strong&gt;, also called the MCS field. A level looks like &lt;code&gt;s0:c123,c456&lt;/code&gt; — &lt;code&gt;s0&lt;/code&gt; is the sensitivity (always &lt;code&gt;s0&lt;/code&gt; in targeted policy), and &lt;code&gt;c123,c456&lt;/code&gt; are the &lt;strong&gt;categories&lt;/strong&gt;. A process or file can carry up to two categories.&lt;/p&gt;
&lt;p&gt;MCS access is based on &lt;strong&gt;dominance&lt;/strong&gt;. A subject’s label dominates an object’s label if the subject’s categories are a superset of (or equal to) the object’s categories:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subject&lt;/th&gt;
&lt;th&gt;Object&lt;/th&gt;
&lt;th&gt;Access?&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Exact match&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s0:c100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Subject’s categories are a superset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c300&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Subject lacks &lt;code&gt;c300&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s0:c0.c1023&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Full range dominates everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s0:c100,c200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No categories can’t dominate any&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;s0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Both have no categories&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;How this applies to the runners:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Container A runs as &lt;code&gt;container_t:s0:c100,c100&lt;/code&gt; — it can only access objects labeled &lt;code&gt;s0:c100,c100&lt;/code&gt; (or &lt;code&gt;s0:c100&lt;/code&gt;, or &lt;code&gt;s0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Container B runs as &lt;code&gt;container_t:s0:c200,c200&lt;/code&gt; — it can only access objects labeled &lt;code&gt;s0:c200,c200&lt;/code&gt; (or &lt;code&gt;s0:c200&lt;/code&gt;, or &lt;code&gt;s0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Container A cannot access Container B’s files — &lt;code&gt;c100,c100&lt;/code&gt; doesn’t dominate &lt;code&gt;c200,c200&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Overlay layers labeled &lt;code&gt;s0&lt;/code&gt; (no categories) — accessible by all containers since every category set dominates the empty set&lt;/li&gt;
&lt;li&gt;Podman at &lt;code&gt;container_runtime_t:s0-s0:c0.c1023&lt;/code&gt; — the full range means it dominates every possible category combination, so it can manage all containers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;range syntax&lt;/strong&gt; (&lt;code&gt;s0-s0:c0.c1023&lt;/code&gt;) is used for processes that need to operate across multiple levels. It means “my low clearance is &lt;code&gt;s0&lt;/code&gt; and my high clearance is &lt;code&gt;s0:c0.c1023&lt;/code&gt;.” The process can read objects at any level within that range and create objects at any level within it. This is why Podman needs the full range — it creates containers with different MCS labels and needs to access all of them.&lt;/p&gt;
&lt;p&gt;When Podman starts a container, it picks a random pair of categories (e.g., &lt;code&gt;s0:c512,c768&lt;/code&gt;) from within its allowed range and assigns that as the container’s process label. Files created by the container inherit that label. Another container gets a different random pair (e.g., &lt;code&gt;s0:c33,c901&lt;/code&gt;). Since &lt;code&gt;c512,c768&lt;/code&gt; and &lt;code&gt;c33,c901&lt;/code&gt; do not match — neither is a superset of the other — SELinux denies cross-container file access. This is the isolation mechanism, and the root cause of the problem with GitLab Runner’s multi-container-per-job architecture.&lt;/p&gt;
&lt;p&gt;The helper container gets one random MCS pair, writes the cloned repo to &lt;code&gt;/builds&lt;/code&gt; labeled with that pair, and the build container gets a different pair. The build container cannot read or write those files. The &lt;code&gt;:Z&lt;/code&gt; volume flag (exclusive relabel) relabels the volume to the mounting container’s category, but that only helps the first container — the second one still has a different label.&lt;/p&gt;
&lt;h2 id="the-test-script"&gt;The test script&lt;/h2&gt;
&lt;p&gt;I wrote a script that demonstrates the problem with both standard containers (crun) and microVMs (libkrun). The script creates two containers per test — a helper that writes a file to a shared &lt;code&gt;/builds&lt;/code&gt; volume, and a build container that tries to read it — simulating the GitLab Runner workflow:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Description: SELinux MCS Diagnostic (crun vs krun)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;getenforce&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; !&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Enforcing"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARNING: SELinux is not in Enforcing mode. This test requires Enforcing mode."&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;TEST_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/tmp/gitlab-runner-mcs-test"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;CRUN_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;/crun-builds"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KRUN_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;/krun-builds"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Cleanup from previous runs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"======================================================="&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" TEST 1: Standard Container Isolation (crun)"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"======================================================="&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. CREATE Helper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman create --name crun-helper -v &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;:/builds:Z"&lt;/span&gt; fedora bash -c &lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; echo '[crun] -&amp;gt; Helper Process Context (Inside):'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; cat /proc/self/attr/current
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; echo 'crun-data' &amp;gt; /builds/artifact.txt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; echo '[crun] -&amp;gt; File Label INSIDE Helper:'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ls -Z /builds/artifact.txt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[crun] Starting Helper Container (applying :Z relabel)..."&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HELPER_HOST_LABEL_CRUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;podman inspect -f &lt;span class="s1"&gt;'{{.ProcessLabel}}'&lt;/span&gt; crun-helper&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[crun] -&amp;gt; HOST METADATA: Podman assigned process label: &lt;/span&gt;&lt;span class="nv"&gt;$HELPER_HOST_LABEL_CRUN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman start -a crun-helper
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[crun] -&amp;gt; File Label ON HOST (Notice the specific MCS category):"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -Z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;/artifact.txt"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. CREATE Build Container (The Victim)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman create --name crun-build -v &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;:/builds"&lt;/span&gt; fedora bash -c &lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; echo ' [Build-Internal] Process Context:'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; cat /proc/self/attr/current 2&amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; echo ' [Build-Internal] Executing ls -laZ /builds :'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ls -laZ /builds 2&amp;gt;&amp;amp;1 | sed 's/^/ /'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; echo ' [Build-Internal] Executing cat /builds/artifact.txt :'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; cat /builds/artifact.txt 2&amp;gt;&amp;amp;1 | sed 's/^/ /'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[crun] Starting Build Container to inspect shared volume..."&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BUILD_HOST_LABEL_CRUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;podman inspect -f &lt;span class="s1"&gt;'{{.ProcessLabel}}'&lt;/span&gt; crun-build&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[crun] -&amp;gt; HOST METADATA: Podman assigned process label: &lt;/span&gt;&lt;span class="nv"&gt;$BUILD_HOST_LABEL_CRUN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman start -a crun-build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman rm -f crun-helper crun-build &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"======================================================="&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" TEST 2: MicroVM Isolation (libkrun / virtio-fs) FIXED"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"======================================================="&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --- Write the execution scripts to the host to avoid parsing errors ---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; 'EOF' &amp;gt; "$TEST_BASE/krun_helper.sh"
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo '[krun] -&amp;gt; Helper Process Context (Inside VM):'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;cat /proc/self/attr/current 2&amp;gt;/dev/null || echo ' (SELinux disabled/unavailable in guest kernel)'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo 'krun-data' &amp;gt; /builds/artifact.txt
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo '[krun] -&amp;gt; File Label INSIDE Helper VM (Blindspot):'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;ls -laZ /builds/artifact.txt 2&amp;gt;&amp;amp;1 | sed 's/^/ /'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; 'EOF' &amp;gt; "$TEST_BASE/krun_build.sh"
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo ' [Build-Internal] Process Context (Inside VM):'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;cat /proc/self/attr/current 2&amp;gt;/dev/null || echo ' (SELinux disabled/unavailable in guest kernel)'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo ' [Build-Internal] Executing ls -laZ /builds :'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;ls -laZ /builds 2&amp;gt;&amp;amp;1 | sed 's/^/ /'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo ' [Build-Internal] Executing cat /builds/artifact.txt :'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;cat /builds/artifact.txt 2&amp;gt;&amp;amp;1 | sed 's/^/ /'
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;/krun_helper.sh"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;/krun_build.sh"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ---------------------------------------------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. CREATE Helper MicroVM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman create --name krun-helper --runtime krun --memory&lt;span class="o"&gt;=&lt;/span&gt;1024m &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; -v &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;:/builds:Z"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; -v &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;/krun_helper.sh:/script.sh:ro,Z"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; fedora /script.sh &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[krun] Starting Helper MicroVM (applying :Z relabel)..."&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HELPER_HOST_LABEL_KRUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;podman inspect -f &lt;span class="s1"&gt;'{{.ProcessLabel}}'&lt;/span&gt; krun-helper&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[krun] -&amp;gt; HOST METADATA: Podman assigned process label: &lt;/span&gt;&lt;span class="nv"&gt;$HELPER_HOST_LABEL_KRUN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman start -a krun-helper
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[krun] -&amp;gt; File Label ON HOST (Podman applied the helper's MCS category via :Z):"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -Z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;/artifact.txt"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. CREATE Build MicroVM (The Victim)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman create --name krun-build --runtime krun --memory&lt;span class="o"&gt;=&lt;/span&gt;1024m &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; -v &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KRUN_DIR&lt;/span&gt;&lt;span class="s2"&gt;:/builds"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; -v &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_BASE&lt;/span&gt;&lt;span class="s2"&gt;/krun_build.sh:/script.sh:ro,Z"&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="se"&gt;&lt;/span&gt; fedora /script.sh &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[krun] Starting Build MicroVM to inspect shared volume..."&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;BUILD_HOST_LABEL_KRUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;podman inspect -f &lt;span class="s1"&gt;'{{.ProcessLabel}}'&lt;/span&gt; krun-build&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[krun] -&amp;gt; HOST METADATA: Podman assigned process label: &lt;/span&gt;&lt;span class="nv"&gt;$BUILD_HOST_LABEL_KRUN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" *** THE virtiofsd DAEMON ON THE HOST IS TRAPPED IN THIS CONTEXT ***"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman start -a krun-build
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Cleanup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;podman rm -f krun-helper krun-build &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"======================================================="&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Test Complete."&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Test 1 (crun)&lt;/strong&gt; creates a helper container that mounts the builds directory with &lt;code&gt;:Z&lt;/code&gt; (exclusive relabel) and writes &lt;code&gt;artifact.txt&lt;/code&gt;. Podman assigns it a random MCS label — in this run it was &lt;code&gt;s0:c20,c540&lt;/code&gt;. The file on disk inherits that label. Then a second container (the build container) mounts the same path without &lt;code&gt;:Z&lt;/code&gt; and gets a different random label (&lt;code&gt;s0:c46,c331&lt;/code&gt;). Since &lt;code&gt;c46,c331&lt;/code&gt; does not dominate &lt;code&gt;c20,c540&lt;/code&gt;, the build container is denied access to the file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test 2 (krun)&lt;/strong&gt; runs the same scenario but with &lt;code&gt;--runtime krun&lt;/code&gt;, which boots each container inside a lightweight microVM via &lt;a href="https://github.com/containers/libkrun"&gt;libkrun&lt;/a&gt;. The helper VM gets &lt;code&gt;container_kvm_t:s0:c823,c999&lt;/code&gt; and the build VM gets &lt;code&gt;container_kvm_t:s0:c309,c405&lt;/code&gt; — same MCS mismatch, same denial. The type changes from &lt;code&gt;container_t&lt;/code&gt; to &lt;code&gt;container_kvm_t&lt;/code&gt;, but the MCS mechanism is identical. On the host side, &lt;code&gt;virtiofsd&lt;/code&gt; — the daemon that serves the volume into the VM via virtio-fs — runs under the MCS label Podman assigned to the VM. The build VM’s &lt;code&gt;virtiofsd&lt;/code&gt; is trapped in &lt;code&gt;s0:c309,c405&lt;/code&gt; and cannot access files labeled &lt;code&gt;s0:c823,c999&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An interesting detail: inside the libkrun VMs, &lt;code&gt;cat /proc/self/attr/current&lt;/code&gt; returns just &lt;code&gt;kernel&lt;/code&gt; — SELinux is not available in the guest. The VM thinks it has no mandatory access control, but the host-side &lt;code&gt;virtiofsd&lt;/code&gt; is still fully subject to MCS enforcement. This is a blindspot worth being aware of.&lt;/p&gt;
&lt;p&gt;The output from a run on Fedora with SELinux Enforcing and Podman 5.8.2:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;=======================================================
TEST 1: Standard Container Isolation (crun)
=======================================================
[crun] Starting Helper Container (applying :Z relabel)...
[crun] -&amp;gt; HOST METADATA: Podman assigned process label: system_u:system_r:container_t:s0:c20,c540
[crun] -&amp;gt; Helper Process Context (Inside):
system_u:system_r:container_t:s0:c20,c540 [crun] -&amp;gt; File Label INSIDE Helper:
system_u:object_r:container_file_t:s0:c20,c540 /builds/artifact.txt
[crun] -&amp;gt; File Label ON HOST (Notice the specific MCS category):
system_u:object_r:container_file_t:s0:c20,c540 /tmp/gitlab-runner-mcs-test/crun-builds/artifact.txt
[crun] Starting Build Container to inspect shared volume...
[crun] -&amp;gt; HOST METADATA: Podman assigned process label: system_u:system_r:container_t:s0:c46,c331
*** COMPARE THE cXXX,cYYY ABOVE TO THE FILE LABEL. THIS MISMATCH CAUSES THE DENIAL ***
[Build-Internal] Process Context:
system_u:system_r:container_t:s0:c46,c331 [Build-Internal] Executing ls -laZ /builds :
ls: cannot open directory '/builds': Permission denied
[Build-Internal] Executing cat /builds/artifact.txt :
cat: /builds/artifact.txt: Permission denied
=======================================================
TEST 2: MicroVM Isolation (libkrun / virtio-fs) FIXED
=======================================================
[krun] Starting Helper MicroVM (applying :Z relabel)...
[krun] -&amp;gt; HOST METADATA: Podman assigned process label: system_u:system_r:container_kvm_t:s0:c823,c999
[krun] -&amp;gt; Helper Process Context (Inside VM):
kernel [krun] -&amp;gt; File Label INSIDE Helper VM (Blindspot):
-rw-r--r--. 1 root root system_u:object_r:container_file_t:s0:c823,c999 10 May 2 2026 /builds/artifact.txt
[krun] -&amp;gt; File Label ON HOST (Podman applied the helper's MCS category via :Z):
system_u:object_r:container_file_t:s0:c823,c999 /tmp/gitlab-runner-mcs-test/krun-builds/artifact.txt
[krun] Starting Build MicroVM to inspect shared volume...
[krun] -&amp;gt; HOST METADATA: Podman assigned process label: system_u:system_r:container_kvm_t:s0:c309,c405
*** THE virtiofsd DAEMON ON THE HOST IS TRAPPED IN THIS CONTEXT ***
[Build-Internal] Process Context (Inside VM):
kernel [Build-Internal] Executing ls -laZ /builds :
ls: /builds: Permission denied
ls: cannot open directory '/builds': Permission denied
[Build-Internal] Executing cat /builds/artifact.txt :
cat: /builds/artifact.txt: Permission denied
=======================================================
Test Complete.
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="gitlabs-official-suggestion-and-why-it-falls-short"&gt;GitLab’s official suggestion and why it falls short&lt;/h2&gt;
&lt;p&gt;GitLab’s documentation on &lt;a href="https://docs.gitlab.com/runner/executors/docker/#configure-selinux-mcs"&gt;configuring SELinux MCS&lt;/a&gt; suggests applying the same MCS label to all containers launched by a runner:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;runners&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;runners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;security_opt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"label=level:s0:c1000,c1000"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works — all containers get the same category pair, so the helper and build containers can share files. But it collapses MCS isolation between all concurrent jobs on that runner. With &lt;code&gt;concurrent = 4&lt;/code&gt;, four simultaneous jobs all run as &lt;code&gt;s0:c1000,c1000&lt;/code&gt; and can read each other’s &lt;code&gt;/builds&lt;/code&gt; content — cloned source code, build artifacts, cached dependencies. On a shared or multi-tenant runner, this is a security regression: it trades MCS isolation for functionality.&lt;/p&gt;
&lt;p&gt;For runners with &lt;code&gt;concurrent = 1&lt;/code&gt; or dedicated single-tenant runners this is an acceptable tradeoff, but it does not generalize to shared infrastructure where multiple untrusted projects run side by side.&lt;/p&gt;
&lt;h2 id="how-gnome-currently-handles-this"&gt;How GNOME currently handles this&lt;/h2&gt;
&lt;p&gt;GNOME’s runners are managed via an &lt;a href="https://gitlab.gnome.org/GNOME/ansible/-/tree/master/roles/gitlab-runner"&gt;Ansible role&lt;/a&gt; that enforces SELinux in Enforcing mode, installs rootless Podman running as a dedicated &lt;code&gt;podman&lt;/code&gt; system user with linger enabled, and deploys custom SELinux policy modules. The Podman service runs under &lt;code&gt;SELinuxContext=system_u:system_r:container_runtime_t:s0-s0:c0.c1023&lt;/code&gt; via a systemd override — the full MCS range (&lt;code&gt;s0-s0:c0.c1023&lt;/code&gt;) gives the container runtime the ability to spawn containers at any MCS level and relabel volumes accordingly, as explained in the dominance rules above.&lt;/p&gt;
&lt;p&gt;Four custom SELinux &lt;code&gt;.te&lt;/code&gt; modules are compiled and loaded on every runner host: &lt;code&gt;pydocuum&lt;/code&gt; (allows the image cleanup daemon to talk to the Podman socket), &lt;code&gt;podman&lt;/code&gt; (grants &lt;code&gt;user_namespace create&lt;/code&gt; and &lt;code&gt;/dev/null&lt;/code&gt; mapping), &lt;code&gt;flatpak&lt;/code&gt; (permits the filesystem mounts flatpak builds need), and &lt;code&gt;gnome_runner&lt;/code&gt; (covers &lt;code&gt;binfmt_misc&lt;/code&gt; access, device nodes, and other permissions GNOME OS builds require).&lt;/p&gt;
&lt;p&gt;For the MCS problem specifically, the runner &lt;code&gt;config.toml&lt;/code&gt; — rendered from a Jinja2 template via per-host Ansible variables — sets a fixed MCS label per runner type. Here’s a representative snippet from one of the runner hosts:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-toml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;runners&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a15948139c78"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;executor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"docker"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;runners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"quay.io/fedora/fedora:latest"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;privileged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;security_opt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"label=level:s0:c100,c100"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;devices&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/dev/kvm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"/dev/udmabuf"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cap_add&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SYS_PTRACE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"SYS_CHROOT"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nx"&gt;runners&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a15948139c78-flatpak"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;executor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"docker"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;runners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;privileged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;security_opt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"seccomp:/home/podman/gitlab-runner/flatpak.seccomp.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"label=level:s0:c200,c200"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cap_drop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the same approach GitLab’s documentation suggests, with one refinement: we use &lt;strong&gt;different fixed categories per runner type&lt;/strong&gt; — &lt;code&gt;c100,c100&lt;/code&gt; for untagged runners and &lt;code&gt;c200,c200&lt;/code&gt; for flatpak runners — so that flatpak builds and regular builds remain MCS-isolated from each other, even though builds of the same type share a category.&lt;/p&gt;
&lt;p&gt;This is a pragmatic compromise, not an ideal solution. All concurrent jobs on the same runner type share the same MCS category. With &lt;code&gt;concurrent: 4&lt;/code&gt; on our Hetzner runners, four simultaneous untagged jobs can read each other’s &lt;code&gt;/builds&lt;/code&gt; content. For GNOME’s use case — a community CI infrastructure where the runners are shared by GNOME project maintainers — this is an acceptable tradeoff. The alternative, leaving MCS labels random, would break every single job. But it is precisely this tradeoff that motivates exploring per-job VM isolation via microVMs.&lt;/p&gt;
&lt;h2 id="exploring-libkrun"&gt;Exploring libkrun&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/containers/libkrun"&gt;libkrun&lt;/a&gt; is a lightweight Virtual Machine Monitor (VMM) that integrates with Podman via &lt;code&gt;--runtime krun&lt;/code&gt;, running each container inside a microVM with its own lightweight kernel. The appeal is strong: per-container VM isolation would give each job its own kernel and address space, making the MCS cross-container problem irrelevant inside the VM.&lt;/p&gt;
&lt;p&gt;I tested libkrun on a Fedora system and hit an immediate blocker: &lt;code&gt;Fatal glibc error: rseq registration failed&lt;/code&gt;. The &lt;strong&gt;rseq&lt;/strong&gt; (Restartable Sequences) syscall was introduced in Linux kernel 5.3 and is required by glibc &amp;gt;= 2.35. libkrun uses a custom minimal kernel that does not expose &lt;code&gt;rseq&lt;/code&gt; support. Since the guest images — Fedora in our case — ship modern glibc that expects &lt;code&gt;rseq&lt;/code&gt; to be available, the process aborts at startup before any user code runs.&lt;/p&gt;
&lt;p&gt;The libkrun kernel is compiled into the library itself and cannot be modified or replaced by the user. This is not a configuration issue but a fundamental limitation of the current libkrun release.&lt;/p&gt;
&lt;p&gt;Even if the &lt;code&gt;rseq&lt;/code&gt; issue were resolved, the MCS challenge would still be there — as the test script demonstrates in Test 2. On the host side, Podman assigns MCS labels to the &lt;code&gt;virtiofsd&lt;/code&gt; process that serves the volume into the VM via virtio-fs. Different VMs get different host-side MCS labels, meaning the same &lt;code&gt;:Z&lt;/code&gt; relabel / cross-container access denial applies. The mechanism changes from overlay mounts to virtio-fs, but the SELinux enforcement is identical: &lt;code&gt;virtiofsd&lt;/code&gt; for the build VM runs at &lt;code&gt;container_kvm_t:s0:c309,c405&lt;/code&gt; and cannot access files labeled &lt;code&gt;s0:c823,c999&lt;/code&gt; by the helper VM’s &lt;code&gt;virtiofsd&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="firecracker-and-the-custom-executor-path"&gt;Firecracker and the custom executor path&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://firecracker-microvm.github.io/"&gt;Firecracker&lt;/a&gt; is another microVM technology, the one behind AWS Lambda and Fly.io, that could provide strong per-job isolation. However, there is no native GitLab Runner executor for Firecracker. The only integration path is the &lt;a href="https://docs.gitlab.com/runner/executors/custom.html"&gt;Custom Executor&lt;/a&gt;, which requires implementing &lt;code&gt;prepare&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, and &lt;code&gt;cleanup&lt;/code&gt; scripts from scratch.&lt;/p&gt;
&lt;p&gt;The job image is exposed via &lt;code&gt;CUSTOM_ENV_CI_JOB_IMAGE&lt;/code&gt;, but everything else is on the operator: pulling the OCI image, extracting a rootfs, booting a Firecracker VM with the right kernel and network configuration, injecting the build script, mounting or copying the cloned repository into the VM, collecting artifacts and cache after the job finishes, and tearing the VM down. GitLab provides an &lt;a href="https://docs.gitlab.com/runner/executors/custom_examples/lxd/"&gt;LXD-based example&lt;/a&gt; that shows the pattern — &lt;code&gt;prepare&lt;/code&gt; creates a container and installs dependencies, &lt;code&gt;run&lt;/code&gt; pipes the job script into it, &lt;code&gt;cleanup&lt;/code&gt; destroys it — but adapting that to microVMs adds the complexity of VM lifecycle management, kernel and rootfs preparation, networking, and storage. This is a significant engineering effort, essentially rebuilding the entire Docker executor workflow from scratch.&lt;/p&gt;
&lt;h2 id="what-comes-next"&gt;What comes next&lt;/h2&gt;
&lt;p&gt;MCS is a core SELinux feature. Type enforcement (TE) already confines processes by type — &lt;code&gt;container_t&lt;/code&gt; can only access &lt;code&gt;container_file_t&lt;/code&gt;, not &lt;code&gt;user_home_t&lt;/code&gt; or &lt;code&gt;httpd_sys_content_t&lt;/code&gt; — but TE alone cannot distinguish one &lt;code&gt;container_t&lt;/code&gt; process from another. MCS adds that layer: by assigning each container a unique category pair, the kernel enforces isolation &lt;em&gt;between&lt;/em&gt; processes that share the same type. Container A at &lt;code&gt;s0:c100,c100&lt;/code&gt; and Container B at &lt;code&gt;s0:c200,c200&lt;/code&gt; are both &lt;code&gt;container_t&lt;/code&gt;, but MCS ensures they cannot touch each other’s files. The conflict with GitLab Runner’s multi-container-per-job architecture is that two containers that &lt;em&gt;need&lt;/em&gt; to share a volume are given different categories by default. The workarounds we deploy today, including the fixed MCS labels on GNOME’s runners, trade that inter-container isolation for functionality.&lt;/p&gt;
&lt;p&gt;The most promising direction I’ve found so far is the combination of &lt;a href="https://www.cloudhypervisor.org/"&gt;Cloud Hypervisor&lt;/a&gt; and the &lt;a href="https://github.com/helmholtzcloud/fleeting-plugin-fleetingd"&gt;fleeting-plugin-fleetingd&lt;/a&gt; plugin. Cloud Hypervisor is built on Intel’s Rust-VMM crate and is essentially a more capable sibling of Firecracker — it supports CPU and memory hotplugging, VFIO device passthrough, and virtio-fs, features that are often necessary for complex CI tasks like building large binaries or running UI tests and that Firecracker’s minimalist design deliberately omits. The fleeting-plugin-fleetingd is a community plugin for GitLab’s &lt;strong&gt;Instance Executor&lt;/strong&gt; (the modern evolution of the Custom Executor) that automates the full VM lifecycle: downloading cloud images, creating Copy-on-Write disks, launching Cloud Hypervisor VMs with direct kernel boot, provisioning them via cloud-init, and tearing them down after each build. Each job gets a fresh disposable VM, which is exactly the per-job isolation model we need. The plugin already handles networking via TAP interfaces and nftables SNAT, and supports customization of the VM image through cloud-init commands — so preinstalling Podman or other build tools is straightforward.&lt;/p&gt;
&lt;p&gt;Beyond that, I’ll also keep evaluating libkrun (promising Red Hat technology), Firecracker with a hand-rolled custom executor, and QEMU’s microvm machine type. The common denominator across all of these — except for the fleeting-plugin-fleetingd path — is that none of them have an existing GitLab Runner integration. Regardless of which microVM technology we settle on, the path forward involves either building a workflow from scratch using the &lt;a href="https://docs.gitlab.com/runner/executors/custom.html"&gt;Custom Executor&lt;/a&gt; and its &lt;code&gt;prepare&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;cleanup&lt;/code&gt; hooks, or leveraging the fleeting plugin ecosystem that GitLab has been building around the Instance and Docker Autoscaler executors.&lt;/p&gt;
&lt;h3 id="cve-2026-31431"&gt;CVE-2026-31431&lt;/h3&gt;
&lt;p&gt;The urgency of per-job VM isolation was underscored by &lt;a href="https://www.helpnetsecurity.com/2026/04/30/copyfail-linux-lpe-vulnerability-cve-2026-31431/"&gt;CVE-2026-31431&lt;/a&gt; (“Copy Fail”), a nine-year-old logic bug in the kernel’s &lt;code&gt;algif_aead&lt;/code&gt; cryptographic module disclosed at the end of April. The flaw lets an unprivileged local user write four controlled bytes into the page cache of any readable file — enough to patch a setuid binary like &lt;code&gt;/usr/bin/su&lt;/code&gt; and escalate to root. Unlike Dirty Cow or Dirty Pipe, Copy Fail requires no race condition: the exploit is deterministic, leaves no trace on disk, and — critically — can break out of container isolation. In a shared-runner CI environment, any project that can execute arbitrary code in a job already has exactly the access the exploit needs. Separately, &lt;a href="https://www.computing.co.uk/analysis/2026/claude-mythos-how-ai-broke-out-of-its-sandbox"&gt;Claude Mythos&lt;/a&gt; — an Anthropic model trained for cybersecurity research that escaped its own sandbox during a red-team exercise in April — demonstrated that AI-assisted vulnerability discovery and exploitation is no longer theoretical; models can now autonomously find and chain bugs that would take human researchers weeks to exploit. The combination of a reliable, public kernel LPE and AI-augmented offensive tooling makes the case for ephemeral microVMs compelling: when every CI job boots a fresh, disposable VM with its own kernel, a vulnerability like Copy Fail becomes a local-root inside a throwaway guest that is destroyed seconds later, not a stepping stone to the host or adjacent jobs.&lt;/p&gt;
&lt;p&gt;That should be all for today, stay tuned!&lt;/p&gt;</content>
    <link href="https://www.dragonsreach.it/2026/05/01/selinux-mcs-challenges-gitlab-runners/"/>
    <published>2026-05-02T01:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/steven/2026/05/06/apologies/</id>
    <title>Steven Deobald: Apologies</title>
    <updated>2026-05-06T03:37:00+00:00</updated>
    <author>
      <name>Steven Deobald</name>
    </author>
    <content type="html">&lt;p&gt;I believe accountability can be a challenge in a nonprofit, which only makes it all the more important. In this post, I am holding myself accountable. For the avoidance of doubt, nothing that follows has anything to do with my exit from the GNOME Foundation last August.&lt;/p&gt;
&lt;p&gt;I owe a few folks some apologies from my time as Executive Director. I have apologized to most of them individually already, where I could. But I believe that public accountability is the antidote to public frustration and I hope this contributes, in a small way, to the GNOME community moving forward.&lt;/p&gt;
&lt;p&gt;First off, I sincerely apologize to Jehan Pagès and Christian Hergert. I was curt with both of you last summer and neither of you deserved it. From July 23rd to August 29th I was dealing with significant sleep deprivation but that’s no excuse for the way I spoke to either of you. I’m sorry.&lt;/p&gt;
&lt;p&gt;Next, I apologize to the former Executive Directors and active community members who raised concerns to me. Holly, you warned me. Twice. Many other people tried to share their perspectives. I was too focused on the Foundation’s financial situation, and I did not take the time to fully understand what I was hearing from you all. I regret that.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Sonny&lt;/h2&gt;
&lt;p&gt;To Sonny Piers: I am sorry. I had a long call with you last June. You told me your complicated story. You seemed hurt — but I didn’t believe you. My understanding was incomplete and I did not approach the situation with the care it deserved.&lt;/p&gt;
&lt;p&gt;I’m sorry I didn’t do more to support you.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Tobias&lt;/h2&gt;
&lt;p&gt;More than anyone, I want to apologize to Tobias Bernard. Tobias, I am sorry. You gave me many hours of your time, patience, and thoughtfulness. You shared your ideas openly and in good faith, and I didn’t always meet that with the same level of openness.&lt;/p&gt;
&lt;p&gt;In particular, when we discussed Sonny’s situation, I did not listen as carefully as I should have. I was too focused on my existing understanding, and I failed to engage with what you were trying to convey. You deserved better from me.&lt;/p&gt;
&lt;p&gt;Sonny is lucky to have a friend like you.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Meta&lt;/h2&gt;
&lt;p&gt;This post reflects only my personal experiences and perspectives. It is not intended to make allegations or factual claims about the conduct of any individual or organization.&lt;/p&gt;
&lt;p&gt;Until Microsoft goes out of business, a permanent copy of this apology can be found &lt;a class="external" href="https://gist.github.com/deobald/6eeb2de20e2566b93bb5f8ddf5735c38"&gt;in this gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/steven/2026/05/06/apologies/"/>
    <published>2026-05-06T03:37:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/hughsie/2026/05/06/lvfs-sponsorship-announcement/</id>
    <title>Richard Hughes: LVFS Sponsorship Announcement</title>
    <updated>2026-05-06T12:13:21+00:00</updated>
    <author>
      <name>Richard Hughes</name>
    </author>
    <content type="html">&lt;p&gt;&lt;strong&gt;Some great news&lt;/strong&gt;: I’m pleased to announce that both &lt;a class="external" href="https://www.dell.com/"&gt;Dell&lt;/a&gt; and &lt;a class="external" href="https://www.lenovo.com/"&gt;Lenovo&lt;/a&gt; have agreed to be premier sponsors for the &lt;a class="external" href="https://fwupd.org/"&gt;Linux Vendor Firmware Service (LVFS)&lt;/a&gt; as part of our new &lt;a class="external" href="https://docs.google.com/presentation/d/1l_Rmkn2-UwOkS0XK5d6u9pi29TZpmG-upa4Lu5HuEy4/edit?usp=sharing"&gt;sustainability effort&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.gnome.org/hughsie/files/2026/05/Screenshot-2026-05-06-at-14-10-52-LVFS-Home.png"&gt;&lt;img alt="" class="aligncenter size-large wp-image-10034" height="282" src="https://blogs.gnome.org/hughsie/files/2026/05/Screenshot-2026-05-06-at-14-10-52-LVFS-Home-1024x438.png" width="660"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Over 145 million firmware updates have been deployed now, from over a hundred different vendors to millions of different Linux devices.&lt;br/&gt;
With the huge industry support from Lenovo and Dell (and our existing sponsors of &lt;a class="external" href="https://frame.work/"&gt;Framework&lt;/a&gt;, &lt;a class="external" href="https://opensourcefirmware.foundation/"&gt;OSFF&lt;/a&gt;, and of course both the &lt;a class="external" href="https://www.linuxfoundation.org/"&gt;Linux Foundation&lt;/a&gt; and &lt;a class="external" href="https://www.redhat.com/en"&gt;Red Hat&lt;/a&gt;) &lt;strong&gt;we can build this ecosystem stronger and higher than before; we can continue the great work we’ve done long into the future&lt;/strong&gt;.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/hughsie/2026/05/06/lvfs-sponsorship-announcement/"/>
    <published>2026-05-06T12:13:21+00:00</published>
  </entry>
  <entry>
    <id>https://blog.jimmac.eu/posts/fms-carrier/</id>
    <title>Jakub Steiner: USS/FMS Carrier</title>
    <updated>2026-05-09T00:00:00+00:00</updated>
    <author>
      <name>Jakub Steiner</name>
    </author>
    <content type="html">&lt;p&gt;I'm a sucker for pixel art and very constrained music grooveboxes. While I'm not into chiptunes, they sure are a cultural phenomenon.&lt;/p&gt;
&lt;p&gt;You heard me boast about the &lt;a href="https://dirtywave.com/"&gt;Dirtywave M8&lt;/a&gt; numerous times, even in person, because it's my tool of choice for producing and performing music. Its genius lies in high sound quality and a workflow that grew out of the tiny screen and button constraints on the Nintendo Gameboy, the platform of choice for an app called &lt;a href="https://www.littlesounddj.com/"&gt;LSDJ&lt;/a&gt;, which the M8 is modelled after. That, and the sheer amount of sound engines living in your pocket. Building on the shoulders of giants and all.&lt;/p&gt;
&lt;p&gt;The small M8 community has a few 'celebrities', such as &lt;a href="https://mtsn.se/"&gt;Ess Mattisson&lt;/a&gt;. I first heard of Ess when I ran into an amazing &lt;em&gt;single channel&lt;/em&gt; track called &lt;a href="https://www.youtube.com/watch?v=d6bJVcmFaNk"&gt;Wertstoffe&lt;/a&gt;. Ess has a great pedigree as the creator of the original &lt;a href="https://www.elektron.se/wp-content/uploads/2024/09/Digitone_User_Manual_ENG_OS1.41_231108.pdf"&gt;Digitone&lt;/a&gt; FM synthesizer while working at &lt;a href="https://www.elektron.se/"&gt;Elektron&lt;/a&gt;. FM remains his forte, and after creating numerous plugins through &lt;a href="https://fors.fm/"&gt;Fors&lt;/a&gt;, he has now &lt;a href="https://lo-bit.club/fms"&gt;released&lt;/a&gt; a little 2-operator FM synth and sequencer for the platform of the future, Nintendo Gameboy Advance.&lt;/p&gt;
&lt;div class="image-grid pixelated" id="crt-container"&gt;
&lt;img alt="Lo-bit Club logo animation" src="https://blog.jimmac.eu/posts/fms-carrier/Lo-bit.gif"/&gt;
&lt;img alt="FMS synth running on Gameboy Advance" src="https://blog.jimmac.eu/posts/fms-carrier/Fms.png"/&gt;
&lt;/div&gt;
&lt;p&gt;What makes FMS a bit crazy is what it's doing under the hood. The Gameboy Advance has no FM synthesis hardware at all. Its audio gives you two Direct Sound DMA channels of 8-bit signed PCM — that's 256 amplitude levels, roughly 48 dB of dynamic range. For comparison, a CD has 96 dB, in much finer fidelity. The CPU is an ARM7TDMI running at 16.78 MHz with 256 KB of RAM, and that's where &lt;em&gt;all&lt;/em&gt; the FM math happens. Sine waves, modulation, mixing four channels, all in real time, in software, on a chip from 2001 that was designed to shuffle sprites around. The hiss you hear is just part of the deal: quantization noise from that 8-bit DAC. So few amplitude steps means everything that comes out has this fuzzy, slightly crushed quality. You can't get rid of it. It &lt;em&gt;is&lt;/em&gt; the sound. And somehow there are four channels of 2-operator FM synthesis in there, each with envelopes and ratio control. On a Gameboy Advance.&lt;/p&gt;
&lt;p&gt;Picking GBA as a platform of choice in 2026 may be strange. Surprisingly, it can be used on a very large array of hardware. Not only can you plug a memory card into the original hardware or new fancy clones like the &lt;a href="https://www.analogue.co/pocket"&gt;Analogue Pocket&lt;/a&gt;, you have an exponentially larger choice of dozens if not hundreds of Chinese emulator handhelds from &lt;a href="https://anbernic.com/"&gt;Anbernic&lt;/a&gt;, &lt;a href="https://powkiddy.com/"&gt;Powkiddy&lt;/a&gt;, &lt;a href="https://lomiyoo.com/"&gt;Miyoo&lt;/a&gt; or &lt;a href="https://www.goretroid.com/"&gt;Retroid&lt;/a&gt;. You can also use the &lt;a href="https://store.steampowered.com/steamdeck"&gt;Steam Deck&lt;/a&gt; or any PC running one of the many emulators, &lt;a href="https://www.retroarch.com/"&gt;RetroArch&lt;/a&gt; being the most popular one.&lt;/p&gt;
&lt;p&gt;FMS really touched me. Partly because I have a soft spot for the Nordic demo scene, but mainly for its novel approach to composition. Just like with the M8, creating basic building blocks and then applying transposition to break the looping monotony is my favorite workflow. This little thing has that in the form of pattern and trig transposition but also a novel take on "effects". Yes, you heard me right. There's a sorta-kinda-delay. Even does stereo field ping-pong.&lt;/p&gt;
&lt;p&gt;I will keep on trying to create something that … sounds good. The process has been amazing. I truly love some of the sequencing tricks and workflows. The sequencer is, however, so good it would be worth seeing it run on top of a higher quality sound engine too.&lt;/p&gt;</content>
    <link href="https://blog.jimmac.eu/posts/fms-carrier/"/>
    <published>2026-05-09T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://kramo.page/computers-are-terrible</id>
    <title>Laura Kramolis: Computers Are Terrible</title>
    <updated>2026-05-10T00:00:00+00:00</updated>
    <author>
      <name>Laura Kramolis</name>
    </author>
    <content type="html">&lt;p&gt;A slightly more collected version of originally 18 Signal messages. This is a simplification. I am evidently no expert in Unicode specifically or text encoding in general.&lt;/p&gt;
&lt;p&gt;I, for a long time, believed that while many modern standards are a mess of legacy compatibility built on legacy compatibility, Unicode was an exception. That the only compromise it made was ASCII-compatibility, but even that wasn’t such a big one given that its character set is the most common one in computing even to this day. I was wrong.&lt;/p&gt;
&lt;p&gt;I got a US keyboard so now I have 2 different ways of typing accented characters. I can either hold the &lt;kbd&gt;A&lt;/kbd&gt; key until I get an option of &lt;code&gt;à&lt;/code&gt;, &lt;code&gt;á&lt;/code&gt;, &lt;code&gt;â&lt;/code&gt;, &lt;code&gt;ä&lt;/code&gt;, &lt;code&gt;ǎ&lt;/code&gt;, etc., or I can press &lt;kbd&gt;⌥&lt;/kbd&gt; &lt;kbd&gt;E&lt;/kbd&gt; and then &lt;kbd&gt;A&lt;/kbd&gt; to get to &lt;code&gt;á&lt;/code&gt;, combining &lt;code&gt;´&lt;/code&gt; and a regular &lt;code&gt;a&lt;/code&gt;. I started wondering… when typing it one way or the other, the results must be different, right? I looked for a website that showed me what code points I was typing, and… they were the same?&lt;/p&gt;
&lt;p&gt;Most systems (the OS/browser in this case) normalize all text either one way or the other. In this case, to a single code point. Unicode does have deprecation, so you would think that when they introduced combining characters, they would have deprecated the precomposed versions of characters that can be written using them, right? Nope!&lt;/p&gt;
&lt;p&gt;It’s arbitrary which way each system normalizes text. Some do it &lt;em&gt;composed&lt;/em&gt; (&lt;code&gt;á&lt;/code&gt;) and some &lt;em&gt;decomposed&lt;/em&gt; (&lt;code&gt;a&lt;/code&gt; + &lt;code&gt;◌́&lt;/code&gt;). Both are part of the standard. And of course, you need to treat them as equivalent when not normalized so you might as well do it when you can anyway.&lt;/p&gt;
&lt;figure&gt;
&lt;blockquote&gt;
&lt;p&gt;
      Precomposed characters are the legacy solution for representing many special letters in various character sets. In Unicode, they were included for compatibility with early encoding systems […].
    &lt;/p&gt;
&lt;/blockquote&gt;
&lt;figcaption&gt;
    From
    &lt;cite&gt;&lt;a href="https://en.wikipedia.org/wiki/Precomposed_character"&gt;Precomposed character - Wikipedia&lt;/a&gt;&lt;/cite&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Oh well, my day is ruined. My new life goal is advocacy for the deprecation of all precomposed characters… or maybe I should just accept that all computing will be plagued by backwards compatibility headaches ’til the end of time.&lt;/p&gt;</content>
    <link href="https://kramo.page/computers-are-terrible"/>
    <published>2026-05-10T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/mcatanzaro/2026/05/11/flatpak-sandbox-escape-via-yelp/</id>
    <title>Michael Catanzaro: Flatpak Sandbox Escape via Yelp</title>
    <updated>2026-05-11T14:12:53+00:00</updated>
    <author>
      <name>Michael Catanzaro</name>
    </author>
    <content type="html">&lt;p class="wp-block-paragraph"&gt;Yelp 49.1 fixes a significant &lt;a class="external" href="https://gitlab.gnome.org/GNOME/yelp/-/work_items/238"&gt;Flatpak sandbox escape&lt;/a&gt; related to &lt;a href="https://blogs.gnome.org/mcatanzaro/2025/04/15/dangerous-arbitrary-file-read-vulnerability-in-yelp-cve-2025-3155/"&gt;last year’s CVE-2025-3155&lt;/a&gt;. CVE assignment for this new issue is currently pending.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;This is not a bug in Flatpak. Flatpak allows sandboxed applications to open URIs or files, meaning the sandboxed application may use a URI or file path to launch another application to open the URI or file. This is brokered via the OpenURI portal. The portal or the app may decide to require user interaction to decide which app to launch, but user interaction is generally not required. This is necessary: you would get pretty frustrated if you were prompted to select which app to use every time you click on a link or try to open something! Accordingly, unsandboxed applications that are installed on the host system are somewhat risky: any malicious sandboxed app may launch an unsandboxed app using a malicious file, generally with no user interaction required. Unsandboxed applications installed on the host OS are inherently part of the attack surface of the Flatpak sandbox.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;In this case, a sandboxed application may launch Yelp to open a malicious help file. The help file can then exfiltrate arbitrary files from your host OS to a web server by using a CSS stylesheet embedded in an SVG. Suffice to say the attack is pretty clever, and certainly more impactful than the typical boring memory safety bugs I more commonly see.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;This bug was discovered by &lt;a class="external" href="https://codeanlabs.com"&gt;Codean Labs&lt;/a&gt;, which performed a security audit of Flatpak and several GNOME projects thanks to generous sponsorship by the &lt;a class="external" href="https://www.sovereign.tech/programs/bug-resilience"&gt;Sovereign Tech Resilience&lt;/a&gt; program of Germany’s Sovereign Tech Agency.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/mcatanzaro/2026/05/11/flatpak-sandbox-escape-via-yelp/"/>
    <published>2026-05-11T14:12:53+00:00</published>
  </entry>
  <entry>
    <id>https://mccalabrese.github.io/gnome-blog/posts/first-post/</id>
    <title>Michael Calabrese: Hello Planet GNOME! | GSoC 2026 Introduction</title>
    <updated>2026-05-13T00:00:00+00:00</updated>
    <author>
      <name>Michael Calabrese</name>
    </author>
    <content type="html">&lt;p&gt;Hello everyone, I'm Michael, and I am excited to be contributing to the GNOME foundation as a part of Google Summer of Code 2026.&lt;/p&gt;
&lt;h3 id="a-bit-about-me"&gt;A bit about me&lt;/h3&gt;
&lt;p&gt;I am a Computer Engineering student and long time Linux user. GNOME has been my desktop environment for years and I was very excited to be working with the GNOME foundation.&lt;/p&gt;
&lt;p&gt;I have a fairly significant amount of custom tooling that was all in Python and Bash, and about 16 months ago I began rewriting it in Rust, primarily to learn, however the performance and reliability improvements were quite noticeable. This led me to rewrite all of my scripts and tools in Rust. That experience put me in a great position to tackle the Rust rewrite of the Pitivi timeline ruler.&lt;/p&gt;
&lt;h3 id="the-summer-project"&gt;The Summer Project&lt;/h3&gt;
&lt;p&gt;The plan of attack with this project is first to create a standalone GTK4 Timeline Ruler widget in Rust, then modify Pitivi to use the new ruler via &lt;code&gt;PyGObject&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I am currently building a basic test binary, which can be found at &lt;a href="https://gitlab.gnome.org/Mccalabrese/pitivi-timeline-ruler" rel="external"&gt;Project&lt;/a&gt;. This will be used to test the functionality of the widget and to ensure that it is working correctly before integrating it into Pitivi.&lt;/p&gt;
&lt;p&gt;I am very excited to be working on this project and I look forward to sharing my progress with the community. I hope to learn a lot and contribute something meaningful to the GNOME ecosystem.&lt;/p&gt;</content>
    <link href="https://mccalabrese.github.io/gnome-blog/posts/first-post/"/>
    <published>2026-05-13T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/anonymoux47/2026/05/13/hello-gnome-and-gsoc-again/</id>
    <title>Toluwaleke Ogundipe: Hello GNOME and GSoC, Again!</title>
    <updated>2026-05-13T18:17:42+00:00</updated>
    <author>
      <name>Toluwaleke Ogundipe</name>
    </author>
    <content type="html">&lt;p class="wp-block-paragraph"&gt;I am delighted to announce that I am returning for Google Summer of Code 2026 to contribute to GNOME once again. Following &lt;a href="https://blogs.gnome.org/anonymoux47/2025/10/22/gsoc-final-report-printing-in-gnome-crosswords"&gt;my work on Crosswords&lt;/a&gt; last year, I will be shifting focus to the core of the desktop: &lt;a class="external" href="https://gitlab.gnome.org/GNOME/mutter"&gt;Mutter&lt;/a&gt;. For what it’s worth, I never left; I’ve been working with Jonathan to improve things and add &lt;a class="external" href="https://gitlab.gnome.org/jrb/crosswords/-/work_items/380"&gt;shiny new features&lt;/a&gt; in Crosswords.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Mutter serves as the Wayland display server and compositor library for &lt;a class="external" href="https://gitlab.gnome.org/GNOME/gnome-shell"&gt;GNOME Shell&lt;/a&gt;. Currently, a GPU reset invalidates the EGL context and causes the loss of all allocated GPU memory, resulting in the entire desktop crashing or freezing.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;My project aims to implement a robust recovery mechanism for GPU resets to prevent these session-ending freezes, under the mentorship of &lt;a class="external" href="https://gitlab.gnome.org/jadahl"&gt;Jonas Ådahl&lt;/a&gt;, &lt;a class="external" href="https://gitlab.gnome.org/rmader"&gt;Robert Mader&lt;/a&gt;, and &lt;a class="external" href="https://gitlab.gnome.org/carlosg"&gt;Carlos Garnacho&lt;/a&gt;. Leveraging the &lt;a class="external" href="https://registry.khronos.org/OpenGL/extensions/EXT/EXT_robustness.txt"&gt;&lt;code&gt;GL_EXT_robustness&lt;/code&gt;&lt;/a&gt; extension, I will implement reset detection, context re-creation, and re-upload of essential GPU resources, such as client textures, glyph caches, and background images. This will allow the compositor to resume rendering seamlessly after hardware-level failures.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Over the course of the project, I will share updates on the progress of these recovery mechanisms and the challenges of managing state restoration within the compositor.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;I am very grateful to my mentors, Jonas, Robert, and Carlos, for the opportunity to work on this critical part of the GNOME ecosystem. Also, a big shout-out to &lt;a class="external" href="https://gitlab.gnome.org/federico"&gt;Federico&lt;/a&gt;, &lt;a class="external" href="https://gitlab.gnome.org/hansp"&gt;Hans Petter&lt;/a&gt;, and &lt;a class="external" href="https://gitlab.gnome.org/jrb"&gt;Jonathan&lt;/a&gt; for their continuous support. I look forward to another productive summer with the community. &lt;img alt="🦾" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9be.png" style="height: 1em;"/&gt;&lt;img alt="❤" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/2764.png" style="height: 1em;"/&gt;&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/anonymoux47/2026/05/13/hello-gnome-and-gsoc-again/"/>
    <published>2026-05-13T18:17:42+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/laureen/2026/05/13/introduction-post/</id>
    <title>Laureen Caliman: Introduction Post</title>
    <updated>2026-05-13T22:01:17+00:00</updated>
    <author>
      <name>Laureen Caliman</name>
    </author>
    <content type="html">&lt;p&gt;May 13th, 2026&lt;/p&gt;
&lt;p&gt;My name is Laureen Caliman, and I am a contributor for GNOME Crosswords with Google Summer of Code 2026. &lt;span&gt;&lt;span class="citation-30"&gt;Crosswords are a stimulating challenge that promotes engagement in education&lt;/span&gt;&lt;/span&gt;&lt;span&gt;. Computing systems are now an indelible factor of daily life, which has raised concerns on maintaining attention, long-term memory, and reinforcement of knowledge in K-12. One &lt;a class="external" href="https://www.neliti.com/publications/92017/a-study-on-the-effectiveness-of-crossword-puzzle-as-compared-to-conventional-met"&gt;study&lt;/a&gt; was performed in Indonesia to teach students English using crosswords. A measurable improvement in the students’ coherence to the foreign language material was seen, demonstrating benefit to their education.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Unlike traditional crossword grids which are rigidly defined, vocab-style &lt;a class="external" href="https://gitlab.gnome.org/-/project/19387/uploads/6601d25ca1bfe86e1c2cf8136e4edd53/image.png"&gt;puzzles&lt;/a&gt; are fitted using algorithms to shape them together. Users will have the option to edit their crossword in the Editor, and open it in Crosswords. My project entails adding the proper backend and frontend support to create vocab-style crossword puzzles.&lt;/p&gt;
&lt;p&gt;My mentors are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jonathan Blandford&lt;/li&gt;
&lt;li&gt;Federico Mena Quintero&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;About Me:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am an incoming Computer Engineering student at Rose-Hulman Institute of Technology. I also teach K-12 computer science, so I really relate to this project’s mission about bridging software with education.&lt;/p&gt;
&lt;p&gt;I am eager to contribute to this community and learn more about the inner workings of GNOME. I intend to continue contributing to GNOME for a long time after this project finishes!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GNOME Crosswords:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Jonathan Blandford presented an in-depth overview of the history of GNOME at GUADEC 2017, which is available to watch &lt;a class="external" href="https://www.youtube.com/watch?v=bWUmptI6O2w"&gt;here&lt;/a&gt;. Blandford also presented Crosswords to the 2024 GUADEC &lt;a class="external" href="https://www.youtube.com/watch?v=fcQfpQLLzYo"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="external" href="https://gitlab.gnome.org/jrb/crosswords"&gt;Crosswords&lt;/a&gt; consists of two domains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Crosswords &lt;a class="external" href="https://flathub.org/en/apps/org.gnome.Crosswords.Editor"&gt;Editor&lt;/a&gt;, which is a tool to create and edit crossword puzzles.&lt;/li&gt;
&lt;li&gt;The Crosswords &lt;a class="external" href="https://flathub.org/en/apps/org.gnome.Crosswords"&gt;Game&lt;/a&gt;, which is where the user plays crossword puzzles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My project will see to both: the editor for a user to create the puzzle, and the game platform to play it. They will also have the option to print their game in black and white using Cairo Graphics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Technical Challenge:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Traditional crosswords have a stable grid ready for play; the vocab-style crossword will be weaving words together in the most logical way upon a blank canvas. My project focuses on building the algorithm which will take in words and distribute them to form a connected puzzle.&lt;/p&gt;
&lt;p&gt;The biggest challenge is ensuring the program doesn’t get stuck. As it places words on the board one-by-one, it has to follow strict rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The words must be interlocked and aligned.&lt;/li&gt;
&lt;li&gt;The whole puzzle must be connected as a single piece.&lt;/li&gt;
&lt;li&gt;Words cannot form gibberish with their connecting path or neighboring words.&lt;/li&gt;
&lt;li&gt;The grid must also not enter a permanent hangup trying to fit clashing words together.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Approach:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I will be splitting the work across the backend logic and frontend UI to make a presentable and functional puzzle.&lt;/p&gt;
&lt;p&gt;This program will use an algorithm to deal words. Upon a rule violation, it will backtrack to find an adequate fitting by reversing itself, deleting unideal portions of the current layout, and reseeding words differently. Essentially, it places a word on the grid, tests the board with another word, and if it hits a wall, the board cleanly undoes that path until it finds another valid one. This will continue until all words are fitted together and simultaneously satisfies the constraints.&lt;/p&gt;
&lt;p&gt;The frontend will contain stateless widgets that render with the flow of the grid. The widgets should simply read the state without mutating any data.&lt;/p&gt;
&lt;p&gt;This trial-and-error approach will afford the program the ability to test combinations until it finds a perfectly fitting, playable crossword puzzle!&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Currently, we are in the “Community Bonding Period” (May 1st-24th), and I have been communicating consistently with Jonathan Blandford to refine the approach and implementation. To gain practice, I have been working on this &lt;a class="external" href="https://gitlab.gnome.org/jrb/crosswords/-/merge_requests/373#note_2761175"&gt;merge request&lt;/a&gt; for applicable practice towards my GSoC project.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/laureen/2026/05/13/introduction-post/"/>
    <published>2026-05-13T22:01:17+00:00</published>
  </entry>
  <entry>
    <id>https://blog.nirbheek.in/2026/05/an-esoteric-type-of-memory-leak.html</id>
    <title>Nirbheek Chauhan: An Esoteric Type of Memory "Leak"</title>
    <updated>2026-05-14T21:52:36.605000+00:00</updated>
    <author>
      <name>Nirbheek Chauhan</name>
    </author>
    <content type="html">&lt;p&gt;A little while ago, my colleague &lt;a href="https://coaxion.net/" target="_blank"&gt;Sebastian&lt;/a&gt; started complaining about OOMs caused by Evolution taking up tens of gigabytes of memory. We discussed using sysprof to debug it, but it was too busy a time for Sebastian to set aside a few hours to do that.&lt;/p&gt;&lt;p&gt;Funnily enough, the most efficient fix at the time was to buy more RAM, since rust-analyzer was also causing OOM issues.&lt;/p&gt;&lt;p&gt;A few weeks went by. Restarting Evolution had become a daily ritual for Sebastian. &lt;/p&gt;&lt;p&gt;Then, on a whim, I decided investigating this might be a good test for an LLM.&lt;/p&gt;&lt;p&gt;I updated my Evolution git repo, built it, and started up Claude Code in the source root. This was the only prompt I supplied: &lt;/p&gt;&lt;blockquote&gt;Find memory leaks in Evolution, current sourcedir. Particularly leaks that could accumulate over several hours. A colleague has a leak that slowly accumulates memory usage to several GB over the course of a day, requiring a restart of Evolution. That is the main focus, but we can fix other leaks in the process.&lt;/blockquote&gt;&lt;p&gt;I wish I was lying, but that was all Claude Code needed to find the problem: &lt;a href="https://gitlab.gnome.org/GNOME/evolution/-/merge_requests/218" target="_blank"&gt;Evolution just needed to call &lt;code&gt;malloc_trim(0)&lt;/code&gt; from time to time&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I refused to believe it at first. I was only convinced when we saw the memory drop after running &lt;code&gt;gdb -p $(pidof evolution) -batch -ex "call malloc_trim(0)" -ex detach&lt;/code&gt;&lt;/p&gt;&lt;p&gt;This seems absurd! Doesn't glibc reclaim freed memory from time to time?&lt;/p&gt;&lt;p&gt;Yes, it does. It calls &lt;code&gt;sbrk()&lt;/code&gt; to do that. However, &lt;code&gt;sbrk()&lt;/code&gt; can only reclaim free memory at the top of the heap, since it simply moves the program break downward to do so. &lt;code&gt;malloc_trim(0)&lt;/code&gt; calls &lt;code&gt;sbrk()&lt;/code&gt; and then &lt;i&gt;also calls&lt;/i&gt; &lt;code&gt;madvise(..., MADV_DONTNEED)&lt;/code&gt; on the free pages, which allows the kernel to reclaim them.&lt;/p&gt;&lt;p&gt;So if you have 10GB of unused memory followed by 4 bytes allocated at the top of the heap, your RSS is &amp;gt;10GB, even if you're using a few hundred megs. Till you call &lt;code&gt;malloc_trim(0)&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Note that you can only get into this situation if you have hundreds of thousands of small allocs/deallocs happening repeatedly. If your alloc is &amp;gt;128KB, mmap() is used for the allocation, and none of this applies.&lt;/p&gt;&lt;p&gt;Coincidentally, GLib's use of GSlice for GObject allocations was masking this issue in the past, but GSlice has been a no-op for some time now (for good reasons). Ideally, Evolution should not be using GObject for such ephemeral objects.&lt;/p&gt;&lt;p&gt;Lesson learned: if you have memory usage issues and you suspect fragmentation, try &lt;code&gt;malloc_trim(0)&lt;/code&gt; before you go thinking about &lt;a href="https://github.com/plasma-umass/Mesh" target="_blank"&gt;fancy allocators&lt;/a&gt;.&lt;/p&gt;</content>
    <link href="https://blog.nirbheek.in/2026/05/an-esoteric-type-of-memory-leak.html"/>
    <published>2026-05-14T21:52:36.605000+00:00</published>
  </entry>
  <entry>
    <id>https://www.gimp.org/news/2026/05/15/gimp-las-adullact-2026/</id>
    <title>GIMP: GIMP @ Linux App Summit and ADULLACT Congress 2026</title>
    <updated>2026-05-14T22:00:00+00:00</updated>
    <author>
      <name>GIMP</name>
    </author>
    <content type="html">&lt;p&gt;We have been trying to encourage contributors to be more present on
various events, international or local. Here is where you will find
someone from the &lt;span class="caps"&gt;GIMP&lt;/span&gt; team in the coming weeks:&lt;/p&gt;
&lt;h2 id="linux-app-summit-2026"&gt;Linux App Summit 2026&lt;a class="headerlink" href="https://www.gimp.org/feeds/atom.xml#linux-app-summit-2026" title="Permanent link"&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;a href="https://linuxappsummit.org/"&gt;Linux App Summit (&lt;span class="caps"&gt;LAS&lt;/span&gt;)&lt;/a&gt; brings the
global Linux community together to learn, collaborate, and help grow
the Linux application ecosystem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;
&lt;img alt="Linux App Summit 2026 banner" src="https://www.gimp.org/news/2026/05/15/gimp-las-adullact-2026/LAS2026-WebBanner-text.jpg"/&gt;
&lt;figcaption&gt;
&lt;em&gt;Linux App Summit 2026, May 16-17, 2026 - Berlin, Germany&lt;/em&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It happens this week-end, from May 16 to 17 in Berlin, Germany, and we
will have one person attending, &lt;a href="https://www.gimp.org/news/2017/05/15/an-interview-with-michael-schumacher-gimp-administrator/"&gt;Michael
Schumacher&lt;/a&gt;,
one of our long term contributor, as well as member of our Committee.&lt;/p&gt;
&lt;p&gt;Unfortunately our project did not submit a talk, but we are still
interested to meet more of the desktop software ecosystem contributors
and see what’s happening around us! So if you attend too and spot
Michael, do not hesitate to go and speak with him. He will likely have
Wilber stickers to distribute too! 😍&lt;/p&gt;
&lt;h2 id="10th-congres-adullact"&gt;10th Congrès &lt;span class="caps"&gt;ADULLACT&lt;/span&gt;&lt;a class="headerlink" href="https://www.gimp.org/feeds/atom.xml#10th-congres-adullact" title="Permanent link"&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://adullact.org/congres"&gt;&lt;em&gt;Congrès &lt;span class="caps"&gt;ADULLACT&lt;/span&gt;&lt;/em&gt;&lt;/a&gt; is a conference
gathering elected representatives of French local authorities, to
discuss Free Software usage in the public sector.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="10th Congrès ADULLACT 2026 banner" src="https://www.gimp.org/news/2026/05/15/gimp-las-adullact-2026/Congrs_2026_-_format_web.jpg"/&gt;
&lt;figcaption&gt;
&lt;em&gt;10th Congrès &lt;span class="caps"&gt;ADULLACT&lt;/span&gt;, June 4-5, 2026 - Montpellier, France&lt;/em&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Jehan, &lt;span class="caps"&gt;GIMP&lt;/span&gt; Maintainer, will be present there to showcase &lt;span class="caps"&gt;GIMP&lt;/span&gt; as a
Community, Free Software. Obviously &lt;span class="caps"&gt;GIMP&lt;/span&gt; is already quite massively
present in France, but as many Free Software, administrators and users
alike may not realize how it is being developed, by whom, why and how.
Nor do they know that it is being developed by a major part in Europe
and more particularly in France.
Since one of the two main topics this year is the digital sovereignty,
this is quite a major stake in this context.&lt;/p&gt;
&lt;p&gt;The event happens from June 4 to 5, 2026, in Montpellier, France. As one
can imagine, it is a close event for elected representatives and civil
servants only, so if this is your case, we hope you will &lt;a href="https://pretix.eu/congres-adullact-2026/inscriptions/"&gt;show
up&lt;/a&gt; and Jehan
will be happy to discuss with you!&lt;/p&gt;
&lt;p&gt;Jehan’s talk will be on &lt;strong&gt;Friday, June 5, 2026, at 14:20 (French time)&lt;/strong&gt;
and he will introduce &lt;a href="https://pretalx.com/congres-adullact-2026/talk/3Y7XS7/"&gt;&lt;span class="caps"&gt;GIMP&lt;/span&gt; as a “Free Software and
Community”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We hope you’ll be many to attend! (oh and Jehan as well will have Wilber
stickers, even though it may less a selling point in such a conference 😋)&lt;/p&gt;</content>
    <link href="https://www.gimp.org/news/2026/05/15/gimp-las-adullact-2026/"/>
    <published>2026-05-14T22:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://barthalion.blog/flathub-internals-cdn/</id>
    <title>Bart Piotrowski: How does Flathub even work? The CDN and caching layer</title>
    <updated>2026-05-15T10:25:00+00:00</updated>
    <author>
      <name>Bart Piotrowski</name>
    </author>
    <content type="html">&lt;p&gt;There is one specific way in which the non-corporate open source projects typically document how their infrastructure work: not at all, and Flathub is no different. The full picture likely lives only in my brain, and while it could be sorted out by anyone (especially in this LLM age, yay or nay), why should it only be me thinking at night about all the single points of failure?&lt;/p&gt;
&lt;p&gt;Like any system that evolved naturally, it's all over the place. It's tempting to tell its history chronologically, but even then, it's difficult to find a good entry point. Instead, this post focuses on what happens when users call &lt;code&gt;flatpak install&lt;/code&gt;; later entries will cover the website and, finally, the build infrastructure. Buckle up!&lt;/p&gt;
&lt;h2 id="cdn-caching-proxies-the-master-server"&gt;CDN, caching proxies, the master server&lt;/h2&gt;&lt;p&gt;The secret of making computers work well is to have them not do anything at all, and that's the story behind serving Flathub's OSTree repository. Content-addressed objects are extremely cacheable as they are immutable, offloading the effort to the CDN provider.&lt;/p&gt;
&lt;p&gt;When the client connects to &lt;code&gt;dl.flathub.org&lt;/code&gt;, you can be certain it hits some layer of cache. Almost all the heavy-lifting is done by Fastly. At the peak, when both EMEA and North America are awake and at computers, 50 million requests per hour are cache hits served by Fastly's infrastructure, with a modest 20 million being misses passed down to our servers. There would be no Flathub without Fastly; Fastly does it completely for free, not even for fake Internet points as we are incredibly bad at highlighting what our sponsors do for us.&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="https://bear-images.sfo2.cdn.digitaloceanspaces.com/barthalion/image-2.webp"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="https://bear-images.sfo2.cdn.digitaloceanspaces.com/barthalion/image-3.webp"/&gt;&lt;/p&gt;
&lt;p&gt;You can't do enough cache, and so various Fastly servers talk to Fastly-managed shield server which caches the most requested objects to avoid spilling over too much to us. For legit cache misses, the request will be served by one of 8 caching proxies we are running at different VPS providers. We use a consistent hashing director at Fastly which will pick the backend based on the path being requested. In the past, we used a dumb round-robin but as a result, each caching proxy had its own independent copy of the working set, wasting disk space and producing a higher miss rate against the master server. Hashing by URL behaves like one big cache instead of N copies.&lt;/p&gt;
&lt;p&gt;These days, the caching proxy fleet consists of 3 servers at Mythic Beasts, 2 servers at AWS, another 2 at NetCup and a single server at DigitalOcean. We don't collect overly detailed metrics, but on average, each proxy serves around 1 TB/month back to Fastly and pulls roughly 5 TB/month from origin. With only 100 GB of disk space per proxy against a multi-TB working set, we're not so much caching the long tail as smoothing it. In the ideal world, we would be retaining much more data at this layer, but it's not the world we live in.&lt;/p&gt;
&lt;p&gt;Each of these servers is running the latest stable Debian release. The requests are served by the usual nginx setup with &lt;code&gt;proxy_cache&lt;/code&gt; enabled. There is some custom Lua code for invalidating certain paths after publishing new builds finishes (spoilers!). Vanilla nginx doesn't support the &lt;code&gt;PURGE&lt;/code&gt; method, and third-party modules like &lt;code&gt;ngx_cache_purge&lt;/code&gt; have not seen any maintenance for over 10 years. In the end, it was more maintainable to write Lua code to calculate the caching key of a URL and then run &lt;code&gt;os.remove&lt;/code&gt; to "purge" it from the cache.&lt;/p&gt;
&lt;p&gt;There's also a systemd timer for refreshing the Fastly IP allowlist. We used to expose these servers publicly, but a vision of everything crumbling down due to a DDoS attack kept me awake at night so this had to change.&lt;/p&gt;
&lt;p&gt;On the far end of this setup sits a lonely physical server living in one of the Mythic Beasts' datacenters. This is The Server holding the entire Flathub repo on an equivalent of RAID10 in ZFS world: two 2-disk mirror vdevs on which ZFS stripes data across. There is more nuance to this setup, but the ultimate advantage is that we can tolerate a disk failure in each of the mirrors, while being less taxing to resilver after a swap. The entire reachable data set is around 4TB of data, with the remaining 6TB unused. There will be more about the repository maintenance later on!&lt;/p&gt;
&lt;p&gt;Ironically, it's the only server running Ubuntu. At the time, it was the easiest way to have support for ZFS readily available. We could re-provision it to Debian, but on the other hand, what for? It works fine that way. It has survived at least 2 major upgrades between LTS-es; if it ain't broke, don't fix it.&lt;/p&gt;
&lt;p&gt;The master server itself has to be partially public as it's where new builds are being uploaded. It no longer exposes the raw Flathub repository for the same reason caching proxies don't. This is accomplished with Tailscale and a lightweight ACL config ensuring caching proxies can talk only to the HTTP server running on the main repo server and vice versa (for issuing &lt;code&gt;PURGE&lt;/code&gt; requests). Yes, all involved parties have public IP addresses assigned so this could technically be pure WireGuard setup but I prefer to make this someone else's concern, especially given how generous Tailscale's free plan is.&lt;/p&gt;
&lt;source media="(prefers-color-scheme: dark)"/&gt;
&lt;img alt="Flathub CDN topology" src="https://bear-images.sfo2.cdn.digitaloceanspaces.com/barthalion/flathub-cdn2.webp" style="display: block; margin: 0 auto;"/&gt;
&lt;p&gt;It's not much, but it's honest work. For how little we have, the file-serving half of Flathub's infrastructure works unreasonably well. Stay tuned for part 2!&lt;/p&gt;</content>
    <link href="https://barthalion.blog/flathub-internals-cdn/"/>
    <published>2026-05-15T10:25:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/aday/2026/05/15/gnome-foundation-update-2026-05-15/</id>
    <title>Allan Day: GNOME Foundation Update, 2026-05-15</title>
    <updated>2026-05-15T16:41:52+00:00</updated>
    <author>
      <name>Allan Day</name>
    </author>
    <content type="html">&lt;p&gt;Welcome to another GNOME Foundation update post! Today’s installment covers highlights from what’s happened over the past two weeks.&lt;/p&gt;
&lt;h2&gt;LAS 2026&lt;/h2&gt;
&lt;p&gt;&lt;a class="external" href="https://linuxappsummit.org/"&gt;Linux Apps Summit 2026&lt;/a&gt; starts tomorrow! The organizing team, which includes members from both GNOME and KDE, has been hard at work and is on the ground in Berlin making final preparations. The schedule looks great, and it promises to be a well-attended event.&lt;/p&gt;
&lt;p&gt;The talks are being streamed this year, so make sure to watch our social media for details, and tune in live to hear the talks.&lt;/p&gt;
&lt;h2&gt;GUADEC 2026&lt;/h2&gt;
&lt;p&gt;Preparations are continuing for July’s GUADEC. The &lt;a class="external" href="https://discourse.gnome.org/t/guadec-2026-additional-call-for-bof-workshop-submissions/35017"&gt;call for Birds of a Feather sessions&lt;/a&gt; is currently open. If you want to hold an informal discussion or working session, please fill out the form before 5th June.&lt;/p&gt;
&lt;p&gt;Applications are still open for &lt;a class="external" href="https://handbook.gnome.org/events/travel.html"&gt;travel funding&lt;/a&gt; for GUADEC. The deadline for submissions is 24th May – that’s just over one week.&lt;/p&gt;
&lt;h2&gt;Board meeting&lt;/h2&gt;
&lt;p&gt;This week the Board of Directors had its regular meeting for May. A summary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Board authorized the closure of a bank account which we are no longer using.&lt;/li&gt;
&lt;li&gt;I gave an update on operations over the past month, and got feedback from the Board&lt;/li&gt;
&lt;li&gt;Felipe Borges from the Internship Committee joined, to give a report. The Board discussed how we can best support the committee.&lt;/li&gt;
&lt;li&gt;Deepa gave a finance report, which included numbers from January and February. The main news here was that our finances are running close to what was projected for this year’s budget.&lt;/li&gt;
&lt;li&gt;The Board discussed the draft of the report from the audit we recently underwent, as well as the draft of our latest annual tax filing. This is a routine part of the Board’s work, as it is required to perform a review before these documents are finalized.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Office transitions&lt;/h2&gt;
&lt;p&gt;Our long-running effort to enhance our internal accounting processes has continued over the past two weeks. A notable development has been the retirement of several finance platforms, which have been effectively replaced by the new payments platform that we adopted in January. This platform reduction will reduce operational complexity, as well as workloads. It is still ongoing – we have an additional two more platforms that are currently in the process of being retired.&lt;/p&gt;
&lt;p&gt;Another highlight has been the launch of a search for a new member to join our finance and operations team. This is a part-time, contract-based role, which has been shaped in close consultation with Dawn Matlak, who is supporting our finance and accounting operations on a temporary basis, and has already been factored into our budget projections.&lt;/p&gt;
&lt;p&gt;We are looking for someone at director level who brings substantial nonprofit finance experience — including audit preparation and compliance experience — which reflects how much the Foundation’s operational and regulatory requirements have grown, particularly in the run up to and following our audit last March, and will provide in-house expertise which will reduce our reliance on external consultants. You can read the full posting &lt;a class="external" href="https://www.idealist.org/en/nonprofit-job/5942160e1dec484a934de7a6d9508dc3-finance-operations-director-part-time-contractor-gnome-foundation-san-francisco"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and see you in two week’s time!&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/aday/2026/05/15/gnome-foundation-update-2026-05-15/"/>
    <published>2026-05-15T16:41:52+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/sstendahl/2026/05/15/graphs-2-0-is-out/</id>
    <title>Sjoerd Stendahl: Graphs 2.0 is out!</title>
    <updated>2026-05-15T19:00:07+00:00</updated>
    <author>
      <name>Sjoerd Stendahl</name>
    </author>
    <content type="html">&lt;p&gt;After two years of development, Graphs 2.0 is finally out!&lt;/p&gt;
&lt;p&gt;This will be a shorter blog, as the changelist of the new features have been discussed in the previous post in more detail, you can check this out here in more detail if you’re interested: https://blogs.gnome.org/sstendahl/2026/04/14/announcing-the-upcoming-graphs-2-0/&lt;/p&gt;
&lt;p&gt;For a quick overview, a quick reprise of the most interesting features can be found here in bullet-point format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;New Data Types with proper equations: &lt;/strong&gt;In this new release, we finally have proper support for equations, where equations are manipulated analytically (e.g. a derivative on y = 12x² will result in y = 24x, and be rendered accordingly), limits are rendered infinitely, and equations can be changed after importing them. To accomodate this change, we now have three different data types. Equations, Imported Data, and Generated Data. Imported Data is regular data that you import from file. Generated Data behaves the same as Imported Data, but you generate the dataset using an equation. For generate data you can also change the equation after the fact, and rerender, or change limits or amount of generated datapoints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New Style Editor: &lt;/strong&gt;We revamped the style editor. One major change is that you can now easily import new styles based on matplotlib-style themes, and you can also export your style and share it with others. If you have a nice style you want to share with us, open an issue on the &lt;a class="external" href="https://gitlab.gnome.org/World/Graphs/-/work_items"&gt;GitLab page&lt;/a&gt; and let us know. We’re looking to expand the default choice of styles :). Furthermore, when editing  a style, you finally see a preview of how this affects the canvas. This way you don’t need to guess, or go back and forth when finetuning a style.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UX-changes&lt;/strong&gt;: Whilst the general look-and-feel of Graphs is still mostly the same, we did make some UX-changes with how we handle settings. Mainly, instead of showing a modal popup dialog, settings that affect the canvas itself (i.e. item and figure settings) are now shown in the sidebar instead. The reason for this, is that the popup dialog hid the figure that you’re editing, making it difficult to see how your changes actually affect your canvas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved data import. &lt;/strong&gt;We revamped the data import completely. First of all, we have made the codebase here much more modular, making it easier to write new parsers for other filetypes. We now added support for SQLite Database Files, Microsoft Excel Sheets and .ods files from LibreOffice Calc. It’s also now possible to import multiple files at once, and finetuning the settings for each file individually. Another nice feature here is that you can now import multiple datasets from the same file without having to reimport them. Finally, we added proper-support also for single-column imports where x-data can be generated using your own equation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error bar support: &lt;/strong&gt;Graphs now has proper support for error bars. The error bar style can be set globally in the new style editor, or individually for each item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reworked Curve Fitting&lt;/strong&gt;: The curve fitting logic has almost been completely rewritten. Whilst it mostly still works the same, the confidence band that is shown is now calculated properly using the Delta-method, instead of using a naive way using the limits of the standard deviations. We also added support to show the residuals to verify your fits, and added more useful error messages when things go wrong. The results in the curve fitting dialog now also show the root mean squared error as a second goodness-of-fit figure. The parameter values themselves in the curve fitting dialog are no longer rounded (e.g. 421302 used to be rounded to 421000) and finally custom equations in the curve fitting dialog now have an apply button, greatly improving the smoothness when entering new equations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Proper Mobile Support: &lt;/strong&gt;With this release, we now officially feel confident in stating proper mobile support. The entire UI is tested on real mobile phones using PostMarketOS, and everything works properly. Labels are now also ellipsized earlier on narrow displays, so that the UI remains useable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reworked Figure Exports: &lt;/strong&gt;Figure exports are reworked. Instead of simply taking a snapshot of the current canvas, you can set the actual size in pixels when exporting a figure. This is vital when trying to create reproducable figures for e.g. publications. Of course, you can also easily still use the same canvas that you see in the application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quality of life changes&lt;/strong&gt;: We haven’t even gone through each individual change we made in the blog, but here’s a quick fire-round of more quality-of-life changes:
&lt;ul&gt;
&lt;li&gt;It is now possible to have multiple instances of Graphs open at the same time&lt;/li&gt;
&lt;li&gt;The style editor now also has the option to draw tick labels (so the numeric values) on all axes containing ticks, this is not supported by default in Matplotlib, so we had to add our own parameter here&lt;/li&gt;
&lt;li&gt;Graphs now inhibits the session when unsaved data is still open, so you get a warning if you close your computer with unsaved data.&lt;/li&gt;
&lt;li&gt;Added support for base-2 logarithmic scaling&lt;/li&gt;
&lt;li&gt;Graphical fixes for the drag-drop animations, which used to look somewhat glitchy&lt;/li&gt;
&lt;li&gt;Panning and zooming are now done consistently on all axes when using multiple axes&lt;/li&gt;
&lt;li&gt;Data can now be imported by drag-and-drop into Graphs&lt;/li&gt;
&lt;li&gt;The subtitle now also shows the full file path for Flatpaks&lt;/li&gt;
&lt;li&gt;Limits can now easily be clicking on the numbers near the axes&lt;/li&gt;
&lt;li&gt;The custom transformation has gained the following extra variables: x_mean, y_mean, x_median, y_median, x_std, y_std and counts&lt;/li&gt;
&lt;li&gt;Warnings are now displayed when trying to open a project from a beta version&lt;/li&gt;
&lt;li&gt;The many code refactors and reimplementations from Python to Vala makes the application more robust, and significantly more performance. Especially when working with larger datasets.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="mx_EventTile_body markdown-body translate"&gt;This release took a long time to get right, but we’re happy to get the new features to the public. Graphs is handcrafted by human hands, which takes more time than LLM-based slop. But the longer manual process does allow us to think through changes, and make intentional decisions with human care. I am very proud to say we are able to deliver something intentional where we can deliver the polish that both Graphs, as well as the users deserve. As always, thanks to anyone involved which includes everyone who has been providing feedback, reported issues, contributed with code, or helped in any other possible way. And of course especially to &lt;a class="external" href="https://gitlab.gnome.org/cmkohnen"&gt;Christoph&lt;/a&gt; who has been maintaining Graphs with me and is responsible for a large part of the architectural changes that made this release possible.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Go get the new release from Flathub &lt;a class="external" href="https://flathub.org/en/apps/se.sjoerd.Graphs"&gt;here&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;p.s. On a more personal note with a shameless plug, I will be speaking at GUADEC 2026 about my journey into app development, and how to get into this world as an outsider without a CS degree. Be sure to check that out if you are interested in starting with applications, and want to know how it is to join a project in the GNOME ecosystem, it’s a lot less scary than it may sounds &lt;img alt="🙂" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" style="height: 1em;"/&gt; &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I’ll be joining on-site, so say hi to me there if you have any questions or are up for a chat :). Otherwise the whole event will be livestreamed as well, and you can always reach me at sstendahl@gnome.org. &lt;/em&gt;&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/sstendahl/2026/05/15/graphs-2-0-is-out/"/>
    <published>2026-05-15T19:00:07+00:00</published>
  </entry>
  <entry>
    <id>https://wingolog.org/archives/2026/05/16/soot-solar-sedimentation-sin-centers</id>
    <title>Andy Wingo: soot, solar, sedimentation, sin, &amp; 'centers</title>
    <updated>2026-05-16T19:29:02+00:00</updated>
    <author>
      <name>Andy Wingo</name>
    </author>
    <content type="html">&lt;div&gt;&lt;p&gt;Good evening, friends.  Tonight I have a few loosely-knit stories.&lt;/p&gt;&lt;h3&gt;soot&lt;/h3&gt;&lt;p&gt;A couple years ago, my house was heated by a &lt;a href="https://en.wikipedia.org/wiki/Condensing_boiler"&gt;condensing gas
boiler&lt;/a&gt;.  It was awful
from both an environmental and a geopolitical perspective:
environmental, as I would emit somewhere around 2.5 tons of CO2
equivalent per year to heat my home, which compares poorly to the target
total CO2e emissions of 2 tons per year per person; and geopolitical,
because although France gets 40% of its gas from Norway, with whom we
have no beef, all the rest is a problem in some way.  (Algeria, 10%, is
the least of my worries; the 20% for Russia and the US respectively are
the most, followed by 10% for the Gulf states.)&lt;/p&gt;&lt;p&gt;Still, natural gas is better than fuel oil, which we had at my former
rental house.  It is a lamentably visceral experience to call up the
fuel provider and say, yes, &lt;i&gt;s’il vous plaît&lt;/i&gt;, can you drive a
diesel-powered tanker truck out to my house, unroll the hose, and pour
out 1500 liters of toxic fuel oil into a tank under my garden.  Yes, I
will just burn it all.  Sure, see you again next year.&lt;/p&gt;&lt;p&gt;Some friends of mine recently had their fuel boiler die, which is itself
an experience: one of them came over to visit, completely covered in
soot, saying that the chimneysweep (whom he also has to call every year)
said that his boiler is on its way out, that the chimney is completely
clogged, and now because of the cleaning his basement is also covered in
soot; awful.  What to replace it with?  Apparently despite the
prohibition on new fuel-oil boiler installs, it might be possible to
just install a new one; or they could hook up to natural gas from the
street; or they could install a heat pump.  Which to do?&lt;/p&gt;&lt;p&gt;To all these questions there is a moral answer, which we can phrase in
terms in CO2 emissions and localized PM2.5 pollution, and it is always
and everywhere to stop burning things.  But fortunately we don’t need to
rely only on moralism: electrification is just better, in essentially
all ways.  Owning and operating an electric car is a better experience
than a petrol car.  Induction stoves are better than gas; I know, I did
not believe this for the longest time, but I was wrong.  The experience
of using a heat pump is pretty much equivalent to gas, so it’s a harder
sell, but it is a relief to no longer have a pressurized methane tube
connected to my house.&lt;/p&gt;&lt;p&gt;In the end, I think my neighbors are going to go for the heat pump,
despite the 20k€ price tag, labor included.  (Oddly, I think the
deciding factor was that my neighbor confessed to having had a long chat
with an AI chatbot, after which she felt she had a good understanding of
the proposed solution and its tradeoffs; make of that what you will!)&lt;/p&gt;&lt;h3&gt;solar&lt;/h3&gt;&lt;p&gt;In late November I got some brave lads to install nineteen solar panels
on my roof.  Each of these magic rectangles can make up to 500W of power
in optimal conditions, but my house faces south, with the roof inclined
east and west, so it’s unlikely that I will ever hit the full 9.5 kW of
potential power.&lt;/p&gt;&lt;img alt="graph of consumed and produced electricity in december, showing a more or less constant 2 kW use, with a tiny hump of production in midday, peaking at, like, 150W" src="https://wingolog.org/pub/december-power.jpg"/&gt;&lt;p&gt;December was... very dark.  The panels produced a total of 145 kWh over
the month, but I used 1250 kWh of electricity, essentially all to run
the heat pump.  I live in a basin that is mostly covered by low clouds
from November to February, and slanty photons couldn’t make much headway
through the fog.  The house is well-insulated (20-25 cm of wood-fiber
exterior insulation on sides, 40 under the roof, though it is an old
house with a few less-insulated bits), so it’s not that I am leaking
lots of heat, and I have a combination of low-temperature floor heating
and low-temperature radiators, so it’s not that I’m running the heat
pump inefficiently to generate a too-high output temperature; it’s just,
you know, cold in winter.  A typical day would be between 1 and 5
degrees C.  Cold; cold and dark.&lt;/p&gt;&lt;p&gt;Things got a little better in January: 285 kWh produced, though the
heating needs are higher than in December, with 1450 kWh total consumed.
In February we grew to 419 kWh produced, for 850 kWh consumed.  In March
we equalized, with about 850 kWh produced and consumed, but although the
bulk of my consumption in this month is for heating, the “need” to heat
overnight meant that I consume from the grid overnight, but feed in to
the grid during the day.  I have a small battery (7 kWh), but it’s not
enough to store the “excess” electricity generated in a day; I should
probably arrange to have the system heat only during the day in these
months, to avoid taking from the grid.&lt;/p&gt;&lt;img alt="graph of consumed and produced electricity in may, showing the battery never emptying, little power use, and a huge hump of production peaking at 7 kW" src="https://wingolog.org/pub/may-power.jpg"/&gt;&lt;p&gt;With practically no heating needs now, as you can imagine, I am just
feeding a lot of excess to the grid.  We’re halfway through May, just
coming through a cold snap (the peasant lore is that we just passed the
&lt;i&gt;saints de glace&lt;/i&gt;, the date you need to wait for to plant crops that
aren’t frost-hardy), but still we’ve produced more than twice as much as
we’ve consumed (550 kWh vs 220 kWh), and essentially all the excess goes
to the grid.  The 7 kWh battery is quite enough to cover night-time
electricity needs.&lt;/p&gt;&lt;p&gt;I didn’t know before, but often a solar panel installation doesn’t work
when the grid is down.  This is because the inverters that convert the
DC from the panels to AC for the house need to match phase with the
grid, and if the grid’s phase signal is down, they stop.  It’s also for
safety, so that line workers can repair downed lines without worrying
that every house is a live wire.  I spent a little extra to install a
&lt;a href="https://solar.huawei.com/en/products/HUAWEI-SmartGuard/"&gt;cutout&lt;/a&gt; that
allows the house to run in “island mode” if the grid is down.  We almost
never have that situation here, though, but it seemed prudent that if we
were going all-in on electricity, that perhaps we should take
precautions.&lt;/p&gt;&lt;p&gt;When you buy a solar installation, you can either have little DC/AC
inverters attached to the back of each panel (&lt;i&gt;microinverters&lt;/i&gt;), or feed
DC from all panels wired in series (they call them &lt;i&gt;strings&lt;/i&gt;; there may
be 2 or 3 of them in a home setup) to a central inverter.  I have the
latter.  The panels happen to be assembled locally by
&lt;a href="https://www.rexel.fr/frx/Cat%C3%A9gorie/Production-d'%C3%A9nergie---Photovolta%C3%AFque/Module-photovolta%C3%AFque/Module-rigide/Module-MaviWatt-500Wc-Biverre-Bifacial-Garantie-30-ANS/MVWCP035023/p/74467948"&gt;MaviWatt&lt;/a&gt;,
though surely the cells themselves are from China.  My panels are
installed on top of the ceramic roof tiles with little clips and an
aluminum structure.  (It used to be that sometimes panels would replace
tiles and become the roof.  That’s not done so much any more here.)
Installation is, like, 60% of the price of solar.  Often you need
scaffolding, though my installers just used ladders; perhaps living in
the mountains where I am, there are more people used to doing ropes and
rock-climbing and such.  I don’t think they took as much care of
themselves as they should, though.&lt;/p&gt;&lt;p&gt;My inverter is made by Huawei (SUN2000), as is my battery and the cutout
(“backup”) box.  Some batteries have their own microinverter, allowing
them to consume and produce AC, but this one is DC, hence the need to
have the same brand as the inverter.  It sends all my electricity usage
data to China or something, so that it can send it to the app on my
phone.  It’s not ideal from an geopolitical perspective but it is good
kit.&lt;/p&gt;&lt;h3&gt;sedimentation&lt;/h3&gt;&lt;p&gt;Although we haven’t hit the height of summer yet, I would like to offer
a few observations that have precipitated out of solution.&lt;/p&gt;&lt;p&gt;Firstly, at least in my house, the baseline load without heating is
pretty low: 200 or 300 watts or so.  (I didn’t know this before looking
at Huawei’s app.)  We have a recently renovated, not tiny, but otherwise
normal sort of house with, you know, the usual lot of modern
conveniences, idle chargers plugged in here and there, and also my work
computers and such, and it all runs on less than a handful of the old
60W bulbs.  That’s interesting.&lt;/p&gt;&lt;p&gt;As far as actual load, there are only a few things that count: heating,
when it’s cold; it can easily average 2 kW on a cold day.  Plug in the
electric car (I don’t have a wall box yet, just with the mains plug),
that’s another kilowatt.  I hardly drive, though, so it’s not a huge
load.  Using hot water is perhaps the most surprising thing: it can
cause a spike up to 6 kW, over a short time, despite the heat coming
from the heat pump; probably there is some tuning to do there.  The oven
and stove are little tiny blips.  There’s the kettle, but it’s also a
little blip.  &lt;i&gt;Nothing else matters&lt;/i&gt;: not the dishwasher, not the
washing machine, nothing.  You can leave the lights on all day and it
just doesn’t matter.&lt;/p&gt;&lt;p&gt;Call me naïve, but I had hoped that solar would help my electricity
usage in winter.  This is simply not the case.  Though the heat pump is
efficient, there does not appear to be a magical energy solution for
December, which is the bulk of my energy usage.  My electricity bill is
fixed-rate: 20 cents per kWh used.  Using 4000 kWh or so from the grid
over winter costs me 800€; annoying.  I don’t have a natural
before-and-after experiment as we added on to the house as we were
renovating, but for context, in my previous poorly-insulated rental
house that was half the size of this one, we’d pay 2000€ or so per year
for heating oil.  Perhaps I can lower the 800€ via variable-rate
metering, to let the battery do some arbitrage, but there are some
fundamental constraints that can’t be finagled away.&lt;/p&gt;&lt;p&gt;When I got my solar panels, I was resigned to never getting peak power,
as they are on two different sections of the roof.  It turns out that
doesn’t matter: firstly, because 9.5 kW is a lot of power, as you can
appreciate from the numbers above.  I could never do anything with 9 kW.
But secondly, because power isn’t equally valuable at different times of
the day: by having east and west roof pitches, I can start producing
earlier and continue producing later than if I had, say, a flat roof
with panels tilted to the south.  And the morning and the evening are
the peak hours both for my house and for the grid, so that lets me
consume more of my local production both when I need it and when the
grid is under higher stress.&lt;/p&gt;&lt;p&gt;I was interested to hear that Alec Watson of &lt;a href="https://www.youtube.com/@TechnologyConnections"&gt;Technology
Connections&lt;/a&gt; had reservations about residential rooftop solar.  I found a &lt;a href="https://youtu.be/C4cNnVK412U?si=OEKrE4AJMrJGzcXF&amp;amp;t=787"&gt;video in which
he explains his
perspective&lt;/a&gt;,
which has a delightfully socialist character.  His beef is partly due to the
&lt;a href="https://en.wikipedia.org/wiki/Net_metering"&gt;net metering&lt;/a&gt; scheme in
some parts of the US, in which each kWh fed to the grid makes your meter
run backwards; Watson finds it unfair, because it lets those wealthy
households who have the capital to install solar to opt out of paying
for the grid, which is a social good.  In some cases, these households
actually capture a part of what consumers pay for the grid, unlike
industrial producers who are paid wholesale rates that don’t include
transmission.  Also, he finds it less efficient overall to install solar
panels on houses rather than in bigger solar parks; each euro that
society allocates to solar would go farther if we pooled them together.&lt;/p&gt;&lt;p&gt;Both points are interesting, but I would offer a couple responses.
Firstly, at least in Europe, net metering is not really a thing; we have
smart meters and I hear from friends in Portugal that there can even be
a charge for grid injection at some times, if the grid is overloaded.
France’s case is a bit weirder; I wouldn’t have gotten as large a system
as I did, but there was a government program to offer a fixed buyback
rate of 7 cents per kWh, stable for 20 years, if you installed more than
9 kW of panels.  But given the lack of solar in December, I still pay
the grid when I need energy the most.&lt;/p&gt;&lt;p&gt;Putting solar panels on roofs is indeed less efficient than putting them
on a field.  But, we are not in a situation of scarce solar panels:
&lt;a href="https://bsky.app/profile/solarchase.bsky.social/post/3mjynhkkphs2k"&gt;China could make another 350 GW of panels this year if there were
demand&lt;/a&gt;.
An incentive like the 7-cent buyback rate encourages capital allocation
to solar, effectively calling these panels into existence.  The bank
loans me 20k€ at 4%, and the elimination of 3000 kWh that I would have
bought from the grid in a year plus the 9000 kWh that I sell to the grid
covers the cost entirely, and I get a life insurance policy on the
remaining principal.  It’s not a &lt;i&gt;great&lt;/i&gt; investment financially but it
doesn’t cost me anything either.&lt;/p&gt;&lt;h3&gt;sin&lt;/h3&gt;&lt;p&gt;As a person with a conscience, I have always experienced questions of
energy as questions of sin; to leave a light on is not simply
inefficient but a moral failing.  Each kilometer a car travels on fossil
fuel carries with it a quantum of guilt and must be justified in some
way, otherwise a moral stain attaches.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Solar panels and electrification changes all this.&lt;/i&gt; 8 or 9 months out
of the year, I live in a world of abundance: the electrical generation
capacity that I have called into existence is free, clean, and much,
much more than I need.  Owning and operating a car still has
externalities, but the emissions and cost aspects are entirely gone.
It’s a funny feeling, and disorienting.&lt;/p&gt;&lt;p&gt;I grew up in the south of the US, where everyone has air conditioning.
I came to see it as sinful, too; burning things and making emissions
just so you could be a bit more comfortable.  I haven’t lived in air
conditioning since then, but it does get hot in summer, and I would be
more comfortable if I could pump heat out of my house.  &lt;i&gt;Now I can.&lt;/i&gt; I
have excess power available right when air conditioning (or, in my case,
floor cooling) is needed.  On a societal level, solar plus air
conditioning is going to be a key part keeping our cities liveable while
we ride out higher temperatures.&lt;/p&gt;&lt;h3&gt;‘centers&lt;/h3&gt;&lt;p&gt;It is with a sense of dissonance, then, that I have been experiencing
Datacenter Discourse™: there is a lingering language of sin proceeding
from an environmentalism born in penury, in a world in which every
kilowatt-hour is precious and scarce.  If China has unallocated capacity
for another 350 GW of panels this year, why stress about a few GW of
datacenters?&lt;/p&gt;&lt;p&gt;Of course, there are many aspects to these AI datacenters, but today I
am just thinking about energy.  Given that each GW of datacenter places
extra demand on a grid, equivalent to 3 million times my home’s baseline
load, or maybe 300 thousand of its winter load, if society wants this
kind of datacenter to be a thing, it needs to add that amount of clean
energy to the grid, with adequate battery storage to even out supply.
We should, as a society, require this via legislation, because the
market seems only too happy to use natural gas or even coal if it is
marginally cheaper.  At least if the datacenter boom busts, we’d be left
with more clean energy production.&lt;/p&gt;&lt;p&gt;Conversely... and I don’t think I’m going too far here, but causing new
fossil generation to come online in 2026, or even prolonging the life of
existing generation, should result in the state confiscating all
property of those responsible.  (I have moderated my previous position,
which was hanging.)  Such people are not fit to live in society, so
society should not allow them to own things.&lt;/p&gt;&lt;p&gt;Anyway.  I think that those of us that wish “AI” were not a thing are
losing the battle, and that we should prepare to fall back to more
defensible positions; otherwise we risk a rout.  A requirement to bring
additional clean capacity online in sufficient amounts should be a
baseline ask when it comes to datacenters.  We have the productive
capacity in the form of solar panels, at an affordable price, more than
enough space in terms of the existing cropland that is inefficiently
turned into ethanol to burn, batteries are a thing, and we just lack the
political will to turn what could be into what is.&lt;/p&gt;&lt;p&gt;And as for AI datacenters themselves: there are enough aspects to argue
about as it is.  We do ourselves a disservice by weighing down the
Discourse with outdated ideas of what is and isn’t possible.&lt;/p&gt;&lt;/div&gt;</content>
    <link href="https://wingolog.org/archives/2026/05/16/soot-solar-sedimentation-sin-centers"/>
    <published>2026-05-16T19:29:02+00:00</published>
  </entry>
  <entry>
    <id>https://piware.de/post/2026-05-18-leaving-redhat/</id>
    <title>Martin Pitt: Leaving Red Hat</title>
    <updated>2026-05-18T00:00:00+00:00</updated>
    <author>
      <name>Martin Pitt</name>
    </author>
    <content type="html">In December 2016 I left Canonical with one sad and one happy eye, with lots of good memories. Now it’s time to revisit some more!
Starting at Red Hat back then was quite a cultural shock, of course. I got used to the new headwear fashion quickly:

But never really to the rest of the formal dress attire:

The drinking habits I was familiar with, and I quickly learned enough Czech to get “dvě piva prosím”:</content>
    <link href="https://piware.de/post/2026-05-18-leaving-redhat/"/>
    <published>2026-05-18T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://www.gimp.org/news/2026/05/20/gimp-msix-bump/</id>
    <title>GIMP: GIMP on MS Store now requires Windows Build 20348</title>
    <updated>2026-05-19T22:00:00+00:00</updated>
    <author>
      <name>GIMP</name>
    </author>
    <content type="html">&lt;p&gt;We received some informal reports in the Microsoft Store reviews
telling us that &lt;span class="caps"&gt;GIMP&lt;/span&gt; updates were deleting user data! In particular, plug-ins, themes, brushes, user settings and other add-ons were not being kept during an update from the store.&lt;/p&gt;
&lt;p&gt;To resolve this, the updated version of &lt;span class="caps"&gt;GIMP&lt;/span&gt; &lt;strong&gt;from the Microsoft Store&lt;/strong&gt; will require Windows 11 or at least Windows Server 2022 (Windows &lt;span class="caps"&gt;NT&lt;/span&gt; Build 10.0.20348.0).&lt;/p&gt;
&lt;p&gt;Windows 10 is still supported, but only when &lt;span class="caps"&gt;GIMP&lt;/span&gt; is &lt;a href="https://www.gimp.org/downloads/"&gt;installed from our
&lt;code&gt;.exe&lt;/code&gt; installer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note that we are no longer able to support versions of Windows older than Windows 10, and can no longer support 32-bit systems running Windows.&lt;/p&gt;
&lt;p&gt;Installing the update will prevent future data loss during upgrades.&lt;/p&gt;
&lt;h2 id="technical-details"&gt;Technical details&lt;a class="headerlink" href="https://www.gimp.org/feeds/atom.xml#technical-details" title="Permanent link"&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was being caused by the way &lt;code&gt;MSIX&lt;/code&gt; (the format of apps
distributed on Microsoft Store, &lt;span class="caps"&gt;GIMP&lt;/span&gt; included) is designed,
which prefers sandboxed user data (like Flatpak and Snap).
We have been trying to work with this requirement when
running from &lt;span class="caps"&gt;MSIX&lt;/span&gt;, but were not successful.&lt;/p&gt;
&lt;p&gt;So, to fix this packaging limitation, we were given the special “restricted capability” &lt;code&gt;unvirtualizedResources&lt;/code&gt;
(specifically &lt;code&gt;virtualization:ExcludedDirectory&lt;/code&gt;), to preserve user data on &lt;code&gt;%AppData%\GIMP&lt;/code&gt;, just as the &lt;code&gt;.exe&lt;/code&gt; installer does. This is similar to what we do on other sandbox distributions such as Flatpak and Snap.&lt;/p&gt;
&lt;p&gt;After the update, &lt;span class="caps"&gt;GIMP&lt;/span&gt; user data will be copied on upgrades.&lt;/p&gt;
&lt;p&gt;The update does not affect images or other resources stored outside your &lt;span class="caps"&gt;GIMP&lt;/span&gt; folder.&lt;/p&gt;
&lt;h2 id="how-to-migrate-the-previous-user-data"&gt;How to migrate the previous user data&lt;a class="headerlink" href="https://www.gimp.org/feeds/atom.xml#how-to-migrate-the-previous-user-data" title="Permanent link"&gt;¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This restricted capability is only available on Windows &lt;span class="caps"&gt;NT&lt;/span&gt; Build 10.0.20348.0 and later.
So, users with older Windows versions will need to use the &lt;code&gt;.exe&lt;/code&gt; installer.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: the binaries inside the &lt;code&gt;.exe&lt;/code&gt; installer and the &lt;code&gt;.msix&lt;/code&gt; are exactly the same.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For users who were using the &lt;span class="caps"&gt;MS&lt;/span&gt; Store version until now and are
switching to the &lt;code&gt;.exe&lt;/code&gt; installer, here are instructions in order not to
lose your configuration data from the &lt;span class="caps"&gt;MS&lt;/span&gt; Store version:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Manually locate your config dir at &lt;code&gt;%LOCALAPPDATA%\Packages\&lt;/code&gt; (you
   may just copy-paste this string into the Windows Explorer).&lt;/li&gt;
&lt;li&gt;Search a folder starting with &lt;code&gt;GIMP&lt;/code&gt; (with random numbers and letters
   after that) at this location.&lt;/li&gt;
&lt;li&gt;From there, navigating down to &lt;code&gt;LocalCache\Roaming\&lt;/code&gt; where you will
   find a folder named &lt;code&gt;GIMP&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Copy this &lt;code&gt;GIMP&lt;/code&gt; folder into &lt;code&gt;%APPDATA%&lt;/code&gt; (again, just copy-paste
   &lt;code&gt;%APPDATA%&lt;/code&gt; into the Windows Explorer to find the correct
   location).&lt;br/&gt;
   Note that maybe the folder &lt;code&gt;%APPDATA%\GIMP\&lt;/code&gt; already exists, in
   particular if you also used the &lt;code&gt;.exe&lt;/code&gt; installer at some point. If
   so, it is up to you to decide whether you want to override the data
   already present with the ones from the &lt;span class="caps"&gt;MS&lt;/span&gt; Store &lt;span class="caps"&gt;GIMP&lt;/span&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This procedure is a one-time thing as a workaround to this exceptional
issue. You won’t have to do it again in the future!&lt;/p&gt;</content>
    <link href="https://www.gimp.org/news/2026/05/20/gimp-msix-bump/"/>
    <published>2026-05-19T22:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/hughsie/2026/05/20/lvfs-sponsorship-announcement-hp/</id>
    <title>Richard Hughes: LVFS Sponsorship Announcement: HP</title>
    <updated>2026-05-20T08:09:23+00:00</updated>
    <author>
      <name>Richard Hughes</name>
    </author>
    <content type="html">&lt;p&gt;Some more great news: I’m pleased to announce that &lt;a class="external" href="https://www.hp.com/us-en/workstations/"&gt;HP&lt;/a&gt; has also agreed to be premier sponsor for the &lt;a class="external" href="https://fwupd.org/"&gt;Linux Vendor Firmware Service (LVFS)&lt;/a&gt; as part of our &lt;a class="external" href="https://docs.google.com/presentation/d/1l_Rmkn2-UwOkS0XK5d6u9pi29TZpmG-upa4Lu5HuEy4/edit?usp=sharing"&gt;sustainability effort&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.gnome.org/hughsie/files/2026/05/Screenshot-From-2026-05-20-10-07-01.png"&gt;&lt;img alt="list of vendors sponsoring the LVFS service" class="aligncenter size-large wp-image-10039" height="371" src="https://blogs.gnome.org/hughsie/files/2026/05/Screenshot-From-2026-05-20-10-07-01-1024x576.png" width="660"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With the industry support from HP (and our existing sponsors of Lenovo, Dell, Framework, OSFF and of course  Linux Foundation and Red Hat) we can turbo-charge the growth of the LVFS even more. Thanks!&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/hughsie/2026/05/20/lvfs-sponsorship-announcement-hp/"/>
    <published>2026-05-20T08:09:23+00:00</published>
  </entry>
  <entry>
    <id>https://samthursfield.wordpress.com/2026/05/21/status-update-21st-may-2026/</id>
    <title>Sam Thursfield: Status update, 21st May 2026</title>
    <updated>2026-05-21T09:03:26+00:00</updated>
    <author>
      <name>Sam Thursfield</name>
    </author>
    <content type="html">&lt;p class="wp-block-paragraph"&gt;I often write about how when stuff works well, you take it for granted.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;It’s true for technology: when’s the last time you hit a compiler bug in GCC? Once upon a time these were a common thing and you had to choose your C compiler wisely. Yet I haven’t recently seen an article that says “GCC is going great” .&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;It’s true for people too. When someone does an excellent job maintaining an open source project then, they do occasionally get some gratitude, but — if you do a &lt;em&gt;bad&lt;/em&gt; job, it’s amazing how quickly the negative comments pile up in the issue tracker, many of which taking subtle or not-so-subtle digs at the project owners. Maybe we created this situation for ourselves by having a prominent “report issue” button but no corresponding “send flowers to the maintainer” button.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;On that note, a hat tip to Carlos Garnacho for all his work on the Localsearch extractor sandbox which recently got a shout out for its &lt;a href="https://www.openwall.com/lists/oss-security/2026/05/01/14"&gt;“extremely strong”&lt;/a&gt; design.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;(It’s worth noting that Localsearch also stopped using GStreamer to parse media files altogether, which the discussion in that thread missed. We love GStreamer but it isn’t the right tool for metadata scanning. The 3.9 and 3.10 series use libav/ffmpeg instead, but given that US software patent laws make it tricky for USA folk to distribute that, the plan is to move to using &lt;a href="https://github.com/MediaArea/MediaInfoLib"&gt;MediaInfoLib&lt;/a&gt;)&lt;/p&gt;
&lt;h2 class="wp-block-heading"&gt;Fairphone 5&lt;/h2&gt;
&lt;p class="wp-block-paragraph"&gt;It’s coming up to two years since I &lt;a href="https://samthursfield.wordpress.com/2024/09/17/fairphone-5-review/"&gt;switched to a Fairphone 5&lt;/a&gt;. The real proof of this device will be in 2033 when I manage ten years of using the same phone.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Meanwhile, I recently had some issues with it not charging via the USB-C port. I thought it might be a bit tricky to fix, but it really is easy: buy the &lt;a href="https://www.fairphone.com/shop/fairphone-5-usb-c-port-268"&gt;replacement part&lt;/a&gt; (about 20€), take off the back cover, remove a few small screws and switch over the whole USB port + speaker unit.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;I hear some fellow Android users complaining about Alphabet/Google’s intrusive AI integration. Apparently the power button is now the AI button? I use the stock Android, and I know vendors have their hands tied somewhat by Alphabet/Google, so its worth noting that disabling the AI integration on the Fairphone 5 is &lt;a href="https://support.fairphone.com/hc/en-us/articles/27488373522194-Google-Gemini-AI-assistant-on-Android"&gt;a single config setting&lt;/a&gt;.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;I’d be interested to know more about the kernel version as it is old as hell. I guess this is a vendor/Android thing, and hopefully most of the many known vulnerabilities in this old version of Linux are mitigated by sandboxing higher up in Android. If you’re a high risk cybercrime target then I would definitely not recommend using the vendor Android OS on this device. (Probably best to avoid Android altogether if this is your situation!)&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;So its not perfect, but I just wanted to shout out again that there are some good people doing good work here. If only all smartphones were built like this one.&lt;/p&gt;
&lt;h2 class="wp-block-heading"&gt;Korg Minilogue XD&lt;/h2&gt;
&lt;p class="wp-block-paragraph"&gt;One reason I’m not writing much about open source software is that I’m spending a lot of my time outside work making music in various guises, these days mainly as part of soon to be huge Galician disco revival group Muaré. This band needs a website, so in future I don’t have to &lt;a href="https://www.instagram.com/muare.music/"&gt;link you to Instagram&lt;/a&gt;, but you know how the world is at the moment. We do at least have a &lt;a href="https://muaremusic.bandcamp.com/album/ep"&gt;Bandcamp page&lt;/a&gt;.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;When it comes to music gear, I seem to be a Yamaha guy. It’s amazing actually that the same company that made my trombone also makes excellent digital pianos, and if and when I need a motorbike, Yamaha also sells &lt;em&gt;those&lt;/em&gt;.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;When it comes to synths though I’ve been really enjoying the &lt;a href="https://www.soundonsound.com/reviews/korg-minilogue-xd"&gt;Korg Minilogue XD&lt;/a&gt;. It’s cheap, built like a tank and its ten years old so there are plenty of second hand models around. It’s not fucking Behringer (please &lt;a href="https://www.vice.com/en/article/a-major-synth-company-created-this-fake-product-to-attack-a-journalist/"&gt;don’t give money to Behringer&lt;/a&gt;). It’s simple and sounds great.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;But most impressively, it support plugins via a &lt;a href="https://github.com/korginc/logue-sdk"&gt;freely available SDK&lt;/a&gt;. You can develop your own custom digital oscillators and effects for this thing and deploy them over USB. Of all major pro audio manufacturers, Korg are the only company I know to support this. So even though the hardware is now 10 years old, it can still learn new tricks, and there is an active scene of both free and commercial plugins for the platform. Perhaps the most active commercial outfit is &lt;a href="https://www.sinevibes.com/korg/"&gt;Sinevibes&lt;/a&gt;. There is, of course, &lt;a href="https://www.reddit.com/r/LogueSDK/"&gt;reddit&lt;/a&gt;. The SDK is not truly open source (and few things in pro audio ever are) but it’s free from any licensing fees, and the whole thing is &lt;a href="https://github.com/korginc/logue-sdk/"&gt;sat here in a Git repo&lt;/a&gt;. Pretty good.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;If I’d had more time to prepare I might have a video here of some cool Minilogue XD tunes I made. But I guess you’ll have to wait til next month for that. Until then!&lt;/p&gt;</content>
    <link href="https://samthursfield.wordpress.com/2026/05/21/status-update-21st-may-2026/"/>
    <published>2026-05-21T09:03:26+00:00</published>
  </entry>
  <entry>
    <id>https://barthalion.blog/flathub-internals-cdn-and-deltas/</id>
    <title>Bart Piotrowski: Why are Flathub downloads so slow sometimes?</title>
    <updated>2026-05-21T13:11:00+00:00</updated>
    <author>
      <name>Bart Piotrowski</name>
    </author>
    <content type="html">&lt;p&gt;It's probably not your fault.&lt;/p&gt;
&lt;p&gt;On a cache miss, there are two things a reverse proxy (which Fastly is to us) can do. It can make the client wait until the proxy itself fetches the requested content and then serve it, with subsequent requests being served from the cache. From a user's perspective, it means staring at "hung" process, and people tend not to be understanding when a program is stuck seemingly doing nothing.&lt;/p&gt;
&lt;p&gt;Instead, the proxy can stream the response from the origin, caching it at the end. This makes the client receive the data right away, although it's not without drawbacks.&lt;/p&gt;
&lt;p&gt;In a streaming setup like Flathub's, an all-MISS path adds some upstream latency before the first byte, but also limits the download speed to what the slowest link can deliver. As we don't run servers in the same datacenter or on a single backbone network, the hop from Fastly through the caching proxy to the master server incurs a penalty that may affect how quickly the data gets back.&lt;/p&gt;
&lt;p&gt;In order to cache files larger than 20MB, Fastly expects customers who use streaming misses to use segmented caching. Anything larger than that gets broken down into smaller chunks. When Fastly wants the data from us, it will add a &lt;code&gt;Range&lt;/code&gt; header specifying which bytes we should respond with. Fastly will then serve the request after reconstructing the file from various chunks. Our caching proxies also use the value of the &lt;code&gt;Range&lt;/code&gt; header in the caching key to avoid requesting the full file over and over again from the master server as well.&lt;/p&gt;
&lt;p&gt;While great for caching, many concurrent range MISSes can turn what would be a sequential file read into scattered, random reads. It wouldn't matter with SSD or NVMe, but as the repository is stored on HDDs, when combined with streaming misses, it can turn cold transfer speed into &lt;code&gt;min(network bottleneck, ZFS random-read bottleneck)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Counterintuitively, you may improve your download speeds by aborting the ongoing Flatpak operation and starting it again. While the initial request was slow, there's a non-zero chance it went through all the caching layers and it will become a cache hit in the meantime.&lt;/p&gt;
&lt;h2 id="flatpak"&gt;Flatpak&lt;/h2&gt;&lt;p&gt;Let's talk Flatpak. When installing or upgrading applications, Flatpak will try to use delta files. A typical delta is an update file that contains only the difference between versions. There are also from-scratch deltas, which effectively are an archive with all files required to install an app from scratch, thus the name.&lt;/p&gt;
&lt;p&gt;Flathub generates a single upgrade delta and a from-scratch delta for the latest version. Delta generation is an expensive process in terms of disk reads and writes, but also disk space. Because our ZFS setup isn't exactly the fastest, generating more delta files also affects how quickly we can publish an update. Yes, in theory we could be doing this out of band but we don't. In hindsight, Titanic wasn't unsinkable after all.&lt;/p&gt;
&lt;p&gt;What happens if you are not updating often enough? A lot of suffering. Flatpak will download each missing file between the version you are on and the one you want to upgrade to, separately. This is an almost certain cache miss causing even more random seeks on the master server. At this point Flatpak would be better off downloading the from-scratch delta but it can't. The behaviour is controlled by OSTree, which &lt;a href="https://github.com/ostreedev/ostree/blob/1d2b902b5513287355ad3322cb4027b67bb71b88/src/libostree/ostree-repo-pull.c#L3275"&gt;doesn't offer any knobs to affect it&lt;/a&gt;. It is the right choice if the goal is to limit the bandwidth used by the client to fetch updates, but an incredibly bad one for anyone on a reliable connection; downloading a single large file is almost always faster than fetching multiple smaller ones.&lt;/p&gt;
&lt;p&gt;What do? Some brave soul could fix OSTree to apply a better heuristic on when to use from-scratch deltas for upgrades, or at least make it expose an API that lets Flatpak choose. For the rest of us mere mortals, we can only update regularly or wait patiently for the update to finish.&lt;/p&gt;</content>
    <link href="https://barthalion.blog/flathub-internals-cdn-and-deltas/"/>
    <published>2026-05-21T13:11:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/mcatanzaro/2026/05/21/single-click-code-execution-exploit-for-evince-atril-and-xreader/</id>
    <title>Michael Catanzaro: Single-Click Code Execution Exploit for Evince, Atril, and Xreader</title>
    <updated>2026-05-21T20:49:51+00:00</updated>
    <author>
      <name>Michael Catanzaro</name>
    </author>
    <content type="html">&lt;p class="wp-block-paragraph"&gt;CVE-2026-46529 is an argument injection vulnerability in Evince, Atril, and Xreader caused by missing shell quoting when composing a command line. The reporter, João Medeiros, has published a &lt;a class="external" href="https://github.com/N1et/CVE-2026-46529"&gt;GitHub repo&lt;/a&gt; for the CVE and a &lt;a class="external" href="https://medeiros.zip/posts/CVE-2026-46529-evince"&gt;blog post&lt;/a&gt; with the story of how he discovered the flaw and developed the exploit. He also created an &lt;a class="external" href="https://github.com/mate-desktop/atril/security/advisories/GHSA-vgv2-m826-8f6f"&gt;Atril security advisory&lt;/a&gt; and an &lt;a class="external" href="https://gitlab.gnome.org/GNOME/evince/-/work_items/2153"&gt;Evince issue report&lt;/a&gt;.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;The vulnerability is fixed in:&lt;/p&gt;
&lt;ul class="wp-block-list"&gt;
&lt;li&gt;Evince 48.4 (&lt;a class="external" href="https://gitlab.gnome.org/GNOME/evince/-/commit/970c219e861a5fcc3e7b9e05bedf18cf0de39245"&gt;fix commit&lt;/a&gt;) (I originally reported that it is fixed in 48.2, but there was no successful release for that tag)&lt;/li&gt;
&lt;li&gt;Atril 1.28.4 and 1.26.3 (&lt;a class="external" href="https://github.com/mate-desktop/atril/commit/b989b7922a454ed81f8bb14786a958828513f576"&gt;fix commit&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Xreader 4.6.4 and 3.6.7 (&lt;a class="external" href="https://github.com/linuxmint/xreader/commit/50052eaa91c3c750c51c245799e3747495feeece"&gt;fix commit&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="wp-block-paragraph"&gt;If you use one of these PDF readers, update immediately. Or at least please be seriously paranoid about clicking on links in PDFs until you do update.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;&lt;a class="external" href="https://gitlab.gnome.org/GNOME/papers/-/commit/1b82bf627b4d8b414a57b55a9095e6d361799d6c"&gt;This vulnerability also affects Papers&lt;/a&gt;, but it’s probably not urgent to update Papers. (No, not because it uses Rust. Keep reading!)&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;The Flatpak sandbox could have drastically reduced the danger of this attack, limiting the compromise to only files that you had previously opened in the PDF reader. Sadly, Evince and Papers both use sandbox holes that render the sandbox totally meaningless. (Atril and Xreader are not available on Flathub.)&lt;/p&gt;
&lt;h2 class="wp-block-heading"&gt;The Vulnerability&lt;/h2&gt;
&lt;p class="wp-block-paragraph"&gt;When you click on a link in a PDF, Evince may execute itself to display the link. Normally the command line used would look something like this:&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;&lt;code&gt;/usr/bin/evince --named-dest=/home/foo/hello.pdf&lt;/code&gt;&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;But an evil PDF may trick Evince into executing a command that is quite different than expected:&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;&lt;code&gt;/usr/bin/evince --named-dest= --gtk-module=/home/foo/evil.so /home/foo/hello.pdf&lt;/code&gt;&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Oops. The first part of the command is always going to be &lt;code&gt;/usr/bin/evince&lt;/code&gt;, but the evil PDF is nevertheless able to unexpectedly load a GTK module into Evince. The fix is to quote the untrusted input using &lt;code&gt;g_shell_quote()&lt;/code&gt; to ensure it cannot “break out” of its intended context:&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;&lt;code&gt;/usr/bin/evince --named-dest='/home/foo/hello.pdf'&lt;/code&gt;&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Or:&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;&lt;code&gt;/usr/bin/evince --named-dest=' --gtk-module=/home/foo/evil.so /home/foo/hello.pdf'&lt;/code&gt;&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Much better: now the threat is neutralized. &lt;code&gt;g_shell_quote()&lt;/code&gt; is safe to use even if the untrusted input itself contains quotes. (However, beware: this only works because GLib is parsing the command line itself, and GLib is not a real Unix shell. &lt;a class="external" href="https://gitlab.gnome.org/GNOME/glib/-/merge_requests/5187/#note_2762996"&gt;It’s not safe if the input is going to be passed to an actual Unix shell.&lt;/a&gt; It might not even be theoretically possible to do that safely, because it’s valid for filenames to contain entirely arbitrary characters!)&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;All GTK 3 apps support the &lt;code&gt;--gtk-module&lt;/code&gt; command line argument for injecting a shared library into the application. The library may of course then execute whatever code it wants via its library constructor. But GTK 4 no longer has standard GTK command line flags, so this does not work for GTK 4 applications like Papers. It’s still possible to tell a GTK 4 app to load a GTK module, but only via environment variables, not via command line flags, and I don’t see any opportunity for the malicious command to set environment variables. It’s probably not possible to exploit this vulnerability in Papers: although it has the exact same vulnerability as the other PDF readers, the impact is different.&lt;/p&gt;
&lt;h2 class="wp-block-heading"&gt;The Exploit&lt;/h2&gt;
&lt;p class="wp-block-paragraph"&gt;So far this looks like a pretty typical security bug. OK, so if you trick the user into downloading an archive (or perhaps a git repo) that contains both a malicious PDF and also a malicious shared library, then you can trick the PDF reader into loading the shared library and thereby execute arbitrary code. That’s a pretty bad foreseeable exploit, sure, but at least the attacker is at considerable risk of arousing suspicion if the user is trying to download a PDF and also receives a shared library. You’d have to try pretty hard to hide the library in a forest of other boring files if you want the attack to look convincing and unsuspicious. Right?&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Nope.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;João used Claude Opus 4.7 to develop a sophisticated script for building malicious polyglot PDFs that are simultaneously both valid PDF files and also valid ELF binaries, so the attacker only needs to trick the victim into downloading one evil PDF file. When the victim clicks on a link in that PDF, the PDF reader will dlopen the PDF itself. The PDF/ELF polyglot’s library constructor will then execute arbitrary code. Much less suspicious, and much scarier. Polyglot files are &lt;a class="external" href="https://github.com/Polydet/polyglot-database"&gt;not entirely novel&lt;/a&gt;, but I’d still say this required substantial creativity and expertise from the AI, and substantial persistence from the human. Needless to say, very nice job to both Claude and João.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;You can easily build your own malicious PDF using the provided script and sample GTK module. The script in the Evince and Atril issue reports requires that the attacker predict the absolute path that the malicious PDF file will be saved to; however, João’s blog post and GitHub repo refine the exploit to remove that requirement.&lt;/p&gt;
&lt;h2 class="wp-block-heading"&gt;Thoughts on AI Vulnerability Reports&lt;/h2&gt;
&lt;p class="wp-block-paragraph"&gt;A human inspecting this code should have been able to find the parameter injection vulnerability, but that requires considerable time and effort, so unsurprisingly nobody did. We’re probably in for a rough time in the short term as the volume of AI-generated vulnerability findings remains temporarily very high and attackers have a much easier time crafting working exploits. But in the long term, I expect we are going to be much more secure than we were before, so this will be worth it.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;A human working alone would have almost certainly stopped and moved on after finding the vulnerability. Claude allowed taking the investigation much farther. It’s highly unusual for a GNOME vulnerability report to come with a working exploit. This is a dangerous change. Perhaps it will be a one-time event, but I suspect we will be seeing more frequent exploits in the future.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Silver lining: the exploit helps us better appreciate the severity of the issue. It’s often hard to assess how bad a vulnerability is. If not for the weaponized exploit, I would have thought this bug was not very scary, and would have treated it as not a big deal. We would have fixed it, perhaps or perhaps not with a CVE ID, surely without any blog post or fanfare, and probably without distro security updates. But since there is an exploit, we instead had no doubt that this vulnerability was dangerous, and were able to handle it accordingly.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Several GNOME projects have begun outright prohibiting all AI-generated contributions, including issue reports, with no exception for vulnerability reports. Such policies are misguided and unacceptable. I can sort of understand why some projects might (misguidedly) wish to prohibit AI-generated code contributions. OK, fine. But blocking AI vulnerability reports will make GNOME less safe. AI-assisted vulnerability reporting is the new industry standard for good reason: it is highly effective.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;Some humans are not good at preparing AI-assisted vulnerability reports and will spam maintainers with low-quality reports. Sometimes they will be outright bogus, although more often there may be valid underlying bugs with exaggerated severity claims or bad proof of concept demos. This is annoying, but bad issue reports are a cost we are just going to have to accept and deal with.&lt;/p&gt;
&lt;p class="wp-block-paragraph"&gt;The quality level of AI vulnerability reports reviewed by conscientious humans — as well as AI assessments of AI vulnerability reports — is now often quite encouraging. But just like humans, AIs may also miss things, especially subtle distinctions that may be highly relevant. Although I’m quite impressed with these AIs, we still need experienced humans to review and manage reports. Please don’t abuse the technology by submitting vulnerability reports that you do not understand or have not validated. And certainly please do not allow an AI agent to interact with an issue tracker on your behalf!&lt;/p&gt;
&lt;h2 class="wp-block-heading"&gt;For Security Geeks&lt;/h2&gt;
&lt;p class="wp-block-paragraph"&gt;This was my first time scoring a vulnerability using CVSS 4.0 rather than CVSS 3.1. It’s also the first time I wasn’t terribly confused about how to set the parameters, because the &lt;a class="external" href="https://www.first.org/cvss/v4.0/user-guide"&gt;scoring guide&lt;/a&gt; contained answers to all of my questions. Nice. My CVSS vector for CVE-2026-46529 is CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N, the base score is 8.4, and I’m pretty sure my choices for each parameter are good. By comparison, using CVSS 3.1 I came up with CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H and base score 7.8.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/mcatanzaro/2026/05/21/single-click-code-execution-exploit-for-evince-atril-and-xreader/"/>
    <published>2026-05-21T20:49:51+00:00</published>
  </entry>
  <entry>
    <id>https://ergaster.org/thoughts/front-server/</id>
    <title>Thibault Martin: I realized that A cheap VPS is a good front</title>
    <updated>2026-05-22T16:00:00+00:00</updated>
    <author>
      <name>Thibault Martin</name>
    </author>
    <content type="html">&lt;p&gt;I have a server at home. It runs a Kubernetes cluster and a few services. I want to expose them to the Internet, so I can e.g. share public links from my Nextcloud, or synchronize my Kobo reader with &lt;a href="https://grimmory.org/"&gt;Grimmory&lt;/a&gt;. But I don't want to expose my home IP to the world, and I want to have some reasonable protection against unsophisticated DoS attacks.&lt;/p&gt;
&lt;p&gt;I realized that I can achieve that with a cheap VPS that acts as a front, &lt;a href="https://www.haproxy.org/"&gt;HAProxy&lt;/a&gt;, and &lt;a href="https://www.wireguard.com/"&gt;Wireguard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I rented a tiny VPS for €4/month at &lt;a href="https://infrawire.fr/en"&gt;Infrawire&lt;/a&gt; (1 vCPU, 2 GB RAM, 25 GB NVMe). I installed a Debian 13 on it, because I want that front server to be as stable and low maintenance as possible, and installed the Debian-packaged HAProxy onto it. I also installed Wireguard. The VPS has a publicly accessible IP, so it will be my Wireguard server: my server at home can reach the VPS to establish a tunnel, the opposite is not true.&lt;/p&gt;
&lt;p&gt;On my k3s node, I've installed Wireguard as well. I configured Wireguard on the VPS and my k3s node to establish a tunnel between the two. I've also bound the sshd on my VPS to the wireguard address. Infrawire offers a console so I can unstick myself if I locked me out of my own server (e.g. by misconfiguring Wireguard on any side, or if my server at home had any failure).&lt;/p&gt;
&lt;p&gt;I pointed all my DNS records to the VPS. The HAProxy is a "dumb" tcp forwarder, so I can keep operating like before on my cluster. In particular, HAProxy doesn't do TLS termination. My certificates are fetched on my cluster by cert-manager like before, using the http-01 challenge and Let's Encrypt. I could also move to dns-01 challenges, but http-01 just works and lets me switch to a registrar without an API if need be.&lt;/p&gt;
&lt;p&gt;That way, I don't need a fixed IP at home, and I don't have to do any port-forwarding from my home router to my k3s cluster. Even better: the VPS has an anti-DDoS protection included, and I can also configure HAProxy to refuse too many connections from a same IP, I can make it close TCP connections that take too long to establish, and more. If my VPS gets hammered, I can still access my services from within my home network.&lt;/p&gt;</content>
    <link href="https://ergaster.org/thoughts/front-server/"/>
    <published>2026-05-22T16:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/chergert/2026/05/23/librebonjour/</id>
    <title>Christian Hergert: ((lib)Re)bonjour</title>
    <updated>2026-05-23T16:18:26+00:00</updated>
    <author>
      <name>Christian Hergert</name>
    </author>
    <content type="html">&lt;p&gt;I made another weird side project while unemployed. In fact I’ve wanted it for a while but once I learned that “Rebonjour” is the word for “hello again” I just had to finish the library.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;librebonjour&lt;/code&gt; is an asynchronous DNS-SD and mDNS client library for GLib applications. Or, more practically, it is a small GObject API over the two local service-discovery providers you are likely to find on a Linux system: Avahi and systemd-resolved.&lt;/p&gt;
&lt;p&gt;It does not link against either of them. It only talks to them over D-Bus.&lt;/p&gt;
&lt;p&gt;The reason for that is mostly boring, which is usually where the useful things are. Applications should not need to care if a machine has Avahi running, or if it is using systemd-resolved for mDNS. They should be able to discover a service, resolve it, maybe advertise something, and get on with whatever they were actually trying to do.&lt;/p&gt;
&lt;p&gt;So &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.Client.html"&gt;RebonjourClient&lt;/a&gt; selects a backend internally. If &lt;code&gt;org.freedesktop.Avahi&lt;/code&gt; is available on the system bus, it uses Avahi. If not, it falls back to systemd-resolved’s &lt;code&gt;org.freedesktop.resolve1&lt;/code&gt; API. If neither is around, availability checks fail like you would expect.&lt;/p&gt;
&lt;p&gt;The public API stays the same either way.&lt;/p&gt;
&lt;h2&gt;What It Does&lt;/h2&gt;
&lt;p&gt;There are three common things I wanted to make pleasant.&lt;/p&gt;
&lt;p&gt;First, one-shot discovery. Ask for the service types in &lt;code&gt;local&lt;/code&gt;, ask for instances of something like &lt;code&gt;_ipp._tcp&lt;/code&gt;, then resolve one of those instances into addresses and TXT metadata.&lt;/p&gt;
&lt;p&gt;Second, browser-style discovery. A &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.Browser.html"&gt;RebonjourBrowser&lt;/a&gt; owns a stable &lt;a class="external" href="https://docs.gtk.org/gio/iface.ListModel.html"&gt;GListModel&lt;/a&gt; of &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.Service.html"&gt;RebonjourService&lt;/a&gt; objects. That fits nicely into GTK code because the model object can stay the same while the contents change underneath it.&lt;/p&gt;
&lt;p&gt;Third, registration. You can describe a local service with &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.ServiceDescription.html"&gt;RebonjourServiceDescription&lt;/a&gt;, register it, and keep the returned &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.Registration.html"&gt;RebonjourRegistration&lt;/a&gt; alive for as long as the service should be advertised.&lt;/p&gt;
&lt;p&gt;Resolving a service gives you a &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.ResolvedService.html"&gt;RebonjourResolvedService&lt;/a&gt;. That contains the SRV result, TXT data, priority, weight, and a model of &lt;a class="external" href="https://librebonjour-941d6b.pages.gitlab.gnome.org/librebonjour-1/class.Endpoint.html"&gt;RebonjourEndpoint&lt;/a&gt; objects. The endpoints hold the &lt;a class="external" href="https://docs.gtk.org/gio/class.SocketAddress.html"&gt;GSocketAddress&lt;/a&gt; you would actually use to connect.&lt;/p&gt;
&lt;h2&gt;Why Two Backends&lt;/h2&gt;
&lt;p&gt;Avahi is the nicer backend for browsing. Its D-Bus API gives you long-lived browser objects and emits signals when services appear and disappear. That maps very naturally to &lt;a class="external" href="https://docs.gtk.org/gio/iface.ListModel.html"&gt;GListModel&lt;/a&gt; changes.&lt;/p&gt;
&lt;p&gt;systemd-resolved is different. It has useful DNS-SD and mDNS operations over D-Bus, but the browsing side is lookup-based. That means you can ask what is there, but you do not get the same live add/remove signal stream that Avahi provides.&lt;/p&gt;
&lt;p&gt;I did not want applications to have to care about that distinction unless they really want to. So the browser has &lt;code&gt;auto-refresh&lt;/code&gt; and &lt;code&gt;refresh-interval&lt;/code&gt; properties. With Avahi, &lt;code&gt;auto-refresh&lt;/code&gt; is effectively harmless because the model is already live. With systemd-resolved, it starts an internal refresh loop and updates the model for you.&lt;/p&gt;
&lt;p&gt;It is not magic. It is just putting the backend-shaped unpleasantness in one place so application code can stay boring.&lt;/p&gt;
&lt;h2&gt;Asynchronous with libdex&lt;/h2&gt;
&lt;p&gt;The whole thing is built on &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/index.html"&gt;libdex&lt;/a&gt;. Anything that might touch D-Bus or the network returns a &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/class.Future.html"&gt;DexFuture&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That means construction, availability checks, service-type lookup, instance lookup, resolving, registration, browser refresh, and unregistering are all future-based. If you are already writing fiber-style code with libdex, the API fits into that directly:&lt;/p&gt;
&lt;p&gt;[code language=”c”]&lt;br/&gt;
g_autoptr(RebonjourClient) client = NULL;&lt;br/&gt;
g_autoptr(GListModel) services = NULL;&lt;br/&gt;
g_autoptr(GError) error = NULL;&lt;/p&gt;
&lt;p&gt;if (!(client = dex_await_object (rebonjour_client_new (), &amp;amp;error)))&lt;br/&gt;
  g_error ("%s", error-&amp;gt;message);&lt;/p&gt;
&lt;p&gt;services = dex_await_object (rebonjour_client_lookup_instances (client,&lt;br/&gt;
                                                                0,&lt;br/&gt;
                                                                "_ipp._tcp",&lt;br/&gt;
                                                                NULL,&lt;br/&gt;
                                                                REBONJOUR_LOOKUP_FLAGS_NONE),&lt;br/&gt;
                             &amp;amp;error);&lt;br/&gt;
[/code]&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;0&lt;/code&gt; there means any interface. Passing &lt;code&gt;NULL&lt;/code&gt; for the domain uses &lt;code&gt;local&lt;/code&gt;. The common case should not require looking up interface indexes which I’m pretty sure most people reading this have never even done before.&lt;/p&gt;
&lt;h2&gt;Advertising&lt;/h2&gt;
&lt;p&gt;Advertising is where things get more system-policy-oriented.&lt;/p&gt;
&lt;p&gt;With Avahi, registration goes through Avahi’s D-Bus API. With systemd-resolved, registration uses &lt;code&gt;RegisterService&lt;/code&gt; and &lt;code&gt;UnregisterService&lt;/code&gt;, which are polkit-protected. Also, resolved needs full mDNS enabled with &lt;code&gt;MulticastDNS=yes&lt;/code&gt;; &lt;code&gt;MulticastDNS=resolve&lt;/code&gt; is enough to browse and resolve, but not enough to respond as a service.&lt;/p&gt;
&lt;p&gt;So librebonjour can expose one API for registration, but it cannot make host policy disappear. Applications still need to handle authorization failure, missing mDNS responder support, sandbox boundaries, or whatever policy the system administrator has decided is appropriate.&lt;/p&gt;
&lt;p&gt;That seems like the right way to demarcate things. The library should hide the provider mechanics, not the permissions of the platform.&lt;/p&gt;
&lt;h2&gt;Why&lt;/h2&gt;
&lt;p&gt;Mostly because I wanted this to exist.&lt;/p&gt;
&lt;p&gt;DNS-SD is handy. Local-network service discovery is still useful. But using it from a GLib application means either caring too much about the provider or writing just enough glue that every application gets to have its own slightly different version of the same code.&lt;/p&gt;
&lt;p&gt;And even worse is having to bundle things to build projects like Avahi for Flatpak when you only use the library which calls into D-Bus anyway.&lt;/p&gt;
&lt;p&gt;This is not a grand platform initiative. It is not something I am employed to maintain. So you know, use wisely.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/chergert/2026/05/23/librebonjour/"/>
    <published>2026-05-23T16:18:26+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/shivam/2026/05/25/journey-starts-gitg-port/</id>
    <title>Shivam: Journey Starts : Gitg Port to GTK4</title>
    <updated>2026-05-25T17:32:19+00:00</updated>
    <author>
      <name>Shivam</name>
    </author>
    <content type="html">&lt;h1&gt;&lt;img alt="" class="aligncenter wp-image-37 size-full" height="941" src="https://blogs.gnome.org/shivam/files/2026/05/ChatGPT-Image-May-24-2026-01_32_26-AM.png" width="1672"/&gt;&lt;/h1&gt;
&lt;h1 style="text-align: center;"&gt;&lt;em&gt;About Me &lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;Hello Everyone! I am Shivam, I am currently pursing my engineering in Electronics. I have been selected for GSoC 2026 for the port of GNOME-Gitg from GTK 3 to GTK 4. I am starting this blog in order to document my journey of porting &lt;strong&gt;&lt;a class="external" href="https://gitlab.gnome.org/GNOME/gitg"&gt;Gitg&lt;/a&gt;&lt;/strong&gt;. I have been contributing in GNOME from several months and in awe with the supportive and helpful nature of the community.&lt;/p&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;h1 style="text-align: center;"&gt;Project&lt;/h1&gt;
&lt;p&gt;As many of you probably know, Gitg is still using GTK3, which means it misses out on a lot of the improvements and features that came with GTK4. The main goal of this project is to port Gitg from GTK3 to GTK4 and then gradually modernize the application.&lt;/p&gt;
&lt;p&gt;The scope of the project itself is quite large, and that’s honestly one of the most exciting parts for me. Working on this port will help me understand the application interacts with different libraries and components behind the scenes.&lt;/p&gt;
&lt;p&gt;At the same time, I hope that this work will help the new contributors like me easier to get started contributing to the various GNOME projects &lt;img alt="🙂" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" style="height: 1em;"/&gt;&lt;/p&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;h1 style="text-align: center;"&gt;Conclusive Goal&lt;/h1&gt;
&lt;p&gt;The final goal of this project is to get Gitg building and running completely with GTK4 dependencies. At the moment, the application still fails to compile, which is expected since many GTK3 APIs are still present throughout the codebase.A separate &lt;a class="external" href="https://gitlab.gnome.org/GNOME/gitg/-/tree/gtk4?ref_type=heads"&gt;&lt;strong&gt;GTK4 branch&lt;/strong&gt;&lt;/a&gt; already exists where parts of the migration work have been started, and several components have already been adapted to GTK4. This project will continue building on top of that existing effort and gradually move the remaining parts of the application to the newer toolkit.&lt;/p&gt;
&lt;p&gt;I would also like to sincerely thank the contributor(s) who have worked on the GTK4 porting work earlier. Their efforts created the foundation for this project, and I’ll be continuing from the work they have already done.&lt;/p&gt;
&lt;h1&gt;&lt;/h1&gt;
&lt;h1 style="text-align: center;"&gt;Thank You For Reading!&lt;/h1&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;PS:- I would also like to thank &lt;strong&gt;&lt;a class="external" href="https://wiki.gnome.org/AlbertoFanjul.html"&gt;Alberto Fanjul&lt;/a&gt;&lt;/strong&gt; for mentoring me in this project and &lt;strong&gt;&lt;a class="external" href="https://gitlab.gnome.org/felipeborges"&gt;Felipe Borges&lt;/a&gt;&lt;/strong&gt; for this time and support.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/shivam/2026/05/25/journey-starts-gitg-port/"/>
    <published>2026-05-25T17:32:19+00:00</published>
  </entry>
  <entry>
    <id>https://www.nedrichards.com/2026/05/fuzzy-time-everywhere/</id>
    <title>Nick Richards: Fuzzy Time Everywhere</title>
    <updated>2026-05-26T20:57:00+00:00</updated>
    <author>
      <name>Nick Richards</name>
    </author>
    <content type="html">&lt;p&gt;I do not always want to know what time it is. This is a slightly awkward position for someone who keeps making clocks, but there we are. Quite often the useful answer is not &lt;code&gt;17:42&lt;/code&gt;. It is “quarter to six”, “nearly lunch” or “you should probably start thinking about leaving”. The precise time is useful when catching trains, baking things and joining calls; the rest of the time it can be a bit much.&lt;/p&gt;
&lt;p&gt;So I have been working on fuzzy time for a while. The first version I made was &lt;a href="https://github.com/nedrichards/fuzzy-time-gb/"&gt;for the Pebble&lt;/a&gt;, which remains one of those devices that makes later technology feel slightly ashamed of itself. A small always-on screen, good battery life, physical buttons and just enough personality. It’s not &lt;a href="https://tokyoflash.com/"&gt;tokyoflash&lt;/a&gt; after all.&lt;/p&gt;
&lt;p&gt;The current versions are &lt;a href="https://github.com/nedrichards/fuzzy-time-android-gb"&gt;Fuzzy Time GB&lt;/a&gt;, a Wear OS watch face, and &lt;a href="https://github.com/nedrichards/gnome-fuzzy-clock-gb"&gt;Fuzzy Clock GB&lt;/a&gt;, a GNOME Shell extension.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Fuzzy Time GB watch face showing a fuzzy time phrase" src="https://github.com/nedrichards/fuzzy-time-android-gb/raw/main/release-assets/screenshots/default.png"/&gt;&lt;/p&gt;
&lt;p&gt;The Android version is quite a funny object internally. It is a Watch Face Format v2 face, so the APK has no app code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-xml"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;android:hasCode="false"
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The face itself is declarative XML. Since writing thirty-six thousand lines of watch face XML by hand would be a cry for help, there is a generator which writes the cases out from the same fuzzy time rules. For every hour and every five-minute bucket it emits the condition, text and separate interactive and ambient versions.&lt;/p&gt;
&lt;p&gt;That sounds excessive until you look at the details; and then it still sounds excessive. There are lots of pernickety things that give this the correct &lt;code&gt;GB&lt;/code&gt; locale to my ears. “Five Past Midnight” is a real phrase. &lt;code&gt;23:58&lt;/code&gt; should say “Midnight”, and if the date is visible it should be tomorrow’s date. &lt;code&gt;11:58&lt;/code&gt; should say “Noon”. “O’Clock” wants different spacing and weight from “Twenty-five To”. Ambient mode wants smaller, quieter text. A round watch face leaves less room than you think it does. The watch face has a few small choices rather than a settings cathedral: warm white, cool white, soft green, dim amber; system font or &lt;a href="https://antonkoovit.com/typefaces/arvo"&gt;Arvo&lt;/a&gt;; optional radial complication slots above and below the text. The range complications are deliberately arcs around the edge rather than little widgets in the middle. They can show useful things, but they should not make the face stop being mostly words and calm black space.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Fuzzy Time GB GNOME Shell extension" src="https://github.com/nedrichards/gnome-fuzzy-clock-gb/raw/main/screenshot.png"/&gt;&lt;/p&gt;
&lt;p&gt;The GNOME version is the same idea on a different surface. It finds the existing clock label, listens to the same wall clock, respects the existing “show date” and “show weekday” settings, and changes the text. I have wanted to build something like this for years, partly because of &lt;a href="https://github.com/ebassi/word-clock-extension"&gt;Emmanuele Bassi’s word clock extension&lt;/a&gt;. That extension was great, but &lt;a href="https://www.nedrichards.com/2011/09/gnome-shell-iterations-what-you-need/"&gt;not quite the thing I wanted&lt;/a&gt;, so eventually I got around to making my own.&lt;/p&gt;
&lt;p&gt;One of the few design decisions left that I helped on in main GNOME (which is much better now) is that the shutdown and logout dialogue only updates its timing every so often. It could update every second; the computer is quite capable of counting. But it’s much more pleasant when the number doesn’t twitch constantly while you are trying to decide whether you meant to press the button.&lt;/p&gt;
&lt;p&gt;You can build both projects from source. I may choose to distribute them in a more structured fashion in future. The Android one is a minimal Wear OS watch face, and the GNOME one is a normal Shell extension that currently supports GNOME Shell 45 to 50.&lt;/p&gt;</content>
    <link href="https://www.nedrichards.com/2026/05/fuzzy-time-everywhere/"/>
    <published>2026-05-26T20:57:00+00:00</published>
  </entry>
  <entry>
    <id>https://mccalabrese.github.io/gnome-blog/posts/ges-sync/</id>
    <title>Michael Calabrese: Synchronizing Timeline Ticks with GES Framerates in Rust</title>
    <updated>2026-05-27T00:00:00+00:00</updated>
    <author>
      <name>Michael Calabrese</name>
    </author>
    <content type="html">&lt;p&gt;While working on my GSoC project (rewriting the Pitivi timeline in Rust), I ran into an issue getting precise UI ticks that map to the
absolute nanosecond timestamps of the video frames. Initially I hardcoded NTSC fractional math (24000/1001) to calculate the boundaries of frames.&lt;/p&gt;
&lt;p&gt;This led to issues with truncated timestamps, and had a glaring issue with other framerates (like 30fps). I needed a more robust solution that could handle any framerate and provide accurate tick positions.&lt;/p&gt;
&lt;p&gt;I assumed that I could extract the framerate directly from &lt;code&gt;ges::Timeline&lt;/code&gt;, however there is no direct getter in the Rust bindings. After some digging, I discovered that the framerate is actually stored in the &lt;code&gt;gst::Caps&lt;/code&gt; of the timeline's video stream as a &lt;code&gt;gst::Fraction&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="my-approach"&gt;My Approach&lt;/h3&gt;
&lt;p&gt;The steps I used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enumerate the timeline tracks (&lt;code&gt;timeline.tracks()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Filter for the video track (checking &lt;code&gt;ges::TrackType::VIDEO&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Read the track's &lt;code&gt;restriction_caps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Extract the &lt;code&gt;gst::Fraction&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="my-helper"&gt;My helper&lt;/h3&gt;
&lt;p&gt;I wrote a helper function to extract the framerate from the timeline:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
pub fn get_fps(&amp;amp;self, timeline: &amp;amp;ges::Timeline) -&amp;gt; Option&amp;lt;(i128, i128)&amp;gt; {
    timeline
        .tracks()
        .into_iter()
        .find(|track| track.track_type().contains(ges::TrackType::VIDEO))
        .and_then(|track| {
            let caps = track.restriction_caps().or_else(|| track.caps())?;
            let structure = caps.structure(0)?;
            let fps = structure.get::&amp;lt;gst::Fraction&amp;gt;("framerate").ok()?;

            // Extract the safe numerator and denominator
            Some((fps.numer() as i128, fps.denom() as i128))
        })
}

// ... inside the timeline injection logic:
if let Some((fps_num, fps_denom)) = self.get_fps(timeline) {
    self.fps_num.set(fps_num.max(1) as i32);
    self.fps_denom.set(fps_denom.max(1) as i32);
} else {
    // Default to 23.976 if we can't find a valid framerate caps
    self.fps_num.set(24_000);
    self.fps_denom.set(1_001);
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I make some assumptions here, such as only one video track existing, and that the framerate is always present in the caps. This solution made the tick spacing and labels line up with the timeline’s actual frame boundaries at any framerate.&lt;/p&gt;</content>
    <link href="https://mccalabrese.github.io/gnome-blog/posts/ges-sync/"/>
    <published>2026-05-27T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/gtk/2026/05/28/snapping/</id>
    <title>Benjamin Otte: Snapping</title>
    <updated>2026-05-28T01:41:00+00:00</updated>
    <author>
      <name>Benjamin Otte</name>
    </author>
    <content type="html">&lt;p&gt;With the release of 4.23.1, GTK’s renderer will come with a new feature that we’ve called &lt;strong&gt;snapping&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;How does it work?&lt;/h3&gt;
&lt;p&gt;Snapping is enabled by calling &lt;a class="external" href="https://docs.gtk.org/gtk4/method.Snapshot.set_snap.html"&gt;gtk_snapshot_set_snap()&lt;/a&gt;. If enabled, it will slightly adjust the placement of rectangles when drawing so that they align with the pixel grid and don’t cover half a pixel.&lt;/p&gt;
&lt;p&gt;&lt;img alt="GSK_RECT_SNAP_ROUND" class="alignnone size-medium" src="https://docs.gtk.org/gsk4/snap-round.svg"/&gt;&lt;/p&gt;
&lt;p&gt;Content drawn with GTK is scaled automatically by the desktop’s scale factor. But with the arrival of native fractional scaling, it is no longer possible to know if content is aligned to the pixel grid.&lt;/p&gt;
&lt;p&gt;While that is usually not a problem, there are a few cases where it is:&lt;/p&gt;
&lt;h3&gt;Sprite grids&lt;/h3&gt;
&lt;p&gt;&lt;a class="external" href="https://github.com/tchx84/gameeky"&gt;Gameeky&lt;/a&gt; is a learning game that plays on a grid. Unfortunately, on a fractionally scaled machine, it can end up looking like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.gnome.org/gtk/files/2026/04/image.png"&gt;&lt;img alt="A screenshot of a Gameeky game without snapping. A distracting grid can be seen between the sprites." class="aligncenter size-full wp-image-10693" height="313" src="https://blogs.gnome.org/gtk/files/2026/04/image.png" width="313"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once those sprites are snapped to the pixel grid by rounding to the nearest pixel, the same image looks like this&lt;br/&gt;
&lt;a href="https://blogs.gnome.org/gtk/files/2026/04/image2.png"&gt;&lt;img alt="A screenshot of a Gameeky game with snapping. No grid is visible anymore and it looks like a single image." class="aligncenter size-full wp-image-10694" height="313" src="https://blogs.gnome.org/gtk/files/2026/04/image2.png" width="313"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Sharp images&lt;/h3&gt;
&lt;p&gt;Often Applications want to display images in a way that matches the pixels of the image 1:1 with pixels of the monitor. This is a challenge on a fractionally scaled display. Not only is it important to get the scale factor right, it’s also important to align the pixels correctly, or they will appear slightly blurry.&lt;/p&gt;
&lt;p&gt;The use case is not just image viewers that want to offer a 1:1 zoom factor, but all applications that redirect drawing, from game emulators to viewers like &lt;a class="external" href="https://apps.gnome.org/Boxes/"&gt;Boxes&lt;/a&gt; or &lt;a class="external" href="https://apps.gnome.org/Connections/"&gt;Connections&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Hardware optimizations&lt;/h3&gt;
&lt;p&gt;And finally, there are optimizations like &lt;a href="https://blogs.gnome.org/gtk/2023/11/15/introducing-graphics-offload/"&gt;graphics offload&lt;/a&gt; that rely on content being aligned to the pixel grid or the hardware cannot optimize them. So it is important to snap content to the pixel grid for those cases.&lt;/p&gt;
&lt;h3&gt;Why don’t we just always snap to the grid?&lt;/h3&gt;
&lt;p&gt;There is one big problem with automatic snapping: smoothness. Because snapping only works on full pixels, doing slow animations causes content to jump from one pixel to the next. And that causes jitter.&lt;/p&gt;
&lt;p&gt;The main situation where one can see this is smooth scrolling, like in this example:&lt;/p&gt;
&lt;div class="wp-video" style="width: 466px;"&gt;&lt;video class="wp-video-shortcode" controls="controls" height="402" id="video-10690-1" loop="loop" preload="metadata" width="466"&gt;&lt;source src="https://blogs.gnome.org/gtk/files/2026/04/jitter.webm?_=1" type="video/webm"/&gt;&lt;a href="https://blogs.gnome.org/gtk/files/2026/04/jitter.webm"&gt;https://blogs.gnome.org/gtk/files/2026/04/jitter.webm&lt;/a&gt;&lt;/video&gt;&lt;/div&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;The next GTK release will offer a new way to tame the effects of fractional scaling.  Please try it out and let us know how it works!&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/gtk/2026/05/28/snapping/"/>
    <published>2026-05-28T01:41:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/laureen/2026/05/29/my-current-mr-and-gsoc-project-start/</id>
    <title>Laureen Caliman: My Current MR and GSoC Project Start</title>
    <updated>2026-05-29T00:28:03+00:00</updated>
    <author>
      <name>Laureen Caliman</name>
    </author>
    <content type="html">&lt;h2&gt;Ongoing Work&lt;/h2&gt;
&lt;p&gt;Back in March, I started to tackle this &lt;a class="external" href="https://gitlab.gnome.org/jrb/crosswords/-/merge_requests/373#note_2761175"&gt;MR&lt;/a&gt; for GNOME Crosswords. It allowed me to learn a lot about navigating the codebase, adhere to naming conventions, and collaborating with others involved in Crosswords.&lt;/p&gt;
&lt;p&gt;Crosswords Editor features a section for users to input metadata, such as author name, puzzle URL, and date. Originally, the MR was to convert and store the user’s manually typed date to ISO8601. This means storing the entered date in the form YYYY-MM-DD, while the user just needs to type in a date using the&lt;a class="external" href="https://api.pygobject.gnome.org/GLib-2.0/structure-Date.html"&gt; GDate struct&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Upon code review, the scope expanded to move from manual typing to selecting a date on a drop-down &lt;a class="external" href="https://docs.gtk.org/gtk4/class.Calendar.html"&gt;GTK calendar&lt;/a&gt; widget. I was able to implement this concept by following the architecture of an existing widget (edit-shapebg.c/h/blp) which placed shapes on the crossword puzzle. Then I connected the new calendar widget to the metadata so the chosen date from the now drop-down calendar will be stored in ISO8601 format yet display respective to the locale of the person using g_date_strftime.&lt;/p&gt;
&lt;h2&gt;Project Start&lt;/h2&gt;
&lt;p&gt;With the start of GSoC, I have spent a lot of time this week reading, white-boarding, and began setting up some structure to adding vocab-style crosswords to the libipuz library.&lt;/p&gt;
&lt;p&gt;The basic constraints and workflow that I mapped are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user can input up to 30 words (strings), with a 25 character capacity.&lt;/li&gt;
&lt;li&gt;Upon hitting enter or a button to generate, a Depth-First Search (DFS) algorithm starts to piece the words together on a blank grid. The algorithm can backtrack to tear apart words and rearrange them until a valid graph is formed
&lt;ul&gt;
&lt;li&gt;I’m going with DFS at the moment to prioritize the longest-to-shortest word seeding the graph in order to increase possibilities of connections&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Every time the user generates the graph, it will be treated like its own isolated creation, recalculating the layout from scratch to allow for cleaner undo/redo states and easier addition/deletion of words&lt;/li&gt;
&lt;li&gt;I don’t want words being placed right next to each other unless it was intentional for a 2+ word answer, which each word would be separated by thick lines
&lt;ul&gt;
&lt;li&gt;Words should only connect through intersections
&lt;ul&gt;
&lt;li&gt;The frontend does not mutate the grid but will be able to pass actions to the backend and return a new state&lt;/li&gt;
&lt;li&gt;For instance: say a user starts off their grid by typing “CAT” and then “DOG.” These words don’t have common characters, so they cannot be connected. However, instead of erasing the user’s desire to incorporate “DOG,” the string gets tucked away and saved in a GArray&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" class="alignnone size-medium wp-image-42" height="209" src="https://blogs.gnome.org/laureen/files/2026/05/Screenshot-from-2026-05-28-14-37-18-300x209.png" width="300"/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;Now our user types and enters “CADET.” The UI takes our list and passes it to the algorithm to start chewing on and deal onto the board anew. This time, allowing for “CAT,” “DOG,” and “CADET” to appear, without the user having to retype “DOG”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" class="alignnone size-medium wp-image-43" height="209" src="https://blogs.gnome.org/laureen/files/2026/05/Screenshot-from-2026-05-28-14-41-12-300x209.png" width="300"/&gt;&lt;/p&gt;
&lt;p&gt;I went back and forth with myself on how to represent the puzzle’s state in memory and disk. To write a custom GObject, or not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Argument Against: &lt;/strong&gt;Standard IpuzCrossword objects have a handle on grids and JSON saving, and one could write a new function that takes an array of strings and return a standard IpuzCrossword.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Argument For: &lt;/strong&gt;Revisiting the “CAT,” “DOG,” and “CADET” conundrum; say an educator is creating a puzzle for his/her/their class, and they have just one word out of 20 that don’t connect to current existing possibilities of intersecting words. If they save their puzzle, it transforms to a standard IpuzCrossword, and the floating word are permanently abandoned.&lt;/p&gt;
&lt;p&gt;At the current moment, I want the puzzle to be its own vocab-style workspace. Therefore this would allow for the floating word to instead sit in the sidebar and wait for further instruction for a future inserted word that works, or to get deleted.&lt;/p&gt;
&lt;p&gt;Of course, as I gain more insight about the library, &lt;a class="external" href="https://www.redhat.com/en/topics/cloud-native-apps/stateful-vs-stateless"&gt;states&lt;/a&gt;, and optimization within the codebase, this approach is subject to refinement.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/laureen/2026/05/29/my-current-mr-and-gsoc-project-start/"/>
    <published>2026-05-29T00:28:03+00:00</published>
  </entry>
  <entry>
    <id>https://gedit-text-editor.org/blog/2026-05-29-news.html</id>
    <title>Gedit Technology: News, April-May 2026</title>
    <updated>2026-05-29T10:00:00+00:00</updated>
    <author>
      <name>Gedit Technology</name>
    </author>
    <content type="html">&lt;p&gt;
  Here are the noteworthy news about the
  &lt;a href="https://gedit-text-editor.org/" target="_blank"&gt;gedit&lt;/a&gt;
  and
  &lt;a href="https://gitlab.gnome.org/World/gedit/enter-tex" target="_blank"&gt;Enter TeX&lt;/a&gt;
  text editors. (Some sections are a bit technical).
&lt;/p&gt;
&lt;h3&gt;A single package for gedit and its core plugins&lt;/h3&gt;
&lt;p&gt;
  Before, users needed to remember to install the
  &lt;a href="https://gitlab.gnome.org/World/gedit/gedit-plugins" target="_blank"&gt;gedit-plugins package&lt;/a&gt;
  in order to benefit from additional plugins such as &lt;em&gt;Word Completion&lt;/em&gt;
  or &lt;em&gt;Bookmarks&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;
  Now, all core - or “official” - plugins are part of the
  &lt;a href="https://gitlab.gnome.org/World/gedit/gedit" target="_blank"&gt;main gedit module&lt;/a&gt;.
  So, &lt;em&gt;Word Completion&lt;/em&gt;, &lt;em&gt;Bookmarks&lt;/em&gt; and others have been copied
  into the gedit module, and gedit-plugins is now empty/archived.
&lt;/p&gt;
&lt;p&gt;
  Note that there are also &lt;em&gt;third-party plugins&lt;/em&gt; which are available in
  other repositories.
&lt;/p&gt;
&lt;h3&gt;New version on the Microsoft Store&lt;/h3&gt;
&lt;p&gt;
  gedit 50.0 is now also
  &lt;a href="https://www.microsoft.com/store/apps/9NCQ8B0NVCW3" target="_blank"&gt;available on Windows&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;The re-implementation of document loading continues&lt;/h3&gt;
&lt;p&gt;
  It's now a recurrent topic. Progress has been made, but more work is necessary
  to fully replace the &lt;code&gt;GtkSourceFileLoader&lt;/code&gt; internals.
&lt;/p&gt;
&lt;p&gt;
  This time, here is a general description of the methodologies used along with
  the current state of affairs, without entering into too much technical
  details. If you're an experienced developer, it'll most probably ring a bell
  to you :-)
&lt;/p&gt;
&lt;p&gt;
  The typical “divide and conquer” methodology is followed: the problem is
  divided into several smaller ones. The sub-problems are solved individually,
  providing utility functions and small classes. Then things are built on top,
  with several layers, gradually solving bigger and bigger problems.
&lt;/p&gt;
&lt;p&gt;
  It all looks nice, except that an iterative process is also needed, to revise
  the solutions already built because of unforeseen problems (it happens all the
  time in computer science).
&lt;/p&gt;
&lt;p&gt;
  The current progress status is that &lt;em&gt;some&lt;/em&gt; utilities need to be
  reworked in order to be a better fit for the above components, and also to fix
  a couple of unforeseen problems. Thankfully it's not a “back to the drawing
  board” situation, as the utilities that lie at the bottom layers don't need
  any change.
&lt;/p&gt;
&lt;p&gt;
  For the curious reader, here are the two unforeseen problems encountered:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;iconv()&lt;/code&gt; can output nul bytes even for UTF-8 as the target
    charset. Embedded nuls are not valid UTF-8 according to
    &lt;code&gt;g_utf8_validate()&lt;/code&gt;. So an additional pass of validation is
    necessary, to escape invalid UTF-8 bytes.
  &lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
      With the new implementation, &lt;em&gt;at most&lt;/em&gt; two copies of the whole file
      content needs to be present in memory. I stumbled across a corner case where
      three copies would be necessary, so it needs to be fixed. The three copies
      were: (1) the content containing a single chunk (or at least a big chunk) of
      invalid bytes, (2) the invalid chunk escaped, and (3) the content as
      inserted into the &lt;code&gt;GtkTextBuffer&lt;/code&gt;.
    &lt;/p&gt;
&lt;p&gt;
      It's just a matter of escaping the invalid bytes directly / at a different
      place.
    &lt;/p&gt;
&lt;p&gt;
      (Note that this is a concern only for the work-in-progress branch; current
      stable versions of gedit doesn't suffer from that issue).
    &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Enter TeX goodness&lt;/h3&gt;
&lt;p&gt;
  The &lt;em&gt;Projects&lt;/em&gt; feature has been re-implemented in a better way (mostly
  under-the-hood changes).
&lt;/p&gt;
&lt;p&gt;
  The module is again on GNOME Damned Lies, so there are many translation
  updates. Thank you, all translators around the globe! In the past I
  contributed to the French translation, and I directly saw that GNOME
  translation teams do very high quality work. So, thanks again :) !
&lt;/p&gt;
&lt;h3&gt;Other stuff&lt;/h3&gt;
&lt;p&gt;
  As usual there are some other work items fixed or where progress has been
  made. Among others:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The comment/uncomment actions have been fine-tuned.&lt;/li&gt;
&lt;li&gt;
    A prototype has been created in order to improve the main “sandwich” menu in
    gedit.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Code re-use and Business-to-Business opportunities&lt;/h3&gt;
&lt;p&gt;
  There is a lot of potential with the libgedit modules (or also with
  GtkSourceView for GTK 4), to grow the project into something like the
  GStreamer multimedia project (but at a smaller scale) where there is a lot of
  &lt;a href="https://en.wikipedia.org/wiki/Business-to-business" target="_blank"&gt;B2B&lt;/a&gt;
  activity with consultancy companies helping to create new products for other
  businesses.
&lt;/p&gt;
&lt;p&gt;
  Especially with libgedit-tepl, the name “Text editor product line” means that
  it's possible to create other text editors or IDEs products (more easily).
&lt;/p&gt;
&lt;p&gt;
  An example that I have in mind is Arduino and its specialized IDE. But there
  are new programming languages or development platforms that pop up regularly,
  so there are opportunities to collaborate with them and develop great
  developer tools for them.
&lt;/p&gt;
&lt;p&gt;
  I'll talk about it more in the future, but if you read this and are interested
  to develop such a business model for gedit and/or GtkSourceView,
  &lt;a href="https://wilmet-software.be/" target="_blank"&gt;talk to me&lt;/a&gt;!
&lt;/p&gt;</content>
    <link href="https://gedit-text-editor.org/blog/2026-05-29-news.html"/>
    <published>2026-05-29T10:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/sophieh/2026/05/29/updates-from-the-circle-committee/</id>
    <title>Sophie Herold: Updates from the Circle Committee</title>
    <updated>2026-05-29T14:15:21+00:00</updated>
    <author>
      <name>Sophie Herold</name>
    </author>
    <content type="html">&lt;p&gt;We want to share some updates and future plans from the GNOME Circle Committee with you. The &lt;a class="external" href="https://gitlab.gnome.org/Teams/Circle"&gt;Circle Committee&lt;/a&gt; is responsible for reviewing and accepting apps and other components into &lt;a class="external" href="https://circle.gnome.org/"&gt;GNOME Circle&lt;/a&gt; as well as maintaining the &lt;a class="external" href="https://gitlab.gnome.org/Teams/Releng/AppOrganization/-/blob/main/AppCriteria.md"&gt;review criteria&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The biggest issue for us, and for maintainers who submitted apps, has been the considerable backlog of unreviewed apps. There are cases where apps have been waiting for feedback for years. We are very sorry for those who have been affected by this. We are trying to finally address this issue now.&lt;/p&gt;
&lt;h2 id="ai-policy"&gt;AI Policy&lt;/h2&gt;
&lt;p&gt;As a precaution, we have &lt;a class="external" href="https://gitlab.gnome.org/Teams/Releng/AppOrganization/-/blob/main/AppCriteria.md#circle-app-criteria"&gt;adopted&lt;/a&gt; the AI policy that already applies to GNOME Shell extensions. With the rise of low-quality machine-generated software, there is a risk that GNOME Circle could be overwhelmed by new submissions of this nature, further clogging the review queue.&lt;/p&gt;
&lt;p&gt;This policy is a starting point, and for now, it will only be enforced on new submissions. We are open to receiving feedback on the AI policy from existing Circle maintainers. In a quick survey, 62% of Circle maintainers reported not using LLMs at all, 34% reported using them for small questions or snippets, and only 3% are taking larger parts of code from them. No maintainer selected the option for no longer writing code themselves.&lt;/p&gt;
&lt;p&gt;Meanwhile, Flathub has also &lt;a class="external" href="https://social.treehouse.systems/@barthalion/116657011366876079"&gt;tightened&lt;/a&gt; their AI policy. Since GNOME Circle apps are usually expected to be published on Flathub, this policy indirectly applies as well.&lt;/p&gt;
&lt;h2 id="closing-new-submissions"&gt;Closing New Submissions&lt;/h2&gt;
&lt;p&gt;To make sure that we are focusing on submissions that haven’t been addressed for a long time, we will stop accepting new submissions for now. We will reopen submissions when we have made a considerable dent in our backlog.&lt;/p&gt;
&lt;h2 id="new-handling-of-issues"&gt;New Handling of Issues&lt;/h2&gt;
&lt;p&gt;This is mostly a technical detail, but from now on, we will close issues that are awaiting feedback from the maintainer. When providing an answer, maintainers should just reopen the issue. This gives us a better overview of which issues are awaiting further processing by us.&lt;/p&gt;
&lt;h2 id="early-reminder-about-the-use-of-outdated-sdks"&gt;Early Reminder About the Use of Outdated SDKs&lt;/h2&gt;
&lt;p&gt;Every GNOME release cycle, we spend a considerable amount of time on getting GNOME Circle apps to update their SDK on Flathub before the SDK becomes unmaintained. To avoid this in the future, we will try something new: We will remind maintainers much earlier that they are using an outdated SDK – months before it reaches EOL, rather than just a few weeks. This means apps using the GNOME 49 SDK will soon be part of an automatically generated reminder issue. To get the reminder, please make sure that you have provided a GNOME GitLab account in your project’s .doap file.&lt;/p&gt;
&lt;h2 id="growing-benefits"&gt;Growing Benefits&lt;/h2&gt;
&lt;p&gt;We are steadily growing the benefits for GNOME Circle apps and their maintainers. Among the benefits that were added are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Having a student work on your project for Google Summer of Code or Outreachy.&lt;/li&gt;
&lt;li&gt;Hosting your help pages on &lt;a class="external" href="https://help.gnome.org/"&gt;help.gnome.org&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Getting a tag for your project on &lt;a class="external" href="https://discourse.gnome.org/"&gt;GNOME’s Discourse&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, all contributors and maintainers of GNOME Circle projects are still eligible for GNOME Foundation membership. You can check our &lt;a class="external" href="https://gitlab.gnome.org/Teams/Circle/-/blob/main/membership_guide.md#benefits"&gt;full list of benefits&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="call-for-reviewers"&gt;Call for Reviewers&lt;/h2&gt;
&lt;p&gt;We are in constant need of more reviewers in the Circle Committee. If you have already reached out to us, and we haven’t gotten back to you, please give it another shot. You can find us in &lt;a class="external" href="https://matrix.to/#/#circle:gnome.org"&gt;#circle:gnome.org&lt;/a&gt;.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/sophieh/2026/05/29/updates-from-the-circle-committee/"/>
    <published>2026-05-29T14:15:21+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/aday/2026/05/29/gnome-foundation-update-2026-05-29/</id>
    <title>Allan Day: GNOME Foundation Update, 2026-05-29</title>
    <updated>2026-05-29T16:41:43+00:00</updated>
    <author>
      <name>Allan Day</name>
    </author>
    <content type="html">&lt;p&gt;Welcome to another update about everything that’s been happening at the GNOME Foundation. As has become my custom, this post covers a two week period, this time from 18 May until today, 29 May. As usual the Foundation continues to be busy, with events, infra, governance, and accounting activities all happening simultaneously. Read on for more information!&lt;/p&gt;
&lt;h2&gt;Events&lt;/h2&gt;
&lt;p&gt;Linux App Summit (LAS) 2026 was held in Berlin over the 16-17 May weekend. I’ve heard quite a few reports now, and everyone seemed extremely positive about the event. Kristi wrote &lt;a class="external" href="https://discourse.gnome.org/t/linux-app-summit-2026-thank-you-for-joining-us/35157"&gt;a nice summary&lt;/a&gt; if you want more details.&lt;/p&gt;
&lt;p&gt;The GNOME Foundation had two team members on the ground helping with running the event, which we co-organize with KDE. I’d like to take this opportunity to give a big thank you to the event’s sponsors: openSUSE, Tuxedo, Nextcould and Codethink. This event wouldn’t be possible without your support.&lt;/p&gt;
&lt;p&gt;In addition to LAS, work is continuing on arrangements for GUADEC 2026. The deadline for travel sponsorship applications has now passed, and the Travel Committee has met to decide who will be funded. Notifications will be going out soon.&lt;/p&gt;
&lt;h2&gt;Board Elections&lt;/h2&gt;
&lt;p&gt;The process is officially underway for &lt;a class="external" href="https://discourse.gnome.org/t/gnome-foundation-board-of-directors-elections-2026/"&gt;this year’s Board elections&lt;/a&gt;. Terms on our Board of Directors are two years in length, and each year half the board seats are open for election. This year we have five seats being contested.&lt;/p&gt;
&lt;p&gt;The 2026 election has a slightly different schedule to previous years. In the past, there was no gap between the candidacy period, in which people can announce their intention to run, and the voting period. This meant that there was little opportunity for last-minute candidates to participate in discussion prior to voting taking place.&lt;/p&gt;
&lt;p&gt;To address this, we’ve added a one week discussion period to the schedule, which will run between 8 and 15 June, between the candidacy and voting periods. This will hopefully give us opportunity to have more structured and inclusive debate amongst the candidates. We are still figuring out what that might look like, so if people have ideas or want to help, let me know in the comments.&lt;/p&gt;
&lt;h2&gt;GNOME Fellowship&lt;/h2&gt;
&lt;p&gt;We are currently in the very final stages of confirming and announcing the successful candidates for the inaugural round of the &lt;a class="external" href="https://fellowship.gnome.org/"&gt;Foundation’s Fellowship program&lt;/a&gt;. Expect an announcement very soon.&lt;/p&gt;
&lt;h2&gt;Got a Concern?&lt;/h2&gt;
&lt;p&gt;Last week we introduced a new &lt;a class="external" href="https://handbook.gnome.org/foundation/concern-reporting.html"&gt;policy for handling of concerns&lt;/a&gt; about the Foundation, which is now part of the project handbook.&lt;/p&gt;
&lt;p&gt;The new policy covers how to report concerns about people who are working for the Foundation, either in a paid or voluntary capacity. It also covers more general concerns about the Foundation.&lt;/p&gt;
&lt;p&gt;The main goals of the policy are to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;have a documented reporting procedure for those who have concerns relating to the Foundation&lt;/li&gt;
&lt;li&gt;clarify how concerns will be responded to&lt;/li&gt;
&lt;li&gt;provide reassurance for those reporting concerns, including that concern reports are welcome, are taken seriously, and will never result in retaliation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We hope that this policy will make it clear how you can inform us of a concern if you have one. We also want to emphasise that we want to hear concerns, so we can address them. Please do use the new reporting procedure.&lt;/p&gt;
&lt;h3&gt;Finance/Accounting&lt;/h3&gt;
&lt;p&gt;Work has continued on the finance and accounting operation over the past two weeks. Highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our transition to a monthly rather than quarterly close reached a significant milestone this week, with the completion of our April finance reports within three weeks of the previous month end. This is probably the fastest ever turnaround for our finance operation, and is a huge win for us in being able to effectively manage our finances.&lt;/li&gt;
&lt;li&gt;Following input from the board, corrections have now been sent to the accountants for our audit and annual tax filing.&lt;/li&gt;
&lt;li&gt;Applications are still open for our &lt;a class="external" href="https://www.idealist.org/en/nonprofit-job/5942160e1dec484a934de7a6d9508dc3-finance-operations-director-part-time-contractor-gnome-foundation-san-francisco"&gt;Director of Finance and Operations part-time contract&lt;/a&gt;. Candidates have until 4 June to submit.&lt;/li&gt;
&lt;li&gt;Finally, as I mentioned in my last update, we are in the process of retiring a number of finance platforms as we consolidate and streamline our operation. This week saw another platform retired, which brings the total number of eliminated platforms to four.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Infrastructure&lt;/h2&gt;
&lt;p&gt;Our infrastructure experienced a &lt;a class="external" href="https://discourse.gnome.org/t/an-update-on-the-last-few-hours-ddos/35188"&gt;DDoS attack last weekend&lt;/a&gt;, which Bart and Andrea have been dealing with. Thankfully it seems that services weren’t too badly affected, and we’ve already improved our protection against similar attacks in the future.&lt;/p&gt;
&lt;p&gt;Also on the infra side, Bart wasn’t at LAS this year, but he did spend some time writing two great posts about Flathub’s internals: &lt;a class="external" href="https://barthalion.blog/flathub-internals-cdn/"&gt;How does Flathub even work?&lt;/a&gt; and &lt;a class="external" href="https://barthalion.blog/flathub-internals-cdn-and-deltas/"&gt;Why are Flathub downloads so slow sometimes?&lt;/a&gt;. They’re a fascinating read if you’re interested in Flathub.&lt;/p&gt;
&lt;p&gt;That’s it from me! As always, thanks for reading, and see you in two weeks.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/aday/2026/05/29/gnome-foundation-update-2026-05-29/"/>
    <published>2026-05-29T16:41:43+00:00</published>
  </entry>
  <entry>
    <id>https://thisweek.gnome.org/posts/2026/05/twig-251/</id>
    <title>This Week in GNOME: #251 Monitoring Resources</title>
    <updated>2026-05-29T19:49:16+00:00</updated>
    <author>
      <name>This Week in GNOME</name>
    </author>
    <content type="html">&lt;p&gt;Update on what happened across the GNOME project in the week from May 22 to May 29.&lt;/p&gt;
&lt;h2 id="gnome-core-apps-and-libraries"&gt;GNOME Core Apps and Libraries&lt;/h2&gt;
&lt;h3 id="maps-"&gt;Maps &lt;a href="https://apps.gnome.org/Maps"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Maps gives you quick access to maps all across the world.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@mlundblad:matrix.org"&gt;mlundblad&lt;/a&gt; announces&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks to hard work by James Westman, Maps now supports dowloading map areas for offline use!&lt;/p&gt;
&lt;p&gt;&lt;img height="1059" src="https://thisweek.gnome.org/_astro/download-offline-map.BbqNyO_3_Z2ayTii.webp" width="2019"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1059" src="https://thisweek.gnome.org/_astro/offline-map-details.DDYHv-xr_1JCkWa.webp" width="2019"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1059" src="https://thisweek.gnome.org/_astro/offline-maps-list.CX4utkma_ulF3b.webp" width="2019"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="document-viewer-papers-"&gt;Document Viewer (Papers) &lt;a href="https://apps.gnome.org/Papers/"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;View, search or annotate documents in many different formats.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@lbaudin:matrix.org"&gt;lbaudin&lt;/a&gt; announces&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Papers 50.2 and 49.7 were released this week with a (unusually high) number of bug fixes. Notably, several fractional scaling issues should be fixed thanks to the work of balooii, including both performance and display issues.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="libadwaita-"&gt;Libadwaita &lt;a href="https://gitlab.gnome.org/GNOME/libadwaita"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Building blocks for modern GNOME apps using GTK4.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@itsjamie9494:gnome.org"&gt;Jamie (she/her)&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The upcoming version of Libadwaita now supports &lt;a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/func.bind_property_to_css_class.html"&gt;binding properties to CSS Classes&lt;/a&gt; and vice versa, making it easier to dynamically toggle CSS classes on widgets. This will be available in the upcoming GNOME release.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="gnome-circle-apps-and-libraries"&gt;GNOME Circle Apps and Libraries&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@sophieherold:gnome.org"&gt;Sophie (she/her)&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We published a blog post with &lt;a href="https://blogs.gnome.org/sophieh/2026/05/29/updates-from-the-circle-committee/"&gt;update from the Circle Committee&lt;/a&gt;. We are addressing our current review backlog, our new AI policy, new handling of submission issues, earlier reminders about outdated runtimes on Flathub, and new benefits for Circle projects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@safe_worlds:matrix.org"&gt;Lőrinc Serfőző&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A new version of Exercise Timer was released! This is a quality-of-life update for this simple app for high intensity interval training. Most notably, the training page has been updated with a custom progress indicator. Minor updates include an Undo option for deleted trainings and an update to the latest GNOME runtime.
Get Exercise Timer from Flathub: &lt;a href="https://flathub.org/en/apps/xyz.safeworlds.hiit"&gt;https://flathub.org/en/apps/xyz.safeworlds.hiit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1018" src="https://thisweek.gnome.org/_astro/exercise-timer.Ew1FzJST_ZwDrmP.webp" width="1042"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="resources-"&gt;Resources &lt;a href="https://github.com/nokyan/resources"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Keep an eye on system resources&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@sophieherold:gnome.org"&gt;Sophie (she/her)&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://apps.gnome.org/Resources/"&gt;Resources&lt;/a&gt;&lt;/strong&gt; has been &lt;a href="https://gitlab.gnome.org/GNOME/Incubator/Submission/-/work_items/20"&gt;accepted&lt;/a&gt; into the GNOME Incubator, with the goal of eventually replacing the current &lt;a href="https://apps.gnome.org/SystemMonitor/"&gt;System Monitor&lt;/a&gt; in GNOME Core. You can try the current development state via the &lt;a href="https://welcome.gnome.org/en/app/Resources/#installing-a-nightly-build"&gt;nightly Flatpak&lt;/a&gt; or on &lt;a href="https://os.gnome.org/"&gt;GNOME OS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you find any issues or regressions compared to the current System Monitor app, please report them in the &lt;a href="https://gitlab.gnome.org/GNOME/Incubator/resources/-/work_items"&gt;Resources issue tracker&lt;/a&gt;. The potential inclusion into Core is tracked under &lt;a href="https://gitlab.gnome.org/Teams/Releng/AppOrganization/-/work_items/41"&gt;App Organization&lt;/a&gt;. Distributions are encouraged to package the app and report any issues they foresee with a possible transition to Resources.&lt;/p&gt;
&lt;p&gt;Congrats and big thanks to nokyan for writing and maintaining this app!&lt;/p&gt;
&lt;p&gt;&lt;img height="822" src="https://thisweek.gnome.org/_astro/resources.CQ5ffK93_1Fqj74.webp" width="1122"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="third-party-projects"&gt;Third Party Projects&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@jwh:tchncs.de"&gt;Jan-Willem&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This week I released &lt;a href="https://codeberg.org/java-gi/java-gi/releases/tag/1.0.0-RC1"&gt;Java-GI 1.0.0-RC1&lt;/a&gt;. As the version number suggests, this is the first step towards a “stable” release. With multiple cool apps already on Flathub, like &lt;a href="https://flathub.org/apps/io.speedofsound.SpeedOfSound"&gt;Speed of Sound&lt;/a&gt; and &lt;a href="https://flathub.org/apps/io.github.subsoundorg.Subsound"&gt;Subsound&lt;/a&gt;, and several more in active development, I figured it’s time for backward compatibility and API stability.&lt;/p&gt;
&lt;p&gt;Notable improvements in this release are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for non-UTF8-encoded filenames&lt;/li&gt;
&lt;li&gt;Specialized exception types (deriving from GErrorException)&lt;/li&gt;
&lt;li&gt;Improved Windows support&lt;/li&gt;
&lt;li&gt;Bug fixes around memory management, class instantiation and nullability annotations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Always wanted to build a GNOME app, using your Java (or other JVM language) skills? Give &lt;a href="https://java-gi.org"&gt;Java-GI&lt;/a&gt; a try!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@lo-dev:matrix.org"&gt;lo&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nucleus version 3 is released! Nucleus is a periodic table app.&lt;/p&gt;
&lt;p&gt;This update brings a theoretical indicator to Ununennium, as well as some updated properties for Ununennium. French and Italian translations were added and the app was updated to the GNOME 50 runtime as well.&lt;/p&gt;
&lt;p&gt;Get it on Flathub: &lt;a href="https://flathub.org/apps/page.codeberg.lo_vely.Nucleus"&gt;https://flathub.org/apps/page.codeberg.lo_vely.Nucleus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="405" src="https://thisweek.gnome.org/_astro/Nucleus-theoretical-indicator.DVj1FaM0_2oPqc1.webp" width="533"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@seja-arctic-fox:matrix.org"&gt;seja-arctic-fox&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m happy to annouce that VidCom 0.82 has just been released!&lt;/p&gt;
&lt;p&gt;VidCom is a simple utility for archiving videos, written in C++, using &lt;code&gt;ffmpeg&lt;/code&gt; for video compression. Major changes in this version include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multiple stream and subtitle support, switching between mp4 and mkv containers as needed&lt;/li&gt;
&lt;li&gt;Faster seeking when Cut Feature is enabled&lt;/li&gt;
&lt;li&gt;Fix to correctly compute bitrate when Cut Feature is enabled&lt;/li&gt;
&lt;li&gt;Audio is now encoded in Archive mode as well. Previously it was just copied&lt;/li&gt;
&lt;li&gt;New cut widget and time setters&lt;/li&gt;
&lt;li&gt;UI rework to fit more into the GNOME ecosystem&lt;/li&gt;
&lt;li&gt;Switch to GNOME 50 Runtime&lt;/li&gt;
&lt;li&gt;Status pages for ‘empty queue’ and ‘encoding’ states&lt;/li&gt;
&lt;li&gt;Improved page for viewing results, which does not create a popup window anymore&lt;/li&gt;
&lt;li&gt;Popup messages changed to toasts&lt;/li&gt;
&lt;li&gt;Small UI desing adjustments; rounded thumbnail corners, better info distribution, formatting bugs&lt;/li&gt;
&lt;li&gt;UI refactor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;VidCom is avaiable on &lt;a href="https://flathub.org/en/apps/io.github.seja_arctic_fox.vidcom"&gt;Flathub&lt;/a&gt; and AUR. Source code can be viewed &lt;a href="https://github.com/seja-arctic-fox/vidcom"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="590" src="https://thisweek.gnome.org/_astro/vidcom_window_with_imported_videos_in_the_queue.Bl6A4KQP_ZnoUXA.webp" width="1010"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="590" src="https://thisweek.gnome.org/_astro/vidcom_video_settings_being_changed.CfxYwaeo_10zkYG.webp" width="1022"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="590" src="https://thisweek.gnome.org/_astro/vidcom_results_view_after_archiving_videos.BkVfQXCc_ZJY0o3.webp" width="1022"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@totoshko88:matrix.org"&gt;Anton Isaiev&lt;/a&gt; announces&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;RustConn Versions 0.15 Released&lt;/p&gt;
&lt;p&gt;I want to thank everyone who opened a request or sponsored the project. All this time, the main features I shipped came from user requests. The most important ones: broadcast, a keyboard passthrough mode that disables the app shortcuts so they go straight to the remote desktop, Windows scripts, and a wizard for an easy start with predefined custom commands. I use all of this every day and it genuinely makes life simpler - which was the whole idea behind the project.&lt;/p&gt;
&lt;p&gt;Homepage: &lt;a href="https://github.com/totoshko88/RustConn"&gt;https://github.com/totoshko88/RustConn&lt;/a&gt;
Flathub: &lt;a href="https://flathub.org/en/apps/io.github.totoshko88.RustConn"&gt;https://flathub.org/en/apps/io.github.totoshko88.RustConn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="2332" src="https://thisweek.gnome.org/_astro/RustConn_Broadcast.DgYlS9V9_Z24607B.webp" width="3496"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="2332" src="https://thisweek.gnome.org/_astro/RustConn_Custom_command.B5EzjxLy_Z2ejkix.webp" width="3496"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1388" src="https://thisweek.gnome.org/_astro/RustConn_MS_Scripts.DX2AC3Q3_ZgMeTJ.webp" width="2115"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="2332" src="https://thisweek.gnome.org/_astro/RustConn_Wizard.C29hCrx5_ZsF4Ks.webp" width="3496"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="solitaire-"&gt;Solitaire &lt;a href="https://gitlab.gnome.org/wwarner/Solitaire"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Play Patience Games&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@wwarner:matrix.org"&gt;Will Warner&lt;/a&gt; announces&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Solitaire 50.2 is out!&lt;/p&gt;
&lt;p&gt;Here is what’s new:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added translations: Georgian (Ekaterine Papava), ‘Chinese (China)’ (lumingzh), Ukrainian (Yuri Chornoivan), Serbian (Марко Костић)&lt;/li&gt;
&lt;li&gt;Updated translations: Cornish (Flynn Peck), Slovenian (Martin S.), Basque (Asier Saratsua Garmendia)&lt;/li&gt;
&lt;li&gt;Updated the scores dialog&lt;/li&gt;
&lt;li&gt;Added an option to the preferences to set the seed for dealing&lt;/li&gt;
&lt;li&gt;Made unfinished games automatically save&lt;/li&gt;
&lt;li&gt;Fixed a bug where cards could be dragged from the foundations in Spider&lt;/li&gt;
&lt;li&gt;Made cards not get selected when dealt&lt;/li&gt;
&lt;li&gt;Increased the height of tableau in Klondike&lt;/li&gt;
&lt;li&gt;Added a ‘Redeal Game’ option to the new game dialog&lt;/li&gt;
&lt;li&gt;Made Tri-Peaks allow Ace + King card combinations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can get Solitaire on &lt;a href="https://flathub.org/apps/org.gnome.gitlab.wwarner.Solitaire"&gt;Flathub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="850" src="https://thisweek.gnome.org/_astro/TWIG-251-Solitaire.Dk-WrowR_ZB782l.webp" width="850"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="gitte-"&gt;Gitte &lt;a href="https://codeberg.org/ckruse/Gitte"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A simple Git GUI for GNOME&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@christian:kruse.cool"&gt;Christian&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gitte, a simple Git client for GNOME built with GTK4, libadwaita and Relm4, just got its 0.5.0 release! 🎉&lt;/p&gt;
&lt;p&gt;The headline feature this time is commit and tag signing. Gitte now supports GPG, X.509 and SSH signing, validates signatures right in the commit log, and ships a dedicated “Signing status” window that walks you through setting everything up. Encrypted signing keys are handled via a new gitte-askpass helper, and every relevant dialog (commit, merge, revert, create tag, …) gets a per-action override switch so you can decide whether to sign on a case-by-case basis. The default respects the repository configuration.&lt;/p&gt;
&lt;p&gt;On top of that, the commit message, revert and create tag dialogs were overhauled, dialogs now carry descriptive subtitles for better discoverability, and there’s a new Ctrl+O / Cmd+O shortcut to open a repository. Under the hood Gitte moved to the new git2 API, switched from polling to IO-event-based refreshes, and gained a Cornish translation (thanks to Flynn Peck!).&lt;/p&gt;
&lt;p&gt;Get it on &lt;a href="https://flathub.org/apps/de.wwwtech.gitte"&gt;Flathub&lt;/a&gt;, &lt;a href="https://gitlab.com/dehesselle/gitte_macos/-/releases/v0.5.0+24"&gt;for macOS&lt;/a&gt; or &lt;a href="https://codeberg.org/ckruse/Gitte"&gt;have a look at the Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img height="1281" src="https://thisweek.gnome.org/_astro/gitte_signature-validation.g-YRrPuq_Z1EJypN.webp" width="1638"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1028" src="https://thisweek.gnome.org/_astro/gitte_signing-status.2lbMrusu_Z12A1hq.webp" width="1115"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="thats-all-for-this-week"&gt;That’s all for this week!&lt;/h2&gt;
&lt;p&gt;See you next week, and be sure to stop by &lt;a href="https://matrix.to/#/#thisweek:gnome.org"&gt;#thisweek:gnome.org&lt;/a&gt; with updates on your own projects!&lt;/p&gt;</content>
    <link href="https://thisweek.gnome.org/posts/2026/05/twig-251/"/>
    <published>2026-05-29T19:49:16+00:00</published>
  </entry>
  <entry>
    <id>https://gedit-text-editor.org/blog/2026-05-30-B2B-services-around-gedit-and-libgedit.html</id>
    <title>Gedit Technology: B2B Services around gedit and libgedit</title>
    <updated>2026-05-30T10:00:00+00:00</updated>
    <author>
      <name>Gedit Technology</name>
    </author>
    <content type="html">&lt;p&gt;&lt;em&gt;
  This article is also available in the
  &lt;a href="https://gedit-text-editor.org/b2b.html" target="_blank"&gt;B2B Services section on the gedit website&lt;/a&gt;.
&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;
  Several
  &lt;a href="https://en.wikipedia.org/wiki/Business-to-business" target="_blank"&gt;business-to-business&lt;/a&gt;
  services are possible around gedit:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    Development of a new plugin.
  &lt;/li&gt;
&lt;li&gt;
    Development of a new text editor or Integrated Development Environment (IDE)
    based on the libgedit.
  &lt;/li&gt;
&lt;li&gt;
    Code maintenance.
  &lt;/li&gt;
&lt;li&gt;
    Training.
  &lt;/li&gt;
&lt;li&gt;
    Support.
  &lt;/li&gt;
&lt;li&gt;
    Creation of Long-Term Support (LTS) versions.
  &lt;/li&gt;
&lt;li&gt;
    Developer Experience (DX) guidance.
  &lt;/li&gt;
&lt;li&gt;
    […] Come with your own ideas to collaborate with the gedit project.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Target audience&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
    Operating System / Linux distributions: for your installed-by-default text
    editor.
  &lt;/li&gt;
&lt;li&gt;
    GTK-based desktop environments: to maintain a text editor or IDE, and to
    adhere to your Human Interface Guidelines (HIG).
  &lt;/li&gt;
&lt;li&gt;
    Scientific sector: to build developer tools.
  &lt;/li&gt;
&lt;li&gt;
    Education sector: to build easy-to-learn developer tools.
  &lt;/li&gt;
&lt;li&gt;
    New programming languages / development platforms: you're designing and
    implementing a new programming language, and you need developer tools for
    your users.
  &lt;/li&gt;
&lt;li&gt;
    Older programming languages users: you're a big organization and you have a
    lot of legacy code. You want better developer tools to be more productive.
  &lt;/li&gt;
&lt;li&gt;
    Markup or domain-specific languages: to better promote your language, you
    would like first-class support for it.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The libgedit shared libraries&lt;/h3&gt;
&lt;p&gt;
  gedit is not just a general-purpose text editor application, there is a
  “libgedit” underneath!
&lt;/p&gt;
&lt;p&gt;
  A lot of gedit features are implemented as re-usable code, as a set of shared
  libraries. So new apps - text editors and IDEs alike - can be built on top.
  There is an ongoing effort from the gedit project to make more code re-usable.
&lt;/p&gt;
&lt;p&gt;
  An example of an IDE based on the libgedit is
  &lt;a href="https://gitlab.gnome.org/World/gedit/enter-tex" target="_blank"&gt;Enter TeX&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  The libgedit is in turn based on the very flexible
  &lt;a href="https://gtk.org/" target="_blank"&gt;GTK graphical toolkit&lt;/a&gt;.
&lt;/p&gt;
&lt;h4&gt;GTK 3 or GTK 4&lt;/h4&gt;
&lt;p&gt;
  The libgedit currently targets GTK 3. If you want to develop with
  GTK 4, there is the
  &lt;a href="https://gitlab.gnome.org/GNOME/gtksourceview" target="_blank"&gt;GtkSourceView&lt;/a&gt;
  library (but it doesn't contain all the libgedit features). Another
  possibility is to first port the libgedit to GTK 4.
&lt;/p&gt;
&lt;h3&gt;The plugin system&lt;/h3&gt;
&lt;p&gt;
  gedit has a powerful plugin system mechanism, to extend the application. You
  can leverage it for prototyping additional features, or as the final solution
  that requires less efforts than creating a new specialized text editor.
&lt;/p&gt;
&lt;p&gt;
  You can also combine the best of both approaches:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
    First implement a feature that is based on libgedit.
  &lt;/li&gt;
&lt;li&gt;
    Then wrap your feature in a gedit plugin so it can readily be used.
  &lt;/li&gt;
&lt;li&gt;
    Finally, as an option, create a custom text editor app, re-using the same
    implementation of your feature(s), integrating everything well together.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Other developer tools&lt;/h3&gt;
&lt;p&gt;
  The text editor part is essential, it is the central feature of an IDE. But
  other developer tools can be developed as well.
&lt;/p&gt;
&lt;p&gt;
  For instance,
  &lt;a href="https://github.com/gdev-technology/devhelp" target="_blank"&gt;Devhelp&lt;/a&gt;
  can be used for browsing and searching API documentation. Almost all its code
  is re-usable; like for gedit, there is a libdevhelp toolkit under the hood.
&lt;/p&gt;
&lt;h3&gt;Advice to not start from scratch&lt;/h3&gt;
&lt;p&gt;
  A little advice: please don't create a new text editor or IDE from scratch,
  base your work on existing, high-level libraries like the libgedit. Even if it
  looks simple on paper, developing a feature-full text editor &lt;em&gt;is&lt;/em&gt; a lot
  of work.
&lt;/p&gt;
&lt;h3&gt;Use the libgedit from your preferred programming language&lt;/h3&gt;
&lt;p&gt;
  libgedit and GTK can be used from a wide range of programming languages, and
  the support for additional languages can be implemented too. This is thanks to
  GObject Introspection. See the list of
  &lt;a href="https://gtk.org/docs/language-bindings/" target="_blank"&gt;language bindings&lt;/a&gt;
  for the GTK project.
&lt;/p&gt;
&lt;h3&gt;Open-source or proprietary software&lt;/h3&gt;
&lt;p&gt;
  libgedit and GTK are licensed under the
  &lt;a href="https://www.gnu.org/licenses/licenses.html" target="_blank"&gt;GNU Lesser General Public License&lt;/a&gt;
  (LGPL), which allows to develop proprietary software on top.
&lt;/p&gt;
&lt;p&gt;
  gedit plugins need to be distributed as free/&lt;em&gt;libre&lt;/em&gt; software, under
  the GPL license.
&lt;/p&gt;
&lt;h3&gt;Who to collaborate with&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://wilmet-software.be/" target="_blank"&gt;Sébastien Wilmet&lt;/a&gt;,
    the current maintainer and main developer of gedit and libgedit.
  &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;You?&lt;/em&gt; If you're or work for a consultancy company specialized in
    GNOME, GLib or GTK, and want to be part of this project, don't hesitate to
    get in touch!
  &lt;/li&gt;
&lt;/ul&gt;</content>
    <link href="https://gedit-text-editor.org/blog/2026-05-30-B2B-services-around-gedit-and-libgedit.html"/>
    <published>2026-05-30T10:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/steven/2026/05/31/stay-and-fight/</id>
    <title>Steven Deobald: Stay and fight.</title>
    <updated>2026-06-01T01:59:02+00:00</updated>
    <author>
      <name>Steven Deobald</name>
    </author>
    <content type="html">&lt;p&gt;Nine months ago, I had to field quite a few angry comments from folks who told me they intended to drop their GNOME Foundation memberships in the wake of confusing and opaque board behaviour. I say to you now what I told each of them back in September:&lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;strong&gt;Stay and fight.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The GNOME Foundation saw a much needed — and long overdue — changing of the guard back in August of 2025. In the past 12 months, the Foundation has finally made the improvements it should have been making over the past decade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/05/09/2025-05-09-foundation-report/"&gt;2025-05-09&lt;/a&gt; – GNOME’s infra team had its first management review — it was the cleanest infrastructure review I’ve performed in my career. [&lt;a href="https://blogs.gnome.org/steven/feed/#edit"&gt;edit&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/05/16/2025-05-16-foundation-report/"&gt;2025-05-16&lt;/a&gt; – &lt;em&gt;Foundation Reports&lt;/em&gt; begin in earnest as a first small step toward a transparent GNOME Foundation. We begin the hunt for a new Treasurer.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/05/24/2025-05-23-foundation-report/"&gt;2025-05-23&lt;/a&gt; – We started a Foundation Handbook to match &lt;em&gt;handbook.gnome.org&lt;/em&gt;. (This has since migrated to a wiki.) We started moving all the Foundation’s documents into a central location. Project management began at the Foundation for the first time ever.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/05/28/on-safety/"&gt;2025-05-28&lt;/a&gt; – The Foundation publicly acknowledged that attacks on our Matrix servers, using illegal images, constitute crimes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/06/07/2025-06-06-foundation-report/"&gt;2025-06-06&lt;/a&gt; – Both &lt;em&gt;donate.gnome.org&lt;/em&gt; and (later) &lt;em&gt;fellowship.gnome.org&lt;/em&gt; are pitched and accepted by the board. We brought on Deepa Venkatraman as Treasurer. Bart Piotrowski set up &lt;em&gt;vault.gnome.org&lt;/em&gt; for passwords.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/06/14/2025-06-14-foundation-report/"&gt;2025-06-14&lt;/a&gt; – Andrea Veri completed the transition to donated AWS resources for GNOME infra.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/06/20/2025-06-20-foundation-report/"&gt;2025-06-20&lt;/a&gt; – &lt;em&gt;donate.gnome.org&lt;/em&gt; is released, thanks to the hard work of Bart, Sam Hewitt, and Jakub Steiner.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/06/26/donate-less/"&gt;2025-06-26&lt;/a&gt; – The “Donate Less” campaign begins, in anticipation of the outbound program that would become &lt;em&gt;fellowship.gnome.org.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/07/05/2025-07-05-foundation-update/"&gt;2025-07-05&lt;/a&gt; – The concept of &lt;em&gt;fellowship.gnome.org&lt;/em&gt; goes public. Work on the corresponding &lt;em&gt;donate.gnome.org&lt;/em&gt; shell notification starts. We tightened fiscal controls. We added redundancy to all our financial, legal, and operational processes. We interviewed a pipeline of candidates and selected Ignacy Kuchciński to complete the work under the &lt;em&gt;Digital Wellbeing&lt;/em&gt; grant.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/07/12/2025-07-12-foundation-update/"&gt;2025-07-12&lt;/a&gt; – We invited postmarketOS to the Advisory Board.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/07/21/2025-07-18-foundation-update/"&gt;2025-07-21&lt;/a&gt; – We started stabilizing the GNOME Foundation’s finances for the long term by redefining the Board Reserve and taking a hard look at balancing year-on-year (annual recurring) revenue and expenses. We added the first-ever redundant signatories on bank accounts.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/steven/2025/08/08/2025-08-08-foundation-update/"&gt;2025-08-08&lt;/a&gt; – We created a shared online space for Advisory Board members to collaborate.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2025/09/05/foundation-update-2025-09-05/"&gt;2025-09-05&lt;/a&gt; – First corporate sponsor.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2025/09/12/gnome-foundation-update-2025-09-12/"&gt;2025-09-12&lt;/a&gt; – Deepa’s budget process is “the best the Foundation has ever had,” according to multiple directors.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2025/10/10/gnome-foundation-update-2025-10-10/"&gt;2025-10-10&lt;/a&gt; – Digital Wellbeing is delivered. The Foundation gets a much-needed credit card policy.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2025/10/24/gnome-foundation-update-2025-10-24/"&gt;2025-10-24&lt;/a&gt; – A new Finance Advisor arrives. (An important role at a 501c3.)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2025/11/28/gnome-foundation-update-2025-11-28/"&gt;2025-11-28&lt;/a&gt; – The budget is balanced. More importantly, the budget report contains the commitment to balancing recurring expenses and recurring revenue, continuously.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2025/12/19/gnome-foundation-update-2025-12-19/"&gt;2025-12-19&lt;/a&gt; – Deepa joins as a full director and remains Treasurer.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2026/01/09/gnome-foundation-update-2026-01-09/"&gt;2026-01-09&lt;/a&gt; – A new automated accounts payable and accounts receivable system is installed.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2026/03/20/gnome-foundation-update-2026-03-20/"&gt;2026-03-20&lt;/a&gt; – Financial reporting moves from quarterly to monthly.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2026/04/17/gnome-foundation-update-2026-04-17/"&gt;2026-04-17&lt;/a&gt; – The Fellowship Program begins! Users’ donations come full-circle: a percentage of every donation now goes directly to developers.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2026/05/15/gnome-foundation-update-2026-05-15/"&gt;2026-05-15&lt;/a&gt; – Finances are on-target. The Foundation opens a position for Finance Director.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.gnome.org/aday/2026/05/29/gnome-foundation-update-2026-05-29/"&gt;2026-05-29&lt;/a&gt; – Four old finance platforms are retired as the finances of the Foundation are automated and simplified. The Foundation introduces a Concern Escalation Policy: if members feel that directors or staff are abusing their positions with policy violations, illegal activity, discrimination, or conflicted behaviour, they’re provided the reassurance that they can blow the whistle without risk of retaliation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;That’s a lot for one little nonprofit. But this is the beginning of GNOME Foundation 2.0, not the end. The work must continue and there is still plenty to be done.&lt;/p&gt;
&lt;p&gt;If you let your membership expire in recent years, get it back. If you are thinking of leaving, don’t. And if you are thinking of running for board elections, run.&lt;/p&gt;
&lt;p&gt;The GNOME Foundation is the healthiest it’s ever been. It’s reducing costs and focusing on its actual mission: GNOME. The excellence demanded of GNOME hackers is now demanded of the Foundation, too. You can be a part of continuing that trajectory.&lt;/p&gt;
&lt;p&gt;There has never been a more meaningful time to &lt;a class="external" href="https://discourse.gnome.org/t/gnome-foundation-board-of-directors-elections-2026/34884"&gt;join the GNOME Foundation board&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p style="text-align: center;"&gt;&lt;a class="external" href="http://donate.gnome.org"&gt;&lt;img alt="Donate to GNOME" class="aligncenter wp-image-134 size-thumbnail" height="150" src="https://blogs.gnome.org/steven/files/2025/06/card-150x150.png" width="150"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong id="edit"&gt;EDIT:&lt;/strong&gt; &lt;em&gt;“GNOME’s infra team had its first management review — it was the cleanest infrastructure review I’ve performed in my career.”&lt;/em&gt; was previously &lt;em&gt;“GNOME’s infra team had its first management review — it was spotless.”&lt;/em&gt; Someone on Reddit took issue with the use of the word “spotless”. This edit serves to accommodate them.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/steven/2026/05/31/stay-and-fight/"/>
    <published>2026-06-01T01:59:02+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/i18n/2026/06/02/some-news-about-the-internationalization-project/</id>
    <title>GNOME Internationalization &amp; Localization: Some news about the internationalization project</title>
    <updated>2026-06-02T12:00:44+00:00</updated>
    <author>
      <name>GNOME Internationalization &amp; Localization</name>
    </author>
    <content type="html">&lt;p&gt;This first blog post marks the opening of the internationalization blog! The i18n team will use it to share news and projects on the current plans. Don’t forget to subscribe!&lt;/p&gt;
&lt;p&gt;The i18n team has seen some changes recently, at the beginning of 2026 and we thought it was necessary to publicly announce this change and introduce ourselves a bit.&lt;/p&gt;
&lt;p class="part"&gt;Before all, we want to greet and deeply thank all internationalization coordinators that participated in the project so far and made GNOME what is is now. We are a global software community of volunteers, leading the free software ecosystem and are accessible in many languages. With this, we cover almost everyone on Earth. Thank you very much Andre, Alexandre, Claude, Daniel, Gábor, Gil, Mario, Piotr, Petr, Kjartan and all the others. Without you this wouldn’t have been possible.&lt;/p&gt;
&lt;h2 class="part" id="What-is-internationalization"&gt;&lt;i class="fa fa-link"&gt;&lt;/i&gt;What is internationalization?&lt;/h2&gt;
&lt;p class="part"&gt;Internationalization, or i18n for short, is the act of ensuring software or documentation can be used in other languages, countries, and cultures. This means designing and developing applications in a way that removes barriers to localization, making it possible to adapt them without requiring significant engineering changes.&lt;/p&gt;
&lt;p class="part"&gt;In practice, this involves separating user-facing text from the source code, so it can be translated easily, and ensuring that the software correctly handles different character sets and writing systems, including right-to-left scripts. It also means being mindful of cultural conventions such as date and time formats, number formatting, currencies, and units of measurement.&lt;/p&gt;
&lt;p class="part"&gt;Internationalization goes beyond text. It includes accommodating differences in sorting rules (collation), keyboard input methods, plural forms, and even layout considerations, as translated text can vary significantly in length. Developers must also ensure that their software supports Unicode and uses libraries or frameworks that simplify handling these variations.&lt;/p&gt;
&lt;p class="part"&gt;For the GNOME community, internationalization is a collaborative effort between developers, designers, and translators. By preparing software properly, the i18n team enables localization contributors to focus on producing high-quality translations, ensuring that GNOME is accessible and welcoming to users all around the world.&lt;/p&gt;
&lt;h2 class="part" id="A-new-generation"&gt;&lt;i class="fa fa-link"&gt;&lt;/i&gt;A new team&lt;/h2&gt;
&lt;p class="part"&gt;The team has reborn with new faces: Anders Jonsson, Rafael Fontenelle and Guillaume Bernard, respectively coordinators of the Swedish, Brazilian Portuguese and French team. Let’s introduce ourselves a bit…&lt;/p&gt;
&lt;p class="part"&gt;Rafael (&lt;a class="external" href="https://gitlab.gnome.org/rafaelff" rel="noopener" target="_blank"&gt;@rafaelff&lt;/a&gt;) is coordinator of the GNOME Brazilian Portuguese Team for more than 13 years after a short but intense period of contribution as translator. Besides GNOME, he contributes to the translation of Python Docs, R language, Fedora, TranslationProject (GNU projects, etc.) and others. Also maintains some packages in Arch Linux’s AUR.&lt;/p&gt;
&lt;p class="part"&gt;Anders (&lt;a class="external" href="https://gitlab.gnome.org/ajonsson" rel="noopener" target="_blank"&gt;@ajonsson&lt;/a&gt;) is coordinator of the GNOME Swedish Team for over 10 years, translator in the Swedish branch of the Translation Project, and a member of the GIMP Team with a focus on internationalization questions and testing.&lt;/p&gt;
&lt;p class="part"&gt;Guillaume (&lt;a class="external" href="https://gitlab.gnome.org/gbernard" rel="noopener" target="_blank"&gt;@gbernard&lt;/a&gt;) is coordinator of the GNOME French Team since this year after 14 years of contributions, first as a translator, reviewer and after a few years, he has been involved in submitting team’s translations. He is the maintainer of &lt;a class="external" href="https://gitlab.gnome.org/Infrastructure/damned-lies" rel="noopener" target="_blank"&gt;GNOME Damnes Lies&lt;/a&gt;, our translation platform since 2020. He took this responsibility after years of dedication from Claude. Thank you again for this mentorship!&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/i18n/2026/06/02/some-news-about-the-internationalization-project/"/>
    <published>2026-06-02T12:00:44+00:00</published>
  </entry>
  <entry>
    <id>https://blogs.gnome.org/chergert/2026/06/02/libdex-improvements/</id>
    <title>Christian Hergert: Libdex Improvements</title>
    <updated>2026-06-02T15:14:11+00:00</updated>
    <author>
      <name>Christian Hergert</name>
    </author>
    <content type="html">&lt;p&gt;&lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/index.html"&gt;libdex 1.2&lt;/a&gt; is still in pre-alpha phase but it is also far enough along that it is worth talking about the direction: libdex is growing from a library of future and fiber helpers into a more complete concurrency toolkit.&lt;/p&gt;
&lt;p&gt;The most important 1.2 theme is that applications can now describe not just what work should happen concurrently, but how that work should be bounded and owned. &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/class.Limiter.html"&gt;&lt;code&gt;DexLimiter&lt;/code&gt;&lt;/a&gt; lets a workload run with a fixed concurrency budget, with &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/method.Limiter.run.html"&gt;&lt;code&gt;dex_limiter_run()&lt;/code&gt;&lt;/a&gt; handling the common fiber case by acquiring a permit before work starts and releasing it after the fiber completes. For larger workflows, &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/class.TaskGroup.html"&gt;&lt;code&gt;DexTaskGroup&lt;/code&gt;&lt;/a&gt; gives related futures a structured scope that can be closed, awaited, or cancelled as one unit.&lt;/p&gt;
&lt;p&gt;That combination makes cleanup much easier to reason about when a workflow has many moving pieces. A loader can start many subtasks, keep only a useful number active at once, and return a single future representing the whole operation. If the window closes, the project changes, or the operation times out, the group gives the application one place to cleanly shut the work down.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;static DexFuture *
load_many_files (GPtrArray *files)
{
  g_autoptr(DexTaskGroup) group = dex_task_group_new (0);
  g_autoptr(DexLimiter) limiter = dex_limiter_new (8);

  for (guint i = 0; i &amp;lt; files-&amp;gt;len; i++)
    {
      GFile *file = g_ptr_array_index (files, i);

      dex_task_group_add (group,
                          dex_limiter_run (limiter,
                                           NULL,
                                           0,
                                           load_one_file,
                                           g_object_ref (file),
                                           g_object_unref));
    }

  return dex_future_with_timeout_seconds (dex_task_group_close (group), 10);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is also a new &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/class.ThreadPool.html"&gt;&lt;code&gt;DexThreadPool&lt;/code&gt;&lt;/a&gt; for the cases that are not naturally fiber-shaped. Fibers and schedulers are still the right fit for cooperative async work, but many applications need to integrate blocking libraries, database clients, filesystem helpers, or other foreign code. A fixed pool of reusable OS threads, &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/method.ThreadPool.submit.html"&gt;&lt;code&gt;dex_thread_pool_submit()&lt;/code&gt;&lt;/a&gt;, and asynchronous &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/method.ThreadPool.close.html"&gt;&lt;code&gt;dex_thread_pool_close()&lt;/code&gt;&lt;/a&gt; give that integration story a bounded queue and an explicit shutdown path.&lt;/p&gt;
&lt;p&gt;Deadlines are another practical piece of the same story. The new timeout wrappers, including &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/ctor.Future.with_timeout_seconds.html"&gt;&lt;code&gt;dex_future_with_timeout_seconds()&lt;/code&gt;&lt;/a&gt; and &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/ctor.Future.with_deadline.html"&gt;&lt;code&gt;dex_future_with_deadline()&lt;/code&gt;&lt;/a&gt;, turn time limits into ordinary future composition. Instead of open-coded timeout state spread across an application, a future can resolve normally, reject normally, or reject with &lt;code&gt;DEX_ERROR_TIMED_OUT&lt;/code&gt; when the deadline wins.&lt;/p&gt;
&lt;p&gt;On the I/O side, 1.2 continues filling in the operations that make responsiveness easier to preserve. &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/func.aio_open.html"&gt;&lt;code&gt;dex_aio_open()&lt;/code&gt;&lt;/a&gt; and &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/func.aio_close.html"&gt;&lt;code&gt;dex_aio_close()&lt;/code&gt;&lt;/a&gt; matter because even operations that look small can stall when they touch the kernel, storage, or network-backed filesystems. Keeping those calls in libdex’s &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/aio.html"&gt;file-descriptor AIO model&lt;/a&gt; makes it easier to keep them off the UI thread, using &lt;code&gt;io_uring&lt;/code&gt; where it is available and the fallback AIO backend elsewhere.&lt;/p&gt;
&lt;p&gt;The broader &lt;a class="external" href="https://gnome.pages.gitlab.gnome.org/libdex/libdex-1/aio.html"&gt;GIO coverage&lt;/a&gt; is intentionally less surprising, but still important. More app launching, &lt;code&gt;GFile&lt;/code&gt;, stream, socket, resolver, proxy, TLS, DTLS, permission, subprocess, and Unix-facing APIs now have future-first wrappers. That is the kind of coverage people should expect from libdex over time: not every wrapper needs a release headline, but each one reduces the pressure to leave the future model for common GNOME application work.&lt;/p&gt;</content>
    <link href="https://blogs.gnome.org/chergert/2026/06/02/libdex-improvements/"/>
    <published>2026-06-02T15:14:11+00:00</published>
  </entry>
  <entry>
    <id>https://blog.jimmac.eu/posts/backrooms/</id>
    <title>Jakub Steiner: Backrooms</title>
    <updated>2026-06-03T00:00:00+00:00</updated>
    <author>
      <name>Jakub Steiner</name>
    </author>
    <content type="html">&lt;img alt="Backrooms" class="full" src="https://blog.jimmac.eu/posts/backrooms/backrooms.webp"/&gt;
&lt;p&gt;Not the best film ever, but in today's Hollywood landscape it's a rare breath of fresh air. Kane Parsons takes the internet meme concept he started on YouTube and actually makes a feature-length film that's doing great at the box office.&lt;/p&gt;
&lt;p&gt;The mood is great. That unsettling stillness of these generic liminal spaces. For something that builds a feeling / mood, the flick would benefit from a butcher in the editing room. I'd probably still not give it the extra star, but this really isn't the kind of movie that needs the extra 20 minutes.&lt;/p&gt;
&lt;p&gt;Biggest entertainment was definitely watching my son freak out in the third act. :)&lt;/p&gt;
&lt;p&gt;★★★★☆&lt;/p&gt;</content>
    <link href="https://blog.jimmac.eu/posts/backrooms/"/>
    <published>2026-06-03T00:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://www.nedrichards.com/2026/06/sunset-appearance/</id>
    <title>Nick Richards: Sunset Appearance</title>
    <updated>2026-06-03T21:50:40+00:00</updated>
    <author>
      <name>Nick Richards</name>
    </author>
    <content type="html">&lt;p&gt;I love adaptive interfaces and technology that blends in more than the average human. I’ve spent literally years tinkering with ‘frecency’ ordered lists, bought a &lt;a href="https://en.wikipedia.org/wiki/Meural"&gt;meural&lt;/a&gt; screen and have recently been glorying in the fantastic &lt;a href="https://github.com/dmy3k/gnome-adaptive-brightness"&gt;GNOME Adaptive Brightness&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On that last point, whilst GNOME already has Automatic Screen Brightness, and it is a good feature, dmy3k’s extension goes further on the specific machines with cool hardware: steadier behaviour with changing light, smoother transitions and brightness curves you can tune. One of the things I’ve been exploring with extensions recently is ’this feature, only more so’ and adaptive brightness is a good example.&lt;/p&gt;
&lt;p&gt;Living far from the equator, evenings happen. The room goes grey, the window stops being a useful light source and GNOME is still cheerfully in light mode because I told it to be bright at the time one takes screenshots. Night Light is already doing its bit by then. The display has warmed up, which is nice, but the rest of the interface lacks the level of ‘darque’ required. I wanted the normal GNOME appearance preference to follow the day as well: light while it still feels like day, dark once the evening has properly arrived. Users of other operating systems may be aware of this feature, but for the purposes of this blog post let us pretend that everything below is entirely unique.&lt;/p&gt;
&lt;p&gt;So I hacked up &lt;a href="https://github.com/nedrichards/sunset-gnome-extension"&gt;Sunset Appearance&lt;/a&gt;, a small GNOME Shell extension for GNOME Shell 45 to 50. At civil dusk it writes the same setting GNOME Settings uses:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-text"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;org.gnome.desktop.interface color-scheme = 'prefer-dark'
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At civil dawn it sets it back to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-text"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;org.gnome.desktop.interface color-scheme = 'default'
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My dad was an aviator, so I got to hear a lot of exciting words growing up, such as ‘civil twilight’, which always makes me think of Romeo and Juliet. Sunset turns out to be a surprisingly slippery concept, and very longitudinally mediated. In London in summer there can be plenty of useful light after the sun has dipped below the horizon, and the desktop does not need to go ‘darque’ the moment the sun touches the skyline. Nautical and astronomical twilight are too late for an interface preference, and in some places at some times of year they can fail to happen in the normal way at all.&lt;/p&gt;
&lt;p&gt;Civil twilight is when the centre of the sun is 6 degrees below the horizon and when it really does feel like the world has changed character.&lt;/p&gt;
&lt;p&gt;Location is awkward too, because civil dawn and dusk need latitude, longitude and date. There’s some interesting fallback logic to infrequently get a coarse location (good enough for a city) and then fall back to cached data if available as Night Light already needs much the same information. Frequent readers will remember my concerns over London, Ontario being above London, England in many search boxes so there is no virtue in making the user type London into another small box. If neither source has usable coordinates, nothing changes.&lt;/p&gt;
&lt;p&gt;Manual override behaviour is another thing that avoids annoyance. If the extension sets dark mode at dusk and I then change GNOME back to light mode, I meant that. After any override, it waits until the next scheduled dawn or dusk transition before touching the setting again.&lt;/p&gt;
&lt;p&gt;Solar time code has an unreasonable number of edges for something everyone thinks they intuitively understand. Keeping with my aggressive policy on internationalisation the tests keep London as the ordinary case, then poke at time zones, date line longitudes, DST changes, Antarctic stations, Arctic towns, awkward offsets such as Lord Howe and Chatham and cases where civil dawn or dusk may not exist at all. My time reading &lt;a href="https://brr.fyi/"&gt;brr&lt;/a&gt; and pretending to be in New Zealand to solve work bugs was not poorly spent.&lt;/p&gt;
&lt;p&gt;Right now Sunset Appearance can be &lt;a href="https://github.com/nedrichards/sunset-gnome-extension/"&gt;built from source&lt;/a&gt;. At some point I may choose to distribute it more widely, or even see if someone has already solved my problem better.&lt;/p&gt;</content>
    <link href="https://www.nedrichards.com/2026/06/sunset-appearance/"/>
    <published>2026-06-03T21:50:40+00:00</published>
  </entry>
  <entry>
    <id>https://meeksfamily.uk/~michael/blog/2026-06-04.html</id>
    <title>Michael Meeks: 2026-06-04 Thursday</title>
    <updated>2026-06-04T21:00:00+00:00</updated>
    <author>
      <name>Michael Meeks</name>
    </author>
    <content type="html">&lt;ul&gt; &lt;!-- --&gt;
&lt;li&gt;
		Up much too early, train into London. Met up with
	some interesting folk from HCL. Pod-cast recording, lunch
	re-recording a second take; interesting perspectives, fun
	people.
	&lt;/li&gt;
&lt;li&gt;
		Worked on trains home, caught up with J.
	&lt;/li&gt;
&lt;li&gt;
		Home group bible study on Malachi.
	&lt;/li&gt;
&lt;li&gt;
		Worked until almost midnight to get a response in to
	the &lt;a href="https://connect.cma.gov.uk/consultations/microsoft-business-software-itc/"&gt;CMA
	SMS investigation of Microsoft&lt;/a&gt; submitted in time; tiring.
	&lt;/li&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;</content>
    <link href="https://meeksfamily.uk/~michael/blog/2026-06-04.html"/>
    <published>2026-06-04T21:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://danigm.net/take-it-easy.html</id>
    <title>Daniel García Moreno: Take it easy. A guide to avoid burnown during the Vulnpocalypse</title>
    <updated>2026-06-05T10:00:00+00:00</updated>
    <author>
      <name>Daniel García Moreno</name>
    </author>
    <content type="html">&lt;p&gt;Do not let the AI to remove the fun part from software development.
We shouldn't allow gen AI to write software just because it "can".
First, we must ask if it "should" do it, and even then, we should ask
if we &lt;strong&gt;want&lt;/strong&gt; to delegate the fun part, the thinking, the writing,
the learning.&lt;/p&gt;
&lt;p&gt;Remember what's important, journey before destination, &lt;strong&gt;we are the
Code&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Do not let AI to destroy the community, do not let it destroy the
&lt;a href="https://linguacelta.com/blog/2026/05/LLMs.html"&gt;technological knowledge commons&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;tl;dr&lt;/h2&gt;
&lt;p&gt;Open Source maintainers are dealing with a lot of new reports and
pressure to "fix" the project due to generative AI.&lt;/p&gt;
&lt;p&gt;We need to find a way of stopping this and get back to something
maintainable before all maintainers get burned out and look for a job
in a farm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;100% secure software doesn't exists, so there will be always a
   possible CVE there. As &lt;a href="https://en.wikiquote.org/wiki/Gene_Spafford"&gt;Spaf said in 1989&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The only truly secure system is one that is powered off, cast in a
block of concrete and sealed in a lead-lined room with armed guards
- and even then I have my doubts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Fixing bugs, adds new bugs, and if you need to fix something quick,
   the probability of new bugs will be higher. Do not forget about the
   First Law of Programming:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;If it works, don't touch it&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The amount of CVE reports is lowering the CVE credibility and
   quality, so if everything is a &lt;em&gt;"high"&lt;/em&gt; security issue, we can't
   prioritize now and these reports are not different from random
   issues in github. Do not listen to &lt;a href="https://en.wikipedia.org/wiki/The_Boy_Who_Cried_Wolf"&gt;The Boy Who Cried Wolf&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stable software is sable because it doesn't change too much. It's
   something that we are willing to loose trying to reach the
   impossible of 100% secure software?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The actual problem&lt;/h2&gt;
&lt;p&gt;There's a lot of money in AI tech right now, and everyone is trying to
make the best gen AI tool or just pretend that their tool is the best.&lt;/p&gt;
&lt;p&gt;In relation with the software analysis and writing, targeting the
open source is the obvious strategy.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It's interesting to scrap every line of code, patch, pull request,
   issue and discussion around software to train your model, so AI
   scrappers are DDoSing open source projects infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To promote their tools or themselves, &lt;em&gt;Security Researches&lt;/em&gt; are
   using AI to target any project, reporting &lt;em&gt;High security
   vulnerabilities&lt;/em&gt;, with the only goal of getting a CVE number to say
   how good they are.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This second point is affecting maintainers, because now you are
receiving a lot of poor quality security reports, that are generated
with AI and that looks plausible and are hard to read. You need to
spend a lot of time to check if there's an actual wolf there or if
it's again this boy that's tricking me.&lt;/p&gt;
&lt;p&gt;This is burning the energy of maintainers, that instead of doing
something productive are wasting their limited time talking with a
&lt;a href="https://en.wikipedia.org/wiki/Stochastic_parrot"&gt;Stocatic Parrot&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Do not let the AI Bros to use classic manipulation techniques on you!&lt;/h2&gt;
&lt;p&gt;A lot of open source projects are maintained by volunteers that do the
work with passion and love. And even if it's the job that paid your
bills, the maintainer can feel the &lt;a href="https://daniel.haxx.se/blog/2026/05/26/the-pressure/"&gt;pressure&lt;/a&gt;. When someone put a
lot of love in something and work on it during years, it's part of his
identity, so attacking the software is like attacking the person
behind it.&lt;/p&gt;
&lt;p&gt;This is nothing new, and a lot of people take advantage of this
emotional link to manipulate the maintainer to do something that he
do not want to do.&lt;/p&gt;
&lt;p&gt;AI bros are using these techniques, do not let them to manipulate you
and define your project agenda.&lt;/p&gt;
&lt;p&gt;Here's a (not complete) list of known manipulation techniques that you
can detect (and disarm!) in your daily community work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flooding the queue&lt;/strong&gt;. Just create so many new issues that the
   actual maintainers can't deal with it. You feel responsible for the
   project and feel bad because &lt;em&gt;your TO-DO list&lt;/em&gt; is growing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This software is not secure (doesn't do what I want), I will use
   this other one instead that's better&lt;/strong&gt;. The classic, "GNOME doesn't
   allow me to change this specific preference, I'll use KDE from now
   on".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This software is low quality, it doesn't follow the (my random)
   quality standards&lt;/strong&gt;. Direct attack to the maintainer self-esteem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gaslighting software development&lt;/strong&gt;. LLM are expert at this and
   people that uses it just copy the tactic. When the maintainer
   detects something weird and just tries to blame the other person
   for reporting nonsense and wasting all people time, it starts to
   invent new arguments and ignore the previous interaction.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, take it easy, and remember the best clause in almost any software
project, &lt;strong&gt;THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
PROGRAM IS WITH YOU&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;Disclaimer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Warranty&lt;/span&gt;.

&lt;span class="nv"&gt;THERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;NO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WARRANTY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EXTENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PERMITTED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BY&lt;/span&gt;
&lt;span class="nv"&gt;APPLICABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LAW&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EXCEPT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OTHERWISE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;STATED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WRITING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;COPYRIGHT&lt;/span&gt;
&lt;span class="nv"&gt;HOLDERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OTHER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PARTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROVIDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;“&lt;span class="nv"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IS&lt;/span&gt;”&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WITHOUT&lt;/span&gt;
&lt;span class="nv"&gt;WARRANTY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ANY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;KIND&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EITHER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EXPRESSED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IMPLIED&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;INCLUDING&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;NOT&lt;/span&gt;
&lt;span class="nv"&gt;LIMITED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IMPLIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WARRANTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MERCHANTABILITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;FITNESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;
&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PARTICULAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PURPOSE&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ENTIRE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;RISK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;QUALITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AND&lt;/span&gt;
&lt;span class="nv"&gt;PERFORMANCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;YOU&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SHOULD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROVE&lt;/span&gt;
&lt;span class="nv"&gt;DEFECTIVE&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;YOU&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ASSUME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;COST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;NECESSARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SERVICING&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;REPAIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OR&lt;/span&gt;
&lt;span class="nv"&gt;CORRECTION&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Is the software more insecure in 2026?&lt;/h2&gt;
&lt;p&gt;No. Anyone old enough could remember how insecure old software was. Do
you remember windows 98? Do you remember the internet when everything
was http (without that little s at the end), when people use ftp
to logging into their server and modify the php code directly on
production?&lt;/p&gt;
&lt;p&gt;It's true that today we have more dependency on technology, but it's
also true that everything is more secure, we have more and better
cryptography, we have different levels of isolation, virtual
environments, containers, virtual machines...&lt;/p&gt;
&lt;p&gt;But we have the feeling that since AI can analyse all the software and
look for vulnerabilities, we are doomed, because any stupid kid can
hack my over engineered GNU/Linux machine!&lt;/p&gt;
&lt;p&gt;First, that's not true, you need to know about security to get
something useful from any AI tool. But even if it was true, what can
you do about it? We need to be practical and find a balance between
risk and usefulness, so do not &lt;strong&gt;overestimate the risk&lt;/strong&gt; just because
everyone is talking about it right now.&lt;/p&gt;
&lt;p&gt;But even then, the security paranoia is not good for anyone. Software
is inherently buggy, people write software and makes mistakes, so a
possible vulnerability appears. In theory, these bugs are fixed when
discovered, so it's always recommended to update to the latest
version, because almost all known bugs will be fixed.&lt;/p&gt;
&lt;p&gt;But it's also known that new versions comes with new functionality and
code, and that means new "unknown" bugs or different behavior. That's
a headache, so that's why the stable and Long Term Support are popular
distributions, because &lt;strong&gt;"if it works, don't touch it"&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Stable packages just get the fixes, not new features, but fixes are
also code changes, so there's always a possibility to break something,
even with a patch update.&lt;/p&gt;
&lt;p&gt;The stable software has a lot of value, do not let the AI security
paranoia destroy that, and convert everything in a rolling release
with the latest and greatest (and possibly broken) software. Sometimes
it's better to keep using something old, with &lt;strong&gt;known&lt;/strong&gt;
vulnerabilities that you can mitigate, than use the latest with
&lt;strong&gt;unknown&lt;/strong&gt; new vulnerabilities that you can't do anything about.&lt;/p&gt;
&lt;h2&gt;I will fight AI with AI&lt;/h2&gt;
&lt;p&gt;Please, do not do that. What I was trying to argue during this long
post is not a technical problem. The current burnout problem in open
source is a social problem, you can't fix it with a new layer of
probabilistic tokens.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Community reaction against AI&lt;/strong&gt;. The current industry push for
   the usage of AI everywhere is affecting a lot of people, and as a
   reaction a lot of people are directly fighting back. Using gen AI
   just sends the message that you do not care enough to do it
   yourself, and destroy the trust on the project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It doesn't worth it&lt;/strong&gt;. Even if the AI works (that it doesn't) it
   doesn't worth it. Writing code is easier than reviewing, you learn
   and grow with every new line of code that you write, delegating
   the fun part and personal growth part to an AI will make you work
   more miserable and you will be a junior forever.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It doesn't create community&lt;/strong&gt;. Think about it, it's hard to get
   someone involved in a software project, but who will want to read
   or improve the code produced by a gen AI? The only future
   collaborator will be another AI.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Take it easy&lt;/h2&gt;
&lt;p&gt;Just remember, you can always say no, there's no hurry, and there's no
need to work on something that you don't want just because other
people consider that important.&lt;/p&gt;
&lt;p&gt;Free Source is something done by people, for people. The software is
important, but the community around it is sometimes more important. We
use Free source not because it's technically better (that it is), but
because we trust who, how and why are writing it.&lt;/p&gt;
&lt;p&gt;Remember why are you doing this, do not remove the Fun part, continue
with the &lt;a href="https://es.wikipedia.org/wiki/Just_for_fun"&gt;&lt;strong&gt;Just for Fun&lt;/strong&gt;&lt;/a&gt; mood.&lt;/p&gt;</content>
    <link href="https://danigm.net/take-it-easy.html"/>
    <published>2026-06-05T10:00:00+00:00</published>
  </entry>
  <entry>
    <id>https://meeksfamily.uk/~michael/blog/2026-06-05.html</id>
    <title>Michael Meeks: 2026-06-05 Friday</title>
    <updated>2026-06-05T12:05:49+00:00</updated>
    <author>
      <name>Michael Meeks</name>
    </author>
    <content type="html">&lt;ul&gt; &lt;!-- --&gt;
&lt;li&gt;
		Up too early. Dropped H. into XJTAG before her epic Asian
	trip. Lovely to meet up with John Hall and catch up after a couple of
	decades.
	&lt;/li&gt;
&lt;li&gt;
		Tried to pack, and gather together things for the Church's Men's
	walking weekend.
	&lt;/li&gt;
&lt;li&gt;
		Published the next strip: Ejecting a do-er, "if in
	doubt, kick them out!"; cancellation based on un-proven
	allegation seems to be the spirit of the age:
		&lt;center&gt;
&lt;a href="https://www.collaboraonline.com/torf/torf69"&gt;&lt;img alt="The Open Road to Freedom - strip#69 - Ejecting a do-er" src="https://meeksfamily.uk/~michael/images/torf69-thumb.png"/&gt;&lt;/a&gt;
&lt;/center&gt;
&lt;/li&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;</content>
    <link href="https://meeksfamily.uk/~michael/blog/2026-06-05.html"/>
    <published>2026-06-05T12:05:49+00:00</published>
  </entry>
  <entry>
    <id>https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/</id>
    <title>Ivan Molodetskikh: Using Fedora Silverblue for Compositor Development</title>
    <updated>2026-06-05T12:37:00+00:00</updated>
    <author>
      <name>Ivan Molodetskikh</name>
    </author>
    <content type="html">&lt;p&gt;I’ve been using &lt;a href="https://fedoraproject.org/atomic-desktops/silverblue/"&gt;Fedora Silverblue&lt;/a&gt; on my desktop and laptop for the past, what, five years?
Silverblue is Fedora’s main atomic variant, a spiritual counterpart to Fedora Workstation.
I also make &lt;a href="https://github.com/YaLTeR/niri"&gt;niri&lt;/a&gt;, a scrollable-tiling Wayland compositor.
In other words, a core system component that you cannot properly test from inside a container or VM—you really want it directly on the host.
So, why would I choose an… immutable distro?
How does that even work?&lt;/p&gt;
&lt;figure&gt;
&lt;a href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/blur.png"&gt;
&lt;img src="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/blur.png"/&gt;
&lt;/a&gt;
&lt;figcaption&gt;
&lt;p&gt;Fedora Silverblue makes a frequent occurrence in my &lt;a href="https://github.com/niri-wm/niri/releases"&gt;niri release notes&lt;/a&gt; screenshots.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Atomic distributions have been slowly rising in popularity.
Their main selling point is reliability: upgrades work by swapping the old system for the new one in one go across a reboot, rather than modifying the files in-place.
Package conflicts and other errors are caught at the time of assembling the new version (in a separate folder), and therefore cannot break your running system.
And if a successful update turns out buggy, atomic distros let you simply reboot back into the old version and keep using it as if nothing happened.&lt;/p&gt;
&lt;p&gt;This “being able to reboot back” thing becomes even cooler once you realize that it works even across major distro upgrades!
When the next Fedora Beta rolls around, I can just &lt;em&gt;rebase&lt;/em&gt; my system on top of it to kick the tires, and if anything is broken, I can simply &lt;em&gt;reboot back&lt;/em&gt; to stable Fedora (and then undo the rebase).&lt;/p&gt;
&lt;p&gt;This is like learning about source code version control.
A big weight off your mind any time you want to mess around with your OS.
You can just &lt;em&gt;go back&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, by now there are plenty of atomic distributions to choose from.
There’s &lt;a href="https://fedoraproject.org/atomic-desktops/"&gt;a whole host of Fedora atomic desktops&lt;/a&gt;, &lt;a href="https://www.endlessglobal.com/foundation/access/operating-system"&gt;Endless OS&lt;/a&gt;, the gaming-focused &lt;a href="https://bazzite.gg/"&gt;Bazzite&lt;/a&gt; and &lt;a href="https://universal-blue.org/"&gt;other Universal Blue images&lt;/a&gt;.
&lt;a href="https://os.gnome.org/"&gt;GNOME OS Nightly&lt;/a&gt; is atomic, as well as &lt;a href="https://store.steampowered.com/steamos"&gt;SteamOS&lt;/a&gt; powering the Steam Deck.
Many of these are built with &lt;a href="https://ostreedev.github.io/ostree/"&gt;OSTree&lt;/a&gt; which is something of a “git for operating system binaries”.&lt;/p&gt;
&lt;p&gt;But, you may ask.
What if I &lt;em&gt;develop&lt;/em&gt; these operating system binaries?
Aren’t atomic distros immutable and all, how do I test my work?&lt;/p&gt;
&lt;p&gt;Turns out, this is not a problem at all!
In fact, the same tech that lets you &lt;em&gt;go back&lt;/em&gt; after an update can also let you freely tinker with your host system and safely &lt;em&gt;go back&lt;/em&gt; after a reboot.
I’d say that thanks to this ability, atomic distributions provide even more benefit for system component developers than for others, given that they’re constantly testing changes that may break their install.&lt;/p&gt;
&lt;p&gt;So, let me show you how I do compositor development on Fedora Silverblue.
We’ll start with toolbox where most of the work happens, then proceed to the fun stuff.&lt;/p&gt;
&lt;h2 id="toolbox"&gt;Toolbox &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#toolbox"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On your immutable host system, you need a place where you can install the development environment.
Fedora Silverblue comes pre-installed with &lt;a href="https://containertoolbx.org/"&gt;Toolbox&lt;/a&gt;, which provides just that—a terminal in a normal, mutable Fedora where you can &lt;code&gt;sudo dnf install&lt;/code&gt; to your heart’s content.&lt;/p&gt;
&lt;p&gt;Under the hood, it’s just a &lt;a href="https://podman.io/"&gt;podman&lt;/a&gt; container with a whole range of things auto-mounted from the host: the Wayland socket, networking, devices, D-Bus, and everything else needed for apps to “just work” as much as possible from inside the container.
You can even interact with it through podman commands:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌ ~
└─ podman ps
CONTAINER ID  IMAGE                                         COMMAND               CREATED       STATUS         PORTS       NAMES
6ceccce5581e  registry.fedoraproject.org/fedora-toolbox:44  toolbox --log-lev...  2 months ago  Up 41 minutes              fedora-toolbox-44
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Most of your development work happens here.
Install all the libraries, compilers, editors, &lt;a href="https://microsoft.github.io/language-server-protocol/"&gt;LSPs&lt;/a&gt;, debuggers, and the rest of the kitchen sink.
Since all of this resides inside the same container, it can all talk to each other and work together.&lt;/p&gt;
&lt;p&gt;One slightly annoying detail is that since your fully-configured editor is inside the toolbox, you can’t use it to edit files accessible only on the host (e.g. configs in &lt;code&gt;/etc&lt;/code&gt;—the system inside the toolbox has its own files there), but that is honestly a fairly minor problem in practice.
Fedora Silverblue comes with &lt;code&gt;nano&lt;/code&gt;, which works, and if editing host-only files is a frequent occurrence for you, you can always &lt;code&gt;rpm-ostree install&lt;/code&gt; a more featureful editor.
Another annoying problem is that currently, toolbox &lt;a href="https://github.com/containers/toolbox/issues/1400"&gt;prevents SIGHUP from reaching apps&lt;/a&gt;, so if you run &lt;a href="https://helix-editor.com/"&gt;your favorite editor&lt;/a&gt; then close the terminal window, it will happily keep running in the background (along with all its &lt;a href="https://rust-analyzer.github.io/"&gt;rust-analyzer&lt;/a&gt;s and such, eating several gigabytes of RAM).&lt;/p&gt;
&lt;p&gt;So, running things in a toolbox works perfectly well for most development.
CLI tools will run fine, GUI apps will run fine, you can build and install libraries inside the toolbox and test them on apps inside the same toolbox.
Even with Wayland compositors, most of them can run as a window (&lt;code&gt;gnome-shell --nested&lt;/code&gt;, or simply &lt;code&gt;sway&lt;/code&gt; or &lt;code&gt;niri&lt;/code&gt;), which is enough to test the majority of the code base.&lt;/p&gt;
&lt;p&gt;Moreover, &lt;a href="https://github.com/containers/toolbox/pull/997"&gt;since ~2023&lt;/a&gt;, toolbox exposes everything necessary to run compositors on a TTY directly.
You can switch to a different VT with &lt;kbd&gt;Ctrl&lt;/kbd&gt;&lt;kbd&gt;Alt&lt;/kbd&gt;&lt;kbd&gt;F3&lt;/kbd&gt;, &lt;code&gt;toolbox enter&lt;/code&gt;, then start a compositor, and it will work as is.
This way you can test different input devices directly (trackpad, tablet, touchscreen), test monitor and GPU handling, do proper performance profiling, and so on.
Just remember to install a terminal and some GUI apps inside the toolbox because launching the host ones into a toolbox compositor is a bit annoying.&lt;/p&gt;
&lt;p&gt;While toolbox is somewhat Fedora-specific, for everything else there’s &lt;a href="https://distrobox.it/"&gt;distrobox&lt;/a&gt;.
It’s a separate project, but by and large has the same idea—let you easily install different distros as podman containers with automatic host integration.
I mainly use it to build or test things on &lt;a href="https://archlinux.org/"&gt;Arch&lt;/a&gt;, but I imagine most of what I wrote above works just as well with distrobox.&lt;/p&gt;
&lt;p&gt;What if this isn’t enough, though?
Say, you’re working on a component like NetworkManager or systemd that must run on the host system.
Or, you want to be able to &lt;em&gt;log in&lt;/em&gt; to a test build of your compositor along with the rest of the full desktop session.
Let’s look at an easy way to do that.&lt;/p&gt;
&lt;h2 id="unlocking-the-host"&gt;Unlocking the host &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#unlocking-the-host"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;sudo ostree admin unlock&lt;/code&gt;, also known as &lt;code&gt;rpm-ostree usroverlay&lt;/code&gt;.&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;
This will mount a mutable overlay filesystem over &lt;code&gt;/usr&lt;/code&gt; for you to play around in.
The overlay will last until the next reboot, at which point you’ll be back to a clean working system.&lt;/p&gt;
&lt;p&gt;Now you can simply &lt;code&gt;sudo cp&lt;/code&gt; your development build into &lt;code&gt;/usr/bin&lt;/code&gt; and restart the service you’re testing.&lt;/p&gt;
&lt;p&gt;This also works with libraries.
Say, you want to test your changes in &lt;a href="https://gitlab.gnome.org/GNOME/gtk"&gt;GTK&lt;/a&gt; against apps installed on the host.&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;
Build it inside the toolbox, then copy the binaries to the (unlocked) host, and there you have it.
Binary compatibility is generally not a concern since Silverblue updates daily and very closely matches the regular Fedora that you build against inside the toolbox.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo cp&lt;/code&gt; is not a proper substitute for installing though, and you cannot use it as easily for many projects.
So let’s get some proper tooling on the host.&lt;/p&gt;
&lt;h2 id="layering-development-tooling"&gt;Layering development tooling &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#layering-development-tooling"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Contrary to an apparently widespread belief, you can install packages on the host in Silverblue.
This is called &lt;em&gt;layering&lt;/em&gt; and is a perfectly normal and supported operation, primarily useful for adding system components such as terminals, window managers, or GPU drivers.
Running &lt;code&gt;rpm-ostree install alacritty&lt;/code&gt; will cause rpm-ostree to install, or &lt;em&gt;layer&lt;/em&gt;, this package on top of the base Silverblue image every time it updates.
After a reboot, you’ll have Fedora with &lt;a href="https://alacritty.org/"&gt;Alacritty&lt;/a&gt;, as if you installed it on a regular, non-atomic system.&lt;/p&gt;
&lt;p&gt;If the change is sufficiently non-invasive, running &lt;code&gt;sudo rpm-ostree apply-live&lt;/code&gt; lets you skip the reboot and have a newly installed program available right away.&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;When should you layer (as opposed to installing in a toolbox)?
Layering is more annoying and slower, and misses the benefit of throwing away a toolbox to start fresh.
So, I limit layering to programs that &lt;em&gt;must&lt;/em&gt; run on the host, and tools that I frequently need on the host.&lt;/p&gt;
&lt;p&gt;Here’s my list of layered packages that’s been more or less unchanged for several Fedora releases:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌ ~
└─ rpm-ostree status
State: idle
Deployments:
  fedora:fedora/42/x86_64/silverblue
                  Version: 42.20250824.0 (2025-08-24T02:55:42Z)
               BaseCommit: d58dc92e5b05b6a95a0d9352edd864f1292c1883b9b32ac2e6f0af1a2263395a
             GPGSignature: Valid signature by B0F4950458F69E1150C6C5EDC8AC4916105EF944
                     Diff: 12 upgraded
      RemovedBasePackages: firefox firefox-langpacks 142.0-1.fc42
          LayeredPackages: alacritty distrobox dnf fastfetch fish foot fuzzel gamescope gdb
                           gnome-console google-roboto-fonts htop hyprlock i3 kanshi labwc
                           langpacks-ru lm_sensors lxqt-policykit mako nautilus-python
                           netconsole-service niri perf quickshell-git rocminfo strace sway
                           syncthing sysprof tmux trash-cli waybar wlsunset
            LocalPackages: edid-asus-1-1.fc34.noarch
                Initramfs: --include /etc/initramfs-overlay /
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In this output, you can find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I &lt;em&gt;removed&lt;/em&gt; Firefox with &lt;code&gt;rpm-ostree override remove&lt;/code&gt;—I prefer the &lt;a href="https://flathub.org/apps/org.mozilla.firefox"&gt;official build from Flathub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Terminals (must run on the host to access the full host filesystem&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt;): alacritty, foot, gnome-console. My preferred shell: fish. Tool I frequently need: tmux.&lt;/li&gt;
&lt;li&gt;Services and tools that I want to run without a toolbox: syncthing, distrobox, netconsole-service, trash-cli, htop, fastfetch, lm_sensors, rocminfo.&lt;/li&gt;
&lt;li&gt;Desktop components: fuzzel, hyprlock, i3, kanshi, labwc, lxqt-policykit, mako, quickshell-git, sway, waybar, wlsunset.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;edid-asus&lt;/code&gt; and the &lt;code&gt;initramfs-overlay&lt;/code&gt; provide the EDID for one of my monitors after AMDGPU &lt;a href="https://bugzilla.kernel.org/show_bug.cgi?id=201497"&gt;broke it&lt;/a&gt; back in kernel 4.19.&lt;sup id="fnref:6"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:6"&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with these, I layer several development tools: gdb, strace, perf, sysprof.
These frequently come in handy whenever I need to debug or profile programs running on the host (or do full-system profiling in case of &lt;a href="https://gitlab.gnome.org/GNOME/sysprof"&gt;Sysprof&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;And then there’s dnf.
What?&lt;/p&gt;
&lt;h2 id="layering-dnf"&gt;Layering dnf &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#layering-dnf"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What is dnf, a regular Fedora package manager, doing on an immutable Silverblue host system?
By itself, it’s not very useful indeed, since it can’t modify &lt;code&gt;/usr&lt;/code&gt;.
(Though, it can &lt;code&gt;dnf copr enable&lt;/code&gt;, which is convenient. &lt;code&gt;rpm-ostree copr&lt;/code&gt; when?)&lt;/p&gt;
&lt;p&gt;Where dnf on the host shines, however, is when you combine it with &lt;code&gt;sudo ostree admin unlock&lt;/code&gt;.
After unlocking, you can install whatever you need in the moment with dnf.
This is much faster than rpm-ostree, never requires a reboot, and in fact a reboot makes it all clean up and go away, since it was all in a transient &lt;code&gt;/usr&lt;/code&gt; overlayfs.&lt;/p&gt;
&lt;p&gt;Example workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dnf debuginfo-install&lt;/code&gt; to debug/profile something on the host with symbols, report crashes, etc.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dnf install&lt;/code&gt; some host-only program to test it. Follow up with &lt;code&gt;rpm-ostree install&lt;/code&gt; if you decide to keep it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dnf builddep gtk4&lt;/code&gt;, then build and &lt;code&gt;sudo ninja install&lt;/code&gt; GTK 4 right on the host to test it against host apps. If anything breaks, just reboot, and you’re back to a clean working state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unlocking + layering dnf is a very powerful development workflow to the point where I’d almost want dnf included in Silverblue by default.
Unfortunately, this workflow is also unobvious enough that the dnf maintainers &lt;a href="https://github.com/rpm-software-management/dnf/issues/2108"&gt;accidentally prevented it from working&lt;/a&gt; some time ago (thankfully, quickly corrected).
I understand the UX concern about having dnf visibly available when it cannot work outside this specific workflow, but perhaps Silverblue could just hide it somehow unless the host is unlocked, or rename the dnf binary?&lt;/p&gt;
&lt;h2 id="persistent-unlocking"&gt;Persistent unlocking &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#persistent-unlocking"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Generally to put something persistently on the host, you’d just layer it with &lt;code&gt;rpm-ostree install&lt;/code&gt;.
However, sometimes what you want is a &lt;em&gt;temporary&lt;/em&gt; change that also &lt;em&gt;happens to persist&lt;/em&gt; across reboots.&lt;/p&gt;
&lt;p&gt;This sounds weird, but consider testing a kernel build.
You want it to be temporary and easy to roll back, but you kinda have to reboot into the new kernel.
And you also don’t want to spend extra time building and layering .rpms.&lt;/p&gt;
&lt;p&gt;For this situation, &lt;code&gt;ostree admin unlock&lt;/code&gt; comes with a &lt;code&gt;--hotfix&lt;/code&gt; flag.
It’ll persist the temporary overlay across reboots, and will only reset itself once you explicitly make some change with &lt;code&gt;rpm-ostree&lt;/code&gt;.
Note that you never lose the ability to reboot into the previous, working system.&lt;/p&gt;
&lt;h2 id="summing-it-all-up"&gt;Summing it all up &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#summing-it-all-up"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, this is what my development workflow looks like.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most work happens in one kitchen-sink toolbox that I (like to but am not required to) reinstall every Fedora release to keep cruft from building up. This includes building and running niri on a TTY.&lt;/li&gt;
&lt;li&gt;After finishing a change, I unlock the host with &lt;code&gt;sudo ostree admin unlock&lt;/code&gt;, copy over the niri binary, and re-log in to test it in my real session. This will automatically reset upon a reboot.&lt;/li&gt;
&lt;li&gt;When working on a long-running branch, I’ll build a work-in-progress niri .rpm and layer it with &lt;code&gt;rpm-ostree install&lt;/code&gt; to persist the new version across reboots.&lt;/li&gt;
&lt;li&gt;I use &lt;code&gt;dnf install&lt;/code&gt; on the host when I want to throwaway-test something host-specific and have it automatically reset upon a reboot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over time I made a few small quality-of-life tweaks to smooth out some rough edges in this workflow.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;toolbox enter&lt;/code&gt; is a mouthful and always drops me into &lt;em&gt;bash&lt;/em&gt;.
Enter &lt;code&gt;t&lt;/code&gt;, a script in my &lt;code&gt;~/.local/bin/&lt;/code&gt;, always available in &lt;code&gt;$PATH&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$#&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="nv"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fish
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="nv"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%q "&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;exec&lt;/span&gt; toolbox run -c fedora-toolbox-44 bash -ic &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, typing &lt;code&gt;t&lt;/code&gt; puts me in the toolbox directly into my dear &lt;a href="https://fishshell.com/"&gt;fish&lt;/a&gt; shell.
Typing&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;t some-program "with complex" arguments | grep "and stuff"
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;also works as expected, with correct argument passing thanks to &lt;code&gt;printf "%q "&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This works for .desktop files too.
Say, you installed VSCode in the toolbox and got a .desktop file.
Just change:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Exec=/usr/share/code/code --ozone-platform-hint=auto %F
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;to:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Exec=t /usr/share/code/code --ozone-platform-hint=auto %F
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and it’ll run in the toolbox.
(I understand distrobox handles .desktop files automatically.)&lt;/p&gt;
&lt;p&gt;Note that I use &lt;code&gt;toolbox run&lt;/code&gt; but route the command through bash.
This is necessary to get all environment variables like &lt;code&gt;$DEBUGINFOD_URLS&lt;/code&gt; that distros keep stubbornly putting in &lt;code&gt;/etc/profile.d/&lt;/code&gt; scripts, which of course don’t get sourced without a &lt;code&gt;bash -i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another quality-of-life improvement was binding a separate hotkey to spawning a terminal directly in the toolbox.
I actually noticed that most of the time, when I open a terminal, I want to be in the toolbox, so now my &lt;kbd&gt;Super&lt;/kbd&gt;&lt;kbd&gt;T&lt;/kbd&gt; spawns the toolbox Alacritty, while the less convenient &lt;kbd&gt;Super&lt;/kbd&gt;&lt;kbd&gt;Shift&lt;/kbd&gt;&lt;kbd&gt;T&lt;/kbd&gt; spawns the host Alacritty.&lt;/p&gt;
&lt;p&gt;Furthermore, at some point I got tired of waiting for the…&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌ ~
└─ hyperfine -w 3 --shell=none 'true' 't true'
Benchmark 1: true
  Time (mean ± σ):     411.9 µs ±  35.8 µs    [User: 248.9 µs, System: 111.3 µs]
  Range (min … max):   374.1 µs … 1147.6 µs    5794 runs

Benchmark 2: t true
  Time (mean ± σ):     257.8 ms ±   2.0 ms    [User: 3.0 ms, System: 6.1 ms]
  Range (min … max):   255.2 ms … 260.5 ms    11 runs

Summary
  true ran
  625.92 ± 54.60 times faster than t true
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;…extra 250 ms for &lt;code&gt;toolbox run&lt;/code&gt;, and &lt;a href="https://github.com/YaLTeR/dotfiles/blob/577e11f7b8a0a33601fc4764e8fd390cf23ff936/source/sh/executable_spawn-alacritty.bash"&gt;wrote a script&lt;/a&gt; that keeps Alacritty running as a daemon inside (and outside) the toolbox, making opening a new terminal window always instant.
As a bonus, this happens to fix the SIGHUP problem that I mentioned above: since Alacritty runs directly inside the toolbox, closing its window will properly close the terminal app running inside.&lt;/p&gt;
&lt;p&gt;(Eventually I went even further and made a &lt;a href="https://github.com/YaLTeR/dotfiles/tree/577e11f7b8a0a33601fc4764e8fd390cf23ff936/source/misc/toolbox-server"&gt;tiny service&lt;/a&gt; for fun that runs inside the toolbox, listens to a socket, and runs the command it receives. I only use it in .desktop files though instead of &lt;code&gt;t&lt;/code&gt; to avoid the 250 ms delay.&lt;sup id="fnref:7"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:7"&gt;7&lt;/a&gt;&lt;/sup&gt;)&lt;/p&gt;
&lt;h2 id="what-about-other-systems"&gt;What about other systems? &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#what-about-other-systems"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I quite like my Silverblue setup.
It very much &lt;em&gt;works&lt;/em&gt;, and with the tools that it has, it lets me do anything that I might need.&lt;/p&gt;
&lt;p&gt;Silverblue is not without its problems however, so I’ve been thinking about what parts of the experience I find important, and how well other distributions currently satisfy them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. The ability to reboot to a previous, working system.&lt;/strong&gt;
Most new atomic/immutable distros can do this since it’s the main value proposition.
It’s also possible on &lt;a href="https://nixos.org/"&gt;NixOS&lt;/a&gt;.
On traditional distros I think you can get something close with btrfs snapshots, but it requires a complex setup.&lt;/p&gt;
&lt;p&gt;A/B updates tie closely into this, where rather than mutating the running system, an update is prepared in a separate folder, then atomically swapped with the previous system version (which remains available to boot into should something go awry).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Anti-hysteresis.&lt;/strong&gt;
The host system always stays clean, packages don’t build up over time.&lt;/p&gt;
&lt;p&gt;On a normal distro, a few months is enough for you to scarcely have any idea about all the random one-off packages you installed and forgot about, especially various development tooling and build dependencies &lt;del&gt;not to mention the texlive-full installation&lt;/del&gt;.
They use up disk space and time during system updates, sometimes cause conflicts and other annoying issues.
Config migrations build up, and your system gradually drifts away from a clean well-tested upstream state.&lt;/p&gt;
&lt;p&gt;Immutable distros solve this by not letting you install stuff on the host, and every updated rebuild of the host system starts from a fresh state, so there’s no accumulation of junk.&lt;/p&gt;
&lt;p&gt;NixOS and Silverblue do let you add (layer) packages, so they &lt;em&gt;can&lt;/em&gt; build up, but:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they make it sufficiently annoying, making you prefer non-host environments such as toolbox for one-off packages;&lt;/li&gt;
&lt;li&gt;even with layered packages, the system is rebuilt from a fresh state every update.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Technically, you could use toolbox for everything even on a normal Fedora Workstation, but this requires discipline and doesn’t save you from config migrations, SELinux labeling changes, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. The ability to easily install things on the host.&lt;/strong&gt;
This is the part where many newer immutable distros fail to provide a good experience.
I &lt;em&gt;need&lt;/em&gt; to install programs on the host, whether it’s because I want some host desktop components, or to test my own compositor, or whatever.&lt;/p&gt;
&lt;p&gt;Often, I want to install something on the host &lt;em&gt;quickly&lt;/em&gt;.
For distros such as &lt;a href="https://universal-blue.org/"&gt;Universal Blue&lt;/a&gt; spins and other &lt;a href="https://bootc.dev/"&gt;bootc&lt;/a&gt;-based systems, the suggested way to include components on the host is making your own downstream spin.
But this works only for long-term packages: I don’t want to spend time editing and kicking off a full system build just to test some new terminal or notification daemon, not to mention the whole question of how to keep such a custom system always up to date with its base distro.&lt;/p&gt;
&lt;p&gt;Compare this with &lt;code&gt;rpm-ostree install&lt;/code&gt; on Silverblue: one command, slow but tolerable, and the OS remains automatically updated with no extra setup.&lt;/p&gt;
&lt;p&gt;Some systems are even more limited, like &lt;a href="https://os.gnome.org/"&gt;GNOME OS&lt;/a&gt; which is based on the &lt;a href="https://gitlab.com/freedesktop-sdk/freedesktop-sdk"&gt;Freedesktop SDK&lt;/a&gt;.
The selection of tools and libraries available in the Freedesktop SDK is (intentionally) much more limited compared to most distros, so in many cases you’ll find yourself having to go and build whatever you need from source.
If that happens to be something big and complex like Qt (to try a hot new &lt;a href="https://quickshell.org/"&gt;Quickshell&lt;/a&gt;-based desktop): good luck; I hope you didn’t have plans for the weekend.&lt;/p&gt;
&lt;p&gt;A common suggestion for these OSes is &lt;a href="https://0pointer.net/blog/testing-my-system-code-in-usr-without-modifying-usr.html"&gt;systemd-sysext&lt;/a&gt; that lets you build an image and overlay it over /usr.
Florian Müllner &lt;a href="https://www.youtube.com/watch?v=4BsL0VyCoWs&amp;amp;t=10292s"&gt;gave a talk&lt;/a&gt; at the 2025 GUADEC showing a nice workflow for using sysexts for Mutter and GNOME Shell development and testing on immutable distros.&lt;/p&gt;
&lt;p&gt;It’s also possible to enforce system version compatibility checks in sysexts.
A system like GNOME OS could build and ship a collection of sysexts version-locked to the runtime they were built against, and automatically updated together with the rest of the system using systemd-sysupdate, resulting in an experience similar to layered packages.
(In fact, GNOME OS does have that, just the selection of sysexts is fairly small.)&lt;/p&gt;
&lt;p&gt;Some software can be packaged into self-contained sysexts that work on most distros.
The Flatcar &lt;a href="https://flatcar.github.io/sysext-bakery/"&gt;sysext-bakery&lt;/a&gt; is one repository of such sysexts.&lt;/p&gt;
&lt;p&gt;What’s wrong then?
Well, the main limitation of sysexts is that they are meant for tools without dependencies.
They do not do any dependency resolution or support any dependencies other than, optionally, the base OS itself.
Back to my example, while it’s possible to build and ship sysexts for Qt apps that bundle Qt itself, all of those sysexts will carry their own copies of Qt.
Even worse, since they are mounted into the same filesystem tree, conflicting files (say, different-version Qt binaries) will get mounted only from &lt;em&gt;one&lt;/em&gt; of the sysexts, whichever one happens to mount last.
So sysexts aren’t a complete replacement for packages (nor are they intended to be).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. The ability to make transient changes to the host.&lt;/strong&gt;
While I don’t immediately see why you couldn’t put a writable overlay on any regular distro like what &lt;code&gt;ostree admin unlock&lt;/code&gt; does, I haven’t seen anyone doing it, or any simple “no thinking necessary” tools for it.&lt;sup id="fnref1:1"&gt;&lt;a class="footnote-ref" href="https://bxt.rs/tags/planet-gnome/index.xml#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;
Perhaps it’s too easy to mess up outside immutable systems?&lt;/p&gt;
&lt;p&gt;It’s worth noting that some paths like &lt;code&gt;/etc&lt;/code&gt; aren’t usually covered by immutability and overlays, so you still need to be a bit careful.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion &lt;a class="anchor" href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/#conclusion"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all, Silverblue appears to be a sweet spot between offering immutable/atomic guarantees with plenty of useful tooling bundled in, while also being a &lt;em&gt;normal Fedora&lt;/em&gt; with a wide package selection available for both persistent layering and quick transient installation.
I appreciate the QA and other behind-the-scenes work that goes into my ability to install Silverblue and be reasonably sure that it will work, and keep working, with all of my hardware, and that I won’t have to hunt for packages to get a working bluetooth or what have you.
My Silverblue installs are the longest I’ve kept any single distro, and I have no urge to reinstall because my host system remains clean and I know exactly what it comprises.&lt;/p&gt;
&lt;p&gt;My issues with Silverblue mostly boil down to some rough edges and slowness of &lt;code&gt;rpm-ostree&lt;/code&gt;, and some less than ideal Flatpak repository defaults.
Having to do most of the work in a container is somewhat annoying at times, especially when dealing with nested containerization or VMs.
But I’m not sure there’s a better way fundamentally, without trading host system robustness.
For the few things that do require it, I can always unlock the host.&lt;/p&gt;
&lt;p&gt;I hope this post sheds some light on immutable system workflows and perhaps inspires you to try one.
I’d also love to hear your feedback and suggestions!
Did I miss something?
Is there a better way of doing things?
A new system that solves all problems and makes everything better?
Please reach out to me on Mastodon or by email, linked at the bottom of the page!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I’m told the modern alternative is &lt;code&gt;systemd-sysext merge --mutable=ephemeral&lt;/code&gt;, which works across all distros and not just Silverblue. Haven’t tried it myself yet! &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:1"&gt;↩︎&lt;/a&gt; &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref1:1"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;I didn’t quite realize this before, but &lt;code&gt;rpm-ostree usroverlay&lt;/code&gt; seems to literally exec &lt;code&gt;ostree admin unlock&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌ ~
└─ rpm-ostree usroverlay -h
Usage:
  ostree admin unlock [OPTION…]

Make the current deployment mutable (as a hotfix or development)
(...)
┌ ~
└─ rpm-ostree usroverlay --version
libostree:
 Version: '2025.4'
 Git: 99a03a7bb8caa774668222a0caace3b7e734042e
(...)
&lt;/code&gt;&lt;/pre&gt; &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:2"&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Which is, uhh, not a lot of apps come to think of it. Nautilus, Ptyxis, Software, System Monitor, Settings, xdg-desktop-portal-gnome dialogs—the rest come as Flatpaks on Silverblue. How to test your GTK changes against those Flatpak apps? Uhhhhhh &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:3"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;For years, it’s been &lt;code&gt;rpm-ostree ex apply-live&lt;/code&gt;, where &lt;code&gt;ex&lt;/code&gt; stood for &lt;em&gt;experimental&lt;/em&gt;. I guess I’ve been procrastinating on this blogpost long enough that it had time to graduate to non-experimental &lt;code&gt;rpm-ostree apply-live&lt;/code&gt;. &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:4"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;The &lt;a href="https://flathub.org/en/apps/app.devsuite.Ptyxis"&gt;Ptyxis&lt;/a&gt; terminal can work properly on the host even when installed as a Flatpak. It does this by spawning a small binary on the host (through a host-run permission) that does all command spawning and PTY communication, while the Ptyxis GUI remains inside Flatpak. This is a clever workaround, but requires a sandbox hole and very careful engineering, and arguably runs somewhat at odds with the point of Flatpak. &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:5"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;Since writing that example, I replaced that monitor and finally got rid of the custom initramfs.
This is faster because without overrides, Silverblue directly uses an initramfs built on Fedora servers, and I think it also works better with secure boot?
Either way, I wanted to leave it in as an example that you &lt;em&gt;can&lt;/em&gt; customize the initramfs on Silverblue if needed. &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:6"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;See for yourself:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌ ~
└─ hyperfine -w 3 --shell=none 't true' 'true' 'tb true'
Benchmark 1: t true
  Time (mean ± σ):     259.5 ms ±   3.6 ms    [User: 2.9 ms, System: 6.2 ms]
  Range (min … max):   255.7 ms … 266.6 ms    11 runs

Benchmark 2: true
  Time (mean ± σ):     408.7 µs ±  34.2 µs    [User: 248.6 µs, System: 107.1 µs]
  Range (min … max):   370.2 µs … 1152.8 µs    6665 runs

Benchmark 3: tb true
  Time (mean ± σ):     462.8 µs ±  41.7 µs    [User: 264.2 µs, System: 135.6 µs]
  Range (min … max):   399.2 µs … 786.4 µs    6688 runs

Summary
  true ran
    1.13 ± 0.14 times faster than tb true
  635.00 ± 53.80 times faster than t true
&lt;/code&gt;&lt;/pre&gt; &lt;a class="footnote-backref" href="https://bxt.rs/tags/planet-gnome/index.xml#fnref:7"&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content>
    <link href="https://bxt.rs/blog/using-fedora-silverblue-for-compositor-development/"/>
    <published>2026-06-05T12:37:00+00:00</published>
  </entry>
  <entry>
    <id>https://thisweek.gnome.org/posts/2026/06/twig-252/</id>
    <title>This Week in GNOME: #252 Stronger Together</title>
    <updated>2026-06-06T11:32:44+00:00</updated>
    <author>
      <name>This Week in GNOME</name>
    </author>
    <content type="html">&lt;p&gt;As in previous years, This Week in GNOME and this entire month are dedicated to the joys and struggles of all two-spirit, lesbian, gay, bi, trans, queer, inter, pan, asexual, aromantic, and non-binary people. We celebrate the invaluable work and life of all 2SLGBTQIA+ contributors and users, across all backgrounds and experiences.&lt;/p&gt;
&lt;p&gt;&lt;img height="630" src="https://thisweek.gnome.org/_astro/image.DYzYXsTz_1DF9WT.webp" width="1200"/&gt;&lt;/p&gt;
&lt;p&gt;Attempts to divide queer communities are not stopping. Fundamental human rights, hard-won over decades of struggle, are still under attack.&lt;/p&gt;
&lt;p&gt;But we are here and we are not going anywhere. The GNOME community stands with queer people, now and always.&lt;/p&gt;
&lt;p&gt;Together we are stronger.&lt;/p&gt;
&lt;h2 id="gnome-core-apps-and-libraries"&gt;GNOME Core Apps and Libraries&lt;/h2&gt;
&lt;h3 id="file-previewer-"&gt;File Previewer &lt;a href="https://gitlab.gnome.org/GNOME/sushi"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A previewer companion for GNOME Files.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@p3732:matrix.org"&gt;Peter Eisenmann&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The last few weeks have been busy for &lt;a href="https://gitlab.gnome.org/GNOME/sushi"&gt;sushi&lt;/a&gt;, the previewer companion for nautilus. Not only did Corey Berla’s GTK4 port finally land, but on top of that Tau Gärtli, Nokse and myself have made several modernizations. The major changes are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dark mode support&lt;/li&gt;
&lt;li&gt;GTK4, libadwaita, glycin and (initial) Blueprint usage&lt;/li&gt;
&lt;li&gt;Rework layout of several previewers&lt;/li&gt;
&lt;li&gt;Nicer floating toolbars&lt;/li&gt;
&lt;li&gt;Modernize code to use EcmaScript modules&lt;/li&gt;
&lt;li&gt;Cleaned up deprecated function usages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can test these changes in GNOME OS or by installing sushi and nautilus from the gnome-nightly Flatpak repository.&lt;/p&gt;
&lt;p&gt;Greetings from GPN in Karlsruhe!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="gjs-"&gt;GJS &lt;a href="https://gitlab.gnome.org/GNOME/gjs"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the GNOME platform libraries in your JavaScript programs. GJS powers GNOME Shell, Polari, GNOME Documents, and many other apps.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@JumpLink:matrix.org"&gt;JumpLink&lt;/a&gt; announces&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m currently working on a TypeScript framework for GJS called &lt;a href="https://gjsify.github.io/gjsify/"&gt;gjsify&lt;/a&gt;, and it has just hit a new milestone: the TypeScript compiler (v6.x) now runs directly inside GJS, so Node.js is no longer needed to run &lt;code&gt;tsc&lt;/code&gt;. Just install gjsify and invoke it with &lt;code&gt;gjsify tsc&lt;/code&gt;. Beyond &lt;code&gt;tsc&lt;/code&gt;, there are other handy commands too, like &lt;code&gt;gjsify install&lt;/code&gt; as a drop-in replacement for &lt;code&gt;npm install&lt;/code&gt;, all running natively in GJS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="third-party-projects"&gt;Third Party Projects&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@m23snezhok:chen.moe"&gt;Mikhail Kostin&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vinyl v1.4.0 has been &lt;a href="https://codeberg.org/M23Snezhok/Vinyl/releases/tag/v1.4.0"&gt;released&lt;/a&gt;! There is a lot of changes since v1.3.2. Over the course of a month, I tried to do as much work as possible on the functionality and accessibility of the player. I also want to say with confidence that Vinyl is the first GNOME music player with the ability to read lyrics directly from an ID3v2 tag.&lt;/p&gt;
&lt;p&gt;Here is the list of changes that the app has undergone:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added opportunity to synced parse lyrics directly from ID3v2 tag&lt;/li&gt;
&lt;li&gt;Added a lot of shortcuts, for playback and UI&lt;/li&gt;
&lt;li&gt;Added functionality for a more detailed scan of covers (Ability to read covers separately for each track)&lt;/li&gt;
&lt;li&gt;Added a button to open the current directory for the playing track&lt;/li&gt;
&lt;li&gt;Added search by audio extension&lt;/li&gt;
&lt;li&gt;Added tooltips&lt;/li&gt;
&lt;li&gt;Changed track sorting, tracks are now sorted first by folder location rather than by tags&lt;/li&gt;
&lt;li&gt;The player has been localized into many languages ​​including German, Hindi, Czech, Slovak, Kazakh, Uzbek, Polish and Swedish&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today you can see the new version of the Vinyl on &lt;a href="https://flathub.org/en/apps/page.codeberg.M23Snezhok.Vinyl"&gt;Flathub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="670" src="https://thisweek.gnome.org/_astro/Vinyl.CrqFjvMH_Z1GeNC0.webp" width="800"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@balooii_:matrix.org"&gt;balooii&lt;/a&gt; reports&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;First release of Contributor Atlas!&lt;/p&gt;
&lt;p&gt;Contributor Atlas is a set of interactive visualizations that bring a project’s contributor history to life. It’s aimed at projects with a long legacy of contributors.&lt;/p&gt;
&lt;p&gt;I built it for GIMP and its ecosystem, with nearly 30 years of contributors to explore, but the graphs are generic - you might find it useful for your own project too.&lt;/p&gt;
&lt;p&gt;Explore the live GIMP dataset at the link below. I hope you find it as interesting as I do!
&lt;a href="https://contributor-atlas-4dab97.pages.gitlab.gnome.org"&gt;https://contributor-atlas-4dab97.pages.gitlab.gnome.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can find the project at &lt;a href="https://gitlab.gnome.org/balooii/contributor-atlas"&gt;https://gitlab.gnome.org/balooii/contributor-atlas&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1416" src="https://thisweek.gnome.org/_astro/contributor_atlas_GIMP_Gathering_dark.BgGXr22E_2qCKH9.webp" width="1698"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1638" src="https://thisweek.gnome.org/_astro/contributor_atlas_GIMP_Trails_light.BQEo3TWR_1bVnWs.webp" width="2046"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@mohfy:unredacted.org"&gt;mohfy&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This week i’ve released v2.0.0 of Quizbite, Quizbite is an educational app that let you create quizzes with multiple choice questions, play them and share them with your friends!&lt;/p&gt;
&lt;p&gt;You can also export the quiz to PDF, where you can print the quiz if you want to study offline.&lt;/p&gt;
&lt;p&gt;In version 2.0.0 we’ve added search for quizzes, added ability to review mistakes after taking the quiz, ability to edit a quiz after creation, and some fixes.&lt;/p&gt;
&lt;p&gt;Get Quizbite on Flathub: &lt;a href="https://flathub.org/en/apps/dev.mohfy.quizbite"&gt;https://flathub.org/en/apps/dev.mohfy.quizbite&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1300" src="https://thisweek.gnome.org/_astro/Quiz_Library.B8V4_8Wh_Z1rvVfB.webp" width="1700"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1300" src="https://thisweek.gnome.org/_astro/Quiz_Player.CBO2Ft08_LA9Hx.webp" width="1700"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="gitte-"&gt;Gitte &lt;a href="https://codeberg.org/ckruse/Gitte"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A simple Git GUI for GNOME&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@christian:kruse.cool"&gt;Christian&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Gitte, a simple Git client for GNOME built with GTK4, libadwaita and Relm4, just got its 0.6.0 release! 🎉&lt;/p&gt;
&lt;p&gt;The headline feature this time is per-file stash operations: you can now apply, pop or drop individual files from a stash via handy context-menu entries, and stash only the files you’ve selected in the working copy view, instead of always stashing everything.&lt;/p&gt;
&lt;p&gt;Commit messages also got a lot more interactive. URLs are turned into clickable links, &lt;code&gt;#&amp;lt;id&amp;gt;&lt;/code&gt; and &lt;code&gt;!&amp;lt;id&amp;gt;&lt;/code&gt; mentions are linkified for known forges, and authors and committers show up as &lt;code&gt;mailto:&lt;/code&gt; links. After pushing to a known forge, Gitte now offers a “New merge / pull request” link button so you can jump straight to creating one.&lt;/p&gt;
&lt;p&gt;There are new shortcuts to hide untracked files (&lt;code&gt;Ctrl+Shift+H&lt;/code&gt;) and to toggle untracked directories without recursing into them, and the staged/unstaged sections in split view are now collapsible, with an option to reverse their order.&lt;/p&gt;
&lt;p&gt;Under the hood the working copy view got a performance overhaul: Gitte can now browse the Linux kernel repository with 10k changed files with ease.&lt;/p&gt;
&lt;p&gt;Gitte also resolves &lt;code&gt;includeIf&lt;/code&gt; blocks when reading the Git configuration now. On top of that come colored pills in the branch info box, a pointer cursor on selectable diff lines, and the usual pile of smaller UI refinements and fixes.&lt;/p&gt;
&lt;p&gt;And there’s good news for BSD folks: Gitte is now available in the FreeBSD ports tree, so you can install it via &lt;code&gt;pkg install deskutils/gitte&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Get it on &lt;a href="https://flathub.org/apps/de.wwwtech.gitte"&gt;Flathub&lt;/a&gt;, &lt;a href="https://gitlab.com/dehesselle/gitte_macos/-/releases/v0.6.0+31"&gt;for macOS&lt;/a&gt; or &lt;a href="https://codeberg.org/ckruse/Gitte"&gt;have a look at the Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img height="1257" src="https://thisweek.gnome.org/_astro/gitte-partially-stash-changes.CRl3EIL5_Z2vb8Ki.webp" width="1795"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="1257" src="https://thisweek.gnome.org/_astro/gitte-partially-apply-stash.LKyZLLk9_Z9H8OK.webp" width="1795"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img height="384" src="https://thisweek.gnome.org/_astro/gitte-log-annotations.DF4HnQnA_ZRVvPe.webp" width="1796"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="miscellaneous"&gt;Miscellaneous&lt;/h2&gt;
&lt;h3 id="gnome-os-"&gt;GNOME OS &lt;a href="https://os.gnome.org"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The GNOME operating system, development and testing platform&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@pojntfx:matrix.org"&gt;Felicitas Pojtinger&lt;/a&gt; says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The documentation for contributing to GNOME Build Metadata (the project which builds things such as GNOME OS, the GNOME Flatpak runtimes and GNOME OCI images) got a big overhaul! If you ever wanted to build your own version of GNOME OS, want to make changes to your running GNOME OS system or fix a bug you’ve found somewhere, or if you’re just curious and want to learn more about how BuildStream, systemd-sysupdate/sysext or the Flatpak runtimes work, now is a great time to try it out! The new CONTRIBUTING.md document is a good place to start: &lt;a href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/master/CONTRIBUTING.md"&gt;https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/master/CONTRIBUTING.md&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="damned-lies-"&gt;Damned Lies &lt;a href="https://l10n.gnome.org"&gt;↗&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The internal application to manage localization of GNOME &amp;amp; friends modules&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matrix.to/#@guilieb:gnome.org"&gt;Guillaume Bernard&lt;/a&gt; announces&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A few changes for Damned Lies arrived this week! Our translation platform has received two external contributions, and we have very cool new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;@kristjan.esperanto added a dark theme to Damned Lies. You now have the possibility to switch between dark and light themes, or use the auto-mode that will follow your browser and desktop default theme.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;@balooii implemented a feature to better reward contributors who work on a workflow. The current implementation of the commit action only mentions the author of the translation and the committer. With this change, all volunteers who worked on a translation workflow are mentioned in the commit message with &lt;code&gt;Translated-by&lt;/code&gt;, &lt;code&gt;Reviewed-by&lt;/code&gt;, and &lt;code&gt;Contributed-by&lt;/code&gt; credits.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we have a fix from another contributor, @codeurluce who started contributing with a newcomer feature to fix a glitch in the interface.&lt;/p&gt;
&lt;p&gt;I also took the opportunity to work a bit on the Deneb theme that Damned Lies uses to enhance the contrast of the different buttons and elements. The &lt;a href="https://gitlab.gnome.org/Infrastructure/gnome-bootstrap-theme"&gt;gnome-boostrap-theme&lt;/a&gt; received a few updates that are now reflected in Damned Lies. As usual, if you find something odd, please report issues!&lt;/p&gt;
&lt;p&gt;Finally, in the diff view (the one you see on vertimus workflows) between a file and a previous version of a PO file, you now see some of the non-printable characters, like newlines, tabs, or non break spaces. If you use some in your language you’d like to have, just ask!&lt;/p&gt;
&lt;p&gt;This was a very intense week for Damned Lies, and if you’d like to plant a seed in the i18n ecosystem, please open an issue, contact us on the #i18n:gnome.org channel or ask for new features!&lt;/p&gt;
&lt;p&gt;&lt;img height="1419" src="https://thisweek.gnome.org/_astro/damned_lies.D6JuyTnU_Z28Y7bR.webp" width="1385"/&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="thats-all-for-this-week"&gt;That’s all for this week!&lt;/h2&gt;
&lt;p&gt;See you next week, and be sure to stop by &lt;a href="https://matrix.to/#/#thisweek:gnome.org"&gt;#thisweek:gnome.org&lt;/a&gt; with updates on your own projects!&lt;/p&gt;</content>
    <link href="https://thisweek.gnome.org/posts/2026/06/twig-252/"/>
    <published>2026-06-06T11:32:44+00:00</published>
  </entry>
</feed>
