Files
nixos/modules/desktop-steam-update.nix

123 lines
3.7 KiB
Nix

# Binary-cache update mechanism for Jovian-NixOS desktops.
#
# Replaces the upstream holo-update/steamos-update stubs with a script that
# checks the private binary cache for a newer system closure, and provides a
# root-level systemd service to apply it. Steam's deck UI calls
# `steamos-update check` periodically; exit 7 = no update, exit 0 = update
# applied or available.
#
# The deploy endpoint is ${binary_cache_url}/deploy/${hostname} — a plain
# text file containing the /nix/store path of the latest closure, published
# by CI after a successful build.
{
pkgs,
lib,
hostname,
username,
site_config,
...
}:
let
deploy-url = "${site_config.binary_cache.url}/deploy/${hostname}";
steamos-update-script = pkgs.writeShellScript "steamos-update" ''
export PATH=${
lib.makeBinPath [
pkgs.curl
pkgs.coreutils
pkgs.systemd
]
}
STORE_PATH=$(curl -sf --max-time 30 "${deploy-url}" || true)
if [ -z "$STORE_PATH" ]; then
>&2 echo "[steamos-update] server unreachable"
exit 7
fi
CURRENT=$(readlink -f /nix/var/nix/profiles/system)
if [ "$CURRENT" = "$STORE_PATH" ]; then
>&2 echo "[steamos-update] no update available"
exit 7
fi
# check-only mode: just report that an update exists
if [ "''${1:-}" = "check" ] || [ "''${1:-}" = "--check-only" ]; then
>&2 echo "[steamos-update] update available"
exit 0
fi
# apply: trigger the root-running systemd service to install the update
>&2 echo "[steamos-update] applying update..."
if systemctl start --wait pull-update-apply.service; then
>&2 echo "[steamos-update] update installed, reboot to apply"
exit 0
else
>&2 echo "[steamos-update] apply failed; see 'journalctl -u pull-update-apply'"
exit 1
fi
'';
in
{
nixpkgs.overlays = [
(_final: prev: {
jovian-stubs = prev.jovian-stubs.overrideAttrs (old: {
buildCommand = (old.buildCommand or "") + ''
install -D -m 755 ${steamos-update-script} $out/bin/holo-update
install -D -m 755 ${steamos-update-script} $out/bin/steamos-update
'';
});
})
];
systemd.services.pull-update-apply = {
description = "Apply pending NixOS update pulled from binary cache";
serviceConfig = {
Type = "oneshot";
ExecStart = pkgs.writeShellScript "pull-update-apply" ''
set -uo pipefail
export PATH=${
lib.makeBinPath [
pkgs.curl
pkgs.coreutils
pkgs.nix
]
}
STORE_PATH=$(curl -sf --max-time 30 "${deploy-url}" || true)
if [ -z "$STORE_PATH" ]; then
echo "server unreachable"
exit 1
fi
CURRENT=$(readlink -f /nix/var/nix/profiles/system)
if [ "$CURRENT" = "$STORE_PATH" ]; then
echo "already up to date: $STORE_PATH"
exit 0
fi
echo "applying $STORE_PATH (was $CURRENT)"
nix-store -r --add-root /nix/var/nix/gcroots/pull-update-apply-latest --indirect "$STORE_PATH" \
|| { echo "fetch failed"; exit 1; }
nix-env -p /nix/var/nix/profiles/system --set "$STORE_PATH" \
|| { echo "profile set failed"; exit 1; }
"$STORE_PATH/bin/switch-to-configuration" boot \
|| { echo "boot entry failed"; exit 1; }
echo "update applied; reboot required"
'';
};
};
# allow the primary user to trigger pull-update-apply without a password
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "pull-update-apply.service" &&
subject.user == "${username}") {
return polkit.Result.YES;
}
});
'';
}