aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-02 19:16:52 -0400
committerCraig Jennings <c@cjennings.net>2026-07-02 19:16:52 -0400
commit03897904c3270c07f2a5e8d3cf0457895dbe0e4f (patch)
tree6b477d3d340b49e79f53268c88bb69ccd729dabc
parent83a351ed83c1e775fb9a1c67174375f34f274aa8 (diff)
downloadarchsetup-03897904c3270c07f2a5e8d3cf0457895dbe0e4f.tar.gz
archsetup-03897904c3270c07f2a5e8d3cf0457895dbe0e4f.zip
feat(vpn): proton CLI replaces the GTK app, tailscale operator at install
The net panel's Tunnels view drives proton-vpn-cli, and the CLI and GTK app can't run concurrently, so the installer swaps them. tailscaled now enables with --now and the install grants operator to the primary user (brief retry — the daemon takes a moment to accept its socket), so tailscale up/down works without sudo from the panel. VM asserts the vpn stack, the retirement, and the OperatorUser pref (format verified against a live daemon).
-rwxr-xr-xarchsetup22
-rw-r--r--scripts/testing/tests/test_packages.py22
2 files changed, 41 insertions, 3 deletions
diff --git a/archsetup b/archsetup
index d6006ea..1fd5317 100755
--- a/archsetup
+++ b/archsetup
@@ -2612,10 +2612,28 @@ install_vpn_tools() {
action="VPN Tools" && display "subtitle" "$action"
pacman_install wireguard-tools # VPN - add configs to /etc/wireguard/
pacman_install systemd-resolvconf # resolvconf for wg-quick DNS integration
- pacman_install proton-vpn-gtk-app # Proton VPN GUI client with system tray
+ # proton-vpn-gtk-app retired 2026-07-02: the net panel's Tunnels view
+ # drives the official CLI, and the two can't run concurrently
+ pacman_install proton-vpn-cli # Proton VPN official CLI
pacman_install tailscale # mesh VPN - run 'tailscale up' to authenticate
- run_task "enabling tailscale service" systemctl enable tailscaled
+ # --now: the operator grant below needs the daemon answering (an unstarted
+ # tailscaled refuses `tailscale set`). Starting pre-auth is harmless.
+ run_task "enabling tailscale service" systemctl enable --now tailscaled
+
+ # Operator mode lets $username run tailscale up/down without sudo — the
+ # net panel's Tunnels view relies on it. Brief retry: the daemon can take
+ # a moment to accept its socket right after the start.
+ action="granting tailscale operator to $username" && display "task" "$action"
+ operator_ok=false
+ for _attempt in 1 2 3 4 5; do
+ if tailscale set --operator="$username" >> "$logfile" 2>&1; then
+ operator_ok=true
+ break
+ fi
+ sleep 2
+ done
+ $operator_ok || error_warn "$action" "1"
}
diff --git a/scripts/testing/tests/test_packages.py b/scripts/testing/tests/test_packages.py
index 5e90cb9..e0387d6 100644
--- a/scripts/testing/tests/test_packages.py
+++ b/scripts/testing/tests/test_packages.py
@@ -61,6 +61,7 @@ def test_dev_tool_present(host, tool):
BLUETOOTH_STACK = ["bluez", "bluez-utils"]
+VPN_STACK = ["wireguard-tools", "proton-vpn-cli", "tailscale"]
@pytest.mark.attribution("archsetup")
@@ -69,7 +70,9 @@ def test_bluetooth_stack_installed(host, pkg):
assert host.package(pkg).is_installed
-RETIRED_PACKAGES = ["blueman", "zoom"] # bt panel replaced blueman; zoom-web replaced zoom
+# bt panel replaced blueman; zoom-web replaced zoom; the net panel's Tunnels
+# view + proton-vpn-cli replaced the GTK app (they can't run concurrently).
+RETIRED_PACKAGES = ["blueman", "zoom", "proton-vpn-gtk-app"]
@pytest.mark.attribution("archsetup")
@@ -80,6 +83,23 @@ def test_retired_package_not_installed(host, pkg):
@pytest.mark.attribution("archsetup")
+@pytest.mark.parametrize("pkg", VPN_STACK)
+def test_vpn_stack_installed(host, pkg):
+ assert host.package(pkg).is_installed
+
+
+@pytest.mark.attribution("archsetup")
+def test_tailscale_operator_granted(host, target_user):
+ # The installer grants operator so the net panel can toggle tailscale
+ # without sudo. Prefs only answer when the daemon is up.
+ if not host.service("tailscaled").is_running:
+ pytest.skip("tailscaled not running")
+ out = host.run("tailscale debug prefs")
+ assert out.rc == 0, "tailscale debug prefs failed"
+ assert '"OperatorUser": "%s"' % target_user in out.stdout
+
+
+@pytest.mark.attribution("archsetup")
def test_eask_installed_user_local(host, home):
# Installed via npm -g --prefix ~/.local as the user; chime and
# linear-emacs shell out to it.