Repository: ublue-os/ublue-update

Issue:
U-Blue Update Systemd service reports failure when sucessfully run
Checking the status it reports a failure exit code, though all of the checks appear to succeed:

```
Brian@fedora ~> systemctl status ublue-update.service
× ublue-update.service - Universal Blue Update Oneshot Service
     Loaded: loaded (/usr/lib/systemd/system/ublue-update.service; static)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: failed (Result: exit-code) since Mon 2024-05-13 07:38:57 EDT; 3min 25s ago
TriggeredBy: ● ublue-update.timer
    Process: 143586 ExecStart=/usr/bin/ublue-update (code=exited, status=1/FAILURE)
   Main PID: 143586 (code=exited, status=1/FAILURE)
        CPU: 375ms

May 13 07:38:56 fedora systemd[1]: Starting ublue-update.service - Universal Blue Update Oneshot Service...
May 13 07:38:57 fedora ublue-update[143586]: [2024-05-13 07:38:57,422] ublue_update.update_checks.system:INFO | No system update available.
May 13 07:38:57 fedora ublue-update[143586]: [2024-05-13 07:38:57,424] ublue_update.update_inhibitors.hardware:INFO | System passed hardware checks
May 13 07:38:57 fedora ublue-update[143586]: [2024-05-13 07:38:57,424] ublue_update.cli:INFO | System passed all update checks
May 13 07:38:57 fedora systemd[1]: ublue-update.service: Main process exited, code=exited, status=1/FAILURE
May 13 07:38:57 fedora systemd[1]: ublue-update.service: Failed with result 'exit-code'.
May 13 07:38:57 fedora systemd[1]: Failed to start ublue-update.service - Universal Blue Update Oneshot Service.
```

```
Brian@fedora /u/s/ublue-os> systemctl start ublue-update.service
Job for ublue-update.service failed because the control process exited with error code.
See "systemctl status ublue-update.service" and "journalctl -xeu ublue-update.service" for details.
Brian@fedora /u/s/ublue-os [1]> echo $status
1
```

Manually running the python script appears to give the same result, checking my exit code for it, and it looks to report a success, so I don't know why systemd is reporting this as a failure.

```
Brian@fedora ~> /usr/bin/ublue-update
[2024-05-13 07:45:07,888] ublue_update.update_checks.system:INFO | No system update available.
[2024-05-13 07:45:07,890] ublue_update.update_inhibitors.hardware:INFO | System passed hardware checks
[2024-05-13 07:45:07,890] ublue_update.cli:INFO | System passed all update checks
Brian@fedora ~> echo $status
0
```

Running `ujust update` manually works fine and correctly updates everything.

Hints from issue comments:
@gerblesh: does the systemd service update packages properly or is it just `ujust update`?@Nitrousoxide: Only ujust update seems to actually update anything.

It's not updated anything in the background in a few weeks.
```
Brian@fedora ~> rpm-ostree status
State: idle
Deployments:
● ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:57678826d4131c5154bfeec4d8dfa7b2873eda880fa6524b5e05c6da449d85ad
                  Version: 40.20240510.0 (2024-05-10T17:00:08Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:1a7a9e5229cfe2ba234ba78292c411b3d53755f39dfe1fa77239e8367c745f2a
                  Version: 40.20240427.0 (2024-04-27T22:34:27Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:8668faa3881d87c73f1394f104c42c7613036b3d6bd502fac36c8f44bb914900
                  Version: 39.20240419.0 (2024-04-19T17:03:42Z)
          LayeredPackages: btrfs-assistant snapper
            LocalPackages: sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes

  ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:latest
                   Digest: sha256:bc069b2d8f9d6e0008654ccb88127725a5b20559ddca77e176d1c3b6d9d02e81
                Timestamp: 2024-01-27T01:59:41Z
            LocalPackages: lact-0.5.0-0.x86_64 sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes
Brian@fedora ~> systemctl status ublue-update.service
× ublue-update.service - Universal Blue Update Oneshot Service
     Loaded: loaded (/usr/lib/systemd/system/ublue-update.service; static)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: failed (Result: exit-code) since Fri 2024-05-24 20:55:59 EDT; 4 da>
TriggeredBy: ● ublue-update.timer
    Process: 428482 ExecStart=/usr/bin/ublue-update (code=exited, status=1/FAIL>
   Main PID: 428482 (code=exited, status=1/FAILURE)
        CPU: 307ms

May 24 20:55:57 fedora systemd[1]: Starting ublue-update.service - Universal Bl>
May 24 20:55:59 fedora ublue-update[428482]: [2024-05-24 20:55:59,133] ublue_up>
May 24 20:55:59 fedora ublue-update[428482]: [2024-05-24 20:55:59,133] ublue_up>
May 24 20:55:59 fedora ublue-update[428482]: [2024-05-24 20:55:59,134] ublue_up>
May 24 20:55:59 fedora systemd[1]: ublue-update.service: Main process exited, c>
May 24 20:55:59 fedora systemd[1]: ublue-update.service: Failed with result 'ex>
May 24 20:55:59 fedora systemd[1]: Failed to start ublue-update.service - Unive>
Brian@fedora ~ [3]> systemctl start ublue-update.service
Job for ublue-update.service failed because the control process exited with error code.
See "systemctl status ublue-update.service" and "journalctl -xeu ublue-update.service" for details.
Brian@fedora ~ [1]> systemctl status ublue-update.service
× ublue-update.service - Universal Blue Update Oneshot Service
     Loaded: loaded (/usr/lib/systemd/system/ublue-update.service; static)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: failed (Result: exit-code) since Tue 2024-05-28 23:02:38 EDT; 5s ago
TriggeredBy: ● ublue-update.timer
    Process: 589499 ExecStart=/usr/bin/ublue-update (code=exited, status=1/FAILURE)
   Main PID: 589499 (code=exited, status=1/FAILURE)
        CPU: 470ms

May 28 23:02:37 fedora systemd[1]: Starting ublue-update.service - Universal Blue Update Oneshot Service...
May 28 23:02:38 fedora ublue-update[589499]: [2024-05-28 23:02:38,585] ublue_update.update_checks.system:INFO | S>
May 28 23:02:38 fedora ublue-update[589499]: [2024-05-28 23:02:38,587] ublue_update.update_inhibitors.hardware:IN>
May 28 23:02:38 fedora ublue-update[589499]: [2024-05-28 23:02:38,587] ublue_update.cli:INFO | System passed all >
May 28 23:02:38 fedora systemd[1]: ublue-update.service: Main process exited, code=exited, status=1/FAILURE
May 28 23:02:38 fedora systemd[1]: ublue-update.service: Failed with result 'exit-code'.
May 28 23:02:38 fedora systemd[1]: Failed to start ublue-update.service - Universal Blue Update Oneshot Service.
```

Running ujust update works successfully though

start:
```
Brian@fedora ~ [3]> ujust update

── 23:05:36 - System update ────────────────────────────────────────────────────
Pulling manifest: ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
Importing: ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable (digest: sha256:e7d73879b80cef2a6bd07e549b7ed29514dcd80ad2275a7c93cd364ccc8ea209)
ostree chunk layers needed: 65 (2.2 GB)
custom layers needed: 3 (2.7 GB)
Checking out tree cab28de... done
...
```
After:
```
Brian@fedora ~> rpm-ostree status
State: idle
Deployments:
  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:e7d73879b80cef2a6bd07e549b7ed29514dcd80ad2275a7c93cd364ccc8ea209
                  Version: 40.20240528.0 (2024-05-28T16:59:41Z)
            SecAdvisories: 4 low, 6 moderate, 2 important
                     Diff: 257 upgraded, 18 removed, 146 added
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

● ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:57678826d4131c5154bfeec4d8dfa7b2873eda880fa6524b5e05c6da449d85ad
                  Version: 40.20240510.0 (2024-05-10T17:00:08Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:1a7a9e5229cfe2ba234ba78292c411b3d53755f39dfe1fa77239e8367c745f2a
                  Version: 40.20240427.0 (2024-04-27T22:34:27Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:8668faa3881d87c73f1394f104c42c7613036b3d6bd502fac36c8f44bb914900
                  Version: 39.20240419.0 (2024-04-19T17:03:42Z)
          LayeredPackages: btrfs-assistant snapper
            LocalPackages: sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes

  ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:latest
                   Digest: sha256:bc069b2d8f9d6e0008654ccb88127725a5b20559ddca77e176d1c3b6d9d02e81
                Timestamp: 2024-01-27T01:59:41Z
            LocalPackages: lact-0.5.0-0.x86_64 sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes
Brian@fedora ~> 
```
@Nitrousoxide: after rebooting into the new image, still the same issue, so nothing got fixed in the interim updates
```
Brian@fedora ~> rpm-ostree status
State: idle
^[[ADeployments:
● ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:e7d73879b80cef2a6bd07e549b7ed29514dcd80ad2275a7c93cd364ccc8ea209
                  Version: 40.20240528.0 (2024-05-28T16:59:41Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:57678826d4131c5154bfeec4d8dfa7b2873eda880fa6524b5e05c6da449d85ad
                  Version: 40.20240510.0 (2024-05-10T17:00:08Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:8668faa3881d87c73f1394f104c42c7613036b3d6bd502fac36c8f44bb914900
                  Version: 39.20240419.0 (2024-04-19T17:03:42Z)
          LayeredPackages: btrfs-assistant snapper
            LocalPackages: sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes

  ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:latest
                   Digest: sha256:bc069b2d8f9d6e0008654ccb88127725a5b20559ddca77e176d1c3b6d9d02e81
                Timestamp: 2024-01-27T01:59:41Z
            LocalPackages: lact-0.5.0-0.x86_64 sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes
Brian@fedora ~> /usr/bin/ublue-update
[2024-05-28 23:39:24,773] ublue_update.update_checks.system:INFO | No system update available.
[2024-05-28 23:39:24,776] ublue_update.update_inhibitors.hardware:INFO | System passed hardware checks
[2024-05-28 23:39:24,776] ublue_update.cli:INFO | System passed all update checks
Brian@fedora ~> echo $status
0
Brian@fedora ~> systemctl start ublue-update.service
Job for ublue-update.service failed because the control process exited with error code.
See "systemctl status ublue-update.service" and "journalctl -xeu ublue-update.service" for details.
Brian@fedora ~ [1]> echo $status
1
Brian@fedora ~> 

```@gerblesh: You appear to have rebased to an unsigned image? I'm not sure if that's affecting anything but the container policy likely is preventing rpm-ostree from updating@gerblesh: try rebasing to a signed image using `rpm-ostree rebase ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:stable` this will likely fix the issue@gmpinder: I'm also having the same issue and I'm on a signed image

```
$> systemctl status ublue-update.service
× ublue-update.service - Universal Blue Update Oneshot Service
     Loaded: loaded (/usr/lib/systemd/system/ublue-update.service; static)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: failed (Result: exit-code) since Mon 2024-06-10 09:43:45 EDT; 3h 56min ago
TriggeredBy: ● ublue-update.timer
    Process: 24820 ExecStart=/usr/bin/ublue-update (code=exited, status=1/FAILURE)
   Main PID: 24820 (code=exited, status=1/FAILURE)
        CPU: 415ms

Jun 10 09:43:43 jerry-desktop systemd[1]: Starting ublue-update.service - Universal Blue Update Oneshot Service...
Jun 10 09:43:44 jerry-desktop ublue-update[24820]: [2024-06-10 09:43:44,934] ublue_update.update_checks.system:INFO | System update available.
Jun 10 09:43:44 jerry-desktop ublue-update[24820]: [2024-06-10 09:43:44,936] ublue_update.update_inhibitors.hardware:INFO | System passed hardware checks
Jun 10 09:43:44 jerry-desktop ublue-update[24820]: [2024-06-10 09:43:44,936] ublue_update.cli:INFO | System passed all update checks
Jun 10 09:43:45 jerry-desktop systemd[1]: ublue-update.service: Main process exited, code=exited, status=1/FAILURE
Jun 10 09:43:45 jerry-desktop systemd[1]: ublue-update.service: Failed with result 'exit-code'.
Jun 10 09:43:45 jerry-desktop systemd[1]: Failed to start ublue-update.service - Universal Blue Update Oneshot Service.
```

```
$> rpm-ostree status
State: busy
Transaction: upgrade
  Initiator: client(id:cli dbus:1.254 unit:tmux-spawn-25ba0e44-0b86-4683-92de-512d934a819d.scope uid:1000)
Deployments:
● ostree-image-signed:docker://registry.gitlab.com/wunker-bunker/wunker-os/jp-desktop-nvidia
                   Digest: sha256:71d0b2d33cb1756ddf359dc3b420b1f327a36f47a42cb6cb977c71728d726e04
                  Version: 40.20240607.0 (2024-06-09T10:43:03Z)
          LayeredPackages: mold
                Initramfs: '"-I /etc/crypttab /usr/lib/modprobe.d/nvidia.conf"'

  ostree-image-signed:docker://registry.gitlab.com/wunker-bunker/wunker-os/jp-desktop-nvidia
                   Digest: sha256:30c60a9fe9232c0cd255d9e0979ee7b0b29a4a896ba28687d6ae8616b817d103
                  Version: 40.20240531.0 (2024-06-01T10:43:23Z)
          LayeredPackages: mold
                Initramfs: '"-I /etc/crypttab /usr/lib/modprobe.d/nvidia.conf"'
```
(ignore the busy state, I kicked off a manual upgrade before copy/pasting here)@Nitrousoxide: > try rebasing to a signed image using `rpm-ostree rebase ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:stable` this will likely fix the issue

Rebasing seems to have worked for me.
```
Brian@fedora ~ [3]> systemctl status ublue-update.service
○ ublue-update.service - Universal Blue Update Oneshot Service
     Loaded: loaded (/usr/lib/systemd/system/ublue-update.service; static)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
     Active: inactive (dead) since Mon 2024-06-10 14:00:00 EDT; 4s ago
TriggeredBy: ● ublue-update.timer
    Process: 9445 ExecStart=/usr/bin/ublue-update (code=exited, status=0/SUCCESS)
   Main PID: 9445 (code=exited, status=0/SUCCESS)
        CPU: 9.871s

Jun 10 13:59:14 fedora flatpak[9585]: system: Updated runtime/org.freedesktop.Platform.ffmpeg_full.i386/x86_64/23.08 from flathub
Jun 10 13:59:15 fedora flatpak[9585]: libostree pull from 'flathub' for runtime/org.freedesktop.Platform/x86_64/23.08 complete
                                      security: GPG: summary+commit 
                                      security: SIGN: disabled http: TLS
                                      delta: parts: 2 loose: 3
                                      transfer: secs: 0 size: 3.8 MB
Jun 10 13:59:15 fedora flatpak[9585]: system: Pulled runtime/org.freedesktop.Platform/x86_64/23.08 from flathub
Jun 10 13:59:16 fedora flatpak[9585]: system: Updated runtime/org.freedesktop.Platform/x86_64/23.08 from flathub
Jun 10 13:59:17 fedora ublue-update[9445]: [2024-06-10 13:59:17,608] ublue_update.cli:INFO | Running update for user: 'Brian'
Jun 10 13:59:17 fedora sudo[9841]:     root : PWD=/ ; USER=Brian ; ENV=DISPLAY=:0 XDG_RUNTIME_DIR=/run/user/1000 DBUS_SESSION_BUS_ADDRESS=unix:>
Jun 10 14:00:00 fedora ublue-update[9445]: [2024-06-10 14:00:00,037] ublue_update.cli:INFO | System update complete
Jun 10 14:00:00 fedora systemd[1]: ublue-update.service: Deactivated successfully.
Jun 10 14:00:00 fedora systemd[1]: Finished ublue-update.service - Universal Blue Update Oneshot Service.
Jun 10 14:00:00 fedora systemd[1]: ublue-update.service: Consumed 9.871s CPU time, 2.0G memory peak, 0B memory swap peak.
Brian@fedora ~ [3]> 
```

```
Brian@fedora ~ [3]> rpm-ostree status
State: idle
Deployments:
● ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:731eea9f7dcb5d28beec5e764f01b1dc3c8ded8d437ab90f34e967a2ab5206d6
                  Version: 40.20240609.0 (2024-06-09T18:07:43Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:5aeb9564d04bab9992aad1464fabfa098cb84d70b7a6da0cfd368adf809cfc3f
                  Version: 40.20240607.0 (2024-06-07T17:01:41Z)
          LayeredPackages: btrfs-assistant snapper
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 

  ostree-unverified-registry:ghcr.io/ublue-os/bazzite-gnome:stable
                   Digest: sha256:8668faa3881d87c73f1394f104c42c7613036b3d6bd502fac36c8f44bb914900
                  Version: 39.20240419.0 (2024-04-19T17:03:42Z)
          LayeredPackages: btrfs-assistant snapper
            LocalPackages: sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes

  ostree-image-signed:docker://ghcr.io/ublue-os/bazzite-gnome:latest
                   Digest: sha256:bc069b2d8f9d6e0008654ccb88127725a5b20559ddca77e176d1c3b6d9d02e81
                Timestamp: 2024-01-27T01:59:41Z
            LocalPackages: lact-0.5.0-0.x86_64 sunshine-0.21.0-1.x86_64
                Initramfs: '"-I /etc/crypttab /etc/modprobe.d/amdgpu.conf"' 
                   Pinned: yes
Brian@fedora ~> 

```
@SNThrailkill: Seeing the same issue. Am on a signed image.

```
systemctl status ublue-update.service
× ublue-update.service - Universal Blue Update Oneshot Service
     Loaded: loaded (/usr/lib/systemd/system/ublue-update.service; static)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
             /usr/lib/systemd/system/ublue-update.service.d
             └─override.conf
     Active: failed (Result: exit-code) since Fri 2024-08-09 21:43:19 CDT; 7s ago
TriggeredBy: ● ublue-update.timer
    Process: 9842 ExecStart=/usr/bin/ublue-update (code=exited, status=1/FAILURE)
   Main PID: 9842 (code=exited, status=1/FAILURE)
        CPU: 242ms

Aug 09 21:43:18 Fedora systemd[1]: Starting ublue-update.service - Universal Blue Update Oneshot Service...
Aug 09 21:43:19 Fedora ublue-update[9842]: [2024-08-09 21:43:19,477] ublue_update.update_checks.system:INFO | No system update available.
Aug 09 21:43:19 Fedora ublue-update[9842]: [2024-08-09 21:43:19,479] ublue_update.update_inhibitors.hardware:INFO | System passed hardware checks
Aug 09 21:43:19 Fedora ublue-update[9842]: [2024-08-09 21:43:19,479] ublue_update.update_inhibitors.custom:INFO | System passed custom checks
Aug 09 21:43:19 Fedora ublue-update[9842]: [2024-08-09 21:43:19,479] ublue_update.cli:INFO | System passed all update checks
Aug 09 21:43:19 Fedora systemd[1]: ublue-update.service: Main process exited, code=exited, status=1/FAILURE
Aug 09 21:43:19 Fedora systemd[1]: ublue-update.service: Failed with result 'exit-code'.
Aug 09 21:43:19 Fedora systemd[1]: Failed to start ublue-update.service - Universal Blue Update Oneshot Service.
```@trevnels: It seems like `topgrade` recently added a (Y/N) prompt to acknowledge breaking changes, which `ublue-update` might not be handling properly. Manually running `topgrade --config /usr/share/ublue-update/topgrade-(user|system).toml` and acknowledging the prompt looks like it's fixed things for me.@liaralabs: Running the topgrade command manually appears to only fix the issue until I reboot my computer -- have to rerun it after every restart in order to kick things back to functional.

Edit: debugged my issue and looks like my specific issue was due to running a custom built image, updating from my own repo/image and using a fork of this script pushed in bazzite. Fixed by updating image-ref in `/usr/share/ublue-os/image-info.json` to point to my actual repo during build@elgabo86: set TOPGRADE_SKIP_BRKC_NOTIFY=true makes bypass the prompt.

Solution patch:
diff --git a/.gitignore b/.gitignore
index e146e19..aab7aa9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,165 @@
-/output
-/dist
-*.egg-info
 *.**.pyc
 *.pyc
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+#   This is especially recommended for binary packages to ensure reproducibility, and is more
+#   commonly ignored for libraries.
+#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+#   in version control.
+#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+#  and can be added to the global gitignore or merged into this file.  For a more nuclear
+#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
diff --git a/src/ublue_update/cli.py b/src/ublue_update/cli.py
index c754fec..e692146 100644
--- a/src/ublue_update/cli.py
+++ b/src/ublue_update/cli.py
@@ -11,7 +11,7 @@
 from ublue_update.update_inhibitors.hardware import check_hardware_inhibitors
 from ublue_update.update_inhibitors.custom import check_custom_inhibitors
 from ublue_update.config import cfg
-from ublue_update.session import get_xdg_runtime_dir, get_active_sessions
+from ublue_update.session import get_active_sessions
 from ublue_update.filelock import acquire_lock, release_lock
 
 
@@ -37,17 +37,12 @@ def notify(title: str, body: str, actions: list = [], urgency: str = "normal"):
         except KeyError as e:
             log.error("failed to get active logind session info", e)
         for user in users:
-            try:
-                xdg_runtime_dir = get_xdg_runtime_dir(user["User"])
-            except KeyError as e:
-                log.error(f"failed to get xdg_runtime_dir for user: {user['Name']}", e)
-                return
             user_args = [
-                "/usr/bin/sudo",
-                "-u",
-                f"{user['Name']}",
-                "DISPLAY=:0",
-                f"DBUS_SESSION_BUS_ADDRESS=unix:path={xdg_runtime_dir}/bus",
+                "/usr/bin/systemd-run",
+                "--user",
+                "--machine",
+                f"{user['user']}@",
+                "--wait",
             ]
             user_args += args
             out = subprocess.run(user_args, capture_output=True)
@@ -119,6 +114,8 @@ def run_updates(system, system_update_available):
             users = []
 
         """System"""
+        # remove backwards compat warnings in topgrade (requires user confirmation without this env var)
+        os.environ["TOPGRADE_SKIP_BRKC_NOTIFY"] = "true"
         out = subprocess.run(
             [
                 "/usr/bin/topgrade",
@@ -136,21 +133,15 @@ def run_updates(system, system_update_available):
 
         """Users"""
         for user in users:
-            try:
-                xdg_runtime_dir = get_xdg_runtime_dir(user["User"])
-            except KeyError as e:
-                log.error(f"failed to get xdg_runtime_dir for user: {user['Name']}", e)
-                break
-            log.info(f"""Running update for user: '{user['Name']}'""")
-
+            log.info(f"""Running update for user: '{user['user']}'""")
             out = subprocess.run(
                 [
-                    "/usr/bin/sudo",
-                    "-u",
-                    f"{user['Name']}",
-                    "DISPLAY=:0",
-                    f"XDG_RUNTIME_DIR={xdg_runtime_dir}",
-                    f"DBUS_SESSION_BUS_ADDRESS=unix:path={xdg_runtime_dir}/bus",
+                    "/usr/bin/systemd-run",
+                    "--setenv=TOPGRADE_SKIP_BRKC_NOTIFY=true",
+                    "--user",
+                    "--machine",
+                    f"{user['user']}@",
+                    "--wait",
                     "/usr/bin/topgrade",
                     "--config",
                     "/usr/share/ublue-update/topgrade-user.toml",
@@ -186,7 +177,6 @@ def run_updates(system, system_update_available):
 
 
 def main():
-
     # setup argparse
     parser = argparse.ArgumentParser()
     parser.add_argument(
diff --git a/src/ublue_update/session.py b/src/ublue_update/session.py
index f02001a..2371452 100644
--- a/src/ublue_update/session.py
+++ b/src/ublue_update/session.py
@@ -2,41 +2,14 @@
 import json
 
 
-def get_xdg_runtime_dir(uid):
-    out = subprocess.run(
-        ["/usr/bin/loginctl", "show-user", f"{uid}"],
-        capture_output=True,
-    )
-    loginctl_output = {
-        line.split("=")[0]: line.split("=")[-1]
-        for line in out.stdout.decode("utf-8").splitlines()
-    }
-    return loginctl_output["RuntimePath"]
-
-
 def get_active_sessions():
     out = subprocess.run(
         ["/usr/bin/loginctl", "list-sessions", "--output=json"],
         capture_output=True,
     )
     sessions = json.loads(out.stdout.decode("utf-8"))
-    session_properties = []
     active_sessions = []
     for session in sessions:
-        args = [
-            "/usr/bin/loginctl",
-            "show-session",
-            f"{session['session']}",
-        ]
-        out = subprocess.run(args, capture_output=True)
-        if out.returncode == 0:
-            loginctl_output = {
-                line.split("=")[0]: line.split("=")[-1]
-                for line in out.stdout.decode("utf-8").splitlines()
-            }
-            session_properties.append(loginctl_output)
-    for session_info in session_properties:
-        graphical = session_info["Type"] == "x11" or session_info["Type"] == "wayland"
-        if graphical and session_info["Active"] == "yes":
-            active_sessions.append(session_info)
+        if session.get("state") == "active":
+            active_sessions.append(session)
     return active_sessions


Test patch:
diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py
index 1b20d8a..913644d 100644
--- a/tests/unit/test_cli.py
+++ b/tests/unit/test_cli.py
@@ -1,7 +1,7 @@
 import pytest
 import sys
 import os
-from unittest.mock import patch, MagicMock, mock_open
+from unittest.mock import patch, MagicMock
 
 # Add the src directory to the sys.path
 sys.path.insert(
@@ -22,7 +22,7 @@
 @patch("ublue_update.cli.subprocess.run")
 def test_notify_no_dbus_notify(mock_run, mock_log, mock_os, mock_cfg):
     mock_cfg.dbus_notify = False
-    assert notify("test_title", "test_body") == None
+    assert notify("test_title", "test_body") is None
 
 
 @patch("ublue_update.cli.cfg")
@@ -42,7 +42,7 @@ def test_notify_uid_user(mock_run, mock_log, mock_os, mock_cfg):
             body,
             "--app-name=Universal Blue Updater",
             "--icon=software-update-available-symbolic",
-            f"--urgency=normal",
+            "--urgency=normal",
         ],
         capture_output=True,
     )
@@ -51,7 +51,7 @@ def test_notify_uid_user(mock_run, mock_log, mock_os, mock_cfg):
 @patch("ublue_update.cli.cfg")
 def test_ask_for_updates_no_dbus_notify(mock_cfg):
     mock_cfg.dbus_notify = False
-    assert ask_for_updates(True) == None
+    assert ask_for_updates(True) is None
 
 
 @patch("ublue_update.cli.cfg")
@@ -59,7 +59,7 @@ def test_ask_for_updates_no_dbus_notify(mock_cfg):
 def test_ask_for_updates_notify_none(mock_notify, mock_cfg):
     mock_cfg.dbus_notify = True
     mock_notify.return_value = None
-    assert ask_for_updates(True) == None
+    assert ask_for_updates(True) is None
     mock_notify.assert_called_once_with(
         "System Updater",
         "Update available, but system checks failed. Update now?",
@@ -210,6 +210,7 @@ def test_run_updates_system(
         ["universal-blue-update-reboot=Reboot Now"],
     )
 
+
 @patch("ublue_update.cli.os")
 @patch("ublue_update.cli.get_active_sessions")
 @patch("ublue_update.cli.acquire_lock")
diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py
index 156def5..551e42d 100644
--- a/tests/unit/test_session.py
+++ b/tests/unit/test_session.py
@@ -7,25 +7,7 @@
     0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../src"))
 )
 
-from ublue_update.session import get_active_sessions, get_xdg_runtime_dir
-
-loginctl_output = b"""
-UID=1001
-GID=1001
-Name=test
-Timestamp=Thu 2024-08-15 18:18:08 UTC
-TimestampMonotonic=293807858
-RuntimePath=/run/user/1001
-Service=user@1001.service
-Slice=user-1001.slice
-Display=c3
-State=active
-Sessions=c4 c3 c1 3
-IdleHint=no
-IdleSinceHint=0
-IdleSinceHintMonotonic=0
-Linger=yes
-"""
+from ublue_update.session import get_active_sessions
 
 loginctl_json_output = b"""
 [
@@ -37,6 +19,7 @@
                 "leader" : 6205,
                 "class" : "manager",
                 "tty" : null,
+                "state": "active",
                 "idle" : false,
                 "since" : null
         },
@@ -48,105 +31,33 @@
                 "leader" : 6230,
                 "class" : "manager",
                 "tty" : null,
+                "state": "inactive",
                 "idle" : false,
                 "since" : null
         }
 ]
 """
 
-session_info = [
-    b"""
-Id=3
-User=1001
-Name=test
-Timestamp=Thu 2024-08-15 18:18:08 UTC
-TimestampMonotonic=293993628
-VTNr=0
-Remote=no
-Service=systemd-user
-Leader=6205
-Audit=3
-Type=wayland
-Class=manager
-Active=yes
-State=active
-IdleHint=no
-IdleSinceHint=0
-IdleSinceHintMonotonic=0
-LockedHint=no
-""",
-    b"""
-Id=c1
-User=1001
-Name=test
-Timestamp=Thu 2024-08-15 18:18:09 UTC
-TimestampMonotonic=295100128
-VTNr=0
-Remote=no
-Service=systemd-user
-Leader=6230
-Audit=3
-Type=unspecified
-Class=manager
-Active=yes
-State=active
-IdleHint=no
-IdleSinceHint=0
-IdleSinceHintMonotonic=0
-LockedHint=no
-""",
-]
-
-
-@patch("ublue_update.session.subprocess.run")
-def test_get_xdg_runtime_dir(mock_run):
-    mock_run.return_value = MagicMock(stdout=loginctl_output)
-    assert get_xdg_runtime_dir(1001) == "/run/user/1001"
-    mock_run.assert_called_once_with(
-        ["/usr/bin/loginctl", "show-user", "1001"], capture_output=True
-    )
-
 
 @patch("ublue_update.session.subprocess.run")
 def test_get_active_sessions(mock_run):
-    mock_session1 = MagicMock(stdout=session_info[0])
-    mock_session2 = MagicMock(stdout=session_info[1])
-    mock_session1.returncode = 0
-    mock_session2.returncode = 0
     mock_run.side_effect = [
         MagicMock(stdout=loginctl_json_output),
-        mock_session1,
-        mock_session2,
     ]
     assert get_active_sessions() == [
         {
-            "": "",
-            "Id": "3",
-            "User": "1001",
-            "Name": "test",
-            "Timestamp": "Thu 2024-08-15 18:18:08 UTC",
-            "TimestampMonotonic": "293993628",
-            "VTNr": "0",
-            "Remote": "no",
-            "Service": "systemd-user",
-            "Leader": "6205",
-            "Audit": "3",
-            "Type": "wayland",
-            "Class": "manager",
-            "Active": "yes",
-            "State": "active",
-            "IdleHint": "no",
-            "IdleSinceHint": "0",
-            "IdleSinceHintMonotonic": "0",
-            "LockedHint": "no",
+            "session": "3",
+            "uid": 1001,
+            "user": "test",
+            "seat": None,
+            "leader": 6205,
+            "class": "manager",
+            "tty": None,
+            "state": "active",
+            "idle": False,
+            "since": None,
         }
     ]
     mock_run.assert_any_call(
         ["/usr/bin/loginctl", "list-sessions", "--output=json"], capture_output=True
     )
-    mock_run.assert_any_call(
-        ["/usr/bin/loginctl", "show-session", "3"], capture_output=True
-    )
-    mock_run.assert_any_call(
-        ["/usr/bin/loginctl", "show-session", "c1"], capture_output=True
-    )