Skip to content

Add OpenVPN Connect as a macOS FMA - #45174

Merged
allenhouchins merged 6 commits into
mainfrom
allenhouchins-add-openvpn-connect
May 12, 2026
Merged

Add OpenVPN Connect as a macOS FMA#45174
allenhouchins merged 6 commits into
mainfrom
allenhouchins-add-openvpn-connect

Conversation

@allenhouchins

@allenhouchins allenhouchins commented May 11, 2026

Copy link
Copy Markdown
Member

Add OpenVPN Connect to maintained apps: create a Homebrew input manifest and add an apps.json entry. Add a darwin output with version 3.8.1 (installer URL, sha256) plus install/uninstall script refs that handle quitting/relaunching and cleanup. Add frontend icon component and register it in the icon map, and include the app icon asset. Default category set to Productivity.

Summary by CodeRabbit

  • New Features
    • Added OpenVPN Connect (v3.8.1) as a supported application for macOS with automated installation and management.
    • Integrated application icon for UI visibility.

Review Change Stack

Add OpenVPN Connect to maintained apps: create a Homebrew input manifest and add an apps.json entry. Add a darwin output with version 3.8.1 (installer URL, sha256) plus install/uninstall script refs that handle quitting/relaunching and cleanup. Add frontend icon component and register it in the icon map, and include the app icon asset. Default category set to Productivity.
fleet-release
fleet-release previously approved these changes May 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/inputs/homebrew/openvpn-connect.json

ERROR: Could not retrieve previous version of file (file may not exist in previous commit)

ee/maintained-apps/outputs/openvpn-connect/darwin.json

ERROR: Could not retrieve previous version of file (file may not exist in previous commit)

@codecov

codecov Bot commented May 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 66.81%. Comparing base (f5c59ae) to head (53f21e3).
⚠️ Report is 17 commits behind head on main.

Files with missing lines Patch % Lines
...s/SoftwarePage/components/icons/OpenvpnConnect.tsx 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #45174   +/-   ##
=======================================
  Coverage   66.80%   66.81%           
=======================================
  Files        2722     2724    +2     
  Lines      219000   219021   +21     
  Branches    10627    10627           
=======================================
+ Hits       146305   146329   +24     
+ Misses      59529    59526    -3     
  Partials    13166    13166           
Flag Coverage Δ
frontend 55.31% <50.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/inputs/homebrew/openvpn-connect.json

ERROR: Could not retrieve previous version of file (file may not exist in previous commit)

ee/maintained-apps/outputs/openvpn-connect/darwin.json

ERROR: Could not retrieve previous version of file (file may not exist in previous commit)

The auto-generated dmg+pkg install script hard-coded the arm64 pkg path
and didn't account for OpenVPN Connect 3.8+ installing into a wrapper
directory (/Applications/OpenVPN Connect/OpenVPN Connect.app) instead of
placing the .app directly under /Applications/. osquery's `apps` table
only directory-scans the top level of /Applications/ and otherwise relies
on LaunchServices to find nested apps, so the freshly installed app
wasn't discovered by `bundle_identifier = 'org.openvpn.client.app'`.

Add a custom install script that more closely replicates Homebrew's pkg
install: mount the DMG, glob for the arm64 pkg from the mount point
(handling the parentheses in the file name), run the installer, and
force LaunchServices to register the resulting .app so osquery picks it
up immediately. Wire the script in via install_script_path on the
homebrew input and regenerate the darwin output.
@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/openvpn-connect/darwin.json

=== Install // 66c63c32 -> c8881523 ===

--- /tmp/old.KmUkPO	2026-05-12 02:13:02.022737935 +0000
+++ /tmp/new.yIGvNR	2026-05-12 02:13:02.022737935 +0000
@@ -1,16 +1,41 @@
 #!/bin/bash
 
-# variables
-APPDIR="/Applications/"
-TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
-# functions
+# Custom install script for OpenVPN Connect on macOS.
+#
+# The Homebrew cask "openvpn-connect" downloads a .dmg that contains both
+# x86_64 and arm64 .pkg installers at the root of the mounted volume:
+#
+#   OpenVPN_Connect_<ver>(<build>)_x86_64_Installer_signed.pkg
+#   OpenVPN_Connect_<ver>(<build>)_arm64_Installer_signed.pkg
+#
+# We only ship FMAs for Apple Silicon (arm64) on macOS, so this script:
+#   1. Mounts the DMG.
+#   2. Locates the arm64 .pkg via a glob (parentheses in the file name make
+#      hard-coding the path brittle across versions).
+#   3. Quits the app if it's running and tracks state for relaunch.
+#   4. Runs `installer -pkg ... -target /` against the mounted pkg, which is
+#      the same operation Homebrew performs for `pkg "..."` artifacts.
+#   5. Detaches the DMG.
+#   6. Forces LaunchServices to register the installed .app bundle.
+#
+# The LaunchServices step is required because OpenVPN Connect 3.8+ installs
+# into a wrapper directory (/Applications/OpenVPN Connect/OpenVPN Connect.app)
+# rather than placing the .app directly under /Applications/. osquery's `apps`
+# table only directory-scans the top level of /Applications/ and otherwise
+# relies on LaunchServices to discover nested apps; without an explicit
+# `lsregister` the freshly installed app may not show up immediately.
+
+set -u
+
+APPDIR="/Applications"
+BUNDLE_ID="org.openvpn.client.app"
+LSREGISTER="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"
 
 quit_and_track_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local timeout_duration=10
 
-  # check if the application is running
   local app_running
   app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null)
   if [[ "$app_running" != "true" ]]; then
@@ -26,13 +51,11 @@
     return
   fi
 
-  # App was running, mark it for relaunch
   eval "export $var_name=1"
   echo "Application '$bundle_id' was running; will relaunch after installation."
 
   echo "Quitting application '$bundle_id'..."
 
-  # try to quit the application within the timeout period
   local quit_success=false
   SECONDS=0
   while (( SECONDS < timeout_duration )); do
@@ -51,13 +74,11 @@
   fi
 }
 
-
 relaunch_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local was_running
 
-  # Check if the app was running before installation
   eval "was_running=\$$var_name"
   if [[ "$was_running" != "1" ]]; then
     return
@@ -72,11 +93,6 @@
 
   echo "Relaunching application '$bundle_id'..."
 
-  # Launch the app in the logged-in user's GUI session. Apps launched by root
-  # won't register with the user's Dock/GUI, so run 'open' as the console user.
-  # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace
-  # and GUI session — 'sudo -u' alone doesn't do this, which can cause
-  # LSOpenURLsWithRole() failures even when 'open' exits 0.
   local open_status=0
   if [[ $EUID -eq 0 ]]; then
     local console_uid
@@ -93,13 +109,70 @@
   fi
 }
 
+if [ -z "${INSTALLER_PATH:-}" ] || [ ! -f "$INSTALLER_PATH" ]; then
+  echo "Missing or invalid INSTALLER_PATH"
+  exit 1
+fi
+
+MOUNT_POINT=$(mktemp -d /tmp/openvpn_connect_dmg.XXXXXX)
+cleanup() {
+  hdiutil detach "$MOUNT_POINT" >/dev/null 2>&1 || true
+  rmdir "$MOUNT_POINT" >/dev/null 2>&1 || true
+}
+trap cleanup EXIT
+
+if ! hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH" >/dev/null; then
+  echo "Failed to mount DMG at $INSTALLER_PATH"
+  exit 1
+fi
+
+# Locate the arm64 installer pkg. We only support Apple Silicon for this FMA,
+# so deliberately skip the x86_64 pkg shipped in the same DMG. Use a glob so
+# parentheses and version/build numbers in the file name don't have to be
+# hard-coded here.
+PKG=""
+for candidate in "$MOUNT_POINT"/*_arm64_Installer_signed.pkg; do
+  if [ -e "$candidate" ]; then
+    PKG="$candidate"
+    break
+  fi
+done
+
+if [ -z "$PKG" ] || [ ! -e "$PKG" ]; then
+  echo "Could not find an arm64 OpenVPN Connect installer pkg in the DMG. Contents:"
+  ls -la "$MOUNT_POINT"
+  exit 1
+fi
+
+echo "Installing $PKG..."
+
+quit_and_track_application "$BUNDLE_ID"
+
+if ! sudo installer -pkg "$PKG" -target /; then
+  echo "installer -pkg failed for $PKG"
+  exit 1
+fi
+
+cleanup
+trap - EXIT
+
+# OpenVPN Connect 3.8+ places the .app inside a wrapper directory rather than
+# directly under /Applications/. osquery's apps table doesn't recurse into
+# /Applications/, so it depends on LaunchServices to find nested .app bundles.
+# Force-register the installed app with LaunchServices so it shows up in
+# osquery's `apps` table immediately.
+if [ -x "$LSREGISTER" ]; then
+  if [ -d "$APPDIR/OpenVPN Connect/OpenVPN Connect.app" ]; then
+    "$LSREGISTER" -f "$APPDIR/OpenVPN Connect/OpenVPN Connect.app" >/dev/null 2>&1 || true
+  elif [ -d "$APPDIR/OpenVPN Connect.app" ]; then
+    "$LSREGISTER" -f "$APPDIR/OpenVPN Connect.app" >/dev/null 2>&1 || true
+  else
+    # As a last resort, recursively register anything OpenVPN Connect-shaped
+    # under /Applications/ so LaunchServices and osquery can find it.
+    "$LSREGISTER" -R -f "$APPDIR/OpenVPN Connect" >/dev/null 2>&1 || true
+  fi
+fi
+
+relaunch_application "$BUNDLE_ID"
 
-# extract contents
-MOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)
-hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH"
-sudo cp -R "$MOUNT_POINT"/* "$TMPDIR"
-hdiutil detach "$MOUNT_POINT"
-# install pkg files
-quit_and_track_application 'org.openvpn.client.app'
-sudo installer -pkg "$TMPDIR/OpenVPN_Connect_3_8_1(5790)_arm64_Installer_signed.pkg" -target /
-relaunch_application 'org.openvpn.client.app'
+echo "OpenVPN Connect installed"

=== Uninstall Script (no changes) ===

Simplified the command execution for refreshing LaunchServices by removing conditional logic for appPath.
@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/openvpn-connect/darwin.json

=== Install // 66c63c32 -> c8881523 ===

--- /tmp/old.zio3JX	2026-05-12 02:42:28.754785051 +0000
+++ /tmp/new.3jZkQv	2026-05-12 02:42:28.754785051 +0000
@@ -1,16 +1,41 @@
 #!/bin/bash
 
-# variables
-APPDIR="/Applications/"
-TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
-# functions
+# Custom install script for OpenVPN Connect on macOS.
+#
+# The Homebrew cask "openvpn-connect" downloads a .dmg that contains both
+# x86_64 and arm64 .pkg installers at the root of the mounted volume:
+#
+#   OpenVPN_Connect_<ver>(<build>)_x86_64_Installer_signed.pkg
+#   OpenVPN_Connect_<ver>(<build>)_arm64_Installer_signed.pkg
+#
+# We only ship FMAs for Apple Silicon (arm64) on macOS, so this script:
+#   1. Mounts the DMG.
+#   2. Locates the arm64 .pkg via a glob (parentheses in the file name make
+#      hard-coding the path brittle across versions).
+#   3. Quits the app if it's running and tracks state for relaunch.
+#   4. Runs `installer -pkg ... -target /` against the mounted pkg, which is
+#      the same operation Homebrew performs for `pkg "..."` artifacts.
+#   5. Detaches the DMG.
+#   6. Forces LaunchServices to register the installed .app bundle.
+#
+# The LaunchServices step is required because OpenVPN Connect 3.8+ installs
+# into a wrapper directory (/Applications/OpenVPN Connect/OpenVPN Connect.app)
+# rather than placing the .app directly under /Applications/. osquery's `apps`
+# table only directory-scans the top level of /Applications/ and otherwise
+# relies on LaunchServices to discover nested apps; without an explicit
+# `lsregister` the freshly installed app may not show up immediately.
+
+set -u
+
+APPDIR="/Applications"
+BUNDLE_ID="org.openvpn.client.app"
+LSREGISTER="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"
 
 quit_and_track_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local timeout_duration=10
 
-  # check if the application is running
   local app_running
   app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null)
   if [[ "$app_running" != "true" ]]; then
@@ -26,13 +51,11 @@
     return
   fi
 
-  # App was running, mark it for relaunch
   eval "export $var_name=1"
   echo "Application '$bundle_id' was running; will relaunch after installation."
 
   echo "Quitting application '$bundle_id'..."
 
-  # try to quit the application within the timeout period
   local quit_success=false
   SECONDS=0
   while (( SECONDS < timeout_duration )); do
@@ -51,13 +74,11 @@
   fi
 }
 
-
 relaunch_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local was_running
 
-  # Check if the app was running before installation
   eval "was_running=\$$var_name"
   if [[ "$was_running" != "1" ]]; then
     return
@@ -72,11 +93,6 @@
 
   echo "Relaunching application '$bundle_id'..."
 
-  # Launch the app in the logged-in user's GUI session. Apps launched by root
-  # won't register with the user's Dock/GUI, so run 'open' as the console user.
-  # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace
-  # and GUI session — 'sudo -u' alone doesn't do this, which can cause
-  # LSOpenURLsWithRole() failures even when 'open' exits 0.
   local open_status=0
   if [[ $EUID -eq 0 ]]; then
     local console_uid
@@ -93,13 +109,70 @@
   fi
 }
 
+if [ -z "${INSTALLER_PATH:-}" ] || [ ! -f "$INSTALLER_PATH" ]; then
+  echo "Missing or invalid INSTALLER_PATH"
+  exit 1
+fi
+
+MOUNT_POINT=$(mktemp -d /tmp/openvpn_connect_dmg.XXXXXX)
+cleanup() {
+  hdiutil detach "$MOUNT_POINT" >/dev/null 2>&1 || true
+  rmdir "$MOUNT_POINT" >/dev/null 2>&1 || true
+}
+trap cleanup EXIT
+
+if ! hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH" >/dev/null; then
+  echo "Failed to mount DMG at $INSTALLER_PATH"
+  exit 1
+fi
+
+# Locate the arm64 installer pkg. We only support Apple Silicon for this FMA,
+# so deliberately skip the x86_64 pkg shipped in the same DMG. Use a glob so
+# parentheses and version/build numbers in the file name don't have to be
+# hard-coded here.
+PKG=""
+for candidate in "$MOUNT_POINT"/*_arm64_Installer_signed.pkg; do
+  if [ -e "$candidate" ]; then
+    PKG="$candidate"
+    break
+  fi
+done
+
+if [ -z "$PKG" ] || [ ! -e "$PKG" ]; then
+  echo "Could not find an arm64 OpenVPN Connect installer pkg in the DMG. Contents:"
+  ls -la "$MOUNT_POINT"
+  exit 1
+fi
+
+echo "Installing $PKG..."
+
+quit_and_track_application "$BUNDLE_ID"
+
+if ! sudo installer -pkg "$PKG" -target /; then
+  echo "installer -pkg failed for $PKG"
+  exit 1
+fi
+
+cleanup
+trap - EXIT
+
+# OpenVPN Connect 3.8+ places the .app inside a wrapper directory rather than
+# directly under /Applications/. osquery's apps table doesn't recurse into
+# /Applications/, so it depends on LaunchServices to find nested .app bundles.
+# Force-register the installed app with LaunchServices so it shows up in
+# osquery's `apps` table immediately.
+if [ -x "$LSREGISTER" ]; then
+  if [ -d "$APPDIR/OpenVPN Connect/OpenVPN Connect.app" ]; then
+    "$LSREGISTER" -f "$APPDIR/OpenVPN Connect/OpenVPN Connect.app" >/dev/null 2>&1 || true
+  elif [ -d "$APPDIR/OpenVPN Connect.app" ]; then
+    "$LSREGISTER" -f "$APPDIR/OpenVPN Connect.app" >/dev/null 2>&1 || true
+  else
+    # As a last resort, recursively register anything OpenVPN Connect-shaped
+    # under /Applications/ so LaunchServices and osquery can find it.
+    "$LSREGISTER" -R -f "$APPDIR/OpenVPN Connect" >/dev/null 2>&1 || true
+  fi
+fi
+
+relaunch_application "$BUNDLE_ID"
 
-# extract contents
-MOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)
-hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH"
-sudo cp -R "$MOUNT_POINT"/* "$TMPDIR"
-hdiutil detach "$MOUNT_POINT"
-# install pkg files
-quit_and_track_application 'org.openvpn.client.app'
-sudo installer -pkg "$TMPDIR/OpenVPN_Connect_3_8_1(5790)_arm64_Installer_signed.pkg" -target /
-relaunch_application 'org.openvpn.client.app'
+echo "OpenVPN Connect installed"

=== Uninstall Script (no changes) ===

@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/openvpn-connect/darwin.json

=== Install // 66c63c32 -> c8881523 ===

--- /tmp/old.Cj9YjE	2026-05-12 02:43:04.404710391 +0000
+++ /tmp/new.qbMlwF	2026-05-12 02:43:04.405710390 +0000
@@ -1,16 +1,41 @@
 #!/bin/bash
 
-# variables
-APPDIR="/Applications/"
-TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
-# functions
+# Custom install script for OpenVPN Connect on macOS.
+#
+# The Homebrew cask "openvpn-connect" downloads a .dmg that contains both
+# x86_64 and arm64 .pkg installers at the root of the mounted volume:
+#
+#   OpenVPN_Connect_<ver>(<build>)_x86_64_Installer_signed.pkg
+#   OpenVPN_Connect_<ver>(<build>)_arm64_Installer_signed.pkg
+#
+# We only ship FMAs for Apple Silicon (arm64) on macOS, so this script:
+#   1. Mounts the DMG.
+#   2. Locates the arm64 .pkg via a glob (parentheses in the file name make
+#      hard-coding the path brittle across versions).
+#   3. Quits the app if it's running and tracks state for relaunch.
+#   4. Runs `installer -pkg ... -target /` against the mounted pkg, which is
+#      the same operation Homebrew performs for `pkg "..."` artifacts.
+#   5. Detaches the DMG.
+#   6. Forces LaunchServices to register the installed .app bundle.
+#
+# The LaunchServices step is required because OpenVPN Connect 3.8+ installs
+# into a wrapper directory (/Applications/OpenVPN Connect/OpenVPN Connect.app)
+# rather than placing the .app directly under /Applications/. osquery's `apps`
+# table only directory-scans the top level of /Applications/ and otherwise
+# relies on LaunchServices to discover nested apps; without an explicit
+# `lsregister` the freshly installed app may not show up immediately.
+
+set -u
+
+APPDIR="/Applications"
+BUNDLE_ID="org.openvpn.client.app"
+LSREGISTER="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"
 
 quit_and_track_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local timeout_duration=10
 
-  # check if the application is running
   local app_running
   app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null)
   if [[ "$app_running" != "true" ]]; then
@@ -26,13 +51,11 @@
     return
   fi
 
-  # App was running, mark it for relaunch
   eval "export $var_name=1"
   echo "Application '$bundle_id' was running; will relaunch after installation."
 
   echo "Quitting application '$bundle_id'..."
 
-  # try to quit the application within the timeout period
   local quit_success=false
   SECONDS=0
   while (( SECONDS < timeout_duration )); do
@@ -51,13 +74,11 @@
   fi
 }
 
-
 relaunch_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local was_running
 
-  # Check if the app was running before installation
   eval "was_running=\$$var_name"
   if [[ "$was_running" != "1" ]]; then
     return
@@ -72,11 +93,6 @@
 
   echo "Relaunching application '$bundle_id'..."
 
-  # Launch the app in the logged-in user's GUI session. Apps launched by root
-  # won't register with the user's Dock/GUI, so run 'open' as the console user.
-  # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace
-  # and GUI session — 'sudo -u' alone doesn't do this, which can cause
-  # LSOpenURLsWithRole() failures even when 'open' exits 0.
   local open_status=0
   if [[ $EUID -eq 0 ]]; then
     local console_uid
@@ -93,13 +109,70 @@
   fi
 }
 
+if [ -z "${INSTALLER_PATH:-}" ] || [ ! -f "$INSTALLER_PATH" ]; then
+  echo "Missing or invalid INSTALLER_PATH"
+  exit 1
+fi
+
+MOUNT_POINT=$(mktemp -d /tmp/openvpn_connect_dmg.XXXXXX)
+cleanup() {
+  hdiutil detach "$MOUNT_POINT" >/dev/null 2>&1 || true
+  rmdir "$MOUNT_POINT" >/dev/null 2>&1 || true
+}
+trap cleanup EXIT
+
+if ! hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH" >/dev/null; then
+  echo "Failed to mount DMG at $INSTALLER_PATH"
+  exit 1
+fi
+
+# Locate the arm64 installer pkg. We only support Apple Silicon for this FMA,
+# so deliberately skip the x86_64 pkg shipped in the same DMG. Use a glob so
+# parentheses and version/build numbers in the file name don't have to be
+# hard-coded here.
+PKG=""
+for candidate in "$MOUNT_POINT"/*_arm64_Installer_signed.pkg; do
+  if [ -e "$candidate" ]; then
+    PKG="$candidate"
+    break
+  fi
+done
+
+if [ -z "$PKG" ] || [ ! -e "$PKG" ]; then
+  echo "Could not find an arm64 OpenVPN Connect installer pkg in the DMG. Contents:"
+  ls -la "$MOUNT_POINT"
+  exit 1
+fi
+
+echo "Installing $PKG..."
+
+quit_and_track_application "$BUNDLE_ID"
+
+if ! sudo installer -pkg "$PKG" -target /; then
+  echo "installer -pkg failed for $PKG"
+  exit 1
+fi
+
+cleanup
+trap - EXIT
+
+# OpenVPN Connect 3.8+ places the .app inside a wrapper directory rather than
+# directly under /Applications/. osquery's apps table doesn't recurse into
+# /Applications/, so it depends on LaunchServices to find nested .app bundles.
+# Force-register the installed app with LaunchServices so it shows up in
+# osquery's `apps` table immediately.
+if [ -x "$LSREGISTER" ]; then
+  if [ -d "$APPDIR/OpenVPN Connect/OpenVPN Connect.app" ]; then
+    "$LSREGISTER" -f "$APPDIR/OpenVPN Connect/OpenVPN Connect.app" >/dev/null 2>&1 || true
+  elif [ -d "$APPDIR/OpenVPN Connect.app" ]; then
+    "$LSREGISTER" -f "$APPDIR/OpenVPN Connect.app" >/dev/null 2>&1 || true
+  else
+    # As a last resort, recursively register anything OpenVPN Connect-shaped
+    # under /Applications/ so LaunchServices and osquery can find it.
+    "$LSREGISTER" -R -f "$APPDIR/OpenVPN Connect" >/dev/null 2>&1 || true
+  fi
+fi
+
+relaunch_application "$BUNDLE_ID"
 
-# extract contents
-MOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)
-hdiutil attach -plist -nobrowse -readonly -mountpoint "$MOUNT_POINT" "$INSTALLER_PATH"
-sudo cp -R "$MOUNT_POINT"/* "$TMPDIR"
-hdiutil detach "$MOUNT_POINT"
-# install pkg files
-quit_and_track_application 'org.openvpn.client.app'
-sudo installer -pkg "$TMPDIR/OpenVPN_Connect_3_8_1(5790)_arm64_Installer_signed.pkg" -target /
-relaunch_application 'org.openvpn.client.app'
+echo "OpenVPN Connect installed"

=== Uninstall Script (no changes) ===

@allenhouchins
allenhouchins marked this pull request as ready for review May 12, 2026 03:18
Copilot AI review requested due to automatic review settings May 12, 2026 03:18
@allenhouchins
allenhouchins requested a review from a team as a code owner May 12, 2026 03:18
@fleet-release
fleet-release requested a review from eashaw May 12, 2026 03:18

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@allenhouchins
allenhouchins merged commit a6d609e into main May 12, 2026
29 of 30 checks passed
@allenhouchins
allenhouchins deleted the allenhouchins-add-openvpn-connect branch May 12, 2026 03:18
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 79c38f5b-6f57-41c1-9562-e3666b202f7f

📥 Commits

Reviewing files that changed from the base of the PR and between fe16654 and 53f21e3.

⛔ Files ignored due to path filters (1)
  • website/assets/images/app-icon-openvpn-connect-60x60@2x.png is excluded by !**/*.png
📒 Files selected for processing (6)
  • ee/maintained-apps/inputs/homebrew/openvpn-connect.json
  • ee/maintained-apps/inputs/homebrew/scripts/openvpn-connect-install.sh
  • ee/maintained-apps/outputs/apps.json
  • ee/maintained-apps/outputs/openvpn-connect/darwin.json
  • frontend/pages/SoftwarePage/components/icons/OpenvpnConnect.tsx
  • frontend/pages/SoftwarePage/components/icons/index.ts

Walkthrough

This PR adds OpenVPN Connect as a managed application to Fleet. It introduces a Homebrew input metadata file specifying the app's bundle identifier and installer type, a comprehensive Bash installer script for macOS that handles DMG mounting, app lifecycle management (detecting and relaunching the running app), LaunchServices registration, and cleanup. The app is registered in the output app registry and receives a macOS-specific definition file with version metadata and embedded install/uninstall script definitions. The frontend receives a new SVG icon component and its integration into the software icon mapping for UI display.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch allenhouchins-add-openvpn-connect

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds OpenVPN Connect as a Fleet-maintained app (FMA) for macOS, wiring it into both the maintained-apps catalog and the Software page UI so it can be distributed and displayed with the correct metadata and icon.

Changes:

  • Added Homebrew input manifest + custom macOS install script for OpenVPN Connect.
  • Added generated maintained-app outputs (darwin version metadata + install/uninstall script refs) and registered the app in apps.json.
  • Added a new Software page icon component and registered it in the software-name-to-icon map.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
frontend/pages/SoftwarePage/components/icons/OpenvpnConnect.tsx Adds the OpenVPN Connect icon component used by the Software page.
frontend/pages/SoftwarePage/components/icons/index.ts Registers the new icon in the icon map and imports it.
ee/maintained-apps/outputs/openvpn-connect/darwin.json Adds the generated macOS output metadata, installer URL/SHA, and install/uninstall script refs.
ee/maintained-apps/outputs/apps.json Registers OpenVPN Connect in the maintained apps catalog list.
ee/maintained-apps/inputs/homebrew/scripts/openvpn-connect-install.sh Adds a custom DMG+PKG install script with quit/relaunch and LaunchServices registration.
ee/maintained-apps/inputs/homebrew/openvpn-connect.json Adds the Homebrew input manifest for OpenVPN Connect.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +5 to +14
const OpenvpnConnect = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" width={32} height={32} {...props}>
<image
width={32}
height={32}
href="data:image/png;base64,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"
/>
</svg>
);
export default OpenvpnConnect;
],
"refs": {
"c8881523": "#!/bin/bash\n\n# Custom install script for OpenVPN Connect on macOS.\n#\n# The Homebrew cask \"openvpn-connect\" downloads a .dmg that contains both\n# x86_64 and arm64 .pkg installers at the root of the mounted volume:\n#\n# OpenVPN_Connect_<ver>(<build>)_x86_64_Installer_signed.pkg\n# OpenVPN_Connect_<ver>(<build>)_arm64_Installer_signed.pkg\n#\n# We only ship FMAs for Apple Silicon (arm64) on macOS, so this script:\n# 1. Mounts the DMG.\n# 2. Locates the arm64 .pkg via a glob (parentheses in the file name make\n# hard-coding the path brittle across versions).\n# 3. Quits the app if it's running and tracks state for relaunch.\n# 4. Runs `installer -pkg ... -target /` against the mounted pkg, which is\n# the same operation Homebrew performs for `pkg \"...\"` artifacts.\n# 5. Detaches the DMG.\n# 6. Forces LaunchServices to register the installed .app bundle.\n#\n# The LaunchServices step is required because OpenVPN Connect 3.8+ installs\n# into a wrapper directory (/Applications/OpenVPN Connect/OpenVPN Connect.app)\n# rather than placing the .app directly under /Applications/. osquery's `apps`\n# table only directory-scans the top level of /Applications/ and otherwise\n# relies on LaunchServices to discover nested apps; without an explicit\n# `lsregister` the freshly installed app may not show up immediately.\n\nset -u\n\nAPPDIR=\"/Applications\"\nBUNDLE_ID=\"org.openvpn.client.app\"\nLSREGISTER=\"/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister\"\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\nif [ -z \"${INSTALLER_PATH:-}\" ] || [ ! -f \"$INSTALLER_PATH\" ]; then\n echo \"Missing or invalid INSTALLER_PATH\"\n exit 1\nfi\n\nMOUNT_POINT=$(mktemp -d /tmp/openvpn_connect_dmg.XXXXXX)\ncleanup() {\n hdiutil detach \"$MOUNT_POINT\" >/dev/null 2>&1 || true\n rmdir \"$MOUNT_POINT\" >/dev/null 2>&1 || true\n}\ntrap cleanup EXIT\n\nif ! hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" >/dev/null; then\n echo \"Failed to mount DMG at $INSTALLER_PATH\"\n exit 1\nfi\n\n# Locate the arm64 installer pkg. We only support Apple Silicon for this FMA,\n# so deliberately skip the x86_64 pkg shipped in the same DMG. Use a glob so\n# parentheses and version/build numbers in the file name don't have to be\n# hard-coded here.\nPKG=\"\"\nfor candidate in \"$MOUNT_POINT\"/*_arm64_Installer_signed.pkg; do\n if [ -e \"$candidate\" ]; then\n PKG=\"$candidate\"\n break\n fi\ndone\n\nif [ -z \"$PKG\" ] || [ ! -e \"$PKG\" ]; then\n echo \"Could not find an arm64 OpenVPN Connect installer pkg in the DMG. Contents:\"\n ls -la \"$MOUNT_POINT\"\n exit 1\nfi\n\necho \"Installing $PKG...\"\n\nquit_and_track_application \"$BUNDLE_ID\"\n\nif ! sudo installer -pkg \"$PKG\" -target /; then\n echo \"installer -pkg failed for $PKG\"\n exit 1\nfi\n\ncleanup\ntrap - EXIT\n\n# OpenVPN Connect 3.8+ places the .app inside a wrapper directory rather than\n# directly under /Applications/. osquery's apps table doesn't recurse into\n# /Applications/, so it depends on LaunchServices to find nested .app bundles.\n# Force-register the installed app with LaunchServices so it shows up in\n# osquery's `apps` table immediately.\nif [ -x \"$LSREGISTER\" ]; then\n if [ -d \"$APPDIR/OpenVPN Connect/OpenVPN Connect.app\" ]; then\n \"$LSREGISTER\" -f \"$APPDIR/OpenVPN Connect/OpenVPN Connect.app\" >/dev/null 2>&1 || true\n elif [ -d \"$APPDIR/OpenVPN Connect.app\" ]; then\n \"$LSREGISTER\" -f \"$APPDIR/OpenVPN Connect.app\" >/dev/null 2>&1 || true\n else\n # As a last resort, recursively register anything OpenVPN Connect-shaped\n # under /Applications/ so LaunchServices and osquery can find it.\n \"$LSREGISTER\" -R -f \"$APPDIR/OpenVPN Connect\" >/dev/null 2>&1 || true\n fi\nfi\n\nrelaunch_application \"$BUNDLE_ID\"\n\necho \"OpenVPN Connect installed\"\n",
"d66adb9e": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\n}\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'org.openvpn.client'\nremove_launchctl_service 'org.openvpn.helper'\nquit_application 'org.openvpn.client.app'\nremove_pkg_files 'org.openvpn.client.pkg'\nforget_pkg 'org.openvpn.client.pkg'\nremove_pkg_files 'org.openvpn.client_framework.pkg'\nforget_pkg 'org.openvpn.client_framework.pkg'\nremove_pkg_files 'org.openvpn.client_launch.pkg'\nforget_pkg 'org.openvpn.client_launch.pkg'\nremove_pkg_files 'org.openvpn.client_uninstall.pkg'\nforget_pkg 'org.openvpn.client_uninstall.pkg'\nremove_pkg_files 'org.openvpn.helper_framework.pkg'\nforget_pkg 'org.openvpn.helper_framework.pkg'\nremove_pkg_files 'org.openvpn.helper_launch.pkg'\nforget_pkg 'org.openvpn.helper_launch.pkg'\nsudo rm -rf '/Applications/OpenVPN Connect'\nsudo rm -rf '/Applications/OpenVPN Connect.app'\n(cd /Users/$LOGGED_IN_USER && 'security' 'delete-keychain' 'openvpn.keychain-db') || true\ntrash $LOGGED_IN_USER '~/Library/Application Support/OpenVPN Connect'\ntrash $LOGGED_IN_USER '~/Library/Logs/OpenVPN Connect'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.openvpn.client.app.helper.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/org.openvpn.client.app.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/org.openvpn.client.app.savedState'\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants