Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Unit]
Description=Check for staged Aurora deployments
Documentation=https://docs.getaurora.dev/
After=uupd.service rpm-ostreed.service

[Service]
Type=oneshot
ExecStart=/usr/libexec/aurora-deployment-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=Periodically check for staged Aurora deployments

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
AccuracySec=5min
Persistent=false
Unit=aurora-deployment-check.service

[Install]
WantedBy=timers.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[Unit]
OnSuccess=aurora-deployment-check.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Watch for staged Aurora deployment status
Documentation=https://docs.getaurora.dev/

[Path]
PathExists=/run/aurora/staged-ready
Unit=aurora-deployment-notifier.service

[Install]
WantedBy=default.target

@renner0e renner0e Sep 3, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could get rid of this duplication with the user and system service units.

I think we might be able to use this neat systemd feature for that

man systemd.unit(5)

Unit names can be parameterized by a single argument called the "instance name". The unit
is then constructed based on a "template file" which serves as the definition of multiple
services or other units. A template unit must have a single "@" at the end of the unit name
prefix (right before the type suffix). The name of the full unit is formed by inserting the
instance name between "@" and the unit type suffix. In the unit file itself, the instance
parameter may be referred to using "%i" and other specifiers, see below.

See for an examplesystemd-zram-setup@.service systemd-zram-setup@zram0.service

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try testing and implementing it this way.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=Notify when an Aurora deployment is ready to boot
Documentation=https://docs.getaurora.dev/

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/libexec/aurora-deployment-notifier

[Install]
WantedBy=default.target
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d /run/aurora 0755 root root -
113 changes: 113 additions & 0 deletions system_files/shared/usr/libexec/aurora-deployment-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env bash

set -euo pipefail

STATUS_DIR="${AURORA_DEPLOYMENT_STATUS_DIR:-/run/aurora}"
FLAG_FILE="${STATUS_DIR}/staged-ready"
STATUS_FILE="${STATUS_DIR}/deployment-status.json"

SOURCE=""
STAGED_ID=""
BOOTED_ID=""

write_status() {
local tmpfile
tmpfile="$(mktemp "${STATUS_DIR}/deployment-status.XXXXXX")"

jq -n \
--arg source "${SOURCE}" \
--arg staged_id "${STAGED_ID}" \
--arg booted_id "${BOOTED_ID}" \
--arg created_at "$(date --iso-8601=seconds)" \
'{
ready: true,
source: $source,
staged_id: $staged_id,
booted_id: $booted_id,
created_at: $created_at
}' > "${tmpfile}"

chmod 0644 "${tmpfile}"
mv -f "${tmpfile}" "${STATUS_FILE}"
printf 'ready\n' > "${FLAG_FILE}"
chmod 0644 "${FLAG_FILE}"
}

clear_status() {
rm -f "${FLAG_FILE}" "${STATUS_FILE}"
}

check_bootc() {
local bootc_json
local staged_id
local booted_id

command -v bootc >/dev/null 2>&1 || return 1
bootc_json="$(bootc status --json 2>/dev/null)" || return 1

staged_id="$(jq -er '
.status as $status
| select($status.staged != null and $status.staged != {})
| (
$status.staged.image.imageDigest
// $status.staged.image.digest
// $status.staged.ostree.checksum
// $status.staged.checksum
// ($status.staged | tostring)
)
' <<< "${bootc_json}" 2>/dev/null)" || return 1

booted_id="$(jq -r '
.status.booted.image.imageDigest
// .status.booted.image.digest
// .status.booted.ostree.checksum
// .status.booted.checksum
// empty
' <<< "${bootc_json}" 2>/dev/null)"

if [[ -n "${staged_id}" && "${staged_id}" != "${booted_id}" ]]; then
SOURCE="bootc"
STAGED_ID="${staged_id}"
BOOTED_ID="${booted_id}"
return 0
fi

return 1
}

check_rpm_ostree() {
local ostree_json
local staged_json
local staged_id
local booted_id

command -v rpm-ostree >/dev/null 2>&1 || return 1
ostree_json="$(rpm-ostree status --json 2>/dev/null)" || return 1

staged_json="$(jq -ec '[.deployments[]? | select(.staged == true)] | first // empty' <<< "${ostree_json}" 2>/dev/null)" || return 1
[[ -n "${staged_json}" ]] || return 1

staged_id="$(jq -r '.checksum // .version // .origin // tostring' <<< "${staged_json}" 2>/dev/null)"
booted_id="$(jq -r '[.deployments[]? | select(.booted == true)] | first | .checksum // .version // .origin // empty' <<< "${ostree_json}" 2>/dev/null)"

if [[ -n "${staged_id}" && "${staged_id}" != "${booted_id}" ]]; then
SOURCE="rpm-ostree"
STAGED_ID="${staged_id}"
BOOTED_ID="${booted_id}"
return 0
fi

return 1
}

main() {
install -d -m 0755 -o root -g root "${STATUS_DIR}"

if check_bootc || check_rpm_ostree; then
write_status
else
clear_status
fi
}

main "$@"
36 changes: 36 additions & 0 deletions system_files/shared/usr/libexec/aurora-deployment-notifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash

set -euo pipefail

STATUS_DIR="${AURORA_DEPLOYMENT_STATUS_DIR:-/run/aurora}"
FLAG_FILE="${STATUS_DIR}/staged-ready"
STATUS_FILE="${STATUS_DIR}/deployment-status.json"
STATE_DIR="${XDG_STATE_HOME:-${HOME}/.local/state}/aurora/deployment-notifier"
LAST_NOTIFIED_FILE="${STATE_DIR}/last-notified"

[[ -f "${FLAG_FILE}" ]] || exit 0
command -v notify-send >/dev/null 2>&1 || exit 0

staged_id=""
if [[ -f "${STATUS_FILE}" ]] && command -v jq >/dev/null 2>&1; then
staged_id="$(jq -r '.staged_id // empty' "${STATUS_FILE}" 2>/dev/null || true)"
fi

if [[ -z "${staged_id}" ]]; then
staged_id="$(sha256sum "${FLAG_FILE}" | cut -d ' ' -f 1)"
fi

mkdir -p "${STATE_DIR}"

if [[ -f "${LAST_NOTIFIED_FILE}" ]] && [[ "$(<"${LAST_NOTIFIED_FILE}")" == "${staged_id}" ]]; then
exit 0
fi

notify-send \
--app-name="Aurora" \
--icon="system-software-update" \
--urgency=normal \
"System update ready" \
"Restart your device to finish applying the staged Aurora update."

printf '%s\n' "${staged_id}" > "${LAST_NOTIFIED_FILE}"
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ import "/usr/share/ublue-os/just/apps.just"
import "/usr/share/ublue-os/just/default.just"
import "/usr/share/ublue-os/just/shared.just"
import "/usr/share/ublue-os/just/update.just"
import "/usr/share/ublue-os/just/60-aurora-deployment-notifier.just"
import? "/usr/share/ublue-os/just/60-custom.just"
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Toggle Aurora staged deployment desktop notifications.
[group('Aurora')]
aurora-update-notifier action="status":
Comment thread
arpit1385 marked this conversation as resolved.
#!/usr/bin/env bash
set -euo pipefail

action="{{ action }}"
system_timer="aurora-deployment-check.timer"
system_service="aurora-deployment-check.service"
user_path="aurora-deployment-notifier.path"

case "${action}" in
enable|on)
systemctl --user enable --now "${user_path}"
sudo systemctl enable --now "${system_timer}"
sudo systemctl start "${system_service}" || true
echo "Aurora update notifications enabled."
;;
disable|off)
systemctl --user disable --now "${user_path}" || true
sudo systemctl disable --now "${system_timer}" || true
rm -f "${XDG_STATE_HOME:-${HOME}/.local/state}/aurora/deployment-notifier/last-notified"
echo "Aurora update notifications disabled."
;;
status)
echo "User notifier:"
systemctl --user --no-pager status "${user_path}" || true
echo
echo "System checker:"
systemctl --no-pager status "${system_timer}" || true
;;
*)
echo "Usage: ujust aurora-update-notifier [enable|disable|status]"
exit 2
;;
Comment on lines +12 to +35

@renner0e renner0e Sep 3, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually have one recipe entrypoint and then use gum to select actions like in this case disable|status and so on. I think this would be nice here as well.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try implementing the entrypoint and selection via gum.

esac