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
15 changes: 12 additions & 3 deletions .github/workflows/finalize-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,21 @@ jobs:
test "$(brew info --json=v2 DevVig/microbridge/microbridge | jq -r '.formulae[0].installed[0].version')" = "$VERSION"
microbridgectl help | grep -q Usage
APP="$HOME/Applications/Microbridge.app"
MARKER="$HOME/Applications/.Microbridge.app.microbridge-brew"
LEGACY_MARKER="$APP/.microbridge-brew"
test -x "$(brew --prefix DevVig/microbridge/microbridge)/bin/microbridged"
brew services start DevVig/microbridge/microbridge
for _ in {1..30}; do
[[ -f "$APP/.microbridge-brew" ]] && break
[[ -f "$MARKER" ]] && break
sleep 1
done
test -f "$APP/.microbridge-brew"
test -f "$MARKER"
test ! -e "$LEGACY_MARKER"
test "$(/usr/libexec/PlistBuddy -c 'Print:CFBundleShortVersionString' "$APP/Contents/Info.plist")" = "$VERSION"
codesign --verify --deep --strict --verbose=4 "$APP"
spctl --assess --type execute --verbose=4 "$APP"
xcrun stapler validate "$APP"
syspolicy_check distribution "$APP"
SERVICE_STATE=""
for _ in {1..30}; do
SERVICE_STATE="$(brew services list | awk '$1 == "microbridge" { print $2; exit }')"
Expand Down Expand Up @@ -92,9 +99,11 @@ jobs:
echo "microbridge service is still registered after uninstall" >&2
exit 1
fi
test -f "$APP/.microbridge-brew"
test -f "$MARKER"
rm -rf "$APP"
rm -f "$MARKER"
test ! -e "$APP"
test ! -e "$MARKER"

promote:
name: promote verified release
Expand Down
7 changes: 5 additions & 2 deletions Formula/microbridge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,18 @@ def install
source_app="#{opt_prefix}/Microbridge.app"
apps_dir="${HOME}/Applications"
dest="${apps_dir}/Microbridge.app"
marker="${dest}/.microbridge-brew"
marker="${apps_dir}/.Microbridge.app.microbridge-brew"
legacy_marker="${dest}/.microbridge-brew"
/bin/mkdir -p "${apps_dir}"
if [ -e "${dest}" ] && [ ! -f "${marker}" ]; then
if [ -e "${dest}" ] && [ ! -f "${marker}" ] && [ ! -f "${legacy_marker}" ]; then
echo "Microbridge: preserving unowned ${dest}" >&2
else
if [ -e "${dest}" ]; then
/bin/rm -rf "${dest}"
fi
/usr/bin/ditto "${source_app}" "${dest}"
# Keep ownership state beside the signed bundle. Adding any file to
# Microbridge.app invalidates its sealed code signature.
/usr/bin/touch "${marker}"
fi
exec "#{opt_bin}/microbridged"
Expand Down
24 changes: 16 additions & 8 deletions apps/microbridge-ui/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,11 +690,12 @@ fn resize_popover(app: AppHandle, height: f64) {
let _ = window.set_size(LogicalSize::new(POPOVER_WIDTH, clamped));
}

/// Install channel of the running app. Homebrew drops a `.microbridge-brew`
/// marker at the bundle root (installed by the formula's service wrapper); its absence
/// means a DMG/manual install. The in-app self-updater only replaces `direct`
/// installs — brew copies are routed to `brew upgrade` so the formula version
/// and the on-disk bundle never drift apart.
/// Install channel of the running app. Homebrew drops an ownership marker next
/// to the bundle (installed by the formula's service wrapper); its absence means
/// a DMG/manual install. The marker must stay outside `Microbridge.app`, because
/// adding a file to the bundle after signing invalidates its sealed signature.
/// The in-app self-updater only replaces `direct` installs — brew copies are
/// routed to `brew upgrade` so the formula version and bundle never drift apart.
#[tauri::command]
fn update_channel() -> String {
if brew_marker_present() {
Expand All @@ -704,15 +705,22 @@ fn update_channel() -> String {
}
}

/// True when the running bundle carries Homebrew's ownership marker.
/// True when the running bundle has Homebrew's ownership marker beside it.
/// `…/Microbridge.app/Contents/MacOS/microbridge-ui` → the bundle root is the
/// third ancestor of the executable.
/// third ancestor of the executable. The in-bundle check is migration support
/// for installs made before the sidecar marker was introduced.
fn brew_marker_present() -> bool {
let Ok(exe) = std::env::current_exe() else {
return false;
};
match exe.ancestors().nth(3) {
Some(bundle) => bundle.join(".microbridge-brew").exists(),
Some(bundle) => {
let sidecar = bundle
.parent()
.map(|parent| parent.join(".Microbridge.app.microbridge-brew"));
sidecar.is_some_and(|marker| marker.exists())
|| bundle.join(".microbridge-brew").exists()
}
None => false,
}
}
Expand Down
18 changes: 14 additions & 4 deletions scripts/smoke-formula.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ VERSION="${2:?usage: $0 path/to/microbridge.rb VERSION ARCH}"
EXPECTED_ARCH="${3:?usage: $0 path/to/microbridge.rb VERSION ARCH}"
TAP="devvig/microbridge-ci"
APP="$HOME/Applications/Microbridge.app"
MARKER="$HOME/Applications/.Microbridge.app.microbridge-brew"
LEGACY_MARKER="$APP/.microbridge-brew"
BREW_LOG="$(brew --prefix)/var/log/microbridge.log"
APP_LOG="${RUNNER_TEMP:-/tmp}/microbridge-app.log"

cleanup() {
brew services stop "$TAP/microbridge" >/dev/null 2>&1 || true
HOMEBREW_NO_INSTALL_CLEANUP=1 brew uninstall "$TAP/microbridge" >/dev/null 2>&1 || true
if [[ -f "$APP/.microbridge-brew" ]]; then
if [[ -f "$MARKER" || -f "$LEGACY_MARKER" ]]; then
rm -rf "$APP"
rm -f "$MARKER"
fi
brew untap "$TAP" >/dev/null 2>&1 || true
}
Expand Down Expand Up @@ -66,12 +69,17 @@ test -x "$PREFIX/bin/microbridgectl"

brew services start "$TAP/microbridge"
for _ in {1..30}; do
[[ -f "$APP/.microbridge-brew" ]] && break
[[ -f "$MARKER" ]] && break
sleep 1
done
test -d "$APP"
test -f "$APP/.microbridge-brew"
test -f "$MARKER"
test ! -e "$LEGACY_MARKER"
test "$(/usr/libexec/PlistBuddy -c 'Print:CFBundleShortVersionString' "$APP/Contents/Info.plist")" = "$VERSION"
codesign --verify --deep --strict --verbose=4 "$APP"
spctl --assess --type execute --verbose=4 "$APP"
xcrun stapler validate "$APP"
syspolicy_check distribution "$APP"

SERVICE_STATE=""
for _ in {1..30}; do
Expand All @@ -98,8 +106,10 @@ fi

# The app is deliberately outside the Cellar so the menu-bar UI survives
# formula upgrades. Remove it only after verifying this install's marker.
test -f "$APP/.microbridge-brew"
test -f "$MARKER"
rm -rf "$APP"
rm -f "$MARKER"
test ! -e "$APP"
test ! -e "$MARKER"
brew untap "$TAP"
trap - EXIT
Loading