From 21cfab20cc323a259dfb548752cc6b9fe2f41b29 Mon Sep 17 00:00:00 2001 From: Mitch Francese <2227948+tux234@users.noreply.github.com> Date: Wed, 11 Mar 2026 10:02:49 -0400 Subject: [PATCH] Add Warp as Fleet maintained app for macOS (#41051) ## Summary - Adds Warp terminal as a Fleet maintained app for macOS (darwin) - Uses direct CDN URL (`releases.warp.dev`) instead of Homebrew's URL which requires `User-Agent: Homebrew` header - Single `WarpDirectInstaller` enricher: overrides URL, sets `sha256: no_check`, strips `.stable_` from version string - Version: `0.2026.02.25.08.24.01` (latest stable) ## Validation checklist - [ ] App can be downloaded using manifest URL - [ ] App installs successfully on macOS host using manifest install script - [ ] App exists in software inventory after install (`dev.warp.Warp-Stable`) - [ ] App uninstalls successfully using manifest uninstall script ## Notes Supersedes #37901 (branch had corrupted git history from a rewrite; this is a clean branch off main). --- .../ingesters/homebrew/external_refs/main.go | 1 + .../ingesters/homebrew/external_refs/warp.go | 22 ++++++++++++++++++ ee/maintained-apps/inputs/homebrew/warp.json | 8 +++++++ ee/maintained-apps/outputs/apps.json | 7 ++++++ ee/maintained-apps/outputs/warp/darwin.json | 21 +++++++++++++++++ .../SoftwarePage/components/icons/Warp.tsx | 14 +++++++++++ .../SoftwarePage/components/icons/index.ts | 2 ++ .../assets/images/app-icon-warp-60x60@2x.png | Bin 0 -> 14919 bytes 8 files changed, 75 insertions(+) create mode 100644 ee/maintained-apps/ingesters/homebrew/external_refs/warp.go create mode 100644 ee/maintained-apps/inputs/homebrew/warp.json create mode 100644 ee/maintained-apps/outputs/warp/darwin.json create mode 100644 frontend/pages/SoftwarePage/components/icons/Warp.tsx create mode 100644 website/assets/images/app-icon-warp-60x60@2x.png diff --git a/ee/maintained-apps/ingesters/homebrew/external_refs/main.go b/ee/maintained-apps/ingesters/homebrew/external_refs/main.go index 810842a5db..8809d586b8 100644 --- a/ee/maintained-apps/ingesters/homebrew/external_refs/main.go +++ b/ee/maintained-apps/ingesters/homebrew/external_refs/main.go @@ -21,6 +21,7 @@ var Funcs = map[string][]func(*maintained_apps.FMAManifestApp) (*maintained_apps "parallels/darwin": {ParallelsVersionShortener}, "github/darwin": {GitHubDesktopVersionShortener}, "camtasia/darwin": {CamtasiaVersionTransformer}, + "warp/darwin": {WarpDirectInstaller}, } func ChromePKGInstaller(app *maintained_apps.FMAManifestApp) (*maintained_apps.FMAManifestApp, error) { diff --git a/ee/maintained-apps/ingesters/homebrew/external_refs/warp.go b/ee/maintained-apps/ingesters/homebrew/external_refs/warp.go new file mode 100644 index 0000000000..374d1d0345 --- /dev/null +++ b/ee/maintained-apps/ingesters/homebrew/external_refs/warp.go @@ -0,0 +1,22 @@ +package externalrefs + +import ( + "strings" + + maintained_apps "github.com/fleetdm/fleet/v4/ee/maintained-apps" +) + +func WarpDirectInstaller(app *maintained_apps.FMAManifestApp) (*maintained_apps.FMAManifestApp, error) { + // Override the Homebrew URL (which requires a User-Agent: Homebrew header) with the direct CDN + // URL. The Homebrew endpoint redirects to this URL, so the DMG is identical. + // Example: version "0.2026.02.25.08.24.stable_01" -> + // https://releases.warp.dev/stable/v0.2026.02.25.08.24.stable_01/Warp.dmg + app.InstallerURL = "https://releases.warp.dev/stable/v" + app.Version + "/Warp.dmg" + app.SHA256 = "no_check" + + // Strip ".stable_" from the version string — the app bundle version omits it. + // Example: "0.2026.02.25.08.24.stable_01" -> "0.2026.02.25.08.24.01" + app.Version = strings.Replace(app.Version, ".stable_", ".", 1) + + return app, nil +} diff --git a/ee/maintained-apps/inputs/homebrew/warp.json b/ee/maintained-apps/inputs/homebrew/warp.json new file mode 100644 index 0000000000..c3351f0c41 --- /dev/null +++ b/ee/maintained-apps/inputs/homebrew/warp.json @@ -0,0 +1,8 @@ +{ + "name": "Warp", + "slug": "warp/darwin", + "unique_identifier": "dev.warp.Warp-Stable", + "token": "warp", + "installer_format": "dmg", + "default_categories": ["Developer tools"] +} diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index 08e3573672..b149abb6f6 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -1695,6 +1695,13 @@ "unique_identifier": "com.wacom.WacomCenter", "description": "Wacom Tablet is a collection of resources for configuring Wacom tablets." }, + { + "name": "Warp", + "slug": "warp/darwin", + "platform": "darwin", + "unique_identifier": "dev.warp.Warp-Stable", + "description": "Warp is a modern, AI-powered terminal built for speed and productivity with features like command search, intelligent completions, and collaborative workflows." + }, { "name": "Webex", "slug": "webex/darwin", diff --git a/ee/maintained-apps/outputs/warp/darwin.json b/ee/maintained-apps/outputs/warp/darwin.json new file mode 100644 index 0000000000..dff831412c --- /dev/null +++ b/ee/maintained-apps/outputs/warp/darwin.json @@ -0,0 +1,21 @@ +{ + "versions": [ + { + "version": "0.2026.02.25.08.24.01", + "queries": { + "exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'dev.warp.Warp-Stable';" + }, + "installer_url": "https://releases.warp.dev/stable/v0.2026.02.25.08.24.stable_01/Warp.dmg", + "install_script_ref": "df0fd0b3", + "uninstall_script_ref": "54d05203", + "sha256": "no_check", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "54d05203": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\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\nsudo rm -rf \"$APPDIR/Warp.app\"\ntrash $LOGGED_IN_USER '~/.warp'\ntrash $LOGGED_IN_USER '~/Library/Application Support/dev.warp.Warp-Stable'\ntrash $LOGGED_IN_USER '~/Library/Logs/warp.log*'\ntrash $LOGGED_IN_USER '~/Library/Preferences/dev.warp.Warp-Stable.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/dev.warp.Warp-Stable.savedState'\n", + "df0fd0b3": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\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 # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; 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 [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; 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 # App was running, mark it for relaunch\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 # 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\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\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 [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; 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 # Try to launch the application\n if osascript -e \"tell application id \\\"$bundle_id\\\" to activate\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nhdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\"\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\"\n# copy to the applications folder\nquit_and_track_application 'dev.warp.Warp-Stable'\nif [ -d \"$APPDIR/Warp.app\" ]; then\n\tsudo mv \"$APPDIR/Warp.app\" \"$TMPDIR/Warp.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Warp.app\" \"$APPDIR\"\nrelaunch_application 'dev.warp.Warp-Stable'\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/Warp.tsx b/frontend/pages/SoftwarePage/components/icons/Warp.tsx new file mode 100644 index 0000000000..5e84bfbb99 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/Warp.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const Warp = (props: SVGProps) => ( + + + +); +export default Warp; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index ed56ba5210..f4b5d059e2 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -216,6 +216,7 @@ import VisualStudioCode from "./VisualStudioCode"; import Vlc from "./Vlc"; import VncViewer from "./VncViewer"; import WacomCenter from "./WacomCenter"; +import Warp from "./Warp"; import WebStorm from "./WebStorm"; import Webex from "./Webex"; import WhatsApp from "./WhatsApp"; @@ -463,6 +464,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { vlc: Vlc, "wacom center": WacomCenter, "wacom tablet": WacomCenter, + warp: Warp, webstorm: WebStorm, webex: Webex, whatsapp: WhatsApp, diff --git a/website/assets/images/app-icon-warp-60x60@2x.png b/website/assets/images/app-icon-warp-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aeeb742d0dcb6222ab733d7056886996ddaefefb GIT binary patch literal 14919 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