Skip to content

Blog

January Updates

Precisely one month since our end of year summary, so, what have we been up to? With a new year, a new start was long overdue. We’re pleased to announce that we’ve finally shifted our butts over to our own server (again).

While this isn’t quite as chunky a news update as the last post, we rather hope you appreciate the regularity of the news.

moss in action

‘tarkah’ has been tirelessly porting moss-service, the core foundation of our automated build system, to a shiny new Rust codebase. While we don’t have an immediately pressing need for the port to come online, it will certainly address some “v1 issues” and ensure the best-in-class development experience for our contributors.

In our pursuit for a sustainable, community oriented project, we’ve been doing a lot of in house organisation. Very importantly, we’ve now relicensed our packaging recipes to MPL-2.0, bringing them in line with the license chosen for our current engineering efforts (moss, etc).

To reiterate a critical point, we require that our contributions are attributed to the virtual collective “Serpent OS Developers” to ensure we’re unable to relicense any contributions without express consent of the contributors involved.

Additionally we picked MPL-2.0 over Zlib due to some distinct advantages in relation to patent trolls. In combination we believe both the project and our users will have the greatest protection from patent trolls and fiscally-motivated relicensing.

As you may recall from the last post, we announced our intention to add system triggers to moss. We also stated that our triggers must run in isolation thanks to the unique architecture of our package management. After much consideration, we’ve landed on a strategy that will work for us.

Every mutable operation in moss results in a fresh internal transaction, which is present as a full /usr tree inside a staging tree. The majority of triggers can be executed here, just before we “activate” the new rootfs. This allows us to detect potential trigger failures, and abort the activation.

These YAML-defined triggers will be run in an isolated environment (clone-based container) with the new /usr and read-only access to /etc.

Once we have a freshly activated /usr (ie new system view) we can run a very limited set of post-activation triggers. An obvious example may be systemctl daemon-reexec. Note that by splitting post-blit and post-activation triggers, we leave the door open to multiple activation strategies for non-simple updates, including soft reboots and kernel patching.

With all of the migration work, our builds have also resumed. In the space of a few short days we’ve had 32 package builds. Ok, not a huge number, but we also have 15 outstanding pull requests to our new recipes repo!

In order to make life not only simpler for us, but for Solus in its future role as a source-derivative of Serpent, we’ve unified all of our git recipe repos into a new single repo, recipes.

Our devops team has been working hard to mitigate bus factor with our transition to the new infrastructure, Bitwarden account, shared DNS, and opentofu configuration.

As part of the recovery process for Solus, the two projects shared resources, including a large Hetzner node. This has actually worked remarkably well for a long time now, however with Serpent growing we do not wish to impact the availability and stability of the Solus update experience.

Long story short, money from GitHub Sponsors (You guys! < 3) is now paying for an AX52 server from Hetzner. It’s sufficiently powerful that we’re running a backup builder there as well as repo management and build controller.

Looking at our project’s use of static generators - we decided to review our hosting for web content. Long story short, we deemed it entirely unnecessary. We’re now using GitHub pages to deploy this website and our documentation site via GitHub actions. Don’t worry, we use git, we have backups, and we manage the infrastructure using IaC practices.

Lately there have been some questions in both Serpent and Solus as to what our baseline will be. In Serpent OS, this will be at minimum x86_64-v2, with x86_64-v3x packages automatically offered if the system base criteria are met.

This decision has been made to offer the widest baseline compatibility without compromising heavily on system performance (Such that x86_64-generic is unsupported in Serpent OS). We will continue offering both v2 and v3x until it is no longer feasible from a storage/financial perspective. Source derivatives (Including Solus) are free to chart their own course here, if necessary, and still benefit from tight upstream integration.

In our next update, we’ll have quite a bit to cover, including:

  • Integrated triggers
  • Progress with GNOME packaging/readiness
  • Boulder / Infrastructure porting progress
  • Actually useful Serpent images

End Of Year Summary

Burning question - how long before we can use Serpent OS on our development systems? It’s a fair question - and one that requires context to answer. Let’s start our new monthly update cycle with a recap of progress so far.

screenshot of moss

We’d like to extend a huge official welcome, and thank you, to newest team member Cory Forsstrom (aka tarkah)!

Firstly, a quote from Cory:

I’ve been a long time Solus user and was very excited about what serpent os was doing. Really got invested once I started diving into the D code and seeing how powerful the tools and ideas were. The Rust rewrite was just a perfect storm for me with my experience there and my desire to make contributions. Getting to know you and ermo has just been icing on the cake, you’ve both been so welcoming and friendly. So lots of fun times.

On the personal side, I’m on the west coast in the States, have a lovely wife, just had a baby girl and am enjoying my time with fatherhood and coding

Chances are you know tarkah for his contributions to iced-rs, and to Solus. His contributions to the moss-rs project have been absolutely critical, and his patience essential as we got ourselves quickly up to speed with Rust. It is entirely fair to say that our Rust efforts would not have been possible without him!

I think it is fair to say that people collectively facepalmed when we announced our plans to adopt Rust - assuming this would be a huge set back. We’re really happy to report this is not the case, and we’ve made tremendous progress in this area.

Our Rust based moss system package tool is now leaps and bounds ahead of its predecessor, supporting the original features and more!

  • State management
  • Garbage collection of old transactions (via state prune)
  • Optimised write order of transactions (see more below)
  • File conflict detection
  • Parallel fetching and decompression of packages
  • Update support (as sync)
  • Local and remote repositories with priority-based layering
  • Support for building with musl for fully self-contained, static builds of moss with zero system dependencies.

We now have a version-agnostic “stone” crate that is more efficient at reading packages than our original D code. In addition, it benefits from the memory safety promises of Rust.

OK, lets look at the problem: Every transaction in moss requires us to generate a new staging tree containing all of the directories and files for the /usr tree, using hard links, from content addressable storage. As one might expect, creating tens of thousands of new nodes is really, really slow!

To alleviate this issue we created a vfs crate in moss to optimise how we construct each transaction tree:

  • Organise all incoming registered paths into a specific order
  • Inject all missing implicitly created directories for accounting
  • Re-parent nodes in tree which live under redirected symlinks
  • Compile into a recursive data-structure using relative names.

There is a multipart “build” for the tree that detects any filesystem conflicts before any files have been written to disk, preventing broken transactions. With the fully built data structure we can recurse a virtual filesystem, making use of the at family of functions like linkat, mkdirat, to “blit” a filesystem tree without requiring any path resolution, in the most efficient order possible.

The net result? New transaction roots are created in milliseconds, not seconds.

moss now offers a sync command in place of the conventional upgrade one might expect. Rather than upgrading to the latest version of a package, we rely on moss and our infrastructure tooling work in conjunction to ensure we can simply synchronize the package selection with the the “tip” candidates in the configured repositories, as ordered by priority. From a distro-builder PoV, we can now revert and pull builds. For a user PoV, you can remove a test repository and moss sync to go back to the official versions of packages.

Generally speaking, when you moss sync you will be seeing new packages, however. :smile: This feature is being built to enable a future feature: exported states. Want to try a new edition? Sync to the lockfile. Need to quickly and reproducibly deploy containers from a locked down configuration? You get the idea.

moss sync

The moss tool is now completely asynchronous, making efficient use of both coroutines and OS threads to perform as much work possible in the shortest space of time. This allows us to download, fetch, check and unpack many packages at the same time without being blocked on network or disk, greatly speeding up the fetch part of a transaction.

This is achieved by building on the famous tokio runtime and :material-github: reqwest crates, among others.

At the time of writing our port of boulder hasn’t quite yet caught up with the original implementation, given all of the ground we covered with moss. With that said, we decided to step back and evaluate where we could improve upon the first version of boulder.

boulder in action

Arguably one of the most important changes: boulder no longer requires running as root. Even better, we make use of user namespaces and execute using clone - meaning we no longer need a separate binary (mason) within the container environment!

Thanks to everything being a self-contained binary, we can tell you up front that you’re using unknown action or definition macros (i.e. %(datadir)) before attempting any builds, saving you valuable time.

When this was first proposed, I did a double take. Breakpoints.. in recipes… ? No, seriously. Not only was it proposed, but between ermo and tarkah, they only went and implemented it. You can now use special macros within your recipe to add debugging breakpoints in your recipe to drop to a shell within the container and debug the more difficult builds!

Our documentation will be updated when the new boulder ships a stable build.

We now build both moss and boulder from the moss-rs repository, allowing them to share the same code and mechanisms for dealing with dependencies, system roots, etc., allowing for far higher levels of integration than were previously possible.

A feature we’re currently working on allows you to use a single directory for the system “root”, where all the unpacking, fetching and databases happen, while almost instantly creating new build roots!

I get it. “All this rewriting - how will you ever make progress” ? It’s a fair question. We didn’t throw anything away, quite the opposite. Our repos, tooling, are all still in use enabling us to build the distribution in parallel to the ongoing rewrites.

For a long time, we’ve had our :material-view-dashboard: dashboard up and running for our build infrastructure. Sure, we’re going to rewrite it beyond the “Proof of concept” stage when required - but for now it still serves us well. Admittedly there is a deep issue within the druntime causing thread leaks over time, but we have it restarting via systemd every 24 hours as a bandaid. Needless to say, we’re big fans of memory safety now.

Our current deployment watches git repos in our :material-github: snekpit collection, and automatically forms build queues from the pending builds, ordering them by dependency. Using two of ermo’s beefy builders, the packages are automatically built and deployed to our repository. Our workflow means that maintainers only have to merge a pull request for builds to appear in the volatile repository.

Despite having some warts, the build infrastructure is still able to use legacy moss and boulder to make our new builds available, and we’ve been minimally patching these old tools to support our transition to the Rust based tooling. As of this moment, moss-rs officially supersedes the D version, and our new boulder is quickly catching up.

Long story short, we’re still building on all fronts and aren’t blocked anywhere.

Builds are published to our volatile repository, and we do have a fully functioning software repository despite being quite small. Once we’re happy with the new moss we’ll speed up in our packaging efforts. With that said, we do have two kernels (kvm and desktop) and even gtk-4 at this early stage!

OK let’s tldr this:

  • Rust ports are coming along fantastically
  • moss has been replaced
  • still making use of existing tools and infrastructure to build the OS
  • actually building the fully bootstrapped, self-contained OS, built on libc++, clang, glibc, etc.
  • actively pushing updates to binary repository with fully automated pipeline
  • new stuff is :rocket: blazing fast

We’re experimenting with system triggers right now, execution units that run to fully bake the OS state after each transaction completes. In keeping with our stateless philosophy (and pending adoption of hermetic /usr), we need triggers that understand the union state of the operating system, not individual per-package triggers.

A YAML-based trigger recipe has been baked up, which deliberately avoids the use of shell helpers and execution security weaknesses by using an extended variant of globs:

let pattern = "/usr/lib/modules/(version:*)/*".parse::<fnmatch::Pattern>()?;

Our new :material-github: fnmatch crate, heavily inspired by Python fnmatch, compiles specially format glob strings to Regex, extending with capture groups for named variables. In YAML, it looks a bit like this:

handlers:
depmod:
run: /sbin/depmod
args: ["-a", "$(version)"]
## Link paths to handlers and filter on the type
paths:
"/usr/lib/modules/(version:*)/kernel" :
handlers:
- depmod
type: directory

Once we roll out the trigger support, we unblock the packaging of critical items like gtk-3 for gdm, as well as enable usable installations and ISOs. Note that they differ from classical triggers due to the architecture of moss: they need to run in an isolated namespace (container) so we can ensure the staged transaction won’t break. Additionally we cache and collect the trigger artefacts to speed up each filesystem operation, giving us a first: versioned state artefacts.

Our plan is to build on my prior work in the Solus boot management design and :material-github: clr-boot-manager, addressing some long standing shortcomings. Most importantly, our new module will not need to inspect or manage the OS filesystem as moss will be able to provide all of the relevant information (full accounting for all used paths in all transactions).

Initially we will focus on UEFI and supporting the :material-github: Discoverable Partitions Specification by way of XBOOTLDR partitions, the ESP and the Boot Loader Interface. Currently we have no plans to support Unified Kernel Images as the approach taken by CBM (and soon, moss) alleviates the data concerns of dealing with vfat. However, as and when UKIs gain configurable, standardised behaviour for cmdline control we will investigate their use. Until that point please note we prebuild our initrd images and ship them directly in our packages, as Solus has done so for years already.

The net gain for taking control of boot management will be the deduplication and garbage collection of assets installed to either the ESP or XBOOTLDR partitions, along with generation of boot entries relevant to Serpent OS: Transaction specific entries allowing us to directly boot back to older installs in case upgrades go wrong.

Last, but certainly not least, this approach will make dual-booting with another OS less irritating by no longer being bound by a fixed ESP size.

Our plan is to produce a GNOME Shell based live ISO containing the bare basics to get everything else validated, and open the path to installations. In short, it will include:

  • Desktop.
  • moss tooling
  • web browser (firefox)
  • terminal (potentially gnome-console)
  • flatpak
  • Eventually: GNOME Software (integrated with flatpak+moss)

It should be obvious we’re not building a general purpose home-use distribution. However, we also won’t stop people using Serpent OS for their needs, and we plan to beef up the repository, fully support flatpak and eventually custom moss source recipe repos. (ala AUR)

Our journey over the last few years through D, DIP1000, Rust and memory safety has been incredibly eye opening for us. To our own surprise, memory safety has become a huge interest and concern for the team. Not only have we embarked on a full transition of our tooling to Rust, we’ve started looking at the OS itself.

As an early indication of our intent, our curl package is now built with the rustls backend and not OpenSSL. Needless to say, we’re very keen to reduce the surface area for attacks by adopting alternative, safer implementations where possible. Other projects we’re keeping a very close eye on include:

With most of us entering our holiday leave, and the new year practically around the corner, the Serpent OS team wishes you many happy returns and a wonderful new year. With one blocker being worked on (triggers), and the last on the horizon (boot management), your dream installation of Serpent OS is firmly within reach.

In the spirit of the season… if you feel like supporting our project, you can help with the rising cost of living and our expanding hosting requirements via GitHub Sponsors!

Sponsor us!

Oxidised Moss

Allow me to start this post by stating something very important to me: I absolutely love the D programming language, along with the expressivity and creative freedom it brings. Therefore please do not interpret this post as an assassination piece.

For a number of months now the Serpent OS project has stood rather still. While this could naively be attributed to our shared plans with Solus - a deeper, technical issue is to be acredited.

img

D isn’t quite there yet. But it will be, some day.

Section titled “D isn’t quite there yet. But it will be, some day.”

Again, allow me to say I have thoroughly enjoyed my experience with D over the last 3 or so years, it has been truly illuminating for me as an engineer. With that said, we have also become responsible for an awful lot of code. As an engineering-led distribution + tooling project, our focus is that of secure and auditable code paths. To that extent we pursued DIP1000 as far as practical and admit it has a way to go before addressing our immediate needs of memory safety.

While we’re quite happy to be an upstream for Linux distributions by way of release channels and tooling releases, we don’t quite have the resources to also be an upstream for the numerous D packages we’d need to create and maintain to get our works over the finish line.

With that said, I will still continue to use D in my own personal projects, and firmly believe that one day D will realise its true potential.

Our priorities have shifted somewhat since the announcement of our shared venture with Solus, and we must make architectural decisions based on the needs of all stakeholders involved, including the existing contributor pool. Additionally, care should be taken to be somewhat populist in our choice of stacks in order to give contributors industry-relevant experience to add to their résumé (CV).

Typically Solus has been a Golang-oriented project, and has a number of experienced developers. With the addition of the Serpent developers, the total cross-over development team has a skill pool featuring Rust and Go, as well as various web stack technologies.

Reconsidering the total project architecture including our automated builds, the following decisions have been made that incorporate the requirements of being widely adopted/supported, robust ecosystems and established tooling:

  • Rust, for low level tooling and components. Chiefly: moss, boulder, libstone
  • ReactJS/TypeScript for our frontend work (Summit Web)
  • Go - for our web / build infrastructure (Summit, Avalanche, Vessel, etc)

The new infrastructure will be brought up using widely available modules, and designed to be scalable from the outset as part of a Kubernetes deployment, with as minimal user interaction as needed. Our eventual plans include rebuilding the entire distribution from source with heavy caching once some part of the dependency graph changes.

This infrastructure will then be extended to support the Solus 4 series for quality of life improvements to Solus developers, enabling a more streamlined dev workflow: TL;DR less time babysitting builds = more Serpent development focus.

Our priority these past few days has been on the new moss-rs repository where we have begun to reimplement moss in Rust. So far we have a skeleton CLI powered by clap with an in-progress library for reading .stone archives, our custom package format.

The project is organised as a Rust workspace, with the view that stone, moss and boulder will all live in the same tree. Our hope is this vastly improves the onboarding experience and opens the doors (finally) to contributors.

It should also be noted that the new tooling is made available under the terms of the Mozilla Public License (MPL-2.0). After internal discussion, we felt the MPL offered the greatest level of defence against patent trolls while still ensuring our code was widely free for all to respectfully use and adapt.

Please also note that we have always, and continue to deliberately credit copyright as:

Copyright © 2020-2023 Serpent OS Developers

This is a virtual collective consisting of all whom have contributed to Serpent OS (per git logs) and is designed to prevent us from being able to change the license down the line, i.e. a community protective measure.

Despite some sadness in the change of circumstances, we must make decisions that benefit us collectively as a community. Please join us in raising a virtual glass to new pastures, and a brave new blazing fast 🚀 (TM) future for Serpent OS and Solus 5.

Cheers!

Snakes On A Boat

We had intended to get a blog post out a little bit quicker, but the last month has been extremely action packed. However, it has paid off immensely. As our friends at Solus recently announced it is time to embark on a new voyage.

dashboard preview

There is very little point in rehashing the post, so I’ll cover the essentials

  • We assisted the Solus team in deploying a complete new infrastructure. Some of this work is ongoing
  • The package delivery pipeline is in place, meaning updates will soon reach users.
  • We’re working towards a mutually beneficial future whereby Solus adopts our tooling.

Oh no, no. The most practical angle to view this from is that Serpent OS is free to build and innovate to create the basis of Solus 5. Outside of the distribution we’re still keen to continue development on our tooling and strategies.

It is therefore critical that we continue development, and find the best approach for both projects, to make the transition to Solus 5 as seamless as possible. To that end we will still need to produce ISOs and have an active community of users and testers. During this transition period, despite being two separate projects, we’re both heading to a common goal and interest.

We have an exciting journey ahead for all of us, and there are many moving parts involved. Until we’re at the point of mutual merge, we will keep the entities and billing separate. Thus, funds to the Solus OpenCollective are intended for use within Solus, whereas we currently use GitHub Sponsors for our own project needs.

Currently Solus and Serpent OS share one server, which was essential for quick turnaround on infrastructure enabling. At the end of this month Serpent OS will migrate from that server to a new, separate system, ensuring the projects are billed separately.

Long story short, if you wish to sponsor Serpent OS specifically, please do so via our GitHub sponsors account as our monthly running costs will immediately rise at the end of this month. If you’re supporting Solus development, please do visit them and sponsor them =)

Glad you asked! Now that the dust is settling, we’re focusing on Serpent OS requirements, and helping Solus where we can. Our immediate goals are to build a dogfooding system for a small collection of developers to run as an unsupported prealpha configuration, allowing us to flesh out the tooling and processes.

This will include a live booting GNOME ISO, and sufficient base packages to freely iterate on moss, boulder, etc as well as our own infrastructure. Once we’ve attained a basic quality and have an installer option, those ISOs will be made available to you guys!

Infrastructure Launched!

After many months and much work, our infrastructure is finally online. We’ve had a few restarts, but it’s now running fully online with 2 builders, ready to serve builds around the clock.

Firstly, I’d like to apologise for the delay since our last blog post. We made the decision to move this website to static content, which took longer than expected. We’re still using our own D codebase, but prebuilding the site (and fake “API”) so we can lower the load on our web server.

Our infrastructure is composed of 3 main components.

This is the page you can see over at dash.serpentos.com. It contains the build scheduler. It monitors our git repositories, and as soon as it discovers any missing builds it creates build tasks for them. It uses a graph to ensure parallel builds happen as much as possible, and correctly orders (and blocks) builds based on build dependencies.

We have 2 instances of Avalanche, our builder tool, running. This accepts configuration + build requests from Summit, reporting status and available builds.

This is an internal repository manager, which accepts completed packages from an Avalanche instance. Published packages land at dev.serpentos.com

Super early days with the infra but we now have builds flowing as part of our continuous delivery solution. Keeping this blog post short and sweet… we’re about to package GNOME and start racing towards our first real ISOs!

If you like what the project is doing, don’t forget to sponsor!