Skip to content

Thursday, 9 July 2026

Introduction

At this year’s LLW we held a workshop to finally come up with something that all present could agree was a solution to the problem that client-side1 JavaScript, CSS etc. gets distributed to the user without proper (or typically any) license and copyright information.

I first presented a short summary of my initial controversial proposal as well as the feedback obtained at FOSDEM, LLW and other sources. Then we discussed in a group consisting of OSPO leaders, FOSS lawyers and FOSS developers on what would be a good solution. Thankfully, we were able to rely quite a bit on the outcomes of a similar “REUSE-ify JS/CSS” workshop at LLW 2025.

To my big surprise, we pretty quickly came to an agreement what such a solution could look like.

In contrast, it was no surprise that the final solution had very little in common with my initial controversial proposal from 2024. So please forget about that one if it is still causing you high blood pressure.

Solution

TL;DR

  1. apply REUSE.software best practices, just as you would with writing in any other programming language
  2. use a tool of your choice to generate either:
    • an SBOMSPDX, CycloneDX, or whatever you prefer
    • an attribution file, of whatever kind you prefer
    • whatever document/file/webpage you feel is the most appropriate way to fulfil your licensing obligations
  3. make sure that the file/page from 2. is linked in a <link> rel="license" href=""> HTML tag in the HTML <head>
  4. create something in the web UI to present this link too, using a <a rel="license" href=""> HTML tag in the HTML <body>

Explanation

Just use REUSE

The first step should be pretty self-evident to any regular reader of my blog. REUSE.software has become the de facto standard for marking source code with licensing and copyright information. It essentially takes the SPDX (ISO/IEC 5962:2021) standard and implements it directly in source code2.

The big difference between this and the initial proposal is that the wrap-all-files-as-snippets hack is not needed – good riddance!

So, just follow the simple instructions on REUSE.software.

Create a compliance document

Regarding the second and third step, already at LLW 2025 we identified that it would be much better to ship a file/document alongside, instead of keeping tags in minified source code. Some companies already reported doing something similar, but not in any standardized way – and that they would very much be in favour of having a convention to follow.

When debating, we quickly came to the conclusion, that different organizations would have different tools3 and different processes on how to generate and handle license compliance artifacts. So we decided to leave the details of what exactly constitutes the best format to each project and organization, and concentrate on the how part instead (see subsection below).

Some options that were brougt up for you to consider:

  • SPDX 2.x SBOM (in a variety of formats)
  • SPDX 3.x SBOM
  • CycloneDX SBOM
  • tool-generated “attribution” file4 – typically in HTML format; typically lists components as PackageURL, their copyright holders and licenses
  • manually written “attribution” document/notice

Distribute the compliance document to machines

And now for the “how” part.

As SBOM are typically primarily machine-readable, it would make sense to use a standard way of communicating said SBOM.

Luckily, the HTML standard already provides for something like this in the headers.

We can simply use a <link> tag with rel=license and the appropriate MIME type.

Where the rel=license attribute specifically is very topical:

license

Valid on the <a>, <area>, <form>, <link> elements, the license value indicates that the hyperlink leads to a document describing the licensing information; that the main content of the current document is covered by the copyright license described by the referenced document. If not inside the <head> element, the standard doesn't distinguish between a hyperlink applying to a specific part of the document or to the document as a whole. Only the data on the page can indicate this.

So this could look something like:

<head>

    <link
        rel="stylesheet"
        href="/static/client/styles-global.8f1bfba40e45c550.css"
        fetchpriority="high"
        />
    <link
        rel="preload"
        href="/static/client/inter-latin.9a3b1bc220d426ef.woff2"
        as="font"
        type="font/woff2"
        crossorigin="anonymous"
        fetchpriority="low"
        />
    <script
        data-cfasync="false"
        data-report-only="on"
        data-prompt="0"
        src="https://transcend-cdn.com/cm/d556c3a1-e57c-4bdf-a490-390a1aebf6dd/airgap.js"
        >
    </script>

<!-- NB: this is the one we’re looking for: -->
    <link
        rel="license"
        href="sbom.spdx.json"
        type="application/spdx+json"
        fetchpriority="high"
        />

</head>

With this in place, if you wanted to check a compliant website/webapp for licensing and copyright information relevant to the software (and styling) your web browser is downloading, all you would need to do is have some software check for the appropriate <link rel="license"/> and download or parse it.

Distribute the compliance document to humans

Understandably, you may5 also want to make it easy for humans to be able to see which licenses apply.

Again, we quickly came to the conclusion that different web apps have different technical or UI capabilities, and different organizations have different approaches too. So anything too rigid would not work.

But what we can do is to create some guidance on how to leverage the above. And, hoo boy, are we in luck today! The <a> HTML tag can also use the rel="license" attribute.

Some ideas on where to put the link though:

  • just a link somewhere, e.g. in the footer
  • (small) banner to pop-up the information
  • an entry in a menu

Note as well, that nothing prevents us from having more than one rel="license" element, so we can serve different formats at the same time this way. Indeed, we could even serve an SBOM (or other licensing document) for each component separately, if we wanted.

As most humans will not readily consume SBOM, let us expand the above example a bit:

<head>
    <!-- A machine-readable SBOM in JSON format -->
    <link
        rel="license"
        href="sbom.spdx.json"
        type="application/spdx+json"
        fetchpriority="high"
        />
    <!-- A human-readable HTML ”attribution” document -->
    <link
        rel="license"
        href="attribution.html"
        type="text/html"
        fetchpriority="high"
        />
</head>
[…]
<body>
[…]
    <footer>
        <!-- A human-readable notice in the footer, linking to the “attribution” document -->
        This website is licensed under 
        <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">CC-BY-SA-4.0</a>
        with the client-side software and styling under several FOSS licenses – the information to which, you can get in
        <a rel="license" href="attribution.html" type="text/html">human-readable</a> and 
        <a rel="license" href="sbom.spdx.json" type="application/spdx+json">machine-readable</a> form.
    </footer>
</body>

Prioritizing the delivery of licensing documents (optional)

Some German colleagues suggested that in their jurisdiction it may be important that license is shared at the exact same time as the content it covers. This raised the question of whether this compliance document should be forcefully pushed to the user’s/visitor’s browser and if so, when.

As the web development continues to be penny-pinching white-space6 in order to have webpages load faster, this is likely to be a show-stopper if we made it obligatory to fetch an SBOM before (or at the same time as) loading JS and CSS.

So the suggestion is, again, to leave it to each project and organization to decide.

Our old friend <link> has some features that help us here too.

You may have noticed in the above example that we used the fetchpriority="high" HTML attribute. As its name implies, this causes the compliance document to load in the browser sooner than other elements.

If you feel this is not fast enough either, you could even try out the rel=preload attribute in combination with <link as="">. But, to be honest, I would expect some big ire from the web developers if you did that, and there seems to be no ideal as="" to “preload as” either, because license is not an option there.

On the flip-side, if you are of the persuasion that licensing information should not hinder the speed the website loads, you could also set fetchpriority="low" instead. Do not come crying to me if a German court decides that you have made a grave mistake, though.

Example

Above I showed how this would look like in HTML itself. Here is a super-simple7 example of how it could look like.

Copyright and licensing

This website is licensed under CC-BY-SA-4.0 with the client-side software and styling under several FOSS licenses – the information to which, you can get in human-readable and machine-readable form.

What about?

Garbage in = garbage out

Did we solve everything now? Is there finally peace on earth and cancer is eradicated? Of course not.

The original sin of developers simply not storing (enough) copyright and licensing information in their software is still here.

But what we have achieve with this, is to provide a solution on how to easily, without much extra work and tooling:

  • store this data – just use REUSE.software as in every other programming language; and
  • provide this data – serve the results in <link rel="license"> and <a rel="license">

Of course, this still leaves work to actually mark all the front-end code with REUSE/SPDX tags, but at least that is fairly easy to do and has a growing following in both the community and industry alike.

So, please, consider this as a call for tagging your web front-end code with REUSE.software. It really is quite easy, I promise!

Size of the website

How does this proposal affect the size of the website and the speed of its loading, you wonder?

I have not done any tests this time round, but unless I heavily misunderstand how HTML (and HTTP) work:

  • the minified JS/CSS itself will not increase a bit;
  • you can tweak the “speed” of your webpage loading by setting the fetchpriority attribute to either
    • low, if you prefer the page to load faster but and OK with the risk; or
    • high if you are risk averse and OK with the page loading slower.

Also see the file-size analysis in my previous blog post on this topic for some actual PoC and tests.

Conclusion

I think we finally cracked it!

This is the plan.

The building blocks already exist.

Now we just need to build it together – each in their own little corner of the web, little by little :)

hook out → well, that was a long journey…

P.S. If you were part of this project and wanted to be attributed, please let me know. Since a lot of it was done in meetings under the Chatham House Rule, I did not attributed without explicit agreement.


  1. Also known as “browser-side” JavaScript/CSS

  2. In fact, SPDX’s Annex H: Specifying SPDX information in source files (a.k.a ”SPDX File Tags”) is there because of REUSE and was developed alongside the version 2 of REUSE specification. 

  3. In case you are looking for a simple tool to generate SBOMs from a REUSE-compliant code base, the easiest way is to simply use REUSE’s own reuse tool. For more tooling suggestions check out Open Source Tooling for Open Source Compliance

  4. For example, you could use the ScanCode toolkit to generate an “attribution” file or FOSSology to generate a “notice“ file. 

  5. Arguably, this is the more important part. 

  6. IMHO, a much bigger loading speed increase could be achieved, by just not bundling everything and the kitchen sink in the JS “required” to parse a website, but what do I know … 

  7. The example also uses an SBOM that is completely unrelated to this website too. It is just for demonstrative purposes. I also did do the <head> part, as I did not want to make my blog show bogus licensing info everywhere. 

Myself and others have been contributing to Koko under the banner of Techpaladin Software. Here’s what we’ve been up to over the past year.

Qt for MCUs 2.12.2 LTS has been released and is available for download. This patch release provides several bug fixes and other improvements while maintaining source compatibility with Qt for MCUs 2.12 (see Qt for MCUs 2.12 LTS released). This release does not add any new functionality however as part of a continuous effort to scale Qt for MCUs to more platforms new Tier-2 board Nuvoton Gerda-4L is now available. 

Wednesday, 8 July 2026

Hi everyone!! So we are halfway through our journey of GSOC 2026. It's time for the midterm and new status updates we have accomplished over the past 6 weeks.

  • During my first and second weeks, I familiarized myself more with the XMPP protocols and clients like Kaidan, etc., which can be used for XMPP server interactions and also created a page for the Mankala Engine using Hugo. I have successfully added the option to register XMPP accounts from within the Mankala Engine and also added an XMPP compliance check in the 2nd week, which makes sure that the selected XMPP server has all the protocols that are needed to play the game.

  • For the next tasks in week 3, I worked on extracting usernames and profile player icons from within the XMPP servers and directly display it as part of the user account in the game. I also fixed the sizes for the different components in the profile page and gave it a proper redesign.

login

  • For weeks 4 and 5, I spent time creating the tournaments. I experimented a bit with the connectivity to connect more than 2 players to an XMPP server, and then created a detailed tournament page for the number of wins, losses, and player match details, and thus implemented the round-robin tournament style. Some more features, like setting up the time limits for each move and accepting game invites, were also added.

tournament

  • In the 6th week, I gave a talk at the ILUGC (Indian Linux Users Group Chennai) virtual meet and got feedback from the players, and implemented better sounds and a sound button for the game. I also added animations for the shells so they get smoothly displaced to their destined pits after each move.

Challenges I faced

The most difficult part while implementing tournaments can be said to connect multiple players and track their moves in real time across the games. The best possible way to fix this was to create a XMPP MUC and then join the player using that and track the moves being sent across the channel. So, for example a move played by Player 1 will be sent to Player 2, to do this we send the request from Player 1's account track the request through the MUC and display it on the Players 2's board and same goes for multiple players present in the game.

Goals for upcoming weeks

A couple of changes were added based on our GSOC proposal, and a lot of new things and features were implemented. In the next half of GSOC, I plan to work on text- and voice-based chat options within the Mankala so that players can communicate with others during their matches. I also plan to add another variant of tournaments, which gives the players a broader number of options to choose from, and add the feature to create a user-defined AI to play against another person or an AI over the network.

Thanks for reading 🚀

Tuesday, 7 July 2026

This week I implemented clipboard auto-clear for KeepSecret (!36).

When a user copies a password, it shouldn't stay in the clipboard indefinitely — that's a real security risk if the clipboard gets inspected, synced, or accessed by another application.

What was implemented:

After copying a password, the clipboard is automatically cleared after 30 seconds. A Kirigami.InlineMessage countdown notification appears in the entry page showing "Password copied. Clipboard will be cleared in X seconds", updating every second. The clipboard is also cleared when the app quits via QCoreApplication::aboutToQuit. Instead of QClipboard::clear() (which on X11 reverts to the previous clipboard entry), the clipboard is overwritten with an empty string. A single repeating QTimer of 1 second handles both the countdown and the clear — subtracting 1 second each tick, stopping and clearing when it reaches 0. The timeout uses std::chrono::seconds as suggested by Marco Martin during review.

Klipper history protection:

One tricky KDE-specific problem: even if you clear the clipboard after the timeout, the password could still be sitting in Klipper's clipboard history. The fix is to add the x-kde-passwordManagerHint MIME type (set to "secret") alongside the password data when copying. Klipper specifically checks for this hint and skips adding that entry to its history entirely — so the password never gets recorded there in the first place. This approach was pioneered by KeePassXC.

I attended my first KDE sprint in Graz, Austria, travelling abroad for the first time. In this late blog post, I discuss the things I did and my thoughts on travel.

Monday, 6 July 2026

Ok, the title is slightly click-baity but hear me out.

So nearly 2 weeks ago, after writing a lot of code for making the font subsetting work for annotations, I found a flaw in my approach.

I was never deleting the old original font after embedding it's subset version.

So what happened is that:

  • Suppose a user creates a new annotation in an empty PDF.
  • The subsetted font gets embedded and used in the PDF.
  • But the original font stays there, taking space.

This is actually slightly worse than when we had no subsetting at all.

So the solution should just be to delete the original font right? Nope

If we simply delete the original font, it would create the following problem:

  • Suppose a PDF with two annotations pointing / using the same font.
  • User edits the 1st annotation.
  • 1st annotation uses the subset font, and the old font gets deleted from the PDF.
  • The 2nd annotation is rendered useless.

When I realized this, I thought I would need to completely change how I do subsetting, and almost all the code I had written will go to waste.

My new idea was to never let the full version of a font to exist inside the PDF. What I mean is subsetting immediately when the font is loaded from the disk and is about to be embedded as a Font object.

But I had a meeting with my mentor Albert Astals Cid yesterday, and we decided to settle on a simpler approach. We can simply detect if the font we want to delete is:- a font we added ourselves or a pre-existing font inside the PDF.

If we added it ourselves, we can safely remove it. Otherwise, let it stay there as it might be in use by other annotations.

I implemented it today, and we have working font subsetting for freetext annotations right now (not merged).
https://gitlab.freedesktop.org/poppler/poppler/-/merge_requests/2220

A simple size experiment

Here's a simple experiment which demonstrates the impact of font subsetting on PDF file size:

Original file size: 105820 bytes = 105.82 KB

After adding an annotation with content "hello world":

Poppler without font subsetting: 504699 bytes = 504.699 KB

Poppler with font subsetting: 145806 bytes = 145.806 KB

That's like a 500% improvement...

What's next

  • Right now, I only do the subsetting for ttf/otf fonts and not for ttc fonts. I need to do that.
  • I need to make the subsetting work for forms as well.

Thank You

Good Night!

The last maintenance release of the 26.04 series is out, bringing the usual batch of bug fixes and workflow and stability improvements. Highlights include fixes for crashes when undoing sequence creation and recording audio without an audio device, as well as improvements to Rectangular Alpha Mask and Rotoscoping effects. This release also continues the security hardening efforts of this cycle by preventing unwanted command execution on MLT versions below 7.40.

For the full changelog continue reading on kdenlive.org.

This is a weekly update from my Google Summer of Code 2026 project with KDE, improving effect widgets in Kdenlive, a free and open source video editor.

Gradient widget: switched to Qt-Color-Widgets

Julius Künzel suggested last week that the Gradient widget be built with an eye toward upstreaming to KDE Frameworks, pointing to Qt-Color-Widgets's GradientEditor class as a reference. It's already vendored inside MLT's Glaxnimate module, so this week I wired it in directly instead of maintaining a fully custom-painted widget.

The vendored color_widgets::GradientEditor gives a native-styled gradient bar with checkerboard alpha preview, drag-and-drop stop reordering, and its own color dialog, all for free.

Fixing undo-stack behavior

The library only emits stopsChanged on completed actions (mouse release, menu add/remove, dialog accept), not per-pixel during drags. That meant two bugs: every plain click created a junk undo-stack entry, and drags had no live preview on the monitor at all.

Fixed with three pieces:

  • commitStops() emits valueChanged(..., true) only when the serialized value actually changed
  • An eventFilter emits valueChanged(..., false) during drag moves, for live monitor preview
  • An echo-guard in slotRefresh() ignores the model value coming back from our own emit; without it, the synchronous refresh resets the editor's selection and kills the drag mid-motion

32-stop cap

MLT's gradientmap filter supports stop.1 through stop.32. The library has no pre-add hook to reject a 33rd stop, so commitStops() rejects after the fact: the just-added stop gets removed and the editor reset under a signal blocker, with no undo entry created. gradientStopsFromString() also truncates at 32 on load, so an over-long saved value can't smuggle in extra stops. Exposed as GradientEditWidget::MaxStops.

Build: configurable vendor path

The path to Qt-Color-Widgets was previously hardcoded assuming a sibling MLT checkout. Replaced with a KDENLIVE_QTCOLORWIDGETS_PATH CMake cache variable; same default, overridable with -D, and a missing path is now a fatal configure error instead of a silent skip that only surfaced at compile time.

Tests

gradienteditwidgettest.cpp now covers a full widget-interaction path with a real timeline document and synthesized mouse events: a plain click produces zero undo entries, a drag produces two preview emissions plus exactly one committed undo entry, and adding a 33rd stop is rejected with the editor staying at 32. All 5 test cases pass, 62 assertions.

What's next

Four commits are done locally (gradient widget + CMake + tests, plus two unrelated Qt 6.10 compat fixes found along the way), but nothing's pushed yet. Waiting on Jean-Baptiste to confirm this is the direction to commit to before opening an MR.

Sunday, 5 July 2026

Make sure you commit anything you want to end up in the KDE Gear 26.08 releases to them

Next Dates:  

  •   July 16, 2026, 23:59 UTC: 26.08 Freeze and Beta (26.07.80) tarball creation
  •   July 17 2026: 26.08 Beta (26.07.80) release
  •   July 30, 2026, 23:59 UTC: 26.08 RC (26.07.90) tarball creation
  •   July 31, 2026: 26.08 RC (26.07.90) Release
  •   August 13, 2026, 23:59 UTC: 26.08 tarball creation
  •   August 14, 2026: 26.08 packages released to packagers
  •   August 20, 2026: 26.08 Release


https://community.kde.org/Schedules/KDE_Gear_26.08_Schedule