Read more of this story at Slashdot.
In recent weeks, I’ve been working on adding key rotation support to flatpak, so that repositories which sign their commits and summary files with a key with an expiry date have a way to push updates to that key to all the clients which use them. Currently that’s not possible without each client manually having its config updated to use the new key data (even if the change in key data is just to bump the expiry date).
In the process I’ve learned a few more things about GPG keys, subkeys, signatures, UIDs, etc., which I thought I might dump here in case it’s useful for someone else (or me, in the future). I don’t claim to be an expert, so I may still be misunderstanding some bits. GPG is complex. One thing which has helped ground things is finding the documentation in RFC 4880 (and related) which defines the GPG packet format.
One thing which keeps flatpak’s use of GPG simple is that it doesn’t use any of the web-of-trust features or trust-on-first-use (TOFU). Its use of GPG is limited to the keyring format (essentially pubring.gpg), for storing and publishing public and private keys, subkeys, signatures, revocations, UIDs; and using them to sign and verify OSTree commits and various repository files (summary, summary.idx, etc.).
Quick primer on the parts of GPGGPG has keyrings: collections of primary keys. A primary key has public and private/secret parts. The way flatpak uses it, the secret part of a key always stays on the server, and is used to generate signatures. The public part is published by the server and configured in every client using that repository, used to verify the commit signatures. Each client has one keyring per remote it has configured. Typically this contains one primary key, but it could contain several, any of which can be used to verify signatures from that remote.
A key is identified using a fingerprint, a 40-character hex string. It can also be identified using a key ID, which is a substring of the fingerprint. There’s also keygrips, but let’s ignore those.
You can see fingerprints for keys using gpg --list-keys --fingerprint.
A primary key has one or more subkeys (at least in flatpak’s usage). All of these keys have public and private/secret parts as above. Each key has a usage which indicates what GPG will let you use it for, such as certifying, signing, authenticating, encrypting. The primary key is typically used to certify its subkeys by creating cross-certification signatures which bind them to the primary key, forming a short chain of trust — anyone who trusts the primary key should trust a subkey which it cross-certifies.
You can see subkeys as the sub lines using gpg --list-keys --with-subkey-fingerprint. The [SCE], [S], [E] (etc.) fields show the usage flags for a key.
The other usage we care about is signing (flatpak doesn’t use authentication or encryption usages). GPG separates keys by usage to prevent attacks where a key is used for a purpose it’s not intended for, and because keys used for different purposes often need to be treated with different levels of care.
In particular, separating by usage means the private/secret part of the primary key can be kept completely offline, and only brought out in a special key signing ceremony when a new subkey needs to be generated and cross-certified. This reduces the risk of the very valuable primary key, which is the root of every client’s trust in the repository, being leaked.
So, we use a signing subkey for day-to-day signing of OSTree commits. For a big flatpak repository, the private/secret part of this subkey might be kept in a hardware security module, so it can’t be exfiltrated from the server if the server were compromised. But there’s still the risk of a compromised server being used to sign things it shouldn’t (such as malicious apps).
That’s a matter for server security, but we can somewhat mitigate against the possibility of the signing subkey being leaked by setting an expiration date on it. Clients might choose not to trust signatures made by it after that date; and gpg certainly wouldn’t allow it to be used to create new signatures.
The expiry date of a key is shown as an expires field in the gpg --list-keys --with-subkey-fingerprint output.
What happens when the subkey expires? By that point, the administrators should have generated another subkey, cross-certified by the primary key in a key signing ceremony (I assume the ceremony involves cake). The private/secret part of the new subkey needs to stay secret, as before; but the public part needs to be distributed to every client’s keyring, along with the new cross-certification signature from the primary key, so the clients know they can trust signatures made by that subkey.
That’s the bit which flatpak is currently lacking.
So in summary: GPG has keyrings. Keyrings have primary keys. Primary keys have one or more subkeys and cross-certification signatures from the primary key on those subkeys. Each subkey has a usage, but flatpak only uses certify (for the primary key) and sign (for the subkeys). Keys can have expiration dates.
And if you want to see the full contents of a keyring, run gpg --list-keys --with-colons. It’ll output everything (no filtering) in a machine readable format described here (best reference I’ve been able to find), which is sometimes easier to use than remembering which --with-blah option to pass to GPG to get it to show the information you want.
What else does GPG have?Quite a few things. We’ll ignore the big things which are not relevant to flatpak.
Each primary key also has one or more UIDs. These are like subkeys in that they are cross-certified by the primary key. Each UID is a user identity — typically a name and email address. If you were using GPG in a web of trust, the binding between the primary key and a UID is what you sign that you trust when you sign someone’s key in a key signing party.
The UIDs are listed below each primary key in gpg --list-keys.
Flatpak doesn’t need UIDs, but they are an unavoidable part of GPG — each primary key must have at least one. A flatpak repository will typically put a server contact email address in the UID and then everyone will ignore it.
UIDs can be revoked; for example if someone loses control of the email address in it and wants their friends to no longer trust emails from it. Flatpak currently doesn’t use this.
What else can be revoked? The cross-certification signatures! You may have heard of a GPG revocation certificate. This is a way of revoking an entire primary key. But there’s also a way of revoking a particular cross-certification signature, meaning that the primary key is still valid/trusted, but the owner of the primary key has lost control of one of the subkeys, and that subkey should no longer be trusted. This is different from key expiration, as it’s a statement that something has explicitly gone wrong.
Because of how GPG is built up as a series of packets of different types, a signature revocation is actually a revocation packet appended to the primary key. This means you can re-cross-certify a subkey after revoking it, by appending another cross-certification packet. And even revoke it again after that. Not sure if there’s a use case for this or if it’s just a consequence of the packet format, but this behaviour does play havoc with working out whether to trust a subkey.
Cross-certification signatures can also have an expiration date built into them, separate from the expiration date of the subkey. I’m not sure of the use case for this either, but there must be one.
Some notes on running GPG on the command lineGPG is historically famously hard to use. I feel this has got better in recent years, particularly for scripting it. In particular it’s added a whole load of --quick-blah commands to generate keys, set expiries, etc. from scripts.
One thing which repeatedly tripped me up before I stopped trying to fight it was its concept of a ’homedir’. GPG needs to look for its keyring (and trust database, and various other files) somewhere, and will not run without them, so you always need to pass it a ‘homedir’ to look for them in. By default, this will be ~/.gnupg, so it’s very easy to accidentally end up operating on your personal GPG keyring when you’re trying to do something in a project.
If using GPG as a tool or in a script, I think you should always create a temporary homedir, pass it as gpg --homedir=/path/to/temp and explicitly import whatever keys or context you need into this homedir before doing whatever operation you need.
This is necessary even if ‘all’ you want to do is view a downloaded .gpg keyring, because what GPG displays may be affected by the trust database in its homedir. So to view a downloaded keyring you should still do something like mkdir temp; gpg --homedir=./temp ./path/to/download.gpg.
If you are trying to sign something, you will typically pass the fingerprint or key ID of a primary key to GPG; for example as gpg --local-user 0xfingerprint --sign ./path/to/file. GPG will helpfully use the usage flags of the subkey of that primary key to choose which subkey to sign with. If you want to sign with a specific subkey, you need to suffix the fingerprint with an exclamation mark (!) otherwise GPG will still choose what it thinks is the most appropriate subkey, which might not align with the subkey you carefully chose. This ! suffix format is common throughout the GPG command line interface for when you want to specify a specific subkey.
SorryThat was more of a braindump than I imagined when I set out to write this. I hope some of it is useful; feedback welcome if I’ve got anything wrong. If any GPG experts fancy reviewing key rotation support in flatpak, the draft implementation is here.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Read more of this story at Slashdot.
Hello,
Here’s some thoughts on software for August.
Bear with me on these broad categories but I think you can group most software projects into one of these groups: art, infrastructure, and activism.
Art is primarily to communicate experiences and feelings to others. Making video games is art. Making digital musical and instruments and visual effects is art. The drawing you did as a child that’s stuck on somebody’s fridge is art. The 3rd year computing student’s university coursework, uploaded to Github without comment and abandoned forever… that’s art, or at least, it’s a sketchbook. The thorny entry to the IOCCC, the optimized inner loop deep in some graphics toolkit, that only a handful of people will ever look at, but all of them will agree: that’s art.
People make art for fun, learning and practice.
Infrastructure is stuff that is needed and expected for the world to function. The definition of infrastructure changes over time, as societies adopt and depend on new technologies. Roads, milk delivery, electricity, bakeries, aqueducts, supermarkets, the internet, trams, the lift in your apartment building, and so on. Many societies depend on software projects now. Web browsers, phone cells, operating systems, social networks, software developer tools, power grid management, Google Maps, and so on.
People make infrastructure for money, or perhaps out of a sense of duty.
Activism is a desire to bring about a particular social or political goal or change. I don’t know when the first activist software project started, but it was no later than the 1980s when the GNU project began its stated mission to make proprietary software unviable via copyleft, and many free software projects followed along. The design of the GNU C compiler was shaped by the mission. Tor began in the 2000s with the goal of ensuring private, uncensored internet access. Bitcoin began with the stated aim of destroying the financial system, the wake of the 2008 bank crisis. Although in many countries it’s now regulated financial infrastructure, which shows you that projects can move between these categories over time.
People spend our energy on activism based on our beliefs, usually a sense of wanting to make the world a better place for everyone, or at least for ourselves, and our friends and family.
Not everything fits into these categories (the biggest gap I can see is experiments and research) but let’s keep this short, I want to use them to look at the conversations I keep seeing in the open source world this year.
When one person sees a project as activism and another sees it as infrastructure, you see some genuinely confused conversations happening.
Codeberg banned projects with largely AI generated code from the site, and Sourcehut is considering doing the same. If you see these projects as Git hosting infrastructure similar to Gitlab and Github, then that decision makes very little sense. Why would they want to host fewer projects? However if you see the project as a group of activists trying to reduce the power and influence of US tech firms, and limit the harms of rapid of adoption of AI, then it makes a lot of sense.
Linux decided to allow some LLM use and not put too many limits, as long as its making the project better. If you see Linux as a bunch of engineers building infrastructure then it’s a very logical decision. But if you thought your contributions were part of some activist movement then that might be a disappointing decision.
Every so often I hear someone say things like “please keep politics out of software”. You can infer that they’re probably talking about infrastructure software — and it’s as misguided as if they said it about any other infrastructure. Is an aqueduct political? If one country is seen as stealing another country’s water then… yes. Can a shipping lane be political? Yes, see numerous examples, including the ongoing US-Iran conflict. Can a road be political? Yes, if it crosses a border, especially if it’s in dispute. Ask someone old from Berlin or the north of Ireland about whether roads can be political.
Maintaining software takes a lot of effort. If someone is putting in that effort without being paid, they have some other motivation for doing it. Humans rarely do difficult, laborious work for no reason. Our motivation might be to learn, to show off, to have fun, to meet people, to collaborate with friends, or it might be to work towards some kind of political or societal change. I’ve probably contributed to open source for all of these reasons at different times.
We are increasingly referring to open source software as “digital infrastructure” and funding some of the maintenance work via corporate money and public money. This is great, but it requires the project to frame itself as infrastructure rather than activism. You are unlikely to get funding from Microsoft if you openly state that your goal is to destroy Microsoft. You are unlikely to get funding from a government if your stated goal is to destroy the modern financial system or prevent all forms of censorship.
Activists using open source licenses have something of a problem to deal with. If your goal is to bring about world peace, you hardly want people building drones and missiles using the software you develop. Yet the open source movement have made it clear that if you try to limit who can use your software, it’s no longer open source. And, many software engineers have made it clear they don’t give a shit about software licensing anyway and they’ll use your code however they want without even reading the license.
You can control access to software infrastructure, of course, just like you can put soldiers and passport controls on a bridge or a road. But you can’t call it open source any more.
The GNOME desktop project is art, infrastructure and activism. The discussion on Reddit is mostly people who design and post desktops and themes for fun. Several corporations build products with GNOME, and treat it as infrastructure. And then there are contributors who want to bring about change, perhaps weakening the power of Big Tech by spreading an ethical alternative to Android and iOS.
GNOME hasn’t made a statement on AI use, and I don’t think we’ve tried very hard to discuss it so far. I wonder if we’re putting it off because we’d have to also discuss whether our goal is to maintain some infrastructure, or build something cool-looking, or bring about meaningful societal change?
Over the summer of 2026, I worked towards bringing the option of playing Vocab-Style puzzles to GNOME Crosswords as part of Google Summer of Code. This entailed adding support to the puzzle library, and writing the backend of the algorithm responsible for grid generation. Jonathan Blandford provides a thorough rundown on the ins and outs of Crosswords with these slides.
The first few weeks of the start of GSoC were spent by adding a drop-down calendar widget to Crosswords Editor, and storing GDate data as ISO8601. We decided to integrate this into my design despite it not being directly related to the proposed project because it still contributed to the Crosswords app.
For the new puzzle type, I started with adding support to the puzzle library, libipuz, which is responsible for formatting and representing puzzles styled as ‘paper-and-pencil’ crosswords. My primary mentor and I bounced ideas back and forth for some time before we started designing and writing the algorithm. We landed on an idea and I created an initial design document for the plan of action to follow for the summer. We decided that aiming for both the backend and frontend in one summer may be more work than we initially thought, so we concluded on focusing exclusively on getting a working algorithm to build from.
The bulk of this summer consisted of writing and reconfiguring the depth-first search backtracking algorithm.
GitLab Links to Code:
An overview of my GitLab profile can be found here.
Design Docs:
Blog Post Links (Most Recent -> Oldest):
I also gave a lightning talk at the 2026 GNOME Users and Developers European Conference here. Thank you to the GNOME Travel Committee for making that opportunity possible.
I still have some work to do for both Libipuz and Crosswords: finish the island-checking function detailed above, open a new MR to choose the most compact/square grid out of 500 options and present that to the user directly rather than them cherry-pick through a large selection, create a new MR to add photos of the puzzle in libipuz using gi-docgen, convert the 500-generated grid code to a PuzzleTask, and incorporate the frontend to make this a fully-functioning part of the game.
I would like to thank my primary mentor, Jonathan Blandford, and my other mentor, Federico Mena Quintero, for their guidance, feedback, patience, and teaching. This program was exactly what I needed to become better at development and serves as my rock to open-source contributions. I learned a lot of valuable skills such as document reading, how much to push in a commit, how to slow down trying to get a lot done at once, but simultaneously how to speed up my progression on the parts that actually matter, code with brevity, and a whole lot of dealing with nasty version control!
I intend to continue contributing to GNOME Crosswords as well as the overall GNOME Foundation. I look forward to collaborating with more people involved in the Foundation!
Read more of this story at Slashdot.