Skip to content

Commit 74dbdf9

Browse files
committed
add pkg creation for macos
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
1 parent 0a9972b commit 74dbdf9

17 files changed

Lines changed: 958 additions & 3 deletions

‎.github/workflows/release.yml‎

Lines changed: 153 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,139 @@ jobs:
291291
path: release/agentdesktop-*
292292
if-no-files-found: error
293293

294+
build-macos-installers:
295+
needs: setup
296+
runs-on: ${{ matrix.runner }}
297+
permissions:
298+
contents: read
299+
strategy:
300+
fail-fast: false
301+
matrix:
302+
include:
303+
- arch: amd64
304+
target: x86_64-apple-darwin
305+
runner: macos-15-intel
306+
- arch: arm64
307+
target: aarch64-apple-darwin
308+
runner: macos-26
309+
env:
310+
AGENTDESKTOP_VERSION: ${{ needs.setup.outputs.version }}
311+
steps:
312+
- name: Checkout
313+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
314+
with:
315+
persist-credentials: false
316+
317+
- name: Install Node
318+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
319+
with:
320+
node-version-file: frontend/.nvmrc
321+
322+
- name: Install Rust target
323+
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master
324+
with:
325+
toolchain: "1.97"
326+
targets: ${{ matrix.target }}
327+
328+
- name: Install frontend dependencies
329+
working-directory: frontend
330+
shell: bash
331+
run: |
332+
corepack enable
333+
pnpm install --frozen-lockfile
334+
335+
# Production signing placeholder: import the Developer ID Application and
336+
# Developer ID Installer certificates into a temporary keychain here.
337+
# Store the certificates and keychain password as GitHub Actions secrets.
338+
# - name: Import Apple signing certificates
339+
# shell: bash
340+
# env:
341+
# APPLE_APPLICATION_CERTIFICATE: ${{ secrets.APPLE_APPLICATION_CERTIFICATE }}
342+
# APPLE_INSTALLER_CERTIFICATE: ${{ secrets.APPLE_INSTALLER_CERTIFICATE }}
343+
# APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
344+
# run: |
345+
# # Create a temporary keychain and import both certificates here.
346+
347+
- name: Build PKG
348+
working-directory: frontend
349+
shell: bash
350+
# Production signing placeholder: expose the imported identities to
351+
# Tauri and package-macos.mjs when certificate import is implemented.
352+
# env:
353+
# APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_APPLICATION_SIGNING_IDENTITY }}
354+
# APPLE_INSTALLER_SIGNING_IDENTITY: ${{ secrets.APPLE_INSTALLER_SIGNING_IDENTITY }}
355+
# APPLE_INSTALLER_KEYCHAIN: ${{ runner.temp }}/agentdesktop-signing.keychain-db
356+
run: pnpm --filter @agentdesktop/desktop-web dist:mac -- --target "${{ matrix.target }}"
357+
358+
- name: Stage PKG
359+
shell: bash
360+
env:
361+
TARGET: ${{ matrix.target }}
362+
ARCH: ${{ matrix.arch }}
363+
OUTPUT_NAME: agentdesktop-macos-${{ matrix.arch }}.pkg
364+
run: |
365+
source_path="target/${TARGET}/release/bundle/pkg/Agent Desktop_${AGENTDESKTOP_VERSION}_${ARCH}.pkg"
366+
test -f "${source_path}"
367+
mkdir -p release
368+
cp "${source_path}" "release/${OUTPUT_NAME}"
369+
370+
# Production notarization placeholder: notarize and staple the signed
371+
# package here, before calculating its checksum or smoke-testing it.
372+
# - name: Notarize and staple PKG
373+
# shell: bash
374+
# env:
375+
# OUTPUT_NAME: agentdesktop-macos-${{ matrix.arch }}.pkg
376+
# APPLE_ID: ${{ secrets.APPLE_ID }}
377+
# APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
378+
# APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
379+
# run: |
380+
# xcrun notarytool submit "release/${OUTPUT_NAME}" \
381+
# --apple-id "${APPLE_ID}" \
382+
# --password "${APPLE_APP_SPECIFIC_PASSWORD}" \
383+
# --team-id "${APPLE_TEAM_ID}" \
384+
# --wait
385+
# xcrun stapler staple "release/${OUTPUT_NAME}"
386+
387+
- name: Checksum PKG
388+
shell: bash
389+
env:
390+
OUTPUT_NAME: agentdesktop-macos-${{ matrix.arch }}.pkg
391+
run: |
392+
(cd release && shasum -a 256 "${OUTPUT_NAME}" > "${OUTPUT_NAME}.sha256")
393+
394+
- name: Smoke test PKG
395+
shell: bash
396+
env:
397+
OUTPUT_NAME: agentdesktop-macos-${{ matrix.arch }}.pkg
398+
run: |
399+
sudo installer -pkg "release/${OUTPUT_NAME}" -target /
400+
sudo launchctl print system/dev.agentdesktop.daemon > /dev/null
401+
deadline=$((SECONDS + 30))
402+
until sudo "/Applications/agentdesktop.app/Contents/MacOS/agentdesktop" status; do
403+
if (( SECONDS >= deadline )); then
404+
echo "Installed CLI could not reach the Agent Desktop daemon" >&2
405+
exit 1
406+
fi
407+
sleep 1
408+
done
409+
410+
- name: Remove smoke-test installation
411+
if: always()
412+
shell: bash
413+
run: |
414+
sudo launchctl bootout system/dev.agentdesktop.daemon || true
415+
sudo rm -f /Library/LaunchDaemons/dev.agentdesktop.daemon.plist
416+
sudo rm -rf "/Applications/agentdesktop.app"
417+
sudo rm -rf /etc/agentdesktop /var/lib/agentdesktop /var/run/agentdesktop
418+
sudo pkgutil --forget dev.agentdesktop.installer || true
419+
420+
- name: Upload unsigned PKG
421+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
422+
with:
423+
name: unsigned-macos-installer-${{ matrix.arch }}
424+
path: release/agentdesktop-macos-*
425+
if-no-files-found: error
426+
294427
build-windows-installers:
295428
needs: setup
296429
runs-on: ${{ matrix.runner }}
@@ -337,7 +470,7 @@ jobs:
337470
shell: bash
338471
run: pnpm --filter @agentdesktop/desktop-web dist:win -- --target "${{ matrix.target }}"
339472

340-
- name: Stage MSI and checksum
473+
- name: Stage MSI
341474
shell: pwsh
342475
env:
343476
TARGET: ${{ matrix.target }}
@@ -349,6 +482,24 @@ jobs:
349482
}
350483
New-Item -ItemType Directory -Force release | Out-Null
351484
Copy-Item $installers[0].FullName "release/$env:OUTPUT_NAME"
485+
486+
# Production signing placeholder: sign the staged MSI here with the
487+
# selected Authenticode provider before checksumming or smoke-testing it.
488+
# - name: Sign MSI
489+
# shell: pwsh
490+
# env:
491+
# AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
492+
# AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
493+
# AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
494+
# OUTPUT_NAME: agentdesktop-windows-${{ matrix.arch }}.msi
495+
# run: |
496+
# # Invoke Azure Artifact Signing or signtool for release/$env:OUTPUT_NAME here.
497+
498+
- name: Checksum MSI
499+
shell: pwsh
500+
env:
501+
OUTPUT_NAME: agentdesktop-windows-${{ matrix.arch }}.msi
502+
run: |
352503
$hash = (Get-FileHash "release/$env:OUTPUT_NAME" -Algorithm SHA256).Hash.ToLowerInvariant()
353504
"$hash $env:OUTPUT_NAME" | Set-Content "release/$env:OUTPUT_NAME.sha256" -Encoding ascii
354505
@@ -397,6 +548,7 @@ jobs:
397548
- push-controller-image
398549
- push-helm-chart
399550
- build-binaries
551+
- build-macos-installers
400552
- build-windows-installers
401553
runs-on: ubuntu-24.04
402554
permissions:

‎Cargo.lock‎

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/agentdesktop/Cargo.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ serde_json.workspace = true
2525
tauri = { version = "2", features = ["image-png", "tray-icon"] }
2626
tauri-plugin-single-instance = "2"
2727
tokio.workspace = true
28+
29+
[target.'cfg(target_os = "macos")'.dependencies]
30+
libc.workspace = true
31+
plist = "1.10"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<array>
5+
<dict>
6+
<key>BundleHasStrictIdentifier</key>
7+
<true/>
8+
<key>BundleIsRelocatable</key>
9+
<false/>
10+
<key>BundleIsVersionChecked</key>
11+
<true/>
12+
<key>BundleOverwriteAction</key>
13+
<string>upgrade</string>
14+
<key>RootRelativeBundlePath</key>
15+
<string>Applications/agentdesktop.app</string>
16+
</dict>
17+
</array>
18+
</plist>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>Label</key>
6+
<string>dev.agentdesktop.daemon</string>
7+
<key>ProgramArguments</key>
8+
<array>
9+
<string>/Applications/agentdesktop.app/Contents/MacOS/agentdesktop</string>
10+
<string>daemon</string>
11+
<string>--config</string>
12+
<string>/etc/agentdesktop/config.yaml</string>
13+
<string>--state-dir</string>
14+
<string>/var/lib/agentdesktop</string>
15+
</array>
16+
<key>RunAtLoad</key>
17+
<true/>
18+
<key>KeepAlive</key>
19+
<true/>
20+
<key>ProcessType</key>
21+
<string>Background</string>
22+
<key>ThrottleInterval</key>
23+
<integer>10</integer>
24+
<key>WorkingDirectory</key>
25+
<string>/var/lib/agentdesktop</string>
26+
</dict>
27+
</plist>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
LABEL="dev.agentdesktop.daemon"
5+
USER_LAUNCH_AGENT_LABEL="dev.agentdesktop.daemon.user"
6+
GROUP_NAME="agentdesktop"
7+
PLIST_PATH="/Library/LaunchDaemons/${LABEL}.plist"
8+
CONFIG_DIRECTORY="/etc/agentdesktop"
9+
CONFIG_PATH="${CONFIG_DIRECTORY}/config.yaml"
10+
STATE_DIRECTORY="/var/lib/agentdesktop"
11+
12+
add_user_to_group() {
13+
username="$1"
14+
if ! /usr/sbin/dseditgroup -q -o edit -n . -a "${username}" -t user "${GROUP_NAME}"; then
15+
echo "warning: could not add ${username} to ${GROUP_NAME}" >&2
16+
fi
17+
}
18+
19+
remove_user_launch_agent() {
20+
username="$1"
21+
uid=$(/usr/bin/id -u "${username}" 2>/dev/null || true)
22+
if [ -n "${uid}" ]; then
23+
/bin/launchctl bootout "gui/${uid}/${USER_LAUNCH_AGENT_LABEL}" >/dev/null 2>&1 || true
24+
fi
25+
home_directory=$(/usr/bin/dscl . -read "/Users/${username}" NFSHomeDirectory 2>/dev/null |
26+
/usr/bin/cut -d ' ' -f 2- || true)
27+
if [ -n "${home_directory}" ]; then
28+
/bin/rm -f "${home_directory}/Library/LaunchAgents/${USER_LAUNCH_AGENT_LABEL}.plist"
29+
fi
30+
}
31+
32+
if ! /usr/sbin/dseditgroup -q -o read -n . "${GROUP_NAME}" >/dev/null 2>&1; then
33+
/usr/sbin/dseditgroup -q -o create -n . \
34+
-r "Agent Desktop local API users" "${GROUP_NAME}"
35+
fi
36+
37+
/usr/bin/dscl . -list /Users UniqueID | /usr/bin/awk '$2 >= 500 && $2 < 65534 { print $1 }' |
38+
while IFS= read -r username; do
39+
remove_user_launch_agent "${username}"
40+
add_user_to_group "${username}"
41+
done
42+
43+
console_user=$(/usr/bin/stat -f "%Su" /dev/console)
44+
case "${console_user}" in
45+
"" | root | loginwindow | _mbsetupuser) ;;
46+
*)
47+
remove_user_launch_agent "${console_user}"
48+
add_user_to_group "${console_user}"
49+
;;
50+
esac
51+
52+
/usr/bin/install -d -o root -g wheel -m 0755 "${CONFIG_DIRECTORY}"
53+
if [ -e "${CONFIG_PATH}" ] && [ ! -f "${CONFIG_PATH}" ]; then
54+
echo "refusing to replace non-file configuration at ${CONFIG_PATH}" >&2
55+
exit 1
56+
fi
57+
if [ ! -e "${CONFIG_PATH}" ]; then
58+
umask 077
59+
printf '{}\n' >"${CONFIG_PATH}"
60+
fi
61+
/usr/sbin/chown root:wheel "${CONFIG_PATH}"
62+
/bin/chmod 0600 "${CONFIG_PATH}"
63+
64+
/usr/bin/install -d -o root -g wheel -m 0700 "${STATE_DIRECTORY}"
65+
/usr/sbin/chown root:wheel "${PLIST_PATH}"
66+
/bin/chmod 0644 "${PLIST_PATH}"
67+
68+
/bin/launchctl bootout "system/${LABEL}" >/dev/null 2>&1 || true
69+
/bin/launchctl bootstrap system "${PLIST_PATH}"
70+
/bin/launchctl enable "system/${LABEL}"
71+
/bin/launchctl kickstart -k "system/${LABEL}"
72+
73+
exit 0
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
LABEL="dev.agentdesktop.daemon"
5+
LEGACY_APPLICATION="/Applications/Agent Desktop.app"
6+
7+
/bin/launchctl bootout "system/${LABEL}" >/dev/null 2>&1 || true
8+
9+
if [ -d "${LEGACY_APPLICATION}" ]; then
10+
legacy_identifier=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" \
11+
"${LEGACY_APPLICATION}/Contents/Info.plist" 2>/dev/null || true)
12+
if [ "${legacy_identifier}" = "dev.agentdesktop.tray" ]; then
13+
/bin/rm -rf "${LEGACY_APPLICATION}"
14+
fi
15+
fi
16+
17+
exit 0

0 commit comments

Comments
 (0)