<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>aahlenst.dev</title>
    <link>https://aahlenst.dev/</link>
    <description>Recent content on aahlenst.dev</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 12 Apr 2026 12:00:00 +0200</lastBuildDate>
    <atom:link href="https://aahlenst.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Autoscaling Forgejo Runner</title>
      <link>https://aahlenst.dev/blog/autoscaling-forgejo-runner/</link>
      <pubDate>Sun, 12 Apr 2026 12:00:00 +0200</pubDate>
      <guid>https://aahlenst.dev/blog/autoscaling-forgejo-runner/</guid>
      <description>&lt;p&gt;Over the last months, the Forgejo community equipped &lt;a href=&#34;https://forgejo.org/&#34;&gt;Forgejo&lt;/a&gt; and &lt;a href=&#34;https://code.forgejo.org/forgejo/runner&#34;&gt;Forgejo Runner&lt;/a&gt; with the necessary building blocks for autoscaling Forgejo Runner. These building blocks should enable developers of workload managers and autoscalers to build reliable and secure integrations for Forgejo Actions. This post aims to provide an overview of the new capabilities, explain how they fit together, and highlight some peculiarities to watch out for.&lt;/p&gt;&#xA;&lt;div class=&#34;not-prose bg-blue-50 border-l-4 border-blue-400 p-4&#34;&gt;&#xA;&#x9;&lt;div class=&#34;flex&#34;&gt;&#xA;&#x9;&#x9;&lt;div class=&#34;shrink-0&#34;&gt;&#xA;&#x9;&#x9;&#x9;&lt;svg class=&#34;h-8 w-8 text-blue-400&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; viewBox=&#34;0 0 24 24&#34;&#xA;&#x9;&#x9;&#x9;&#x9; aria-hidden=&#34;true&#34;&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; stroke-width=&#34;2&#34;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;  d=&#34;M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z&#34;&gt;&lt;/path&gt;&#xA;&#x9;&#x9;&#x9;&lt;/svg&gt;&#xA;&#x9;&#x9;&lt;/div&gt;&#xA;&#x9;&#x9;&lt;div class=&#34;admonition ml-3 text-blue-700&#34;&gt;&#xA;&#x9;&#x9;&#x9;Forgejo 15.0 and Forgejo Runner 12.8 or newer are required unless noted otherwise.&#xA;&#x9;&#x9;&lt;/div&gt;&#xA;&#x9;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;h2 id=&#34;autoscaling-in-a-nutshell&#34; class=&#34;group flex whitespace-pre-wrap items-center -ml-4 pl-4&#34;&gt; &lt;a class=&#34;absolute -ml-8 flex items-center opacity-0 border-0 group-hover:opacity-100&#34; href=&#34;#autoscaling-in-a-nutshell&#34; aria-label=&#34;anchor&#34;&gt;&#xA;        &lt;div class=&#34;w-6 h-6 text-red-400 ring-1 ring-red-900/5 rounded-md shadow-xs flex items-center justify-center hover:ring-red-900/10 hover:shadow-sm hover:text-red-700 dark:bg-red-700 dark:text-red-300 dark:shadow-none dark:ring-0&#34;&gt;&#xA;            &lt;svg class=&#34;w-4 h-4&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; viewBox=&#34;0 0 24 24&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; stroke-width=&#34;2&#34; d=&#34;M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1&#34;&gt;&lt;/path&gt;&lt;/svg&gt;&#xA;        &lt;/div&gt;   &#xA;    &lt;/a&gt;&lt;span&gt;Autoscaling in a Nutshell&lt;/span&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;To scale Forgejo Runner instances up and down, an external system has to perform the following tasks:&lt;/p&gt;</description>
    </item>
    <item>
      <title>systemd Credentials in Spring Boot</title>
      <link>https://aahlenst.dev/blog/systemd-credentials-in-spring-boot/</link>
      <pubDate>Thu, 10 Jul 2025 12:00:00 +0100</pubDate>
      <guid>https://aahlenst.dev/blog/systemd-credentials-in-spring-boot/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://systemd.io/&#34;&gt;systemd&lt;/a&gt;, Linux&amp;rsquo;s most widely used system and service manager, introduced &lt;a href=&#34;https://systemd.io/CREDENTIALS/&#34;&gt;system and service credentials&lt;/a&gt; with version 247. They allow for securely passing passwords and keys to applications, thereby solving a longstanding problem. Let&amp;rsquo;s find out how we can access them in &lt;a href=&#34;https://spring.io/projects/spring-boot&#34;&gt;Spring Boot&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introducing-systemd-credentials&#34; class=&#34;group flex whitespace-pre-wrap items-center -ml-4 pl-4&#34;&gt; &lt;a class=&#34;absolute -ml-8 flex items-center opacity-0 border-0 group-hover:opacity-100&#34; href=&#34;#introducing-systemd-credentials&#34; aria-label=&#34;anchor&#34;&gt;&#xA;        &lt;div class=&#34;w-6 h-6 text-red-400 ring-1 ring-red-900/5 rounded-md shadow-xs flex items-center justify-center hover:ring-red-900/10 hover:shadow-sm hover:text-red-700 dark:bg-red-700 dark:text-red-300 dark:shadow-none dark:ring-0&#34;&gt;&#xA;            &lt;svg class=&#34;w-4 h-4&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; viewBox=&#34;0 0 24 24&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; stroke-width=&#34;2&#34; d=&#34;M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1&#34;&gt;&lt;/path&gt;&lt;/svg&gt;&#xA;        &lt;/div&gt;   &#xA;    &lt;/a&gt;&lt;span&gt;Introducing systemd Credentials&lt;/span&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;In their simplest form, systemd credentials are straightforward:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Finding EFI Firmware That Is Compatible</title>
      <link>https://aahlenst.dev/blog/finding-efi-firmware-that-is-compatible/</link>
      <pubDate>Sun, 07 Jul 2024 12:00:00 +0200</pubDate>
      <guid>https://aahlenst.dev/blog/finding-efi-firmware-that-is-compatible/</guid>
      <description>&lt;p&gt;I run some QEMU/KVM virtual machines as part of one of my GitHub Actions workflows. To reduce the workflow&amp;rsquo;s runtime and to help make it reproducible, it uses pre-built disk images and pre-defined XML domain configurations for &lt;a href=&#34;https://libvirt.org/&#34;&gt;libvirt&lt;/a&gt;. That worked well until I changed the workflow to use the &lt;a href=&#34;https://github.blog/changelog/2024-05-14-github-hosted-runners-public-beta-of-ubuntu-24-04-is-now-available/&#34;&gt;new Ubuntu 24.04 images&lt;/a&gt;. Afterwards, libvirt rejected the domain configuration with an error I had not encountered before:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;libvirt.libvirtError: operation failed: Unable to find &amp;rsquo;efi&amp;rsquo; firmware that is compatible with the current configuration&lt;/p&gt;</description>
    </item>
    <item>
      <title>Storing Blobs on the GitHub Container Registry</title>
      <link>https://aahlenst.dev/blog/storing-blobs-on-github-container-registry/</link>
      <pubDate>Sat, 06 Jul 2024 12:00:00 +0200</pubDate>
      <guid>https://aahlenst.dev/blog/storing-blobs-on-github-container-registry/</guid>
      <description>&lt;p&gt;Recently, I had the need to access some virtual machine images in one of my GitHub Actions workflows. As they came in at more than 1 GB, I was hard-pressed for a place to store them that was also easy to access from a GitHub Actions workflow. If only I could upload a ZIP archive to &lt;a href=&#34;https://github.com/features/packages&#34;&gt;GitHub Packages&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;p&gt;It turns out that it is not only possible but also much easier than I imagined it to be. Let&amp;rsquo;s learn how.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Helping You Find the JDK That Fits Your Needs</title>
      <link>https://aahlenst.dev/blog/helping-you-find-the-jdk-that-fits-your-needs/</link>
      <pubDate>Wed, 27 Sep 2023 12:00:00 +0200</pubDate>
      <guid>https://aahlenst.dev/blog/helping-you-find-the-jdk-that-fits-your-needs/</guid>
      <description>&lt;p&gt;In the last few years, the choice of JDKs has exploded. Almost everyone offers one, even &lt;a href=&#34;https://microsoft.com/openjdk/&#34;&gt;Microsoft&lt;/a&gt;. &lt;a href=&#34;https://faculty.washington.edu/jdb/345/345%20Articles/Iyengar%20%26%20Lepper%20(2000).pdf&#34;&gt;Unsurprisingly&lt;/a&gt;, people struggle to pick a JDK and are looking for help.&lt;/p&gt;&#xA;&lt;p&gt;While we can learn that &lt;a href=&#34;https://medium.com/@javachampions/java-is-still-free-3-0-0-ocrt-2021-bca75c88d23b&#34;&gt;Java Is Still Free&lt;/a&gt; and get told &lt;a href=&#34;https://whichjdk.com/&#34;&gt;which JDK we should use&lt;/a&gt;, nobody seems to provide a comprehensive overview of the differences between the various JDKs. The best I could find is &lt;a href=&#34;https://www.azul.com/products/core/jdk-comparison-matrix/&#34;&gt;OpenJDK vs Oracle JDK – Comparison Table&lt;/a&gt; authored by Azul&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Testing Container Images</title>
      <link>https://aahlenst.dev/blog/testing-container-images/</link>
      <pubDate>Fri, 23 Dec 2022 12:00:00 +0100</pubDate>
      <guid>https://aahlenst.dev/blog/testing-container-images/</guid>
      <description>&lt;p&gt;More and more software is delivered as a container image for container runtimes like &lt;a href=&#34;https://www.docker.com/&#34;&gt;Docker&lt;/a&gt;, &lt;a href=&#34;https://podman.io/&#34;&gt;Podman&lt;/a&gt;, and &lt;a href=&#34;https://containerd.io/&#34;&gt;Containerd&lt;/a&gt;. Even simple container images require substantial logic for their creation and configuration (for example, the &lt;a href=&#34;https://github.com/nginxinc/docker-nginx/blob/5ce65c3efd395ee2d82d32670f233140e92dba99/Dockerfile-debian.template&#34;&gt;official nginx image&lt;/a&gt;). Hence, container images should be automatically tested like all other software deliverables to prevent bugs and security issues from creeping in.&lt;/p&gt;&#xA;&lt;p&gt;In this article, I present multiple tools that help to examine container images and their configuration.&lt;/p&gt;&#xA;&lt;p&gt;The basis forms a hypothetical container image for the webserver &lt;a href=&#34;https://nginx.org/&#34;&gt;nginx&lt;/a&gt; called &lt;code&gt;myimage&lt;/code&gt;:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Comparing Parallel Test Execution in JUnit 5, Gradle, and Maven</title>
      <link>https://aahlenst.dev/blog/comparing-parallel-test-execution-in-junit5-gradle-maven/</link>
      <pubDate>Thu, 01 Dec 2022 12:00:00 +0100</pubDate>
      <guid>https://aahlenst.dev/blog/comparing-parallel-test-execution-in-junit5-gradle-maven/</guid>
      <description>&lt;p&gt;JUnit 5, Gradle, and Maven: All offer parallel execution of unit tests. With so many options, I wondered whether it makes a difference what I pick. It does.&lt;/p&gt;&#xA;&lt;h2 id=&#34;capabilities-of-the-contenders&#34; class=&#34;group flex whitespace-pre-wrap items-center -ml-4 pl-4&#34;&gt; &lt;a class=&#34;absolute -ml-8 flex items-center opacity-0 border-0 group-hover:opacity-100&#34; href=&#34;#capabilities-of-the-contenders&#34; aria-label=&#34;anchor&#34;&gt;&#xA;        &lt;div class=&#34;w-6 h-6 text-red-400 ring-1 ring-red-900/5 rounded-md shadow-xs flex items-center justify-center hover:ring-red-900/10 hover:shadow-sm hover:text-red-700 dark:bg-red-700 dark:text-red-300 dark:shadow-none dark:ring-0&#34;&gt;&#xA;            &lt;svg class=&#34;w-4 h-4&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; viewBox=&#34;0 0 24 24&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; stroke-width=&#34;2&#34; d=&#34;M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1&#34;&gt;&lt;/path&gt;&lt;/svg&gt;&#xA;        &lt;/div&gt;   &#xA;    &lt;/a&gt;&lt;span&gt;Capabilities of the Contenders&lt;/span&gt;&#xA;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;junit-5&#34; class=&#34;group flex whitespace-pre-wrap items-center -ml-4 pl-4&#34;&gt; &lt;a class=&#34;absolute -ml-8 flex items-center opacity-0 border-0 group-hover:opacity-100&#34; href=&#34;#junit-5&#34; aria-label=&#34;anchor&#34;&gt;&#xA;        &lt;div class=&#34;w-6 h-6 text-red-400 ring-1 ring-red-900/5 rounded-md shadow-xs flex items-center justify-center hover:ring-red-900/10 hover:shadow-sm hover:text-red-700 dark:bg-red-700 dark:text-red-300 dark:shadow-none dark:ring-0&#34;&gt;&#xA;            &lt;svg class=&#34;w-4 h-4&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; viewBox=&#34;0 0 24 24&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; stroke-width=&#34;2&#34; d=&#34;M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1&#34;&gt;&lt;/path&gt;&lt;/svg&gt;&#xA;        &lt;/div&gt;   &#xA;    &lt;/a&gt;&lt;span&gt;JUnit 5&lt;/span&gt;&#xA;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://junit.org/junit5/docs/5.9.0/user-guide/index.html#writing-tests-parallel-execution&#34;&gt;Parallel test execution is an experimental feature of JUnit 5&lt;/a&gt; that has been available since version 5.3. Once enabled, you can define whether you want to run top-level test classes or methods sequentially, concurrently or any combination thereof. JUnit 5 runs all tests in a single JVM using a &lt;a href=&#34;https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/util/concurrent/ForkJoinPool.html&#34;&gt;ForkJoinPool&lt;/a&gt;. There are various knobs to control how many tests should be run in parallel.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Fast, Reliable Integration Tests with Spring Boot and Flyway</title>
      <link>https://aahlenst.dev/blog/fast-reliable-integration-tests-with-spring/</link>
      <pubDate>Fri, 25 Nov 2022 12:00:00 +0100</pubDate>
      <guid>https://aahlenst.dev/blog/fast-reliable-integration-tests-with-spring/</guid>
      <description>&lt;p&gt;For integration tests to be effective, they must be reliable and fast. If tests take too long to run, nobody will run them. If tests are unreliable, everybody will ignore them.&lt;/p&gt;&#xA;&lt;p&gt;To be reliable, tests may not result in false positives or negatives. Furthermore, they should not be flaky. That can be achieved by isolating the tests from each other, for example, by supplying a dedicated test database to each test with the help of &lt;a href=&#34;https://www.testcontainers.org/&#34;&gt;Testcontainers&lt;/a&gt;. Additionally, tests should start from a known, consistent good state. That can be achieved by resetting the database to a known, good state before every test. Unfortunately, all that additional work makes tests slower.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Keeping the Growing Number of Flyway Migrations in Check</title>
      <link>https://aahlenst.dev/blog/keeping-the-growing-number-of-flyway-migrations-in-check/</link>
      <pubDate>Thu, 24 Nov 2022 12:00:00 +0100</pubDate>
      <guid>https://aahlenst.dev/blog/keeping-the-growing-number-of-flyway-migrations-in-check/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://flywaydb.org&#34;&gt;Flyway&lt;/a&gt; is a fantastic tool for managing an application&amp;rsquo;s database alongside the application&amp;rsquo;s source code. But even in small projects, the number of migrations grows inevitably. That is no problem for application startup. But if you use Flyway to initialise the database before every integration test to ensure your tests are independent and reliable, the tests take longer with every migration you add. For example, if you have 50 migrations that take 1 second to run and there are 600 test methods, you would spend 10 CPU minutes alone on creating test databases. There must be a better way.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Managing Xcode on the Command Line</title>
      <link>https://aahlenst.dev/blog/managing-xcode-on-the-command-line/</link>
      <pubDate>Thu, 23 Dec 2021 12:00:00 +0100</pubDate>
      <guid>https://aahlenst.dev/blog/managing-xcode-on-the-command-line/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://github.com/xcpretty/xcode-install&#34;&gt;xcode-install&lt;/a&gt; is a nifty tool to install and manage Xcode over the command line. Furthermore, it supports installing multiple Xcode versions side-by-side. It can even install all kinds of simulators and works great with automation tools like Ansible.&lt;/p&gt;&#xA;&lt;div class=&#34;not-prose bg-green-50 border-l-4 border-green-400 p-4&#34;&gt;&#xA;&#x9;&lt;div class=&#34;flex&#34;&gt;&#xA;&#x9;&#x9;&lt;div class=&#34;shrink-0&#34;&gt;&#xA;&#x9;&#x9;&#x9;&lt;svg class=&#34;h-8 w-8 text-green-400&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; viewBox=&#34;0 0 24 24&#34;&#xA;&#x9;&#x9;&#x9;&#x9; aria-hidden=&#34;true&#34;&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&lt;path stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; stroke-width=&#34;2&#34;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;  d=&#34;M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z&#34;&gt;&lt;/path&gt;&#xA;&#x9;&#x9;&#x9;&lt;/svg&gt;&#xA;&#x9;&#x9;&lt;/div&gt;&#xA;&#x9;&#x9;&lt;div class=&#34;admonition ml-3 text-green-700&#34;&gt;&#xA;&#x9;&#x9;&#x9;Are you more of a GUI person? You might find &lt;a href=&#34;https://github.com/RobotsAndPencils/XcodesApp&#34;&gt;XcodesApp&lt;/a&gt; helpful.&#xA;&#x9;&#x9;&lt;/div&gt;&#xA;&#x9;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;xcode-install uses &lt;a href=&#34;https://fastlane.tools/&#34;&gt;fastlane&lt;/a&gt; under the covers. It downloads everything from the &lt;a href=&#34;https://developer.apple.com/&#34;&gt;Apple Developer Portal&lt;/a&gt;. Consequently, you need a free ADP login to use xcode-install.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
