diff options
| author | sommerfeld <sommerfeld@sommerfeld.dev> | 2026-09-22 13:57:08 +0100 |
|---|---|---|
| committer | sommerfeld <sommerfeld@sommerfeld.dev> | 2026-09-22 13:57:08 +0100 |
| commit | d4eddbc4a7b46c9e53fdd47b9feff0c2e75ec8d7 (patch) | |
| tree | d535d38eb24ba1a8d04cae12e5d6bbdc96c3b43a | |
| parent | 1e19a0c7cbb87302bbe7fa6a60ad53738719a095 (diff) | |
| download | dotfiles-d4eddbc4a7b46c9e53fdd47b9feff0c2e75ec8d7.tar.gz dotfiles-d4eddbc4a7b46c9e53fdd47b9feff0c2e75ec8d7.tar.bz2 dotfiles-d4eddbc4a7b46c9e53fdd47b9feff0c2e75ec8d7.zip | |
Permit Mattermost Snap tray communication
| -rw-r--r-- | canonical/systemd/dotfiles-mattermost-keyring.service | 2 | ||||
| -rw-r--r-- | docs/canonical-laptop.md | 11 | ||||
| -rw-r--r-- | scripts/mattermost_keyring.py | 48 | ||||
| -rw-r--r-- | tests/test_mattermost_keyring.py | 17 |
4 files changed, 71 insertions, 7 deletions
diff --git a/canonical/systemd/dotfiles-mattermost-keyring.service b/canonical/systemd/dotfiles-mattermost-keyring.service index fd75f86..d392a78 100644 --- a/canonical/systemd/dotfiles-mattermost-keyring.service +++ b/canonical/systemd/dotfiles-mattermost-keyring.service @@ -1,5 +1,5 @@ [Unit] -Description=Allow Mattermost Snap to use GNOME Keyring +Description=Allow Mattermost Snap to use GNOME Keyring and the tray After=snapd.apparmor.service snapd.service apparmor.service Before=display-manager.service ConditionPathExists=/var/lib/snapd/apparmor/profiles/snap.mattermost-desktop.mattermost-desktop diff --git a/docs/canonical-laptop.md b/docs/canonical-laptop.md index a03db70..7485b6c 100644 --- a/docs/canonical-laptop.md +++ b/docs/canonical-laptop.md @@ -217,15 +217,22 @@ profiles. Global user-namespace restrictions stay enabled. Test `aibox -p` and a rootless container. If AppArmor denies another executable, inspect the exact denial before adding a rule. Do not allow every program under `/nix/store`. -## Mattermost Keyring +## Mattermost Keyring And Tray The Mattermost Snap lacks the `password-manager-service` plug. `canonical-system` installs `dotfiles-mattermost-keyring.service` and its path watcher. They add -Secret Service D-Bus access to the Mattermost profile at boot and when snapd +Secret Service and Chromium tray D-Bus access to the Mattermost profile at boot and when snapd replaces it. The Snap keeps its normal updates and AppArmor enforcement. This permission gives Mattermost access to the user's unlocked keyring; it does not restrict access to Mattermost's own entries. +The tray rules allow GNOME to read the icon, receive updates, and operate its +menu through `/org/chromium/StatusNotifierItem/*` and `/org/chromium/DbusMenu`. +They apply only to the Mattermost profile on the session bus, with unconfined +desktop peers. They do not grant memory-statistics or idle-monitor access. +Run `just canonical-system` to install the rules. To reload them explicitly, run +`sudo systemctl restart dotfiles-mattermost-keyring.service`. + After applying this to a running session, quit Mattermost, including its tray process, and start it again. Check the result: diff --git a/scripts/mattermost_keyring.py b/scripts/mattermost_keyring.py index a54ed6d..59bec1b 100644 --- a/scripts/mattermost_keyring.py +++ b/scripts/mattermost_keyring.py @@ -1,4 +1,4 @@ -"""Permit the Mattermost Snap to use the desktop Secret Service.""" +"""Permit the Mattermost Snap to use the desktop keyring and tray.""" import os import re @@ -22,15 +22,55 @@ dbus (receive, send) interface=org.freedesktop.Secret.{Collection,Item,Prompt,Service,Session} peer=(label=unconfined), """ +TRAY_MARKER = "# dotfiles: Mattermost Chromium tray access" +TRAY_RULES = """ +dbus (receive) + bus=session + path=/org/chromium/StatusNotifierItem/[0-9]* + interface=org.freedesktop.DBus.Properties + member=Get{,All} + peer=(label=unconfined), +dbus (send) + bus=session + path=/org/chromium/StatusNotifierItem/[0-9]* + interface=org.freedesktop.DBus.Properties + member=PropertiesChanged + peer=(label=unconfined), +dbus (send) + bus=session + path=/org/chromium/StatusNotifierItem/[0-9]* + interface=org.kde.StatusNotifierItem + member=New* + peer=(label=unconfined), +dbus (receive) + bus=session + path=/org/chromium/StatusNotifierItem/[0-9]* + interface=org.kde.StatusNotifierItem + member={Activate,ContextMenu,Scroll,SecondaryActivate,ProvideXdgActivationToken,XAyatanaSecondaryActivate} + peer=(label=unconfined), +dbus (send) + bus=session + path=/org/chromium/DbusMenu{,/[0-9]*} + interface=com.canonical.dbusmenu + member={LayoutUpdated,ItemsPropertiesUpdated} + peer=(label=unconfined), +dbus (receive) + bus=session + path=/org/chromium/DbusMenu{,/[0-9]*} + interface={org.freedesktop.DBus.Properties,com.canonical.dbusmenu} + member={Get*,AboutTo*,Event*} + peer=(label=unconfined), +""" def patch_profile(text: str) -> str: profiles = re.findall(r'^profile "([^"]+)"', text, re.MULTILINE) if profiles != [PROFILE.name] or not text.rstrip().endswith("}"): raise ValueError("Unexpected Mattermost AppArmor profile format.") - if MARKER in text: - return text - return text.rstrip()[:-1] + MARKER + "\n" + RULES + "}\n" + for marker, rules in [(MARKER, RULES), (TRAY_MARKER, TRAY_RULES)]: + if marker not in text: + text = text.rstrip()[:-1] + marker + "\n" + rules + "}\n" + return text def install_profile(text: str) -> None: diff --git a/tests/test_mattermost_keyring.py b/tests/test_mattermost_keyring.py index 93cc96d..78da9fa 100644 --- a/tests/test_mattermost_keyring.py +++ b/tests/test_mattermost_keyring.py @@ -8,6 +8,23 @@ from scripts import mattermost_keyring class MattermostKeyringTests(unittest.TestCase): + def test_adds_tray_rules_to_existing_keyring_patch(self): + original = ( + 'profile "snap.mattermost-desktop.mattermost-desktop" {\n' + + mattermost_keyring.MARKER + + "\n" + + mattermost_keyring.RULES + + "}\n" + ) + patched = mattermost_keyring.patch_profile(original) + self.assertIn("path=/org/chromium/StatusNotifierItem/[0-9]*", patched) + self.assertIn("interface=org.kde.StatusNotifierItem", patched) + self.assertIn("path=/org/chromium/DbusMenu{,/[0-9]*}", patched) + self.assertEqual(patched.count(mattermost_keyring.MARKER), 1) + self.assertEqual(mattermost_keyring.patch_profile(patched), patched) + self.assertNotIn("IdleMonitor", patched) + self.assertNotIn("smaps_rollup", patched) + def test_adds_rules_only_once(self): original = 'profile "snap.mattermost-desktop.mattermost-desktop" {\n}\n' patched = mattermost_keyring.patch_profile(original) |
