Repository navigation
Releases: CatDogBark/Amahi-kai
Release list
Amahi-kai 1.6.0
A pass over everything Amahi-kai does as root: the Cloudflare Tunnel runs as a user of its own, deleting a pool wipes only the drives ZFS says are its own, what an app is given in a share comes through root's own mount, share folders and blocking's lists are handled more carefully, and every argument the root helper takes is now tried with bad values in CI.
🔒 Security & Fixes
- Tighter around what runs as root — From a review of the root helper and the scripts around it:
- System Update makes the app's working folders as the app user, and hands files back to it only from inside their own folder.
- A dnsmasq config line too long for dnsmasq to read whole is refused, and so is a Samba line ending in a backslash (on a share's Advanced settings too).
- A server with no git history stops at System Update instead of fetching code it can't check.
- The update and catalog locks are root's alone, and hostnames and the names in DNS configs are plain ASCII.
- Device names from DHCP reach DNS after 5 seconds, so a burst of them is one reload of Unbound.
- The System journal is narrower (Settings → Help, Download logs and a problem's report) — Amahi-kai's services, the ones it runs and the kernel's errors, not the whole of the system's log, which also names sudo's commands and SSH logins.
- Rack updated for published advisories, among them a High one (a denial of service through multipart uploads).
- Deleting a pool wipes only the drives it's really using — A drive that had failed or been pulled was wiped by the name it last had, and that name can belong to another drive by now, with that drive's data on it. Now only drives ZFS has open, with ZFS's own label, are wiped; a partition beside them that Amahi-kai can't identify stays; and a pool's log, cache, spare and special drives count as in use, so they can't be picked for something else.
- Every pool coming onto the server gets the same checks — Bringing a pool back online skipped the checks Import has, and it may have been anywhere since. Both now mount a pool's datasets one at a time, only in the folder each one's name gives and never through a link on the pool, make the pool's own folder root's whatever the drive says, and turn off setuid, device files and ZFS's sharing settings. A pool stays off ZFS's boot list until it has passed, so a failure, or a power cut, leaves nothing for the next boot to mount.
- A share's folder can't be made at a name Greyhole or the Trash owns — A share folder is made as the app's user, and at one of those names (Greyhole's trash, its metadata store and backups, the folder a Trash restore stages a file in, Samba's recycle bin) it would stand where root puts files it later copies into a share. Those names are refused now, and a share's folder is removed through the folder above it, so a link put in the path can't move the removal somewhere else.
- Blocking's lists are read as bytes, capped as they're read, and changed one at a time — A list is whatever was downloaded: one bad byte used to stop a whole refresh part-way, and a huge list was read into memory before its size was checked. A refresh, a pause and a resume can no longer cross each other and leave the paused list as the live one.
- Smaller network fixes — Router mode refuses the loopback, Docker's and Tailscale's interfaces for either side, as This NAS already did. A netplan file holding something YAML won't load is passed over instead of failing the change. Search domains a device advertises are shown only when they really are domain names. Firewall rules are taken apart as words only when that's what they are, and the interface names in the router's saved state are read as names or not at all.
- Two known gaps written down (
docs/security/PRIVILEGE-ESCALATION-MITIGATION.md) — Greyhole's work queue has to stay open to every local account and its root daemon doesn't hold itself to the pool's folders, which is Greyhole's own design; and a setuid file can run as root from a ZFS snapshot, which this version of ZFS has no setting against. Neither is something Amahi-kai can close, so both are stated plainly instead. - ZFS saying a pool is busy for a second no longer fails Delete or Take offline — ZFS can refuse either for a moment with nothing using the pool. Amahi-kai now asks again for up to 15 seconds; what really holds a pool still gets you the reason.
- The Cloudflare Tunnel no longer runs as root —
cloudflaredruns as a user made for it, and systemd hands it the token. Whoever holds a token decides from Cloudflare's side where a tunnel connects, so it shouldn't be able to reach what root can. System Update moves a tunnel that's set up, restarting it once, and puts its old unit back if it doesn't come up. - Everything an app is given in a share goes through the root helper's own mount — A whole share or a pooled share's copy folder used to be handed to Docker by its path, as folders of a share no longer were, and Docker follows a link there each time it starts a container. System Update makes each app's container again once for this, so an app given a share restarts once, keeping its version and data. One that's stopped stays stopped.
- Making an app's container again never moves it to a newer image — An app with no record of its definition (installed before those were kept) could be moved to the catalog's version, with no copy of its data first.
- An app's copy of its ping is made in a folder only root can reach, since Docker keeps an image's special file modes when it copies a file out. A manifest can't set
FILE__DOCKER_MODSeither, and a share named only with dots can't be given to an app. - An app's update goes back to the version it ran after any kind of failure, not only some, and putting a copy of its data back waits until Docker has really removed its container. One app's trouble no longer stops the others when the pool's drives or the DNS change.
- Stricter paths and names — Share paths with control characters, and
lmhostsnames outside what a hostname can hold, are refused. Bad text in a list of addresses or domains is a refusal now, not an internal error. - The root helper's log misses nothing — A request with bytes JSON can't write used to leave no line in
helper.log, and neither did a second job refused for an app. Secrets are filtered however deep they are in a request, and long lists are cut.
🔧 Architecture & Code Quality
- Every argument of the root helper is tried with bad values — A table of all its operations, with their own checks running, that fails CI until a new operation is listed.
- Real tools read what the checks approve — A CI job with Ubuntu 24.04's dnsmasq, Samba, Unbound and radvd, so a difference between a check and the tool shows up as a failed job.
Amahi-kai 1.5.3
Following the dev branch, which isn't signature-checked, takes root's permission on the server, and System Status says which updates are signed.
🔒 Security & Fixes
- Following the dev branch takes root's permission (Settings → System Status) — The development channel installs the newest code on the dev branch, which isn't signature-checked: whoever controls Amahi-kai's repository decides what such a server installs. So a server now switches to it only when root allows that on the server itself (
sudo touch /etc/amahi-kai/allow-development); until then Follows greys it out and says how. Nobody signed in to the web UI, nor anything acting as them, can move a server off signed releases. A server installed for development, or already following the dev branch, keeps it, and any server can leave it. Follows also says plainly that releases are signed and checked, and the dev branch isn't.
Amahi-kai 1.5.2
Amahi-kai installs a new release only when it's signed with one of its release keys, and a problem's report leaves out keys.
🔒 Security & Fixes
- Unsigned releases are refused — On the releases and release candidates channels, Amahi-kai now installs a new release only when it's signed with one of the release keys. One that isn't is never offered: Settings → System Status and the System Update dialog say Refused, with why, and the server stays on the version it has. The development channel, which follows the dev branch, works as before: it has no releases to sign. Before this, a refusal's reason could have been mistaken for a very old root helper, which updates without the check; now only that helper's own answer is.
- Reports leave out keys (Settings → Help → Report a problem) — An SSH public key quoted in a report kept half of itself: its slashes stopped the rule that takes out keys. Now whole public keys, a signature or private key's armoured text, and long runs of key text in a log line are replaced by stand-ins, as SSH fingerprints already were. A release key's name (like
release-key-a) stays, since it's public and helps find a fault.
Amahi-kai 1.5.1
Releases are signed now: when Amahi-kai finds a new release, it checks which release key signed it and says so on System Status and in What's new.
🔒 Security & Fixes
- Signed releases — Each release is now signed with a release key, and every server keeps the list of those keys (
/etc/amahi-kai/allowed_signers). When Amahi-kai finds a new release, it checks the signature, and Settings → System Status and the System Update dialog say which key signed it, or why it isn't signed. For now an unsigned release still installs; a later version will refuse one. A release tag that isn't signed is never published.
🔧 Architecture & Code Quality
- The repository's front page — GitHub now recognizes the license:
COPYINGholds the GNU AGPL v3 on its own, and the original Amahi notice that came before it is kept word for word inNOTICE.md. The README shows the latest release, the license and a screenshot.SECURITY.mdsays how to report a security problem privately and what happens next,CODE_OF_CONDUCT.mdsays what's expected in issues and pull requests, pull requests start from a template, and GitHub's code scanning (CodeQL) checks the code. - CI reads, nothing more — The checks' access to the repository is read-only.
Amahi-kai 1.5.0
When something goes wrong, Amahi-kai helps you say so: Settings → Help shows this server and its logs, and Report a problem puts a report together, names and addresses taken out, for GitHub or email. Every page also says it's working while it waits.
🚀 Major Features
- Report a problem (Settings → Help, and a red flag's Report this problem) — Puts a report together for you: what happened, what you expected and how to make it happen again, in your words, then this server's details and the newest lines of the logs most likely to show the fault, with an app's own when it needs attention. The server's name, users, shares and what's in them, pools, devices, addresses, email addresses and anything that looks like a key are replaced by stand-ins like
<share-1>(the same name always the same one); a switch shows them as they are, and any of it can be changed. Amahi-kai sends nothing itself: Open on GitHub opens a new issue filled in (a report too long for the link is also saved as a file to attach), Send by email opens your email app, and Download report and Copy give you the text. - Settings → Help (Settings) — A new tab for when something isn't working: Report a problem; this server in a few lines (Amahi-kai's version and update channel, the system, its processor and memory, the system disk, the storage pools, the apps and whether any service is down); and the logs, a tab each: Amahi-kai's own, the root helper's (every change made as root, without passwords or keys), the last System Update, the system journal and each app's own output. Download logs saves them all as one text file. It replaces the old debug pages, whose system log was one Ubuntu no longer keeps; their old address leads here.
🔒 Security & Fixes
- Every page says it's working while it waits — Pressing a button that sends a form (Network, DNS, ZFS Pools, Settings, Shares, the setup wizard, and the rest) left the page as it was until the next one came, with only the browser's tab showing anything happening, so a slow save looked like nothing happened and invited a second press. Now the button shows a spinner and "Working…", the form's buttons wait, and a save still running after a few seconds says so in a flag. Back brings the page as it was before.
- Flags instead of pop-up boxes — The few places that told you something went wrong in a browser pop-up (the Apps page, ZFS Pools, Security, Remote Access, Shares, System Update's Check now) use the side flags like every other page.
- A flag for something that broke offers to report it — A red flag now says whether you need to change something (a name taken, a choice missing) or something broke (a command failed, a service didn't start, the router's rules weren't rewritten). The first has Dismiss; the second also has Report this problem, started with what went wrong and where. Red flags stay until dismissed. A job in its window (an install, System Update) that ends in ✗ leaves one too, for the page its button reloads.
🔧 Architecture & Code Quality
- Reporting a problem on GitHub — New issues use forms: a problem asks for the version, what happened and how to make it happen again; an idea asks what and why. A security problem goes privately, through the repository's Security tab or by email (
SECURITY.md).CONTRIBUTING.mdsays how to become a contributor.
Amahi-kai 1.4.4
Transmission saves its downloads into shares, Uptime Kuma's ping monitors work, and Gitea keeps its repositories in a share folder.
🔒 Security & Fixes
- Uptime Kuma's ping monitors work (Apps) — A ping monitor was always down with "spawn EPERM": the
pingin Uptime Kuma's image is marked to need raw sockets, which Amahi-kai doesn't give apps, and Linux then refuses to run it at all. An app's manifest can now name its ping (ping: /usr/bin/ping), and Amahi-kai mounts a copy of that same file, taken from the same image without the mark, in its place: it pings the way Docker lets any container, and the app still gets no raw sockets. - Transmission can save downloads into a share (Apps) — Given a share with read and write, Transmission was denied writing into it: its image starts as root and then switches to the app's user with the groups the image itself lists, which dropped the
usersgroup Amahi-kai gives it. Now an app like that, given a share to write into, runs withusersas its own group (PGID), so it writes where the share lets theusersgroup write, and its files stay editable over SMB. - Gitea can keep its repositories in a share (Apps) — Install now asks Gitea's shares, and a share folder given read and write can hold its repositories instead of the system disk: set Repository Root Path to that folder under
/shareson Gitea's first page. The app catalog had it first; this is the copy that comes with Amahi-kai, and the wiki. - Transmission's and Uptime Kuma's first sign-in say what their first pages need (Apps) — Transmission downloads to the system disk until its preferences point Download to at a share folder you gave it (under
/shares) and its temporary folder is off, and its sign-in note now says so. Uptime Kuma's first page asks which database to use before the admin account (SQLite is the simple one).
🔧 Architecture & Code Quality
- Browser tests give Chrome longer to start — On CI's runners the first browser test, right after Chrome's cold start, sometimes timed out opening its page while every other test passed. The browser tests now allow 30 seconds a command and a minute for Chrome to start; one that hangs still fails.
Amahi-kai 1.4.3
Apps can write into shares on a ZFS pool: Gitea, Transmission and bitTube install with read and write on one.
🔒 Security & Fixes
- Apps can write into shares on a ZFS pool (Apps) — An app given read and write on a share (Transmission, Gitea, bitTube) failed to install when the share was on a ZFS pool: Amahi-kai gives the app's folder a default ACL, so what the app makes there stays editable over SMB, and ZFS on Linux leaves ACLs off unless asked, so setting it failed with "Operation not supported". New pools have ACLs on (
acltype=posixacl, kept beside each file withxattr=sa); on a pool made before, the share's dataset gets them the first time an app is given write access there. Files already on the pool keep their permissions.
Amahi-kai 1.4.2
The root helper's source is split by area, for working on it; nothing changes in what Amahi-kai does.
🔧 Architecture & Code Quality
- The root helper's source is split by area —
libexec/amahi-helperhad grown to 7,800 lines in one file. Its code now sits in nine parts inlibexec/amahi-helper.d/(core, sharing, disks, ZFS pools, Greyhole, DNS, network, apps, system), each area's operations beside their code, moved unchanged: every setting, operation and method is byte for byte what it was. It's still installed as one file:bin/amahi-join-helperputs the parts in place, and the installer self-tests that file before it replaces the helper, as before, so the helper that runs as root still loads nothing but Ruby's standard library. Nothing changes in what it does. - Brakeman reads the root helper now — CI's security scanner only reads
.rbfiles, so it never saw the helper as one file without an extension. It does now, and the three lines it flags, there all along, are recorded inconfig/brakeman.ignorewith why each is safe: the HTTPS apps' health check (a TLS handshake with the app on the server itself), the app catalog'sgit(an argument list, no shell), and netplan's settings copied in memory.
Amahi-kai 1.4.1
The Apps page puts your apps first, each saying whether it's running, and gives each app a page of its own for everything else.
🚀 Major Features
- The Apps page, laid out again (Apps) — Your apps come first, as cards that say in a word whether each is Running, Stopped, Installing… or Needs attention, with Open (or Start) and Manage; below them, Add apps lists the catalog's other apps by category, with Install. Before, one table mixed both, the state of an app was only told by its buttons, and each app's sign-in and passwords sat on a row of their own that read like another app. Manage opens the app's own page, with everything else: how to sign in and the passwords Amahi-kai made for it, hidden until Show (Copy copies one without showing it), its address, ports and version (Update, Undo update), its shares and storage (Change), and Stop and Uninstall. The Installed tab is gone; its old address opens the Apps page.
🔧 Architecture & Code Quality
- Lucide's licence ships with its icons — The icons on Amahi-kai's pages are Lucide's (ISC licence; the ones derived from Feather, MIT), and their licence notice now sits beside them (
app/assets/images/icons/LICENSE-lucide), as both licences ask.
Amahi-kai 1.4.0
Devices keep their names wherever DHCP puts them and apps reach them by name, so a camera viewer needs no fixed addresses; Install asks for shares only for apps that work with files in them; and bitStream brings the home's cameras to the browser, Android and the KDE desktop.
🚀 Major Features
- Devices can be named without fixing their address (Network → Devices) — Name on a device gives it a name of your own that follows it wherever DHCP puts it, answering in DNS at once (
carport-cam, andcarport-cam.home.arpa): reach it by its name and let its address change. Unfix keeps the device's name now, and Forget drops it. Devices whose own names have an underscore (Wyze cameras ask forWYZE_CAKP2JFUS-…) answer with a hyphen in its place instead of not at all. A device can't be calledignoreorinfinite: dnsmasq read those as orders, and a device namedignoregot no address. - Apps reach devices by their names (Apps) — While the NAS's DNS is on, apps ask it, so an app reaches a device by its name on Network → Devices (a camera viewer at
carport-cam, say), and apps get the NAS's blocklists too; before, they asked the NAS's upstream servers, which know none of the LAN's names. Turning DNS on or off makes the apps' containers again in the background, keeping their data, and so does this update, once, on a NAS whose DNS is on: each app restarts for a minute or so after it. - bitStream joins the app catalog (Apps) — The home's cameras, live: in the browser, on Android (its app downloads from bitStream itself and updates itself from there) and in a KDE Plasma widget, with switches for Wyze floodlights. Cameras are added by their names on Network → Devices. One password, made at install, for its pages, its streams and its API.
🔒 Security & Fixes
- Install asks for shares only for apps that use them (Apps) — Every app's Install asked which shares to give it, Vaultwarden, Gitea and Uptime Kuma too, which never read a file in one: an app given shares it has no use for only gets files it shouldn't see. Now an app that works with files in shares says so in the catalog (
shares: true, orwrites_shares), and only those ask: Jellyfin, PiGallery2, Transmission and bitTube. The others install without the dialog (bitShare's asks only for its ZFS pool), and their rows have no shares line, unless they were given shares before. Vaultwarden's row has a link of its own to give it its new address after the NAS is renamed in Tailscale (it was the shares' Change).