feat(packaging): add desktop launcher entries for both GUI dashboards
The tray applet shipped with a .desktop file but the GUI dashboards had none, so desktop users had no menu entry for them. Unlike the tray entry, these carry no autostart key: a dashboard window should open when the operator asks for it, not at login. Tests assert the Exec names match the pyproject console scripts and that neither entry can regain an autostart key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JX86xeoBJVBb16qHkDf53K
This commit is contained in:
parent
3dd82ab18b
commit
1d1dee7f6e
4 changed files with 58 additions and 0 deletions
|
|
@ -215,6 +215,13 @@ Notes:
|
||||||
`gui/model.py` stays import-clean so headless builders can run the test
|
`gui/model.py` stays import-clean so headless builders can run the test
|
||||||
suite without a display server or `PySide6` installed.
|
suite without a display server or `PySide6` installed.
|
||||||
|
|
||||||
|
`packaging/enodia-sentinel-gui.desktop` and
|
||||||
|
`packaging/enodia-sentinel-gui-qt.desktop` are application-menu launchers.
|
||||||
|
Unlike `enodia-sentinel-tray.desktop`, they carry no autostart key — a
|
||||||
|
dashboard window should open when the operator asks for it, not at login.
|
||||||
|
Desktop packagers may install them to `/usr/share/applications/`; source
|
||||||
|
installs can copy them to `~/.local/share/applications/`.
|
||||||
|
|
||||||
## Terminal TUI and Completion
|
## Terminal TUI and Completion
|
||||||
|
|
||||||
The terminal dashboard is stdlib-only and available through
|
The terminal dashboard is stdlib-only and available through
|
||||||
|
|
|
||||||
11
packaging/enodia-sentinel-gui-qt.desktop
Normal file
11
packaging/enodia-sentinel-gui-qt.desktop
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Enodia Sentinel Dashboard (Qt)
|
||||||
|
GenericName=Security Dashboard
|
||||||
|
Comment=Read-only Qt desktop dashboard for the Enodia Sentinel security agent
|
||||||
|
Exec=enodia-sentinel-gui-qt
|
||||||
|
Icon=security-high
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;Security;Monitor;
|
||||||
|
Keywords=security;ids;ips;edr;intrusion;monitor;
|
||||||
|
StartupNotify=true
|
||||||
11
packaging/enodia-sentinel-gui.desktop
Normal file
11
packaging/enodia-sentinel-gui.desktop
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Enodia Sentinel Dashboard
|
||||||
|
GenericName=Security Dashboard
|
||||||
|
Comment=Read-only desktop dashboard for the Enodia Sentinel security agent
|
||||||
|
Exec=enodia-sentinel-gui
|
||||||
|
Icon=security-high
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;Security;Monitor;
|
||||||
|
Keywords=security;ids;ips;edr;intrusion;monitor;
|
||||||
|
StartupNotify=true
|
||||||
|
|
@ -166,5 +166,34 @@ class TestTrayDesktopEntry(unittest.TestCase):
|
||||||
self.assertRegex(text, r"(?m)^Name=.*Sentinel")
|
self.assertRegex(text, r"(?m)^Name=.*Sentinel")
|
||||||
|
|
||||||
|
|
||||||
|
class TestGuiDesktopEntries(unittest.TestCase):
|
||||||
|
ENTRIES = {
|
||||||
|
"packaging/enodia-sentinel-gui.desktop": "enodia-sentinel-gui",
|
||||||
|
"packaging/enodia-sentinel-gui-qt.desktop": "enodia-sentinel-gui-qt",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_desktop_files_launch_gui_entry_points(self):
|
||||||
|
for path, exec_name in self.ENTRIES.items():
|
||||||
|
with self.subTest(path=path):
|
||||||
|
text = _read(path)
|
||||||
|
self.assertIn("[Desktop Entry]", text)
|
||||||
|
self.assertIn("Type=Application", text)
|
||||||
|
self.assertRegex(text, rf"(?m)^Exec={exec_name}$")
|
||||||
|
self.assertRegex(text, r"(?m)^Name=.*Sentinel")
|
||||||
|
|
||||||
|
def test_gui_entry_points_match_pyproject_scripts(self):
|
||||||
|
scripts = tomllib.loads(_read("pyproject.toml"))["project"]["scripts"]
|
||||||
|
for exec_name in self.ENTRIES.values():
|
||||||
|
with self.subTest(script=exec_name):
|
||||||
|
self.assertIn(exec_name, scripts)
|
||||||
|
|
||||||
|
def test_gui_entries_are_launchers_not_autostart(self):
|
||||||
|
# The tray applet is opt-in autostart; the dashboards are menu
|
||||||
|
# launchers and must never start themselves at login.
|
||||||
|
for path in self.ENTRIES:
|
||||||
|
with self.subTest(path=path):
|
||||||
|
self.assertNotIn("Autostart", _read(path))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue