Skip to content

kuma v0.13.0

Choose a tag to compare

@github-actions github-actions released this 20 Aug 04:44

The declaration could name an app and not say what it was allowed to touch, and that was the largest of a family: state that survives every rebuild, that the file cannot express, and that nothing on the machine will tell you about. This release closes the biggest one, draws the line around the rest, and makes the line a test rather than an intention.

It also stopped kuma sync from reporting success over a declaration it had never read, which is the bug that started the sweep.

Added

  • [overrides] declares Flatpak permissions, per app and per scope. The declaration could always name an app; it could not say what that app is allowed to touch, so every permission on the machine was undeclared state that survived every rebuild and that nothing could see.

Convergence is per key, not per file. kuma sets the keys you declare, removes the keys it set that you stopped declaring, and copies every other line through untouched, so Flatseal stays the editor people reach for and this file stays the record. The two meet at kuma capture. A key kuma never set is never kuma's to delete, even when it sits in the same group and contradicts what was just declared.

The shape is Flatpak's own override file rather than flatpak override's flag strings, which is a consequence of the above and not a preference: from a flag string kuma cannot tell which file key a --nofilesystem lands in without reimplementing flatpak's parser, and not knowing the key means the only safe convergence is replacing the whole file, which is exactly the authority per-key ownership refuses to take. flatpak override --show round-trips into it.

Both stores are covered. System scope is the default because that is where kuma installs the apps it declares; scope = "user" writes the per-user store, applied by a systemd --user unit rather than by root reaching into a home. One app declares into one store.

kuma diff and kuma capture see them, which is what makes the declaration owning permissions mean anything. diff reports both directions, a declared key the machine lacks and a key kuma set that the declaration stopped naming, and stays silent about keys kuma never set: those are somebody's machine, not drift. capture offers the reverse, turning a permission you toggled in Flatseal into a declaration entry, and offers it only for apps the declaration already installs, because a machine accumulates override files for software that left years ago. kuma check counts them.

Applied at boot and by kuma sync, deliberately never on the daily timer. An install arriving at a random hour is additive and idempotent; a permission reverting at a random hour changes what a running app can reach, and a toggle that silently flips back tomorrow afternoon is indistinguishable from a bug. The rule fits in a sentence: declared permissions are restored when you boot, and the session in between is yours.

  • kuma doctor reports a unit that is enabled and has no unit file. Found by reading a real machine: an enablement symlink in default.target.wants pointed at a unit file that had been deleted, systemctl is-enabled answered not-found, and every other surface said the machine was in sync. Nothing fails, because a unit that was never found can never fail, which is exactly why nothing reported it.

Narrow on purpose. /etc on a real machine carries dozens of legitimately local files and a check that lists them all is one people learn to scroll past, but a link into a .wants directory is a machine saying it will start something at every boot, and a missing target makes that sentence false.

  • kuma add --flatpak refuses an id Flathub does not list. The converger installs the whole declared list in one command, so a name that does not resolve fails the unit and the apps beside it never install, on that boot and every boot after: a typo taking down convergence for everything else. [services] has checked unit names at build time since it existed and this list checked nothing at all.

Checked against flatpak's own cached appstream data, never the network, so declaring a package cannot hang on a captive portal or fail on a plane. No cache to read means the check does not run rather than that the name is wrong, and a refusal names the way out, since a cache can be behind a genuinely new app.

  • [system.ca_certificates] declares the certificate authorities a machine trusts on top of the ones Fedora ships, keyed by the name each one gets on disk. The certificate goes in the declaration rather than beside it: a file that points at a path somewhere else is not one file any more, and a CA certificate is public by construction, which is what makes that safe here and unsafe for anything in [user].

A private key pasted in by mistake is refused rather than warned about, because it would be baked world-readable into every image built from that declaration and pushed to a registry. The anchors land under /etc by a COPY, so kuma doctor watches them for free, and update-ca-trust runs in the layer that adds them rather than leaving a trust store that only becomes true at boot.

Changed

  • kuma sync says which declaration it converged to. It starts the same convergers boot does, those read what the image baked, and an edit that has not been built cannot reach them however often sync runs. It reported "Converged" anyway and then offered kuma diff to "confirm the machine now matches its declaration", which was an instruction to go watch it fail.

  • kuma add, kuma remove and kuma capture no longer end with "flatpak and brew changes converge on the machine at boot and daily". That sentence sat under the kuma build and kuma switch edges and read as the alternative to them, when what converges at boot and daily is the previous list, forever, until a build of the edit boots. They now say that instead.

Fixed

  • A declared system.timezone was owned by the image and watched by nobody. kuma writes the timezone as ln -sfn /usr/share/zoneinfo/<zone> /etc/localtime, and the scan that works out which /etc files an image owns read only COPY destinations and shell redirects, so the single file that key exists to produce fell outside every check kuma has.

It matters most on an installed machine, because Anaconda writes its own /etc/localtime first, and ostree's merge keeps a local file over every future image: a declared timezone would simply never take effect, with nothing anywhere saying so. kuma doctor now grades it like any other file the image owns, and ln -s is read as the third way a build writes into /etc.

Static x86_64 binary, no runtime dependencies.

$ curl -LO https://github.com/Letdown2491/kuma-linux/releases/download/v0.13.0/kuma-x86_64-unknown-linux-musl
$ chmod +x kuma-x86_64-unknown-linux-musl && sudo mv kuma-x86_64-unknown-linux-musl /usr/local/bin/kuma

Verify it came from this workflow:

$ cosign verify-blob \
    --bundle kuma-x86_64-unknown-linux-musl.bundle \
    --certificate-identity-regexp '^https://github.com/Letdown2491/kuma-linux/' \
    --certificate-oidc-issuer https://token.actions.githubusercontent.com \
    kuma-x86_64-unknown-linux-musl

Built from 96bcc308878fc7fb70ee02b7412bde00b965fa77.