Skip to content

Commit 72b2c69

Browse files
committed
Merge main into peer-ffi and re-pin radiance to the peer integration branch
The branch was 88 commits behind main. Only go.mod/go.sum conflicted; the lantern-core FFI additions auto-merged. radiance is pinned to the smc/unbounded integration tip so this compiles against the peer API. Re-pin to a released radiance version once radiance #589 and #590 merge.
2 parents ced78e1 + 8a9af4a commit 72b2c69

205 files changed

Lines changed: 14169 additions & 2212 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
TEST_PATH="${TEST_PATH:-integration_test/vpn/macos_connect_smoke_test.dart}"
5+
ARTIFACT_DIR="${ARTIFACT_DIR:-smoke-artifacts/macos}"
6+
RUN_CONNECT_SMOKE="${RUN_CONNECT_SMOKE:-true}"
7+
ENABLE_IP_CHECK="${ENABLE_IP_CHECK:-false}"
8+
FORCE_FULL_TUNNEL="${FORCE_FULL_TUNNEL:-true}"
9+
EXTENSION_TIMEOUT_SECONDS="${EXTENSION_TIMEOUT_SECONDS:-120}"
10+
APP_INSTALL_DIR="${APP_INSTALL_DIR:-/Applications/Lantern.app}"
11+
LANTERN_LOG_DIR="${LANTERN_LOG_DIR:-/Users/Shared/Lantern/Logs}"
12+
DMG_MOUNT_DIR=""
13+
14+
if ! [[ "$EXTENSION_TIMEOUT_SECONDS" =~ ^[1-9][0-9]*$ ]]; then
15+
printf 'EXTENSION_TIMEOUT_SECONDS must be a positive integer, got %q.\n' \
16+
"$EXTENSION_TIMEOUT_SECONDS" >&2
17+
exit 2
18+
fi
19+
20+
log_step() {
21+
printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*" >&2
22+
}
23+
24+
trim_trailing_slashes() {
25+
local path="$1"
26+
while [[ "$path" != "/" && "$path" == */ ]]; do
27+
path="${path%/}"
28+
done
29+
printf '%s\n' "$path"
30+
}
31+
32+
find_first_name() {
33+
local root="$1"
34+
local name="$2"
35+
36+
if [[ -z "$root" || ! -e "$root" ]]; then
37+
return 1
38+
fi
39+
40+
find "$root" -maxdepth 4 -name "$name" -print -quit
41+
}
42+
43+
copy_app_bundle() {
44+
local source
45+
local destination
46+
source="$(trim_trailing_slashes "$1")"
47+
destination="$(trim_trailing_slashes "$2")"
48+
49+
if [[ "$source" == "$destination" ]]; then
50+
printf '%s\n' "$destination"
51+
return
52+
fi
53+
54+
log_step "Copying Lantern app from $source"
55+
rm -rf "$destination"
56+
mkdir -p "$(dirname "$destination")"
57+
ditto "$source" "$destination"
58+
xattr -dr com.apple.quarantine "$destination" 2>/dev/null || true
59+
printf '%s\n' "$destination"
60+
}
61+
62+
extract_app_zip() {
63+
local zip_path="$1"
64+
local tmp_dir
65+
tmp_dir="$(mktemp -d)"
66+
trap 'rm -rf "$tmp_dir"' RETURN
67+
68+
log_step "Extracting Lantern app from $zip_path"
69+
ditto -x -k "$zip_path" "$tmp_dir"
70+
71+
local app_path
72+
app_path="$(find_first_name "$tmp_dir" "Lantern.app" || true)"
73+
if [[ -z "$app_path" ]]; then
74+
printf 'Lantern.app not found inside %s\n' "$zip_path" >&2
75+
return 1
76+
fi
77+
78+
copy_app_bundle "$app_path" "$APP_INSTALL_DIR"
79+
}
80+
81+
detach_dmg() {
82+
if [[ -n "$DMG_MOUNT_DIR" && -d "$DMG_MOUNT_DIR" ]]; then
83+
local mount_dir="$DMG_MOUNT_DIR"
84+
hdiutil detach "$mount_dir" -quiet || true
85+
rmdir "$mount_dir" 2>/dev/null || true
86+
DMG_MOUNT_DIR=""
87+
fi
88+
}
89+
90+
copy_app_from_dmg() {
91+
local dmg_path="$1"
92+
local mount_dir
93+
mount_dir="$(mktemp -d)"
94+
DMG_MOUNT_DIR="$mount_dir"
95+
96+
log_step "Mounting Lantern DMG $dmg_path"
97+
hdiutil attach "$dmg_path" -nobrowse -readonly -mountpoint "$mount_dir" >/dev/null
98+
99+
local app_path
100+
app_path="$(find_first_name "$mount_dir" "Lantern.app" || true)"
101+
if [[ -z "$app_path" ]]; then
102+
printf 'Lantern.app not found inside %s\n' "$dmg_path" >&2
103+
detach_dmg
104+
return 1
105+
fi
106+
107+
copy_app_bundle "$app_path" "$APP_INSTALL_DIR"
108+
detach_dmg
109+
}
110+
111+
resolve_app_path() {
112+
if [[ -n "${APP_PATH:-}" && -x "$APP_PATH/Contents/MacOS/Lantern" ]]; then
113+
copy_app_bundle "$APP_PATH" "$APP_INSTALL_DIR"
114+
return
115+
fi
116+
117+
local dmg_path
118+
dmg_path="$(find_first_name "${DMG_ARTIFACT_DIR:-}" "*.dmg" || true)"
119+
if [[ -n "$dmg_path" ]]; then
120+
copy_app_from_dmg "$dmg_path"
121+
return
122+
fi
123+
124+
local app_zip
125+
app_zip="$(find_first_name "${APP_ARTIFACT_DIR:-}" "Lantern.app.zip" || true)"
126+
if [[ -n "$app_zip" ]]; then
127+
extract_app_zip "$app_zip"
128+
return
129+
fi
130+
131+
local app_artifact
132+
app_artifact="$(find_first_name "${APP_ARTIFACT_DIR:-}" "Lantern.app" || true)"
133+
if [[ -n "$app_artifact" ]]; then
134+
copy_app_bundle "$app_artifact" "$APP_INSTALL_DIR"
135+
return
136+
fi
137+
138+
local candidates=(
139+
"build/macos/Build/Products/Release/Lantern.app"
140+
"build/macos/Build/Products/Debug/Lantern.app"
141+
"build/macos/Runner.app"
142+
)
143+
144+
for candidate in "${candidates[@]}"; do
145+
if [[ -d "$candidate" ]]; then
146+
copy_app_bundle "$candidate" "$APP_INSTALL_DIR"
147+
return
148+
fi
149+
done
150+
151+
printf 'Lantern.app was not found. Set APP_PATH, or provide APP_ARTIFACT_DIR/DMG_ARTIFACT_DIR.\n' >&2
152+
return 1
153+
}
154+
155+
capture_command() {
156+
local name="$1"
157+
shift
158+
159+
log_step "Capturing $name"
160+
"$@" >"$ARTIFACT_DIR/$name.txt" 2>&1 || true
161+
}
162+
163+
capture_lantern_logs() {
164+
local output_dir="$ARTIFACT_DIR/lantern-logs"
165+
mkdir -p "$output_dir"
166+
167+
if [[ -d "$LANTERN_LOG_DIR" ]]; then
168+
cp -R "$LANTERN_LOG_DIR/." "$output_dir/" 2>/dev/null || true
169+
else
170+
printf 'No Lantern log directory found at %s\n' "$LANTERN_LOG_DIR" \
171+
>"$output_dir/missing.txt"
172+
fi
173+
}
174+
175+
reset_lantern_logs() {
176+
log_step "Resetting Lantern logs at $LANTERN_LOG_DIR"
177+
rm -rf "$LANTERN_LOG_DIR"
178+
mkdir -p "$LANTERN_LOG_DIR"
179+
}
180+
181+
capture_unified_logs() {
182+
log_step "Capturing unified logs"
183+
log show \
184+
--last 30m \
185+
--style syslog \
186+
--predicate 'subsystem == "org.getlantern.lantern" OR subsystem == "org.getlantern.lantern.PacketTunnel"' \
187+
>"$ARTIFACT_DIR/unified-lantern.log" 2>&1 || true
188+
}
189+
190+
capture_screenshot() {
191+
log_step "Capturing screenshot"
192+
screencapture -x "$ARTIFACT_DIR/screenshot.png" 2>/dev/null || true
193+
}
194+
195+
capture_diagnostics() {
196+
local reason="$1"
197+
198+
mkdir -p "$ARTIFACT_DIR"
199+
log_step "Capturing diagnostics: $reason"
200+
{
201+
printf 'reason=%s\n' "$reason"
202+
date
203+
} >"$ARTIFACT_DIR/diagnostics.txt"
204+
205+
capture_command "systemextensionsctl-list" systemextensionsctl list
206+
capture_command "process-list" ps aux
207+
capture_command "packet-tunnel-processes" pgrep -fl "org.getlantern.lantern.PacketTunnel"
208+
capture_lantern_logs
209+
capture_unified_logs
210+
capture_screenshot
211+
}
212+
213+
quit_lantern() {
214+
log_step "Asking Lantern to quit"
215+
osascript -e 'tell application id "org.getlantern.lantern" to quit' >/dev/null 2>&1 || true
216+
osascript -e 'tell application "Lantern" to quit' >/dev/null 2>&1 || true
217+
sleep 2
218+
}
219+
220+
packet_tunnel_processes() {
221+
pgrep -fl "org.getlantern.lantern.PacketTunnel" 2>/dev/null || true
222+
}
223+
224+
wait_for_packet_tunnel_exit() {
225+
local timeout_seconds="${1:-30}"
226+
227+
for ((i = 0; i < timeout_seconds; i++)); do
228+
if [[ -z "$(packet_tunnel_processes)" ]]; then
229+
log_step "PacketTunnel is not running"
230+
return 0
231+
fi
232+
sleep 1
233+
done
234+
235+
packet_tunnel_processes >"$ARTIFACT_DIR/packet-tunnel-still-running.txt"
236+
printf 'PacketTunnel was still running after disconnect/quit\n' >&2
237+
return 1
238+
}
239+
240+
run_with_timeout() {
241+
local timeout_seconds="$1"
242+
shift
243+
244+
"$@" &
245+
local command_pid=$!
246+
local deadline=$((SECONDS + timeout_seconds))
247+
248+
while kill -0 "$command_pid" 2>/dev/null; do
249+
if ((SECONDS >= deadline)); then
250+
kill -TERM "$command_pid" 2>/dev/null || true
251+
sleep 2
252+
if kill -0 "$command_pid" 2>/dev/null; then
253+
kill -KILL "$command_pid" 2>/dev/null || true
254+
fi
255+
wait "$command_pid" 2>/dev/null || true
256+
return 124
257+
fi
258+
sleep 1
259+
done
260+
261+
local exit_code=0
262+
wait "$command_pid" || exit_code=$?
263+
return "$exit_code"
264+
}
265+
266+
run_system_extension_preflight() {
267+
local app_executable="$1"
268+
local output="$ARTIFACT_DIR/system-extension-preflight.jsonl"
269+
local process_timeout=$((EXTENSION_TIMEOUT_SECONDS + 10))
270+
271+
log_step "Running macOS system extension preflight"
272+
set +e
273+
run_with_timeout "$process_timeout" "$app_executable" \
274+
--smoke-activate-system-extension \
275+
--timeout-seconds "$EXTENSION_TIMEOUT_SECONDS" \
276+
>"$output" 2>&1
277+
local exit_code=$?
278+
set -e
279+
280+
cat "$output"
281+
case "$exit_code" in
282+
0)
283+
return 0
284+
;;
285+
20)
286+
printf 'System extension approval is missing on this runner. Approve Lantern in System Settings or install the MDM approval profile, then rerun this smoke test.\n' >&2
287+
;;
288+
21)
289+
printf 'System extension activation requires a reboot before this smoke test can connect.\n' >&2
290+
;;
291+
124)
292+
printf 'System extension preflight exceeded the %s-second wrapper deadline (activation timeout: %s seconds), followed by a 2-second termination grace period.\n' \
293+
"$process_timeout" "$EXTENSION_TIMEOUT_SECONDS" >&2
294+
;;
295+
*)
296+
printf 'System extension preflight failed with exit code %s.\n' "$exit_code" >&2
297+
;;
298+
esac
299+
300+
return "$exit_code"
301+
}
302+
303+
run_flutter_connect_smoke() {
304+
local args=(
305+
"test"
306+
"$TEST_PATH"
307+
"-d"
308+
"macos"
309+
"--reporter=expanded"
310+
"--dart-define=DISABLE_SYSTEM_TRAY=true"
311+
)
312+
313+
if [[ "$ENABLE_IP_CHECK" == "true" ]]; then
314+
args+=("--dart-define=ENABLE_IP_CHECK=true")
315+
fi
316+
317+
if [[ "$FORCE_FULL_TUNNEL" == "true" ]]; then
318+
args+=("--dart-define=SMOKE_FORCE_FULL_TUNNEL=true")
319+
fi
320+
321+
log_step "Running macOS connect smoke: flutter ${args[*]}"
322+
flutter "${args[@]}"
323+
}
324+
325+
on_exit() {
326+
local status=$?
327+
328+
quit_lantern
329+
if [[ "$status" -ne 0 ]]; then
330+
capture_diagnostics "failure"
331+
fi
332+
detach_dmg
333+
334+
exit "$status"
335+
}
336+
337+
trap on_exit EXIT
338+
339+
mkdir -p "$ARTIFACT_DIR"
340+
reset_lantern_logs
341+
capture_command "systemextensionsctl-list-initial" systemextensionsctl list
342+
343+
app_path="$(resolve_app_path)"
344+
app_executable="$app_path/Contents/MacOS/Lantern"
345+
if [[ ! -x "$app_executable" ]]; then
346+
printf 'Lantern executable not found at %s\n' "$app_executable" >&2
347+
exit 1
348+
fi
349+
350+
if [[ "$RUN_CONNECT_SMOKE" == "true" ]]; then
351+
run_system_extension_preflight "$app_executable"
352+
run_flutter_connect_smoke
353+
else
354+
log_step "Skipping macOS connect smoke test."
355+
fi
356+
357+
quit_lantern
358+
wait_for_packet_tunnel_exit 30
359+
capture_diagnostics "success"

0 commit comments

Comments
 (0)