<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Snaps on Jon Seager</title><link>https://jnsgr.uk/tags/snaps/</link><description>Recent content in Snaps on Jon Seager</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 02 Nov 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://jnsgr.uk/tags/snaps/index.xml" rel="self" type="application/rss+xml"/><item><title>Ubuntu Summit 25.10: Personal Highlights</title><link>https://jnsgr.uk/2025/11/ubuntu-summit-25/</link><pubDate>Sun, 02 Nov 2025 00:00:00 +0000</pubDate><guid>https://jnsgr.uk/2025/11/ubuntu-summit-25/</guid><description>&lt;blockquote&gt;
&lt;p&gt;This article was originally posted &lt;a href="https://discourse.ubuntu.com/t/ubuntu-summit-25-10-personal-highlights/71509" target="_blank" rel="noreferrer"&gt;on the Ubuntu Discourse&lt;/a&gt;, and is reposted here. I welcome comments and further discussion in that thread.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I recently had the privilege of attending the &lt;a href="https://ubuntu.com/summit" target="_blank" rel="noreferrer"&gt;Ubuntu Summit 25.10&lt;/a&gt;. Ubuntu Summits have a relatively long history. Some years ago Canonical ran the ‘Ubuntu Developer Summits (UDS)’, but recently the events were brought back and reimagined as the ‘Ubuntu Summit’.&lt;/p&gt;
&lt;p&gt;For the most recent Summit, we tried out a new format. We invited a select few folks to come and give talks at our London office, with a small in-person crowd. In addition, the event was livestreamed, and we encouraged people to host &amp;ldquo;watching parties&amp;rdquo; across the world as part of &lt;a href="https://ubuntu.com/community/docs/locos?next=%2Fg1m%2F" target="_blank" rel="noreferrer"&gt;Ubuntu Local Communities (LoCos)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While Ubuntu may feature in the name, the event does not require talks to be centred on Ubuntu, and in fact is aiming to draw contributions from our partners and from right across the open source community, whether or not the content is relevant to Ubuntu or Canonical - it&amp;rsquo;s designed to be a showcase for the very best of open source, and this year I felt that the talks were of a particularly high calibre.&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;ll highlight some of my favourite talks, in no particular order! If any of these catch your interest, you can see &lt;a href="https://discourse.ubuntu.com/t/ubuntu-summit-25-10-timetable/65271" target="_blank" rel="noreferrer"&gt;when they were aired&lt;/a&gt; and catch-up on the &lt;a href="https://www.youtube.com/live/bEEamxJ60aI" target="_blank" rel="noreferrer"&gt;Day 1&lt;/a&gt; and &lt;a href="https://www.youtube.com/live/WvNgMEumSoA" target="_blank" rel="noreferrer"&gt;Day 2&lt;/a&gt; streams.&lt;/p&gt;
&lt;h2 id="doom-in-space" class="relative group"&gt;DOOM in Space &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#doom-in-space" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href="04.png"&gt;
&lt;figure&gt;
&lt;picture
class="mx-auto my-0 rounded-md"
&gt;
&lt;source
srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_65dfe195c8d0716f.webp 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_9322be6f635856bb.webp 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_9172933e609edc31.webp 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_8b2cd4b205915e58.webp 1280w
"
sizes="100vw"
type="image/webp"
/&gt;
&lt;img
width="1280"
height="720"
class="mx-auto my-0 rounded-md"
alt="opening slide for doom in space talk"
loading="lazy" decoding="async"
src="https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_2091739036a71cb.png" srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_b9533f51793b46ca.png 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_2091739036a71cb.png 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/04_hu_9ae56e6f039ce272.png 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/04.png 1280w
"
sizes="100vw"
/&gt;
&lt;/picture&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What a way to kick off the Summit! &lt;a href="https://discourse.ubuntu.com/t/doom-in-space/67019" target="_blank" rel="noreferrer"&gt;DOOM in Space&lt;/a&gt; was a talk given by &lt;a href="https://olafurw.com/aboutme/" target="_blank" rel="noreferrer"&gt;Ólafur Waage&lt;/a&gt;, who introduced himself as a &amp;ldquo;professional keyboard typist&amp;rdquo;!&lt;/p&gt;
&lt;p&gt;The talk was immediately after Mark Shuttleworth&amp;rsquo;s opening remarks, and covered his journey in getting DOOM to run on the European Space Agency&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/OPS-SAT" target="_blank" rel="noreferrer"&gt;OPS-SAT&lt;/a&gt; satellite. DOOM has famously been ported to &lt;a href="https://en.wikipedia.org/wiki/List_of_Doom_ports" target="_blank" rel="noreferrer"&gt;many devices&lt;/a&gt;, though some were only questionably &amp;ldquo;running&amp;rdquo; the game.&lt;/p&gt;
&lt;p&gt;Ólafur covered how he became involved in the project, and the unique approach they needed to take to guarantee success, since they would only get a very limited amount of time in order to conduct their &amp;ldquo;experiment&amp;rdquo; on the satellite.&lt;/p&gt;
&lt;p&gt;Of particular note was the work done to integrate imagery from the OPS-SAT&amp;rsquo;s onboard camera into the game, which involved some clever reassigning of colors in the game&amp;rsquo;s original palette to more faithfully represent the imagery taken from the camera in-game.&lt;/p&gt;
&lt;h2 id="infrastructure-wide-profiling-of-nvidia-cuda" class="relative group"&gt;Infrastructure-Wide Profiling of Nvidia CUDA &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#infrastructure-wide-profiling-of-nvidia-cuda" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href="03.jpeg"&gt;
&lt;figure&gt;
&lt;picture
class="mx-auto my-0 rounded-md"
&gt;
&lt;source
srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_c19c7f7a82ce28ec.webp 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_3289cc8a3c6ace68.webp 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_63ea02edaca8b2f8.webp 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_47b446e14afc4dc7.webp 1320w
"
sizes="100vw"
type="image/webp"
/&gt;
&lt;img
width="1600"
height="900"
class="mx-auto my-0 rounded-md"
alt="opening slide for profiling talk"
loading="lazy" decoding="async"
src="https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_a857ebebb22203c0.jpeg" srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_ee47e997a3027b8c.jpeg 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_a857ebebb22203c0.jpeg 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_a29a7d039dd13cc1.jpeg 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/03_hu_cb8dc774efe7bf9f.jpeg 1320w
"
sizes="100vw"
/&gt;
&lt;/picture&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://discourse.ubuntu.com/t/infrastructure-wide-profiling-of-nvidia-cuda/67248" target="_blank" rel="noreferrer"&gt;This talk&lt;/a&gt; was given by &lt;a href="https://github.com/brancz" target="_blank" rel="noreferrer"&gt;Frederic Branczyk&lt;/a&gt;, CEO and Founder of &lt;a href="https://polarsignals.com" target="_blank" rel="noreferrer"&gt;Polar Signals&lt;/a&gt;. Canonical has partnered with Polar Signals a couple of times in recent years. They were part of our journey to &lt;a href="https://ubuntu.com/blog/ubuntu-performance-engineering-with-frame-pointers-by-default" target="_blank" rel="noreferrer"&gt;enabling frame pointers by default&lt;/a&gt; on Ubuntu, and many of our teams have been using their zero-instrumentation &lt;a href="https://github.com/parca-dev/parca-agent" target="_blank" rel="noreferrer"&gt;eBPF profiler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While CPU profiling has been commonplace for developers for many years, giving the ability to analyse CPU and memory-bound workloads, profiling GPU workloads has been less prominent, and is particularly difficult in production.&lt;/p&gt;
&lt;p&gt;Polar Signals advocate for &amp;ldquo;continuous profiling&amp;rdquo;, which means running a profiler at all times, on all nodes, in production. The benefit of this is that when an issue occurs, you don&amp;rsquo;t have to set up a profiler and try to reproduce the issue - you already have the data. It also negates the uncertainty of the impact a profiler might have on the code during reproduction. This would have been difficult with traditional profiling tools, but with technologies like &lt;a href="https://ebpf.io/" target="_blank" rel="noreferrer"&gt;eBPF&lt;/a&gt;, the overhead of the profiler is incredibly low compared to the potential performance gains from acting on the data it produces.&lt;/p&gt;
&lt;p&gt;In this talk, Frederic outlined the work they have done bringing infrastructure-wide profiling of CUDA workloads into Polar Signals Cloud. Their approach combines the &lt;a href="https://docs.nvidia.com/cupti/" target="_blank" rel="noreferrer"&gt;CUPTI profiling API&lt;/a&gt; with &lt;a href="https://docs.ebpf.io/linux/concepts/usdt/" target="_blank" rel="noreferrer"&gt;USDT&lt;/a&gt; probes and eBPF into a pipeline, relying upon the ability to inject a small library into CUDA workloads using the &lt;code&gt;CUDA_INJECTION64_PATH&lt;/code&gt; without modification.&lt;/p&gt;
&lt;p&gt;You can see more details &lt;a href="https://www.polarsignals.com/blog/posts/2025/10/22/gpu-profiling" target="_blank" rel="noreferrer"&gt;on their website&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="inference-snaps" class="relative group"&gt;Inference Snaps &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#inference-snaps" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href="02.png"&gt;
&lt;figure&gt;
&lt;picture
class="mx-auto my-0 rounded-md"
&gt;
&lt;source
srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_1d018afaaf936f4c.webp 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_633333fcdd4ed333.webp 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_9d1bbcb6c1e5044a.webp 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_ca0ce363eac0f419.webp 1280w
"
sizes="100vw"
type="image/webp"
/&gt;
&lt;img
width="1280"
height="720"
class="mx-auto my-0 rounded-md"
alt="opening slide for inference snaps talk"
loading="lazy" decoding="async"
src="https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_d3e5811b82e6933.png" srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_ebbc2e9e26d4db3.png 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_d3e5811b82e6933.png 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/02_hu_711ebc18bd1dda97.png 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/02.png 1280w
"
sizes="100vw"
/&gt;
&lt;/picture&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This talk served as the first &lt;a href="https://canonical.com/blog/canonical-releases-inference-snaps" target="_blank" rel="noreferrer"&gt;public announcement&lt;/a&gt; of Inference Snaps from Canonical, which represents a few months of working combining many of the new technologies behind Snaps.&lt;/p&gt;
&lt;p&gt;As Large Language Models continue to gain pace along with the rest of the AI community, silicon manufacturers are increasingly including dedicated hardware in commodity CPUs and GPUs, as well as shipping dedicated accelerators for some workloads.&lt;/p&gt;
&lt;p&gt;AI models often need to be tuned in some way in order to work optimally - for example &lt;a href="https://huggingface.co/docs/optimum/en/concept_guides/quantization" target="_blank" rel="noreferrer"&gt;quantisation&lt;/a&gt; which aims to reduce the computational memory costs of running inference on a given model.&lt;/p&gt;
&lt;p&gt;Inference snaps provide a hassle-free mechanism for users to obtain the &amp;ldquo;famous model&amp;rdquo; they want to work with, but automatically receive a version of that model which is optimised for the silicon in their machine, removing the need to spend hours on HuggingFace trying to identify the correct model to download that matches with their hardware.&lt;/p&gt;
&lt;p&gt;Using our extensive partner network, we&amp;rsquo;ll continue to work with multiple silicon vendors to ensure that models are available for the latest hardware as it drops, and provide a consistent experience to Ubuntu users that wish to work with AI.&lt;/p&gt;
&lt;p&gt;Find out more in the &lt;a href="https://canonical.com/blog/canonical-releases-inference-snaps" target="_blank" rel="noreferrer"&gt;announcement&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="nøughty-linux-ubuntus-stability-meets-nixpkgs-freshness" class="relative group"&gt;Nøughty Linux: Ubuntu’s Stability Meets Nixpkgs’ Freshness &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#n%c3%b8ughty-linux-ubuntus-stability-meets-nixpkgs-freshness" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href="05.png"&gt;
&lt;figure&gt;
&lt;picture
class="mx-auto my-0 rounded-md"
&gt;
&lt;source
srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_a99f9dc0efe25bc0.webp 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_dc0c16f39603b598.webp 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_40086b0b15441a95.webp 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_d2c99ab7d8057151.webp 1280w
"
sizes="100vw"
type="image/webp"
/&gt;
&lt;img
width="1280"
height="720"
class="mx-auto my-0 rounded-md"
alt="opening slide for noughty linux talk"
loading="lazy" decoding="async"
src="https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_61b22107d4c49f5e.png" srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_448ff89cbcd9feba.png 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_61b22107d4c49f5e.png 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/05_hu_fc9324d6dc71ff1c.png 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/05.png 1280w
"
sizes="100vw"
/&gt;
&lt;/picture&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This &lt;a href="https://discourse.ubuntu.com/t/noughty-linux-ubuntus-stability-meets-nixpkgs-freshness/69962" target="_blank" rel="noreferrer"&gt;talk&lt;/a&gt; was a bit of a guilty pleasure for me! Delivered by &lt;a href="https://wimpysworld.com/" target="_blank" rel="noreferrer"&gt;Martin Wimpress (wimpy)&lt;/a&gt;, the audience were shown how they could take a stock Ubuntu Server deployment, and use a collection of scripts to layer a cutting-edge GUI stack on top using &lt;a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noreferrer"&gt;Nixpkgs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wimpy outlined his motivation as wanting to rely upon the stable kernel and hardware support offered by Ubuntu, but wanting to be more experimental with his desktop environment and utilities - preferring a tiling window management experience.&lt;/p&gt;
&lt;p&gt;Having spent some years on NixOS, Wimpy was recently required to run a security &amp;ldquo;agent&amp;rdquo; for work, which was very difficult to enable on NixOS, but worked out of the box on Ubuntu. Recognising the need to make the switch, he was reluctant to move away from the workflow he&amp;rsquo;d built so much muscle-memory around - and so &lt;a href="https://noughtylinux.org/" target="_blank" rel="noreferrer"&gt;Nøughty Linux&lt;/a&gt; was born!&lt;/p&gt;
&lt;p&gt;Nøughty Linux is not a Linux distribution, rather a set of configurations for an Ubuntu Server machine. It utilises &lt;a href="https://github.com/soupglasses/nix-system-graphics" target="_blank" rel="noreferrer"&gt;&lt;code&gt;nix-system-graphics&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/numtide/system-manager" target="_blank" rel="noreferrer"&gt;&lt;code&gt;system-manager&lt;/code&gt;&lt;/a&gt; and is actually &lt;em&gt;very&lt;/em&gt; similar to a configuration I ran in my own &lt;a href="https://github.com/jnsgruk/nixos-config" target="_blank" rel="noreferrer"&gt;nixos-config&lt;/a&gt; repository for my laptop for a while - though Wimpy has chased down significantly more of the papercuts than I did!&lt;/p&gt;
&lt;h2 id="are-we-stuck-with-the-same-desktop-ux-forever" class="relative group"&gt;Are we stuck with the same Desktop UX forever? &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#are-we-stuck-with-the-same-desktop-ux-forever" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;a href="06.png"&gt;
&lt;figure&gt;
&lt;picture
class="mx-auto my-0 rounded-md"
&gt;
&lt;source
srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_9509dcaa896a87c.webp 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_cd096a2b6be3a7cf.webp 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_e7aaa31012bfd7fe.webp 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_8caa86dfbc373634.webp 1280w
"
sizes="100vw"
type="image/webp"
/&gt;
&lt;img
width="1280"
height="720"
class="mx-auto my-0 rounded-md"
alt="opening slide for desktop ux talk"
loading="lazy" decoding="async"
src="https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_652830ca100ce6c5.png" srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_942ca798315d8db4.png 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_652830ca100ce6c5.png 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/06_hu_63850a6cf7ed9e47.png 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/06.png 1280w
"
sizes="100vw"
/&gt;
&lt;/picture&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jenson.org/" target="_blank" rel="noreferrer"&gt;Scott Jenson&lt;/a&gt; delivered an incredibly engaging &lt;a href="https://discourse.ubuntu.com/t/are-we-stuck-with-the-same-desktop-ux-forever/67253" target="_blank" rel="noreferrer"&gt;talk&lt;/a&gt; in which he posited that desktop user experience has somewhat stagnated, and worse that many of the patterns we&amp;rsquo;ve become used to on the desktop are antiquated and unergonomic.&lt;/p&gt;
&lt;p&gt;The crux of the talk was to focus on user &lt;em&gt;experience&lt;/em&gt;, rather than user &lt;em&gt;interfaces&lt;/em&gt; - challenging developers to think about how people learn, and how desktops could benefit more from design affordances by rethinking some critical elements such as window management or text editing.&lt;/p&gt;
&lt;p&gt;Using his years of experience at Apple, Symbian and Google, Scott delivered one of the most engaging conference talks I&amp;rsquo;ve seen, and I thoroughly recommend watching it on our YouTube channel!&lt;/p&gt;
&lt;h2 id="honorable-mentions" class="relative group"&gt;Honorable Mentions &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#honorable-mentions" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;In addition to the talks above, it was a delight to meet &lt;a href="https://cs.ru.nl/~M.Schoolderman/" target="_blank" rel="noreferrer"&gt;Mark Schoolderman&lt;/a&gt; from the &lt;a href="https://trifectatech.org/" target="_blank" rel="noreferrer"&gt;Trifecta Tech Foundation&lt;/a&gt; in-person, who led the work on &lt;a href="https://github.com/trifectatechfoundation/sudo-rs" target="_blank" rel="noreferrer"&gt;&lt;code&gt;sudo-rs&lt;/code&gt;&lt;/a&gt; as part of our &amp;ldquo;Oxidising Ubuntu&amp;rdquo; story, and interesting to hear about the value the project derived from Ubuntu&amp;rsquo;s &lt;a href="https://documentation.ubuntu.com/project/MIR/main-inclusion-review/" target="_blank" rel="noreferrer"&gt;Main Inclusion Review&lt;/a&gt; process as part of landing &lt;code&gt;sudo-rs&lt;/code&gt; in &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Equally, I was delighted that &lt;a href="https://github.com/kaplun" target="_blank" rel="noreferrer"&gt;Samuele Kaplun&lt;/a&gt; from &lt;a href="https://proton.me/" target="_blank" rel="noreferrer"&gt;Proton&lt;/a&gt; could join us to talk about the work we&amp;rsquo;ve been doing together on bringing first-class Snap packages for &lt;a href="https://proton.me/mail" target="_blank" rel="noreferrer"&gt;Proton Mail&lt;/a&gt;, &lt;a href="https://protonvpn.com/?ref=pme_lp_b2c_proton_submenu" target="_blank" rel="noreferrer"&gt;Proton VPN&lt;/a&gt;, &lt;a href="https://proton.me/pass" target="_blank" rel="noreferrer"&gt;Proton Pass&lt;/a&gt; and &lt;a href="https://proton.me/authenticator" target="_blank" rel="noreferrer"&gt;Proton Authenticator&lt;/a&gt; to the &lt;a href="https://snapcraft.io/publisher/proton-ag" target="_blank" rel="noreferrer"&gt;Snap store&lt;/a&gt;, and their reasons for choosing Snaps, adventures with &lt;a href="https://snapcraft.io/docs/snap-confinement" target="_blank" rel="noreferrer"&gt;confinement&lt;/a&gt;, and more.&lt;/p&gt;
&lt;p&gt;I was delighted to see &lt;a href="https://www.craigloewen.com/" target="_blank" rel="noreferrer"&gt;Craig Loewen&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/clintrutkas/" target="_blank" rel="noreferrer"&gt;Clint Rutkas&lt;/a&gt; present on their &lt;a href="https://discourse.ubuntu.com/t/engineering-wsl-in-the-open-a-deep-dive-into-open-sourcing-wsl-at-microsoft/67022" target="_blank" rel="noreferrer"&gt;journey&lt;/a&gt; open sourcing the &lt;a href="https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux" target="_blank" rel="noreferrer"&gt;Windows Subsystem For Linux (WSL)&lt;/a&gt;, which represents a growing proportion of Ubuntu users, and a key bridge to open source development for many.&lt;/p&gt;
&lt;p&gt;Finally, thank you to &lt;a href="https://github.com/utkarsh2102" target="_blank" rel="noreferrer"&gt;Utkarsh&lt;/a&gt; for this wonderful slide as part of his talk on Ubuntu Snapshot Releases:&lt;/p&gt;
&lt;p&gt;&lt;a href="01.jpg"&gt;
&lt;figure&gt;
&lt;picture
class="mx-auto my-0 rounded-md"
&gt;
&lt;source
srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_33528e98771d0bee.webp 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_3200c3c97ea3fdc8.webp 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_bdcdf80fde7402d2.webp 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_dee895df12e2c378.webp 1320w
"
sizes="100vw"
type="image/webp"
/&gt;
&lt;img
width="1445"
height="813"
class="mx-auto my-0 rounded-md"
alt="a slide depicting my profile picture, but with laser eyes and the title &amp;ldquo;violence&amp;rdquo;"
loading="lazy" decoding="async"
src="https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_25071a7fcfa9dc2a.jpg" srcset="https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_aa0d0f0d8dcb5517.jpg 330w,https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_25071a7fcfa9dc2a.jpg 660w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_f6f1d1cda3bd05f2.jpg 1024w
,https://jnsgr.uk/2025/11/ubuntu-summit-25/01_hu_41b986c0c48d6e4d.jpg 1320w
"
sizes="100vw"
/&gt;
&lt;/picture&gt;
&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="conclusion" class="relative group"&gt;Conclusion &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#conclusion" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Overall, I found the Ubuntu Summit 25.10 a really enjoyable event, with talks that were uniformly high in quality, charisma and creativity. I&amp;rsquo;m pleased that Canonical has broadened the Summit&amp;rsquo;s reach and I hope it continues to serve as a platform to showcase the very best open source innovation.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;</description></item><item><title>Integration testing with NixOS in Github Actions</title><link>https://jnsgr.uk/2024/02/nixos-vms-in-github-actions/</link><pubDate>Sat, 10 Feb 2024 00:00:00 +0000</pubDate><guid>https://jnsgr.uk/2024/02/nixos-vms-in-github-actions/</guid><description>&lt;h2 id="introduction" class="relative group"&gt;Introduction &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#introduction" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;While in my own time I&amp;rsquo;ve tended toward NixOS over the past 18 months, in my day-to-day work for &lt;a href="https://canonical.com" target="_blank" rel="noreferrer"&gt;Canonical&lt;/a&gt; I&amp;rsquo;m required to interact with a fair few of our products - and particularly build tools.&lt;/p&gt;
&lt;p&gt;I frequently need to use some combination of &lt;a href="https://snapcraft.io/docs" target="_blank" rel="noreferrer"&gt;Snaps&lt;/a&gt;, &lt;a href="https://juju.is/docs/juju/charmed-operator" target="_blank" rel="noreferrer"&gt;Charms&lt;/a&gt; and &lt;a href="https://ubuntu.com/server/docs/rock-images/introduction" target="_blank" rel="noreferrer"&gt;Rocks&lt;/a&gt;. Each of these have their own &amp;ldquo;craft&amp;rdquo; build tools (&lt;a href="https://github.com/snapcore/snapcraft" target="_blank" rel="noreferrer"&gt;&lt;code&gt;snapcraft&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/canonical/charmcraft" target="_blank" rel="noreferrer"&gt;&lt;code&gt;charmcraft&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/canonical/rockcraft" target="_blank" rel="noreferrer"&gt;&lt;code&gt;rockcraft&lt;/code&gt;&lt;/a&gt;), which are distributed exclusively as Snap packages and thus a little tricky to consume from NixOS.&lt;/p&gt;
&lt;h2 id="the-problem" class="relative group"&gt;The Problem &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#the-problem" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Packaging the tools for Nix was a little repetitive, but not particularly difficult. They&amp;rsquo;re all built with Python, and share a common set of libraries. Testing that the packages were working correctly (i.e. could actually build software) &lt;em&gt;on NixOS&lt;/em&gt; using the &lt;em&gt;NixOS version of LXD&lt;/em&gt; in Github Actions proved more difficult.&lt;/p&gt;
&lt;p&gt;Github Actions defaults to Ubuntu as the operating system for its runners - an entirely sensible choice, but not one that was going to help me test packages could work together on NixOS.&lt;/p&gt;
&lt;p&gt;I could have hosted my own Github Actions runners to solve the problem, but I didn&amp;rsquo;t want to maintain such a deployment.&lt;/p&gt;
&lt;p&gt;For a while I relied on just testing each of the crafts locally before pushing, and the CI simply installed the Nix package manager on the runners (using the &lt;em&gt;excellent&lt;/em&gt; &lt;a href="https://github.com/DeterminateSystems/nix-installer" target="_blank" rel="noreferrer"&gt;Nix installer from Determinate Systems&lt;/a&gt;) and ensured that the build could succeed, but this left a lot to be desired - particularly when I accidentally (and somewhat inevitably) broke one of the packages.&lt;/p&gt;
&lt;h2 id="kvm-for-github-actions" class="relative group"&gt;KVM for Github Actions &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#kvm-for-github-actions" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Some time later I came across &lt;a href="https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/" target="_blank" rel="noreferrer"&gt;this post&lt;/a&gt; on the Github Blog, stating the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Starting on February 23, 2023, Actions users [&amp;hellip;] will be able to make use of hardware acceleration [&amp;hellip;].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What follows is an example of a relatively simple addition to a Github Workflow to enable KVM on Github Actions runners:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Enable KVM group perms&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; echo &amp;#39;KERNEL==&amp;#34;kvm&amp;#34;, GROUP=&amp;#34;kvm&amp;#34;, MODE=&amp;#34;0666&amp;#34;, OPTIONS+=&amp;#34;static_node=kvm&amp;#34;&amp;#39; | sudo tee /etc/udev/rules.d/99-kvm4all.rules
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; sudo udevadm control --reload-rules
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; sudo udevadm trigger --name-match=kvm&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Given the ability to relatively easily create NixOS VMs from a machine configuration, this should enable me to run a NixOS VM inside my Github Actions runners, and use that VM to run end to end tests of my craft packages.&lt;/p&gt;
&lt;p&gt;After some quick tests, I confirmed that the above snippet worked just fine on the freely available runners that are assigned to public projects. After &lt;a href="https://hachyderm.io/@jnsgruk/111449289662026017" target="_blank" rel="noreferrer"&gt;tooting excitedly&lt;/a&gt; about this, it was also picked up by the folks at Determinate Systems who &lt;a href="https://octodon.social/@grahamc/111450168028125913" target="_blank" rel="noreferrer"&gt;promptly added support&lt;/a&gt; for this in their Nix install Github Action - enabling the feature by default.&lt;/p&gt;
&lt;h2 id="building-vms-with-nix" class="relative group"&gt;Building VMs with Nix &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#building-vms-with-nix" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;A really nice feature of NixOS that I discovered relatively late, is that given a NixOS machine configuration &lt;a href="https://gist.github.com/FlakM/0535b8aa7efec56906c5ab5e32580adf" target="_blank" rel="noreferrer"&gt;it&amp;rsquo;s trivial to build a virtual machine&lt;/a&gt; image for that configuration. This has the nice property that one can actually boot a VM-equivalent of any previously defined machines. You could, for example, boot a VM-equivalent of my laptop with the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nix run github:jnsgruk/nixos-config#nixosConfigurations.freyja.config.system.build.vm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In order to test my craft tools, I needed a relatively simple NixOS VM that had LXD enabled, and my craft tools installed. My test VM &lt;a href="https://github.com/jnsgruk/crafts-flake/blob/f63f315ee2832a112e0777b8af575297c8c9e62d/test/vm.nix" target="_blank" rel="noreferrer"&gt;configuration&lt;/a&gt; looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nix" data-lang="nix"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;modulesPath&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flake&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}:&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="c1"&gt;# A nice helper that handles creating the VM launch script, which in turn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ensures the disk image is created as required, and QEMU is launched&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# with sensible parameters.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;imports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="n"&gt;modulesPath&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/virtualisation/qemu-vm.nix&amp;#34;&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="c1"&gt;# Define the version of NixOS and the architecture.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stateVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;23.11&amp;#34;&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="n"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hostPlatform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;x86_64-linux&amp;#34;&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="c1"&gt;# This overlay is provided by the crafts-flake, and ensures that&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# &amp;#39;pkgs.snapcraft&amp;#39;, &amp;#39;pkgs.charmcraft&amp;#39;, &amp;#39;pkgs.rockcraft&amp;#39; all resolve to&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# the packages in the flake.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overlays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;flake&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overlay&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="c1"&gt;# These values are tuned such that the VM performs on Github Actions runners.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;virtualisation&lt;/span&gt; &lt;span class="o"&gt;=&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="n"&gt;forwardPorts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2222&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;guest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;;&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="n"&gt;cores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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="n"&gt;memorySize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5120&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="n"&gt;diskSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10240&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&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;# Configure the root user without password and enable SSH.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# This VM will only ever be used in short-lived testing environments with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# no inbound networking permitted, so there is minimal (if any) risk.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# If you put this VM on the internet, you can keep the pieces! :)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;networking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;firewall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&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="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&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="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;openssh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PermitRootLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;yes&amp;#34;&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="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extraUsers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;password&amp;#34;&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="c1"&gt;# Ensure that LXD is installed, and started on boot.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;virtualisation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lxd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&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="c1"&gt;# Include the `craft-test` script, ensuring the craft apps are installed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# and included in its PATH.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemPackages&lt;/span&gt; &lt;span class="o"&gt;=&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="n"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeShellApplication&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="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;craft-test&amp;#34;&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="n"&gt;runtimeInputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;unixtools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xxd&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;snapcraft&lt;/span&gt; &lt;span class="n"&gt;charmcraft&lt;/span&gt; &lt;span class="n"&gt;rockcraft&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="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;builtins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readFile&lt;/span&gt; &lt;span class="sr"&gt;./craft-test&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&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&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Anybody can build and launch this VM trivially:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nix run github:jnsgruk/crafts-flake#testVM
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="writing-a-github-workflow" class="relative group"&gt;Writing a Github workflow &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#writing-a-github-workflow" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;All the building blocks are in place! I wanted to keep the actual workflow definition for the tests as clean and understandable as possible, so I put together the &lt;a href="https://github.com/jnsgruk/crafts-flake/blob/f63f315ee2832a112e0777b8af575297c8c9e62d/test/craft-test" target="_blank" rel="noreferrer"&gt;&lt;code&gt;craft-test&lt;/code&gt;&lt;/a&gt; script as a small helper which automates the building of real artefacts. An example invocation might be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash craft-test snapcraft
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;On each invocation, the script creates temporary directory, clones some representative build files for the selected craft tool, and launches the craft. The repos it uses for the representative packages are hard-coded for each craft for now.&lt;/p&gt;
&lt;p&gt;I wrote one more &lt;a href="https://github.com/jnsgruk/crafts-flake/blob/f63f315ee2832a112e0777b8af575297c8c9e62d/test/vm-exec" target="_blank" rel="noreferrer"&gt;small helper script&lt;/a&gt; to simplify connecting to the VM with the required parameters. It&amp;rsquo;s a wrapper around &lt;code&gt;ssh&lt;/code&gt; and &lt;code&gt;sshpass&lt;/code&gt; that&amp;rsquo;s hard-coded with the credentials of the test VM (don&amp;rsquo;t @ me!), and executes commands over SSH in the test VM. Using this script, one can &lt;code&gt;bash vm-exec -- craft-test snapcraft&lt;/code&gt; and the &lt;code&gt;craft-test&lt;/code&gt; script will be executed over SSH in the VM.&lt;/p&gt;
&lt;p&gt;With all that said and done, the resulting &lt;a href="https://github.com/jnsgruk/crafts-flake/blob/f63f315ee2832a112e0777b8af575297c8c9e62d/.github/workflows/test.yaml" target="_blank" rel="noreferrer"&gt;workflow&lt;/a&gt; is pleasingly simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;charmcraft&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rockcraft&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;snapcraft&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Checkout flake&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Install nix&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;DeterminateSystems/nix-installer-action@v9&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Build and run the test VM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; nix run .#testVm -- -daemonize -display none&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Test ${{ matrix.package }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; nix run .#testVmExec -- craft-test ${{ matrix.package }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;A separate job is run for each of the crafts, and a real artefact is built in each, giving reasonable confidence that the consumers of my flake will be successful when building snaps, rocks and charms natively on NixOS. A successful run can be seen &lt;a href="https://github.com/jnsgruk/crafts-flake/actions/runs/7772604925" target="_blank" rel="noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="summary" class="relative group"&gt;Summary &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" style="text-decoration-line: none !important;" href="#summary" aria-label="Anchor"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;In this article we&amp;rsquo;ve covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enabling KVM on Github Runners&lt;/li&gt;
&lt;li&gt;Building NixOS VMs using Flakes&lt;/li&gt;
&lt;li&gt;Booting NixOS VMs in Github Actions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;d like to build snaps, rocks or charms and you&amp;rsquo;re running NixOS, you can run the tools individually from my flake:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run charmcraft&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nix run github:jnsgruk/crafts-flake#charmcraft
&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;# Run rockcraft&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nix run github:jnsgruk/crafts-flake#rockcraft
&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;# Run snapcraft&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nix run github:jnsgruk/crafts-flake#snapcraft
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Or you can check out the &lt;a href="https://github.com/jnsgruk/crafts-flake" target="_blank" rel="noreferrer"&gt;README&lt;/a&gt; for instructions on how to integrate into your Nix config using overlays!&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all for now! 🤓&lt;/p&gt;</description></item></channel></rss>