Repository navigation
Releases: ventura8/Ubuntu-Hello
Release list
v1.2.8
Ubuntu Hello v1.2.8 - Keyring Repair
This release adds a one-click repair for a login keyring that stopped accepting your password, and detects the problem in Settings.
🔧 What's in this release
- 🔑 Repair a login keyring that stopped unlocking. A login keyring can get damaged, or its password can drift away from your login password (seen after another app wrote to the keyring while it was open). Face login still works, but the keyring then rejects every password: the one Ubuntu Hello hands over and the one you type. Until now that failed silently and left you with keyring prompts. New
sudo ubuntu-hello keyring repairstores your current password first, then renames the oldlogin.keyringtologin.keyring.broken-<date>(kept, never deleted). Your next login creates a fresh keyring that unlocks automatically. Passwords saved in the old keyring need to be entered again. GNOME Keyring only; KWallet users are pointed to System Settings. ⚠️ Settings detects it for you. When auto-unlock is on and your login keyring is still locked in your running session, the Keyring tab shows a warning and a Repair Keyring button that runs the same repair after checking your password.- 📖 Troubleshooting. The README explains how to tell a broken keyring from a face-login problem: if your typed password is rejected too, the keyring is the cause.
- 🧹 Code quality. Clears the SonarCloud findings in the PAM helper wait loop. The signal-retry logic is now one small function, and a new test interrupts a real wait with a signal to prove it retries.
Nine new translatable strings, translated in all 98 languages. No new config keys.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA (Ubuntu 22.04, 24.04 and 26.04). On 22.04 use the PPA: the .deb assets above are built on 26.04:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.8 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.7...v1.2.8
v1.2.7
Ubuntu Hello v1.2.7 - No More Login Hangs on a Stuck TPM
This is a reliability release: login can no longer hang on a stuck TPM or keyring helper when keyring/KWallet unlocking is enabled.
🔧 What's in this release
- ⏱️ Login can no longer hang on a stuck keyring helper. When keyring/KWallet unlocking is enabled, the PAM module runs root helpers: the
tpm2_*steps that unseal the keyring password after a face match, andkeyring enable, which caches the password at login. It waited for them with no time limit, so a hung TPM device or resource manager froze the login. Each helper now has 30 seconds. It runs in its own process group, and if it is still running at the deadline the whole group is killed. Login then carries on without the keyring step: face auth is unaffected, and the keyring is just not unlocked or the password not cached that time. - 🧪 Tests.
pam-maincovers a helper that never exits, one that prints and then hangs (its partial output is kept), output held open by a background child, and a slow helper inside the limit.
No new config keys and no new or changed translatable strings.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA (Ubuntu 22.04, 24.04 and 26.04). On 22.04 use the PPA: the .deb assets above are built on 26.04:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.7 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.6...v1.2.7
v1.2.6
Ubuntu Hello v1.2.6 - Code Quality Cleanup
This is a maintenance release: it clears the last open SonarCloud issue in the PAM module and fixes a test that failed on arm64. Nothing changes for users.
🔧 What's in this release
- 🧹 SonarCloud: no open issues. The root-helper function added in v1.2.5 (
run_root_helper()in the PAM module) was flagged as too complex: a cognitive complexity of 40 against SonarCloud's limit of 25. It is now split into small helpers for pipe setup, stdin/stdout wiring, the uid-0 spawn, writing the input, reading the output and waiting for the child. Behaviour is unchanged. - 🧪 Test fix for arm64. The arm64 release build runs under qemu emulation, where starting a missing helper binary starts the child, which then exits 127, instead of failing at spawn. The test now accepts either way, because both mean the helper failed. This made the v1.2.5 GitHub Release build fail on arm64. The fix was released by re-tagging v1.2.5.
No product behaviour changes, no new config keys and no new or changed translatable strings. The v1.2.5 security fix is unchanged.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA (Ubuntu 22.04, 24.04 and 26.04). On 22.04 use the PPA: the .deb assets above are built on 26.04:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.6 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.5...v1.2.6
v1.2.5
Ubuntu Hello v1.2.5 - Root Helper Hardening (Security Fix)
This is a security release: it fixes a local privilege escalation in the keyring/KWallet unlocking path. Anyone with keyring unlocking enabled should upgrade.
🔧 What's in this release
- 🔒 Security fix: root code execution through the keyring helpers. When keyring/KWallet unlocking was enabled, the PAM module started two root helpers through
popen(): the TPM unseal steps after a face match, andubuntu-hello keyring enablefrompam_sm_setcred. That runs/bin/shas uid 0 with the calling user's environment. The setuid program (su,sudo, …) has already had glibc remove the loader variables such asLD_PRELOAD, butPATH,PYTHONPATHandBASH_ENVwere still there. The TPM step rantpm2_*by bare name, so the shell found it through the caller'sPATH. Theubuntu-hellowrapper ran Python without-E, soPYTHONPATHapplied. Where/bin/shis bash,BASH_ENVwas read too, because the module had already set both uids to 0. A local user with keyring unlocking enabled could set one of these, runsu $USER, authenticate with their own password or face, and have their code run as root without any sudo rights.- Every root helper now starts through one function,
run_root_helper(). It usesposix_spawnwith an absolute path and a fixed argument list, with no shell, and passes only the scrubbed environmentcompare.pyalready used: a fixedPATHplus checked locale variables. - The TPM unseal is now three direct runs of
/usr/bin/tpm2_createprimary,tpm2_loadandtpm2_unseal. The temporary context files are removed withunlink(). - Sealing the keyring password at login runs
python3 -E -s cli.py keyring enable -U <user>directly, with the password on stdin, instead of the/bin/shubuntu-hellowrapper. The username no longer passes through a shell string.
- Every root helper now starts through one function,
- 🧪 Tests.
pam-mainnow checks thatLD_PRELOADandPYTHONPATHset in the parent arrive empty in a root helper. It also runs the TPM unseal chain against faketpm2_*tools, checking each step's arguments, failures and context-file cleanup, and runskeyring enableagainst a fake CLI. The keyring paths oftry_set_keyring_authtokand setcred's handling of the helper's result are covered too.
Upgrade if you use keyring/KWallet unlocking. Nothing changes in how face login or keyring unlocking work: no new config keys and no new or changed translatable strings.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA (Ubuntu 22.04, 24.04 and 26.04). On 22.04 use the PPA: the .deb assets above are built on 26.04:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.5 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.4...v1.2.5
v1.2.4
Ubuntu Hello v1.2.4 - Coverage Above 90% in SonarQube Cloud
This is a quality release: SonarQube Cloud coverage goes from 87% to over 90%, with new tests for the PAM module's Enter-key device and theme detection. Nothing changes for users.
🔧 What's in this release
- 🔎 SonarQube Cloud coverage above 90%. Sonar reported 87%, held down by the C++ PAM module's branch coverage (38%). Most of those branches were not decisions in the source: gcc adds an exception-unwinding edge for every call that may throw, and no test can choose to take one. The C++ report now leaves out those and the branches gcc proves unreachable (
gcovr --exclude-throw-branches --exclude-unreachable-branches), which drops about 300 of them. Overall coverage is now 90.7%. - 🧪 New tests.
- The PAM module's Enter-key device (
enter_device.cc, used by theinputworkaround) had no tests.pam-mainnow runs it with libevdev's uinput calls stubbed: a refused/dev/uinput, a full Enter press, and a failed write at each step. It goes from 0% to 100%. - Theme detection: the light and "no answer" results for KDE, XFCE, MATE and LXQt, the GTK icon-theme fallback, and
ThemeWatchersurviving a missing monitor tool, a broken pipe and errors on shutdown.
- The PAM module's Enter-key device (
No product code changes, no new config keys and no new or changed translatable strings.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA (Ubuntu 22.04, 24.04 and 26.04). On 22.04 use the PPA: the .deb assets above are built on 26.04:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.4 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.3...v1.2.4
v1.2.3
Ubuntu Hello v1.2.3 - Ubuntu 22.04 Support, PAM and CLI Fixes, Full Coverage in Sonar
This release adds support for Ubuntu 22.04 LTS (jammy): the PPA now publishes a jammy build (#17), and a new CI cell and the booted-OS tier keep it working. Tests written for this port found and fixed three real bugs in the PAM module and the CLI, including ubuntu-hello disable emptying config.ini. SonarQube Cloud now sees the C++ PAM module's coverage too.
🔧 What's in this release
- 🐧 New: Ubuntu 22.04 (jammy) support (#17). On 22.04,
apt updatefailed with "does not have a Release file" because the PPA only built noble and resolute. It now builds jammy too. Jammy ships meson 0.61, GTK 4.6, PyGObject 3.42 and Python 3.10, so:- The build no longer needs meson 0.64.
install_data(preserve_path:)became a per-file install that keeps thecli/,recorders/andrubberstamps/layout. - Settings and the setup wizard load on GTK 4.6.
GtkPicture:content-fit(4.8) is dropped at load time, where GTK 4.6's default scaling already looks the same. The wizard'sGtkCenterBoxchildren use typed<child>elements instead of the 4.10*-widgetproperties. - Confirmation dialogs fall back to a small modal window where GTK has no
Gtk.AlertDialog(4.10). - On 22.04 the dropdowns in Settings have no type-ahead search. PyGObject 3.42 cannot pass GTK the search expression, so they are plain dropdowns there. Everything else works the same.
- The KDE theme probe installs
kreadconfig5where KF6 does not exist (libkf6config-bin | libkf5config-bin).
- The build no longer needs meson 0.64.
- ✅ Verified on a booted 22.04. The booted-OS tier passes on a clean 22.04 cloud image. It covers the package install, face-auth PAM through
sudo, the greeter rule, reboot persistence and purge. On 22.04 the polkit agent helper is setuid (polkit 0.105), so there is no sandbox to relax and the drop-in has no effect. The tier checks that instead of simulating a sandbox. v1.2.2 and older were built for 26.04 only, so on 22.04 there is no previous release to upgrade from. - 🐛 Fix:
ubuntu-hello disablecould emptyconfig.ini. On a config without thedisabledkey, the in-place rewrite crashed halfway and left a 0-byte file. It also reported success without changing anything when the line was spelleddisabled=false. It now uses the same section-aware, atomic editor as Settings. It adds the key when missing, keeps comments, and a failed write leaves the old file intact. - 🐛 Fix: the PAM module's "Unknown error" message read past its string.
S("Unknown error: ") + statusadded the exit code to achar *, which is pointer arithmetic, not string concatenation. An unexpected compare exit code showed the user bytes from past the end of the message. It now prints the code. - 🐛 Fix: a PAM password task that never started could abort the host process.
optional_task::stop()joined or cancelled a thread that did not exist when the task was never activated, for example the password watcher underpam_sm_open_session. It now returns early. - 🐛 Smaller fixes.
ubuntu-hello testno longer crashes on a model whosedatalist is empty, and prints its resolution as width × height.compare.pyno longer divides by zero on an empty camera frame.
- 🔎 Coverage and duplication (SonarQube Cloud).
- The Python gate now measures the same files Sonar does. The untested
cli/*.pymodules were never counted locally. 150+ new tests take the combined Python coverage to 97%. - The C++ PAM module now uploads gcov coverage (
gcovr --sonarqube), with a newpam-maintest formain.cc's gates, error reporting, helper sanitising andpam_sm_*entry points. - The one duplicated block (
detect_desktop(), in both the theme probe and the wallet backend) is now shared.
- The Python gate now measures the same files Sonar does. The untested
No new config keys and no new or changed translatable strings.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA (Ubuntu 22.04, 24.04 and 26.04). On 22.04 use the PPA: the .deb assets above are built on 26.04:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.3 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.2...v1.2.3
v1.2.2
Ubuntu Hello v1.2.2 - Verified Model Downloads, Keyring Seal Safety, SonarQube Cloud
This release closes an integrity gap in how the setup wizard fetches the face-recognition models, which it downloads and unpacks as root, and fixes four ways enabling keyring unlock could go wrong: losing the previous seal, choosing TPM sealing on a partial tpm2-tools install, accepting an empty piped password, and a Settings edit deleting comments from config.ini. Under the hood, the project now runs SonarQube Cloud static analysis locally and in CI, and went from 356 findings to none.
🔧 What's in this release
- 🛡️ Security: the setup wizard now verifies the face models it downloads. When the models are missing, the wizard runs
dlib-data/install.shas root to fetch the three dlib archives and unpack them. It unpacked whatever arrived: there was no integrity check, and thegithub.com/.../raw/URLs it used answer with a redirect. Each archive is now checked against a pinned SHA-256 before anything is unpacked. The pins are the same onespackage-configure.shalready used for the packaged install path, so the two paths now agree where before only one of them verified. Redirects are also refused: the canonicalraw.githubusercontent.comURLs serve the files directly, and wget gets--max-redirect=0while curl gets--max-redirs 0 --proto-redir =https. A mismatch aborts the download, and the wizard reports it as a failed download. - 🔐 Fix: switching keyring unlock between TPM and software sealing could lose the seal. Each sealing path deleted the other mechanism's credential before writing its own, so a failure in between (a TPM command, encryption or a file write) left the user with no usable seal. The previous credential is now kept until its replacement is on disk.
- 🧰 Fix:
keyring enablecould fail mid-seal on a partialtpm2-toolsinstall. It chose TPM sealing whentpm2_createprimaryandtpm2_unsealwere present, but sealing also runstpm2_createand restoring runstpm2_load. All four are now required; if any is missing it falls back to software sealing. - 🚫 Fix: an empty piped password was sealed and reported as success.
echo | ubuntu-hello keyring enable(EOF or a bare newline) sealed an empty string, but unsealing treats an empty result as failure, so the seal never unlocked anything. It is now rejected, as the interactive prompt already did. - 📝 Fix: a Settings edit deleted comments from
config.ini. Replacing a key treated any indented line after it as part of the old value, including indented#/;comments. Comments are now kept, while the old value's real continuation lines are still dropped, so astamp_rulesupdate never leaves a stale rule behind. - 🔏 Fix: source installs set
config.inito0744. The Meson install path gave the file an execute bit, diverging from every package path, fromdocs/SECURITY.mdand from the booted-OS mode check. It is now0644. - ⏱️ Fix: the auth window's user lookup could hang. Its last-resort
loginctlcall had no timeout, so a stalledlogindcould block the authentication window. It is now bounded at 5 seconds, like the Settings window's. - 🔎 New: SonarQube Cloud.
./scripts/ci-sonar.shruns the analysis locally in a pinned Docker scanner, and CI scans as a step in thecoveragejob, with a quality gate on pushes tomasterand on pull requests from this repository (fork pull requests skip the scan, as they cannot read theSONAR_TOKENsecret). The project went from 356 findings to 0, with 0 bugs and 0 vulnerabilities and A ratings for reliability, security and maintainability. Most of the fixes above came out of that work or its code review. Where a rule misreads this project's idioms (GTK CSS selectors, kernel-mirroringv4l2names, kwallet-pam's fixed PBKDF2 parameters, the PAM module's mandatory C-ABI casts), it is scoped per rule and per path, with the reason written next to it, and never suppressed in the source. - ⚙️ CI: runs once per pull request.
pushandpull_requestboth fired for every PR branch and landed in different concurrency groups, so every push ran the whole matrix twice.pushnow fires formasteronly. The booted-OS tier runs on same-repository release pull requests (feature/v*), and is guarded so a fork cannot trigger it.
No new config keys, no new or changed translatable strings, and no dependency changes. Desktop, greeter and wallet compatibility is unchanged: GNOME, KDE Plasma, XFCE, Cinnamon, MATE, Budgie and LXQt with GDM, SDDM and LightDM; GNOME Keyring (pam_gnome_keyring) and KWallet (pam_kwallet5).
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA remains available:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.2 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.1...v1.2.2
v1.2.1
Ubuntu Hello v1.2.1 - Clean-Install Fix, Settings Env Hardening, Booted-OS + Footage Test Tiers
This release fixes the 1.2.0 package failing to configure on a clean Ubuntu 26.04, closes a local root-execution path through the polkit-elevated Settings process, stops the PAM module from hijacking the host process's syslog identity, makes the confirmations config migration run for package installs, corrects the mode of config.ini, and adds the two test tiers that found all of it: a booted-OS tier (a clean Ubuntu, Fedora or Arch under QEMU/KVM with an emulated TPM) and a recorded-footage tier (the real recognition loop on real camera frames, no face pixels kept). Plural-form translations are now linted and declared in every catalog.
🔧 What's in this release
- 📦 Fix: fresh install failed on a clean Ubuntu 26.04. The package builds dlib from source (the archive has no
python3-dlib) and the toolchain it needs was only Recommended. apt never upgrades an already-installed package to satisfy a Recommends, so on an image whosepython3lagged the archivepython3-devwas silently skipped, the build died onPython.h: No such file or directory, dpkg stayed half-configured and every login fell through to the password. Developer machines that already had the headers never saw it. The toolchain is now a hard dependency unless the distro's dlib is installed (python3-dlib | python3-dev,| python3-pip,| cmake,| g++); Fedora/openSUSE gainpython3-devel/gcc-c++/ Pillow, Archgcc/python-pillow. Reproduced and verified on a clean cloud image. - 🛡️ Security fix: the elevated Settings process accepted arbitrary environment variables from argv.
ubuntu-hello-gtkforwards the desktop's display and locale variables acrosspkexecas--env-KEY=valuearguments and restored every such argument into its environment as root. polkit pins only the interpreter and the script path, so a local user who can pass theauth_adminprompt could append--env-PATH=/tmp/evil:…or--env-LD_PRELOAD=…and have the root process — which spawnsubuntu-hello,sudo,gsettingsandloginctlby bare name — execute their binary as root. The restore now accepts only the fixed display/locale allowlist thatelevate()sends (one shared constant for sender and receiver), drops everything else with a stderr notice, and as root pinsPATHto a fixed system value before any helper is spawned. Reported by an automated security review; unit tests cover the injectedPATH/LD_*/PYTHON*/HOMEcases. - 🪵 Fix: the PAM module hijacked the host's syslog identity.
openlog("pam_ubuntu_hello")withoutcloselog()tagged every later line ofsudoor the display manager aspam_ubuntu_hello. The identity is now scoped to the module's own logging (SyslogIdentityScope). - ⚙️ Fix: the
confirmationsmigration never ran for package installs. It lived in the source installer only;.deb/RPM/Arch upgrades left the key out and fell back to a single frame. It now lives inconfig_ensure.pyandpackage-configure.shruns it on every install and upgrade — hand edits, comments and a hand-tightened threshold are kept, verified on a real 1.1.6 → 1.2.1 apt upgrade. - 🔏 Fix:
config.iniwas installed executable (0755→0644);docs/SECURITY.mdnow describes the real/etc/ubuntu-hello/layout (0755 directory, secrets in 0700 subdirectories). - 🔐 Fix: on Fedora/Arch the module could break password authentication. The authselect/Arch PAM line used
[success=end default=ignore];endis a Debian pam-auth-update macro, not raw PAM syntax, so Linux-PAM let the module's skip return (AUTHINFO_UNAVAILfor SSH / no camera / disabled) surface — an SSH or camera-less login failed instead of falling through to the password. Now[success=done default=ignore]. Found with a live before/after on a booted Fedora guest. - 👻 Fix: face auth spawned a GTK overlay that crashed on a headless box.
compare.pystarted the on-screen auth overlay unconditionally, but under PAM there is no display, so on a server or SSHsudoit crashed on open and left an apport report every time (auth still fell back to the password). The overlay is now spawned only when a display is reachable. - 🪟 Fix: the post-install wizard crashed on a headless machine. It assumed
DISPLAY=:0; installing over SSH started GTK with no display and left an apport crash report. It now launches only when a display actually exists. - 🧩 Fix: the Arch PAM module failed to load, breaking face auth entirely on Arch. It links
libINIReader.so.0(libinih) andlibevdev, but those were build-only deps, so pacman never installed them and PAM could notdlopenthe module. Both are now runtime dependencies. - 🏗️ Fix: the Arch package could not build dlib and then skipped the security setup. Its deps listed
gcc/cmakebut notmake, so cmake could not build dlib, and that failure aborted the post-install before PAM and the polkit drop-in were written.makeis now a dependency and the dlib build runs last and non-fatally on every format, so the security config is always applied. - 🧹 Fix:
dnf removeleft/usr/lib64/ubuntu-hellobehind (untracked__pycache__); the shared pre-remove step now sweeps every lib dir and drops the emptied directory. - 🖥️ New: booted-OS test tier (
scripts/vm/,tests/vm/). A clean Ubuntu 26.04, Fedora 44 or Arch cloud image boots under QEMU/KVM with a swtpm TPM 2.0 and scenario scripts run inside over SSH: install (PAM line, drop-in, tmpfiles, catalogs, dlib, file modes), config migration,sudothrough PAM with a synthetic model (fails closed without a camera, wrong password refused, caller environment never inherited, syslog identity kept), the greeter HARD RULE (pam_probe.pyruns the real PAM stack forgdm-passwordand counts prompts: withworkaround = offthe module never asks itself), the polkit helper sandbox with a real TPM seal/unseal, a real reboot, purge (nothing left, no crash reports), and an upgrade from the previous GitHub release. Onelib.shholds what differs per distro.UH_VM_PKG_DIRtests packages built from the tree; CI runs a matrix job per distro on release branches. Every fix above was found by it. - 🎞️ New: recorded-footage test tier (
tests/footage/). Replays real-camera clips throughcompare.py's actual scan loop, the real dlib detector/predictor/encoder and the real nod rubber stamp: enrollment on real frames, the same face at Secure from another clip, no face never passing, the agreeing-frames gate, a real nod passing and holding still failing fail-closed, Secure margin. Privacy: only de-identified per-frame signals exist (dark flag, face rect, five landmarks, descriptor), the pixels were shredded, the signals stay off the repository, and CI uses a synthetic set with the measured shape. - 🌍 i18n: plural forms.
ngettext()entries were invisible to the lint and an untranslated plural shipped everywhere with the lint green; plural entries are now linted and every catalog header carries the language'sPlural-Formsrule so Python's gettext picks the right form. Catalogs are refreshed for 1.2.1 (template version, source references).
No new config keys or strings. Runtime dependencies: the dlib build toolchain is now a proper dependency where the distro ships no dlib. Desktop / greeter / wallet compatibility is unchanged.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA remains available:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.1 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.0...v1.2.1
v1.2.0
Ubuntu Hello v1.2.0 - Keyring-Unseal Fix, Second-Model Wizard, Auth Notifications, GTK 4 + Hardening
This release fixes TPM-sealed keyring unlock under polkit, teaches the setup wizard to enroll a second face model for different lighting, adds native desktop notifications for every face-auth attempt (with the diagnostics behind the result), moves Settings / wizard / overlay to GTK 4, hardens how the root PAM module launches its compare.py helper, and refreshes every product and CI dependency pin to its latest final release. The hardening was in response to an automated vulnerability-scanner report of a potential local privilege escalation via a user-controlled PATH. On review the chain was not exploitable as described (details below), but the code relied on an unspecified corner of libc behaviour, so it is now explicit and no longer depends on it.
🔒 What's in this release
- Reported:
pam_ubuntu_hello.sospawnedcompare.pyas root withposix_spawnp(..., envp = nullptr)and never dropped privileges;compare.pythen started the auth overlay withsubprocess.Popen(["ubuntu-hello-gtk", ...])— a bare-namePATHlookup. The scanner concluded that a local user could plant~/.local/bin/ubuntu-hello-gtkand have it executed as root the moment face auth started (e.g.su <enrolled-user>). - Why it was not exploitable: on glibc/Linux,
posix_spawnp()with aNULLenvpgives the child an empty environment, not the caller's — verified with a small test program (FOO=bar ./t→envprints nothing). With noPATHset at all, both glibc'sexecvp()and Python'ssubprocessfall back to/bin:/usr/bin, soubuntu-hello-gtkalready resolved to/usr/bin/ubuntu-hello-gtk;~/.local/binwas never searched. The premise of an "inherited environment" was wrong. - Hardened anyway — PAM module: the helper is now started with
posix_spawn()and an explicit minimal environment (PATH=/usr/sbin:/usr/bin:/sbin:/binonly), so the calling user'sPATH,PYTHONPATH,LD_PRELOAD, … can never reach the root helper regardless of libc behaviour. The interpreter runs aspython3 -E -s(ignorePYTHON*variables, no user site-packages).-Iwas deliberately not used: it would also drop the script directory fromsys.path, which would breakcompare.py's sibling imports (snapshot,paths_factory,recorders, …). - Hardened anyway —
compare.py: the auth overlay is now spawned via an absolute path (GTK_BIN_PATH = "/usr/bin/ubuntu-hello-gtk"), matching the existingBUSCTL_PATHpattern. No child of the root helper is resolved by bare name any more. - Docs:
docs/SECURITY.mdgains a "No Inherited Environment / PATH" bullet;docs/architecture/README.md§3.1 andAGENTS.mdnow describe the explicit-env spawn and-E -sflags. - 🔑 Fix: TPM-sealed keyring unlock failed under polkit (worked at GDM): every
pkexec/ App Center prompt loggedFailed to unseal keyring password from TPM. polkit ≥ 126 runspolkit-agent-helper-1as a hardened transient unit (DevicePolicy=strict,ProtectSystem=strict); the shipped drop-in only re-allowed the camera and/dev/uinput, so/dev/tpmrm0wasOperation not permittedand the transient.ctxfiles under/etc/ubuntu-hello/tpm-keys/hit a read-only filesystem. All three drop-in writers (install.sh,package-configure.sh,install_config.py) now addDeviceAllow=char-tpm rw,DeviceAllow=/dev/tpm0 rw,ReadWritePaths=/etc/ubuntu-hello/tpm-keys. Reproduced layer-by-layer withsystemd-rununder the unit's exact hardening and verified live:PAM_AUTHTOK set successfully for keyring unlockingon a real polkit prompt. Regression tests intest_install_download.py/test_packaging_release.py. - 🧑🎨 Setup wizard: second face model under different lighting: a single model recorded in daylight often lands just past the certainty threshold in the evening under lamps (or vice-versa), which shows up as intermittent "timeout reached" instead of a clear error (root-caused on real hardware: certainty 3.37–3.6 vs 3.5). Slide 4 now runs two passes: after the first scan it re-labels itself "Add a second face model (recommended)", explains why (lighting) and how (change the room light / desk lamp, turn away from the window, put on the glasses you sometimes wear), restarts the live preview and offers Scan second model. Either pass can be skipped, but not both: skipping pass 1 makes pass 2 required (Skip hidden, "Add a face model (required)"); a failed second scan is non-fatal (retry or skip) whereas a failed only-scan still stops the wizard. Models are labelled
Setup lighting 1/Setup lighting 2. Settings also shows a warning bar on the Models tab while exactly one model is enrolled, with an Add a second model action. 18 new strings translated in all 98 catalogs. Unit tests + real-GTK E2E (UH_REAL_GTK=1) cover both passes and both skip paths. - 🧑🎨 Guided multi-sample enrollment (Windows Hello style): a model was one descriptor from one frame, which is why logins landed just past the threshold intermittently.
ubuntu-hello addnow guides you through six small head movements (about a minute) and keeps up to 13 descriptors per model; the wizard and Settings show the live prompt and progress (the scan no longer blocks the UI), and the same prompt is mirrored on a notification card right under the camera. The optional second scan stays, now recommended for glasses on/off, a change of facial hair or different lighting. Fixes the winning-model lookup for multi-sample models. - 🔔 New: native desktop notifications for every face-auth attempt (
notify.py,org.freedesktop.Notifications): one card updated in place — "Face authentication · sudo — 👀 Looking for your face…" stays on screen for the whole scan (critical urgency: GNOME never auto-hides it), then becomes Face recognized · sudo — ✓ Full Name · 1.3 s (removed aftersuccess_linger= 3 s) or Face not recognized — ✗ No match in 8 s · 💡 add a model in this light (stays in the list). Titles name the requester (sudo,su,authorization,screen unlock) because the PAM module now forwards the PAM service tocompare.py.[notifications] details = trueadds model, certainty/threshold, frames, dark frames, camera, pid, timeout, load. The notification id is persisted per user so consecutive attempts reuse the same card; a detached helper closes the success card and acts as a watchdog for a helper that died mid-scan. Layout follows GNOME Shell 50's rules read from its source (one-line body,<b>only; nodesktop-entry/transient; low urgency never banners). Becausecompare.pyruns as root with an empty environment, cards are sent on the target user's session bus by dropping to that uid before exec'ing the absolute/usr/bin/gdbus; greeter logins, missing gdbus, or any error silently disable it — never the auth result. Verified live on GNOME 50 / Wayland, including a real polkit prompt: the polkit helper drop-in now setsProtectHome=tmpfs+BindReadOnlyPaths=-/run/user(yeshid/run/user, so no card could ever be delivered from Settings / App Center /pkexec;/homeand/rootstay empty inside the unit, only the runtime dir is bound back — security review) andReadWritePaths=-/run/ubuntu-hellofor the root-only id state, created at boot by a newtmpfiles.d/ubuntu-hello.conf. Strings translated in all 98 catalogs;libglib2.0-bin/glib2added to core runtime deps. - ⚙️ Settings → Notifications tab: switches for Show notifications, Notification sounds and Include diagnostics (
[notifications] enabled/sound/details), written with a new comment-preservingconfig_edit.set_option()(the bare-keyubuntu-hello setis ambiguous between sections). "Add new user" removed from the Models tab. Wizard: Back button on every page after the first (Cancel only on page 1) with per-page cleanup — camera scan cancelled and single device list on re-entry, chosen camera kept selected, IR test capture released, download not restarted, second scan resumed instead of a third model. First scan is required, only the second can be skipped; the two-scan plan is explained up front. - 🔐 New: Settings → Security tab, agreeing-frame matching and recalibrated levels: a face used to be accepted on the first frame that fell under the match threshold. A scan takes dozens of independent looks at the camera, so the deciding frame was the minimum of many draws and a single blurred or oddly lit frame from a stranger could carry the whole attempt. New
[video] confirmationsrequires several separate frames to agree before the match is trusted (Fast 2, Balanced 3, Secure 4); the real user reaches the count in well under a second. The thresholds were also recalibrated from measured logins rather than one sample — the previous Secure value matched no frame at all once the room light changed, and with a single enrolled model the distance to the same face drifts by about 0.4 between lighting conditions. Levels are now Fast 3.5 / Balanced 3.0 / Secure 2.6, with strictness carried by the frame count. A new Settings → Security tab exposes the three levels plus an opt-in Ask me to nod to confirm switch, which the setup wizard's security page now offers too (its last page also saves on Finish rather than on arrival, so a level changed there is no longer lost) (a photo held up to the camera cannot nod; a video replay still can, the documented limit of challenge-response). Nod detection was rewritten around anchored nose displacement, the challenge prompt is mirrored to the notification card because the auth overlay can never open a display under PAM, and a liveness check that crashes now denies. Upgrades keep their own threshold and only gain the new key; a hand-tightened config stays on a single frame so the migration cannot break an existing...
v1.1.6
Ubuntu Hello v1.1.6 - Session-Idle Self-Abort (Best-Effort) + Dependency Updates
This release adds a best-effort self-abort for a running face scan when the session genuinely goes idle, plus packaging/CI dependency updates. It does not fully resolve face recognition continuing to run after Esc at a GNOME/GDM lock screen — read the "Known limitation" bullet below before relying on it for that.
🐛 What's in this release
- New: session-idle self-abort: with the shipped default
core.workaround = off, nothing in the PAM module was ever told to cancel a runningcompareprocess — the only existing cancel path only fires when a concurrent password-watch thread wins the race, and that only exists when a workaround is enabled. - Deliberately did not widen PAM-side password watching to add this.
AGENTS.mdcarries an explicit HARD RULE over that exact code, guarding against a worse prior incident: doing so previously broke GDM login outright (selecting a user immediately bounced back to the account list). - Added a same-process signal instead:
compare.pynow runs a daemon thread that polls its own login1 session'sIdleHintviabusctl(absolute path, since this runs as root during PAM auth) roughly twice a second. On an observedfalse → truetransition (edge-triggered — an already-idle session at scan start, the normal case when waking a lock screen, does not trigger this) it sends the processSIGTERMso the existing main-thread handler does cleanup, rather than touching the camera directly from the watcher thread. Fails open ifbusctl/logind are unavailable or return anything other than exactlyb true/b false. New config:core.abort_on_session_idle(defaulttrue). ⚠️ Known limitation, confirmed by live testing: after building this, live D-Bus capture across a real Esc-at-lock-screen repro (system bus + user session bus, multiple rounds) showedIdleHintnever transitions on GNOME/GDM for that scenario — Esc only toggles GNOME Shell's internal password-prompt-vs-idle-clock view, with no external signal we could find (logind IdleHint,xdg-desktop-portal Inhibit,org.gnome.ScreenSaver.ActiveChangedall stayed unchanged;WakeUpScreen/Mutter.IdleMonitorfire but also on ordinary interaction, so using them risks aborting legitimate scans). On GNOME/GDM this is currently a dormant safety net, not a fix for Esc. Kept because it's harmless and may help elsewhere.- Also this release: bumped the Flatpak runtime/SDK to
25.08and several pinned GitHub Actions (upload-artifact,download-artifact,setup-buildx-action,setup-qemu-action) to their current latest releases, plus CI hardening (explicit least-privilegepermissions:on the lint/coverage/compat jobs, and exposing the GitHub Actions cache runtime variables thatbuildx'stype=ghacache backend needs) and two thread-safety fixes in the idle watcher found in PR review — including a race where a latebusctlreading arriving after a concurrent successful/failed exit could override the decided exit code with abort code12. - Verified: confirmed
busctl's output format directly against a real login1 session on real hardware, matching the parser exactly. Full unit test coverage for the idle-state probe (including malformed-output and absolute-path cases) and the edge-triggered watcher thread; full test suite passes.
📥 Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands — the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA remains available:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.1.6 tag, review it, then run locally — do not pipe a moving branch URL directly to bash.
Full Changelog: v1.1.5...v1.1.6