Files
c5575e9d9a Add PSSO end to end integration tests (#48589)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #47171

Added integration tests for the fleet-psso feature and added PSSO
functionality to our MDM test client - idea being it is so tightly
integrated into the MDM side of things on the Apple side AND we ideall
want osquery-perf to be able to exercise it(coming in the next PR)

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Apple Platform SSO (PSSO) support for device registration,
password login, key requests, and key exchange.
* Added a simulator/test device for exercising the full PSSO workflow
end-to-end.
* Made PSSO AASA development app IDs configurable and enhanced macOS
PSSO activity in performance testing (with new counters).
  * Improved local macOS Desktop packaging/signing configurability.

* **Bug Fixes**
* Strengthened PSSO token/crypto handling, including algorithm pinning,
key ID canonicalization, encrypted assertion `typ` validation, and
replay protection.

* **Tests**
* Added extensive crypto interoperability tests (including Apple
known-answer vectors) plus new end-to-end integration coverage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Magnus Jensen <magnus@fleetdm.com>
2026-07-10 18:51:33 -04:00

207 lines
7.3 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_DIR="$SCRIPT_DIR/build"
APP_DIR="$BUILD_DIR/Fleet Desktop.app"
PKG_DIR="$BUILD_DIR/pkg"
DIST_DIR="$BUILD_DIR/dist"
# Package + app bundle identifier. Override for a dev-team build so the pkg and
# its quit/relaunch scripts match the app's bundle ID (see build.sh).
APP_BUNDLE_ID="${APP_BUNDLE_ID:-com.fleetdm.fleet-desktop}"
# Only build if app doesn't exist or if FORCE_REBUILD is set
if [ ! -d "$APP_DIR" ] || [ "${FORCE_REBUILD:-}" = "1" ]; then
echo "Building Fleet Desktop app..."
bash "$SCRIPT_DIR/build.sh"
else
echo "Using existing app at $APP_DIR (skip rebuild)"
# Verify the app is signed if it exists
if codesign --verify "$APP_DIR" &>/dev/null; then
echo "App is already signed, using as-is"
else
echo "Warning: App exists but is not signed"
fi
fi
echo "Preparing package structure..."
rm -rf "$PKG_DIR" "$DIST_DIR"
mkdir -p "$PKG_DIR/Applications"
# Use ditto to preserve extended attributes and signatures
ditto "$APP_DIR" "$PKG_DIR/Applications/Fleet Desktop.app"
# Create preinstall script to check MDM and quit the app if running
cat > "$PKG_DIR/preinstall" << 'PREINSTALL_EOF'
#!/bin/bash
# Preinstall script: verify MDM enrollment, gracefully quit Fleet Desktop
# if it is running, and track its state so postinstall can relaunch it.
MDM_PLIST="/Library/Managed Preferences/com.fleetdm.fleetd.config.plist"
if [ ! -f "$MDM_PLIST" ]; then
echo "ERROR: Fleet Desktop requires an MDM-enabled Mac." >&2
echo "The managed preferences file was not found at: $MDM_PLIST" >&2
echo "Please enroll this device via MDM before installing Fleet Desktop." >&2
exit 1
fi
BUNDLE_ID="com.fleetdm.fleet-desktop"
# Root-owned, not world-writable, so it isn't open to the symlink/TOCTOU races
# that /tmp would be. Cleared at boot, which is fine — the flag only needs to
# survive between preinstall and postinstall of a single installer run.
RUNNING_FLAG="/var/run/.fleet_desktop_was_running"
# Clean up any stale flag from a previous install
rm -f "$RUNNING_FLAG"
# Check if a GUI user is logged in (osascript won't work otherwise)
console_user=$(stat -f "%Su" /dev/console 2>/dev/null || echo "root")
if [[ "$console_user" == "root" || "$console_user" == "loginwindow" ]]; then
# No GUI session — nothing to quit or relaunch
exit 0
fi
# Check if the app is running
if osascript -e "application id \"$BUNDLE_ID\" is running" 2>/dev/null | grep -qi "true"; then
# Mark that it was running so postinstall can relaunch
touch "$RUNNING_FLAG"
# Attempt graceful quit
osascript -e "tell application id \"$BUNDLE_ID\" to quit" 2>/dev/null || true
# Wait up to 10 seconds for the process to exit
for i in $(seq 1 10); do
if ! pgrep -f "$BUNDLE_ID" >/dev/null 2>&1 && ! pgrep -x "FleetDesktop" >/dev/null 2>&1; then
break
fi
sleep 1
done
# Force kill if still running
if pgrep -x "FleetDesktop" >/dev/null 2>&1; then
pkill -x "FleetDesktop" 2>/dev/null || true
sleep 1
fi
fi
exit 0
PREINSTALL_EOF
chmod +x "$PKG_DIR/preinstall"
# Create postinstall script to set ownership/permissions and relaunch if needed
cat > "$PKG_DIR/postinstall" << 'POSTINSTALL_EOF'
#!/bin/bash
# Postinstall script: set ownership/permissions and relaunch if the app was running
APP_PATH="/Applications/Fleet Desktop.app"
BUNDLE_ID="com.fleetdm.fleet-desktop"
RUNNING_FLAG="/var/run/.fleet_desktop_was_running"
# Set ownership to root:admin
chown -R root:admin "$APP_PATH"
# Set permissions to 755
chmod -R 755 "$APP_PATH"
# Ensure the executable has proper permissions
chmod +x "$APP_PATH/Contents/MacOS/FleetDesktop"
# Relaunch the app if it was running before the install
if [ -f "$RUNNING_FLAG" ]; then
rm -f "$RUNNING_FLAG"
# Check if a GUI user is logged in
console_user=$(stat -f "%Su" /dev/console 2>/dev/null || echo "root")
if [[ "$console_user" != "root" && "$console_user" != "loginwindow" ]]; then
# Open the app as the console user (not as root)
sudo -u "$console_user" open "$APP_PATH" 2>/dev/null || true
fi
fi
exit 0
POSTINSTALL_EOF
chmod +x "$PKG_DIR/postinstall"
# The scripts above are written from quoted heredocs (no expansion), so patch the
# app bundle ID they quit/relaunch in place. Targets only the BUNDLE_ID line, so
# the fleetd managed-preferences path (com.fleetdm.fleetd.config.plist) is untouched.
sed -i '' "s|^BUNDLE_ID=\"com.fleetdm.fleet-desktop\"$|BUNDLE_ID=\"$APP_BUNDLE_ID\"|" \
"$PKG_DIR/preinstall" "$PKG_DIR/postinstall"
# Extract version from Info.plist
VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$APP_DIR/Contents/Info.plist")
PKG_NAME="fleet_desktop-v${VERSION}.pkg"
echo "Building component package..."
mkdir -p "$DIST_DIR"
COMPONENT_PKG="$BUILD_DIR/fleet-desktop-component.pkg"
pkgbuild \
--root "$PKG_DIR/Applications" \
--scripts "$PKG_DIR" \
--identifier "$APP_BUNDLE_ID" \
--version "${VERSION}" \
--install-location /Applications \
"$COMPONENT_PKG"
# Create distribution XML for custom installer title
DIST_XML="$BUILD_DIR/distribution.xml"
cat > "$DIST_XML" << DIST_EOF
<?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="2">
<title>Fleet Desktop v${VERSION}</title>
<options customize="never" require-scripts="false" hostArchitectures="x86_64,arm64"/>
<installation-check script="mdm_check()"/>
<script>
function mdm_check() {
if (system.files.fileExistsAtPath('/Library/Managed Preferences/com.fleetdm.fleetd.config.plist')) {
return true;
}
my.result.title = 'Installation Failed';
my.result.message = 'Fleet Desktop requires an MDM-enabled Mac. Please enroll this device via MDM before installing Fleet Desktop.';
my.result.type = 'Fatal';
return false;
}
</script>
<choices-outline>
<line choice="default"/>
</choices-outline>
<choice id="default" title="Fleet Desktop">
<pkg-ref id="${APP_BUNDLE_ID}"/>
</choice>
<pkg-ref id="${APP_BUNDLE_ID}" version="${VERSION}" onConclusion="none">fleet-desktop-component.pkg</pkg-ref>
</installer-gui-script>
DIST_EOF
echo "Building product package with custom installer title..."
productbuild \
--distribution "$DIST_XML" \
--package-path "$BUILD_DIR" \
"$DIST_DIR/$PKG_NAME"
# Clean up component package
rm -f "$COMPONENT_PKG"
# --- Optional installer signing (local development) -------------------------
# Sign the .pkg with a Developer ID Installer cert so it can be pushed through
# Fleet / MDM like production. Leave unset to get an unsigned pkg (fine for a
# manual `installer -pkg` on your own test Mac). CI signs in a separate step.
if [ -n "${INSTALLER_SIGNING_IDENTITY:-}" ]; then
echo "Signing installer with: $INSTALLER_SIGNING_IDENTITY"
SIGNED_PKG="$DIST_DIR/${PKG_NAME%.pkg}-signed.pkg"
productsign --sign "$INSTALLER_SIGNING_IDENTITY" --timestamp \
"$DIST_DIR/$PKG_NAME" "$SIGNED_PKG"
mv "$SIGNED_PKG" "$DIST_DIR/$PKG_NAME"
pkgutil --check-signature "$DIST_DIR/$PKG_NAME"
fi
echo "Package created: $DIST_DIR/$PKG_NAME"
# Output for GitHub Actions (if running in CI)
if [ -n "${GITHUB_OUTPUT:-}" ]; then
echo "PKG_PATH=$DIST_DIR/$PKG_NAME" >> "$GITHUB_OUTPUT"
echo "PKG_NAME=$PKG_NAME" >> "$GITHUB_OUTPUT"
echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
fi