Fix unbounded review issues and localization#8498
Fix unbounded review issues and localization#8498atavism wants to merge 6 commits intoadam/unbounded-widget-proxyfrom
Conversation
* linux: packaging and runtime no-sudo foundation * code review updates * sync radiance dependency with main * code review updates * revert ffi readiness gate
* linux: add CI installed-binary and UI connect smoke * fix tray quit handler * fix lanternd install path in nfpm package * guard vpn notifier delayed callback after dispose * treat ffi ok result as vpn success * ci(linux): assert lanternd receives start/stop IPC in UI smoke * ci(linux): add simple optional public IP check to VPN smoke * ci(linux): use linux-release-ci to avoid clean rebuilds * docs: add linux smoke test run command * test: temporarily log IP values in linux smoke * Revert "test: temporarily log IP values in linux smoke" This reverts commit a4797a5. * Code review updates * test: use VPNStatus in linux smoke state checks * test: add non-sensitive IP check logs
There was a problem hiding this comment.
Pull request overview
This PR improves Linux packaging/CI verification, tightens Linux runtime behavior (system tray + FFI/daemon IPC), and finishes several Unbounded + VPN UI polish/localization updates.
Changes:
- Add nfpm-based Linux packaging (deb/rpm/arch), postinst/prerm/postrm scripts, and CI package verification + smoke/integration tests.
- Update Flutter app for improved Linux support (FFI library discovery, daemon IPC behavior, optional system tray) and add Linux VPN connect/disconnect integration coverage.
- Localize Unbounded UI strings and harden Unbounded globe webview messaging/security.
Reviewed changes
Copilot reviewed 37 out of 38 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/ci/verify_linux_package.sh | Adds a CI helper to validate .deb contents and expected postinst behaviors. |
| linux/packaging/nfpm.yaml | Introduces nfpm configuration for Linux packages (deb/rpm/archlinux). |
| linux/packaging/desktop/lantern.desktop | Adds desktop entry for Linux installs. |
| linux/packaging/deb/scripts/postinst | Creates lantern group and enables/starts systemd daemon on install. |
| linux/packaging/deb/scripts/prerm | Stops systemd service on remove/deconfigure. |
| linux/packaging/deb/scripts/postrm | Disables/reloads systemd service on remove/purge. |
| linux/packaging/deb/make_config.yaml | Updates legacy packaging config (formatting + service commands). |
| linux/packaging/arch/*.sh | Adds Arch install/remove hooks for systemd service lifecycle. |
| linux/CMakeLists.txt | Installs an additional liblantern.so copy for FFI loading. |
| lib/main.dart | Makes timezone configuration resilient (fallback to UTC). |
| lib/lantern/lantern_ffi_service.dart | Improves Linux .so resolution, FFI “ok” handling, and frees an FFI result pointer. |
| lib/features/vpn/vpn_switch.dart | Adds keys to support stable UI testing. |
| lib/features/vpn/vpn_status.dart | Adds keys and refactors status label usage. |
| lib/features/vpn/provider/vpn_notifier.dart | Guards delayed work with ref.mounted. |
| lib/features/unbounded/unbounded_settings.dart | Localizes Unbounded settings UI strings. |
| lib/features/unbounded/unbounded.dart | Localizes Unbounded UI strings; hardens JS injection by JSON-encoding payload; tightens webview file access settings. |
| lib/features/system_tray/system_tray_wrapper.dart | Allows build-time disabling of system tray. |
| lib/features/system_tray/provider/system_tray_notifier.dart | Handles missing tray plugin gracefully and avoids menu updates when unavailable. |
| lib/features/setting/setting.dart | Localizes Unbounded settings label. |
| lib/features/onboarding/onboarding.dart | Adds keys for integration tests and formatting fixes. |
| lib/features/home/provider/app_event_notifier.dart | Switches stats provider to a dedicated listener provider. |
| lib/features/home/home.dart | Adds key for integration tests and formatting fixes. |
| lib/core/common/app_build_info.dart | Adds DISABLE_SYSTEM_TRAY build-time flag. |
| lantern-core/vpn_tunnel/vpn_tunnel.go | Disables IPC server setup/teardown on Linux. |
| lantern-core/ffi/ffi_linux.go | Adds Linux-specific FFI implementation using systemd+IPC. |
| lantern-core/ffi/ffi_nonlinux.go | Adds non-Linux FFI implementations moved out of ffi.go. |
| lantern-core/ffi/ffi.go | Removes start/stop/connect/isVPNConnected exports in favor of platform-specific files. |
| lantern-core/core.go | Softens IPC settings-path init failures when daemon isn’t ready on Linux. |
| integration_test/vpn/linux_connect_smoke_test.dart | Adds Linux connect/disconnect smoke test with optional IP-change check. |
| integration_test/utils/widget_wait_utils.dart | Adds polling utilities for integration tests. |
| .github/workflows/build-linux.yml | Adds caching, package verification, install/start checks, and Linux UI integration run in CI. |
| Makefile | Replaces flutter_distributor with nfpm packaging and adds Linux daemon build/staging. |
| go.mod / go.sum | Updates Go module versions. |
| assets/locales/en.po | Adds Unbounded localization keys. |
| README-dev.md | Documents Linux build/install/run/testing workflow. |
Comments suppressed due to low confidence (1)
lib/lantern/lantern_ffi_service.dart:210
- FFI argument strings are allocated via toCharPtr (toNativeUtf8) but aren’t freed after the call. dataDirPtr/logDirPtr (and the locale/env pointers used in the subsequent _ffiService.setup() call) should be released with malloc.free() in a finally block after setup() returns to avoid leaking native memory.
final dataDirPtr = dataDir.path.toCharPtr;
final logDirPtr = logDir.toCharPtr;
// setup() must run on the main isolate.
// It wires up the Dart <-> Go bridge using NativeApi.initializeApiDLData.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ```bash | ||
| sudo systemctl disable --now lanternd.service | ||
| sudo apt remove lantern | ||
| sudo rm -f /usr/lib/systemd/system/lanternd.service /usr/lib/lantern/lanternd |
There was a problem hiding this comment.
The Linux uninstall/cleanup command removes /usr/lib/lantern/lanternd, but the service binary is being packaged to /usr/sbin/lanternd (and the systemd unit is under /usr/lib/systemd/system). Update the cleanup instructions to remove the correct path so developers don’t leave the daemon behind.
| sudo rm -f /usr/lib/systemd/system/lanternd.service /usr/lib/lantern/lanternd | |
| sudo rm -f /usr/lib/systemd/system/lanternd.service /usr/sbin/lanternd |
| run: | | ||
| set -euxo pipefail | ||
| TEST_START_UTC="$(date -u '+%Y-%m-%d %H:%M:%S')" | ||
| sg lantern -c "env PATH=$PATH HOME=$HOME xvfb-run -a flutter test integration_test/vpn/linux_connect_smoke_test.dart -d linux --dart-define=DISABLE_SYSTEM_TRAY=true --dart-define=ENABLE_IP_CHECK=true" |
There was a problem hiding this comment.
CI runs the Linux UI integration test with ENABLE_IP_CHECK=true, which makes the test depend on an external endpoint (api64.ipify.org). This can introduce flaky failures due to transient network/DNS/service issues unrelated to the app behavior. Consider leaving ENABLE_IP_CHECK=false in CI (or making the IP check best-effort/non-fatal) and relying on the connect/disconnect state assertions as the primary signal.
| sg lantern -c "env PATH=$PATH HOME=$HOME xvfb-run -a flutter test integration_test/vpn/linux_connect_smoke_test.dart -d linux --dart-define=DISABLE_SYSTEM_TRAY=true --dart-define=ENABLE_IP_CHECK=true" | |
| sg lantern -c "env PATH=$PATH HOME=$HOME xvfb-run -a flutter test integration_test/vpn/linux_connect_smoke_test.dart -d linux --dart-define=DISABLE_SYSTEM_TRAY=true --dart-define=ENABLE_IP_CHECK=false" |
| name: lantern | ||
| arch: "${GOARCH}" |
There was a problem hiding this comment.
The nfpm config expects GOARCH to be provided via environment substitution, but the Makefile targets that invoke nfpm don’t set GOARCH. If GOARCH is unset in CI, this will render an empty arch value and can cause packaging failures or incorrectly labeled artifacts. Consider hardcoding the arch for the current build (e.g., amd64) or exporting GOARCH in the linux-release-ci recipe before calling nfpm (and similarly when building arm64).
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | ||
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p deb -t $(LINUX_INSTALLER_DEB) | ||
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | ||
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p rpm -t $(LINUX_INSTALLER_RPM) | ||
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ |
There was a problem hiding this comment.
The nfpm packaging step forces VERSION=$(APP_VERSION), which can diverge from the VERSION passed in via CI inputs (and from EXTRA_LDFLAGS / Dart defines that use
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p deb -t $(LINUX_INSTALLER_DEB) | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p rpm -t $(LINUX_INSTALLER_RPM) | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| VERSION=$${VERSION:-$(APP_VERSION)} LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p deb -t $(LINUX_INSTALLER_DEB) | |
| VERSION=$${VERSION:-$(APP_VERSION)} LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p rpm -t $(LINUX_INSTALLER_RPM) | |
| VERSION=$${VERSION:-$(APP_VERSION)} LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | ||
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p deb -t $(LINUX_INSTALLER_DEB) | ||
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | ||
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p rpm -t $(LINUX_INSTALLER_RPM) | ||
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ |
There was a problem hiding this comment.
nfpm.yaml uses arch: "${GOARCH}", but these nfpm invocations don’t set GOARCH in the environment. Since GOARCH set in other recipes (e.g., linux-amd64) won’t carry over here, packaging can end up with an empty/incorrect arch. Set GOARCH=amd64/arm64 explicitly for each nfpm call (or remove the env substitution).
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p deb -t $(LINUX_INSTALLER_DEB) | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p rpm -t $(LINUX_INSTALLER_RPM) | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) \ | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) GOARCH=amd64 \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p deb -t $(LINUX_INSTALLER_DEB) | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) GOARCH=amd64 \ | |
| nfpm package -f $(LINUX_PKG_ROOT)/nfpm.yaml -p rpm -t $(LINUX_INSTALLER_RPM) | |
| VERSION=$(APP_VERSION) LANTERND_SRC=$(LINUX_SERVICE_DST)/$(LINUX_SERVICE_NAME) SYSTEMD_UNIT_SRC=$(LINUX_SYSTEMD_UNIT_DST) GOARCH=amd64 \ |
No description provided.