From 03897904c3270c07f2a5e8d3cf0457895dbe0e4f Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 2 Jul 2026 19:16:52 -0400 Subject: feat(vpn): proton CLI replaces the GTK app, tailscale operator at install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- archsetup | 22 ++++++++++++++++++++-- scripts/testing/tests/test_packages.py | 22 +++++++++++++++++++++- 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") @@ -79,6 +82,23 @@ def test_retired_package_not_installed(host, pkg): assert not host.package(pkg).is_installed +@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 -- cgit v1.2.3