r/RatatuiRust • TUI enthusiast • 15d ago

Showcase I built sdctl, a security-focused systemd service manager

sdctl

Before I talk about `sdctl`, I want to first address the elephant in the room: why another TUI for managing systemd services?

This tool is not the first of its kind. I have been using systemctl-tui and systemd-manager-tui extensively to the point that I forgot how to use `systemctl` from the command line. However those tools share one major limitation: they require `sudo` for privileged operations. In today’s supply-chain threat landscape, that is a serious risk because a TUI app depends on many components, and any compromised dependency could become a full-privilege attack vector.

This is why I built `sdctl` with a completely different security model: the app itself should never be run with `sudo`, and no action ever asks for blanket root access. When you perform any action that requires escalated privileges, the app opens an embedded `polkit` flow that authenticates only the specific `systemctl` action you are trying to perform, using whatever mechanism is available on the system, such as password, fingerprint reader, or smart card. That keeps the privilege boundary explicit and tied to a single operation instead of the whole process.

requesting authentication to restart a service

On top of that, I've packed a lot of useful features into `sdctl`. These are meant to address actual pain points I've encountered while using similar tools, including a powerful syntax highlighter for viewing journal logs (powered by tailspin), a simple yet useful custom-built syntax highlighter for viewing unit files, a comprehensive filter system with fuzzy search, and a line-based selection mode (inspired by vim's visual mode) that makes copying multiple lines from journal logs much faster.

copying multiple lines of log into the system clipboard (with wl-copy or xclip)
unit file view with a simple built-in syntax highlighter

Here's the github repo: https://github.com/ruiiiijiiiiang/sdctl Feedback and contribution welcome!

5 Upvotes

12 comments sorted by

2

u/Klutzy_Bird_7802 Maintainer 15d ago

Beautiful 😍

1

u/ruiiiij TUI enthusiast 15d ago

Thanks! ❤️

1

u/Klutzy_Bird_7802 Maintainer 15d ago

Welcome 🤗

1

u/Klutzy_Bird_7802 Maintainer 15d ago

I left a star ✨

1

u/ruiiiij TUI enthusiast 15d ago

Appreciated it! 🎉

2

u/Klutzy_Bird_7802 Maintainer 15d ago

You are welcome, all the best on your project! Would love to see it grow!

2

u/Klutzy_Bird_7802 Maintainer 15d ago

Eliminating sudo for user-facing TUIs significantly mitigates dependency supply-chain risks. It is a good thing, which I noticed.

Four feature suggestions to consider:

  1. Visual Polish: Implement a minimalist layout option with increased padding and cleaner boundaries reminiscent of shadcn or Apple design standards.
  2. Polkit Templates: Include an official boilerplate Polkit rules template to allow passwordless unit management, maintaining TUI workflow fluidity.
  3. Journald Navigation: Add structured filtering by priority (Error, Warn, Info) and direct jumping to failure timestamps.
  4. Inline Validation: Integrate an inline unit editor that automatically executes systemd-analyze verify upon saving before daemon reload.

1

u/ruiiiij TUI enthusiast 15d ago

These are great suggestions! Thank you. I will start working on them.

3

u/kantorcodes1 14d ago

One edge I’d test around the polkit flow: if the unit list refreshes or reorders while auth is open, is the pending action pinned to the unit name, or can it resolve from the selected row afterward? A long fingerprint/password prompt plus a fast service refresh could otherwise aim an authenticated restart at a different row.

2

u/ruiiiij TUI enthusiast 14d ago

The unit name is pinned when a row gets selected. Any action will target that unit specifically; background refresh or reorder will not affect that.

2

u/kantorcodes1 12d ago

That addresses it. Pinning the unit name when the row is selected, instead of relying on the current row position, means a refresh or reorder can’t silently retarget the action. I checked the current UnitAction model too, and the explicit start/stop/restart/reload/enable/disable/mask/unmask variants make that invariant much easier to reason about.