Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 111 additions & 6 deletions .github/scripts/macos_smoke_suite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,113 @@ RUN_CONNECT_SMOKE="${RUN_CONNECT_SMOKE:-true}"
ENABLE_IP_CHECK="${ENABLE_IP_CHECK:-false}"
FORCE_FULL_TUNNEL="${FORCE_FULL_TUNNEL:-true}"
EXTENSION_TIMEOUT_SECONDS="${EXTENSION_TIMEOUT_SECONDS:-120}"
APP_INSTALL_DIR="${APP_INSTALL_DIR:-${RUNNER_TEMP:-/tmp}/lantern-macos-smoke/Lantern.app}"
LANTERN_LOG_DIR="${LANTERN_LOG_DIR:-/Users/Shared/Lantern/Logs}"
DMG_MOUNT_DIR=""

log_step() {
printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*"
printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*" >&2
}

find_first_name() {
local root="$1"
local name="$2"

if [[ -z "$root" || ! -e "$root" ]]; then
return 1
fi

find "$root" -maxdepth 4 -name "$name" -print -quit
}

copy_app_bundle() {
local source="$1"
local destination="$2"

log_step "Copying Lantern app from $source"
rm -rf "$destination"
mkdir -p "$(dirname "$destination")"
ditto "$source" "$destination"
xattr -dr com.apple.quarantine "$destination" 2>/dev/null || true
printf '%s\n' "$destination"
}

extract_app_zip() {
local zip_path="$1"
local tmp_dir
tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' RETURN

log_step "Extracting Lantern app from $zip_path"
ditto -x -k "$zip_path" "$tmp_dir"

local app_path
app_path="$(find_first_name "$tmp_dir" "Lantern.app" || true)"
if [[ -z "$app_path" ]]; then
printf 'Lantern.app not found inside %s\n' "$zip_path" >&2
return 1
fi

copy_app_bundle "$app_path" "$APP_INSTALL_DIR"
}
Comment thread
Copilot marked this conversation as resolved.

detach_dmg() {
if [[ -n "$DMG_MOUNT_DIR" && -d "$DMG_MOUNT_DIR" ]]; then
local mount_dir="$DMG_MOUNT_DIR"
hdiutil detach "$mount_dir" -quiet || true
rmdir "$mount_dir" 2>/dev/null || true
DMG_MOUNT_DIR=""
fi
}

copy_app_from_dmg() {
local dmg_path="$1"
local mount_dir
mount_dir="$(mktemp -d)"
DMG_MOUNT_DIR="$mount_dir"

log_step "Mounting Lantern DMG $dmg_path"
hdiutil attach "$dmg_path" -nobrowse -readonly -mountpoint "$mount_dir" >/dev/null

local app_path
app_path="$(find_first_name "$mount_dir" "Lantern.app" || true)"
if [[ -z "$app_path" ]]; then
printf 'Lantern.app not found inside %s\n' "$dmg_path" >&2
detach_dmg
return 1
fi

copy_app_bundle "$app_path" "$APP_INSTALL_DIR"
detach_dmg
}

resolve_app_path() {
if [[ -n "${APP_PATH:-}" ]]; then
if [[ -n "${APP_PATH:-}" && -x "$APP_PATH/Contents/MacOS/Lantern" ]]; then
printf '%s\n' "$APP_PATH"
return
fi

local dmg_path
dmg_path="$(find_first_name "${DMG_ARTIFACT_DIR:-}" "*.dmg" || true)"
if [[ -n "$dmg_path" ]]; then
copy_app_from_dmg "$dmg_path"
return
fi

local app_zip
app_zip="$(find_first_name "${APP_ARTIFACT_DIR:-}" "Lantern.app.zip" || true)"
if [[ -n "$app_zip" ]]; then
extract_app_zip "$app_zip"
return
fi

local app_artifact
app_artifact="$(find_first_name "${APP_ARTIFACT_DIR:-}" "Lantern.app" || true)"
if [[ -n "$app_artifact" ]]; then
copy_app_bundle "$app_artifact" "$APP_INSTALL_DIR"
return
fi

local candidates=(
"build/macos/Build/Products/Release/Lantern.app"
"build/macos/Build/Products/Debug/Lantern.app"
Expand All @@ -31,7 +127,8 @@ resolve_app_path() {
fi
done

printf '%s\n' "${candidates[0]}"
printf 'Lantern.app was not found. Set APP_PATH, or provide APP_ARTIFACT_DIR/DMG_ARTIFACT_DIR.\n' >&2
return 1
}

capture_command() {
Expand All @@ -46,14 +143,20 @@ capture_lantern_logs() {
local output_dir="$ARTIFACT_DIR/lantern-logs"
mkdir -p "$output_dir"

if [[ -d "/Users/Shared/Lantern/Logs" ]]; then
cp -R "/Users/Shared/Lantern/Logs/." "$output_dir/" 2>/dev/null || true
if [[ -d "$LANTERN_LOG_DIR" ]]; then
cp -R "$LANTERN_LOG_DIR/." "$output_dir/" 2>/dev/null || true
else
printf 'No Lantern log directory found at /Users/Shared/Lantern/Logs\n' \
printf 'No Lantern log directory found at %s\n' "$LANTERN_LOG_DIR" \
>"$output_dir/missing.txt"
fi
}

reset_lantern_logs() {
log_step "Resetting Lantern logs at $LANTERN_LOG_DIR"
rm -rf "$LANTERN_LOG_DIR"
mkdir -p "$LANTERN_LOG_DIR"
}

capture_unified_logs() {
log_step "Capturing unified logs"
log show \
Expand Down Expand Up @@ -177,13 +280,15 @@ on_exit() {
if [[ "$status" -ne 0 ]]; then
capture_diagnostics "failure"
fi
detach_dmg

exit "$status"
}

trap on_exit EXIT

mkdir -p "$ARTIFACT_DIR"
reset_lantern_logs
capture_command "systemextensionsctl-list-initial" systemextensionsctl list

app_path="$(resolve_app_path)"
Expand Down
14 changes: 11 additions & 3 deletions .github/workflows/app-smoke-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ on:
type: boolean
default: true
macos_connect_smoke:
description: "Include macOS connect/disconnect smoke when platforms=all (requires approved system extension)"
description: "Include macOS connect/disconnect smoke when platforms=all (requires self-hosted runner with approved system extension)"
required: false
type: boolean
default: false
Expand Down Expand Up @@ -113,7 +113,6 @@ jobs:

macos:
needs: prepare
# macOS smoke stays opt-in for "all" until runners have system-extension approval.
if: ${{ inputs.platforms == 'macos' || (inputs.platforms == 'all' && inputs.macos_connect_smoke) }}
uses: ./.github/workflows/build-macos.yml
secrets:
Expand All @@ -128,9 +127,18 @@ jobs:
version: ${{ needs.prepare.outputs.version }}
build_type: nightly
installer_base_name: ${{ needs.prepare.outputs.installer_base_name }}

macos-connect-smoke:
needs: [prepare, macos]
if: ${{ inputs.platforms == 'macos' || (inputs.platforms == 'all' && inputs.macos_connect_smoke) }}
uses: ./.github/workflows/macos-connect-smoke.yml
secrets:
APP_ENV: ${{ secrets.APP_ENV }}
with:
version: ${{ needs.prepare.outputs.version }}
build_type: nightly
enable_ip_check: ${{ inputs.enable_ip_check }}
force_full_tunnel_smoke: ${{ inputs.force_full_tunnel_smoke }}
run_connect_smoke: true

windows:
needs: prepare
Expand Down
45 changes: 13 additions & 32 deletions .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,6 @@ on:
installer_base_name:
required: true
type: string
run_connect_smoke:
description: "Run macOS connect/disconnect smoke test"
required: false
type: boolean
default: false
enable_ip_check:
description: "Enable public IP change validation in macOS connect smoke"
required: false
type: boolean
default: false
force_full_tunnel_smoke:
description: "Force full tunnel routing mode in macOS connect smoke"
required: false
type: boolean
default: true

jobs:
build-macos:
permissions:
Expand Down Expand Up @@ -180,25 +164,22 @@ jobs:
BUCKET: ${{ vars.S3_RELEASES_BUCKET }}
run: bash ./.github/scripts/check_macos_sysext_build.sh

- name: macOS connect smoke suite
if: ${{ inputs.run_connect_smoke }}
- name: Package macOS app artifact
shell: bash
timeout-minutes: 20
env:
APP_PATH: build/macos/Build/Products/Release/Lantern.app
ARTIFACT_DIR: ${{ runner.temp }}/macos-smoke-artifacts
ENABLE_IP_CHECK: ${{ inputs.enable_ip_check }}
FORCE_FULL_TUNNEL: ${{ inputs.force_full_tunnel_smoke }}
RUN_CONNECT_SMOKE: true
run: ./.github/scripts/macos_smoke_suite.sh

- name: Upload macOS smoke diagnostics
if: ${{ always() && inputs.run_connect_smoke }}
run: |
APP_PATH="build/macos/Build/Products/Release/Lantern.app"
if [[ ! -d "$APP_PATH" ]]; then
printf 'Lantern.app not found at %s\n' "$APP_PATH" >&2
exit 1
fi

ditto -c -k --keepParent "$APP_PATH" "$RUNNER_TEMP/Lantern.app.zip"

- name: Upload macOS app
uses: actions/upload-artifact@v4
with:
name: macos-smoke-diagnostics
path: ${{ runner.temp }}/macos-smoke-artifacts
if-no-files-found: ignore
name: lantern-macos-app
path: ${{ runner.temp }}/Lantern.app.zip
retention-days: 2

- name: Upload macOS installer
Expand Down
Loading