Skip to content

fix(xpc): make MenuBarItemService work for ad-hoc-signed builds on macOS 26 - #950

Open
pdurlej wants to merge 2 commits into
jordanbaird:macos-26from
pdurlej:pr/xpc-isfromsameteam-guard
Open

pdurlej wants to merge 2 commits into
jordanbaird:macos-26from
pdurlej:pr/xpc-isfromsameteam-guard

Conversation

@pdurlej

@pdurlej pdurlej commented May 25, 2026

Copy link
Copy Markdown

What

Restores MenuBarItemService XPC connectivity for community ad-hoc-signed builds of Ice on macOS 26 Tahoe.

Why

On macOS 26, the new XPCSession.setPeerRequirement(.isFromSameTeam()) API silently rejects every peer when the calling process has no Team Identifier — which is the case for any ad-hoc-signed build (every community fork, every xcodebuild from source). The current Listener.swift and MenuBarItemServiceConnection.swift unconditionally apply this requirement, so:

  • The XPC listener is created but rejects the parent app's connection
  • The client Connection.sourcePID(...) always returns nil
  • MenuBarItemManager.uncheckedCacheItems logs Missing sourcePID for ... every few seconds
  • The Menu Bar Layout settings pane has no PIDs to render — shows empty rows / blank list

This is the upstream class causing:

Combined: ~130 reactions across the bug class.

How

Introduces a shared MenuBarItemService.ownTeamIdentifier() helper in Shared/Services/MenuBarItemService.swift that returns the running process's Team Identifier via SecStaticCode, or nil if the binary is ad-hoc-signed.

Both sides of the XPC handshake gate their .isFromSameTeam() enforcement on ownTeamIdentifier() != nil:

  • MenuBarItemService/Listener.swift — listener falls back to unrestricted activation when no Team ID is available
  • Ice/MenuBar/MenuBarItems/MenuBarItemServiceConnection.swift — client skips setPeerRequirement(.isFromSameTeam()) when no Team ID is available

Developer-ID-signed builds (App Store / future TestFlight / signed releases) keep strict same-team enforcement automatically — the helper returns the real Team ID and the requirement applies on both sides. Only community ad-hoc builds skip the requirement, which is the only configuration that can't satisfy it anyway.

Testing

Verified on:

  • macOS 26.5 Tahoe, MacBook Pro Apple Silicon
  • Ad-hoc-signed build (xcodebuild from source): Menu Bar Layout pane populates correctly, all three sections (Visible / Hidden / Always-Hidden) render menu bar items
  • Developer-ID-signed + Apple-notarized build: same behavior, strict same-team requirement still enforced (verified via codesign -dv showing both peers signed by same Team ID)

A working signed + notarized DMG that ships these commits is available for reviewers who want to test without rebuilding: https://github.com/pdurlej/Ice/releases/latest (same com.jordanbaird.Ice bundle ID, drop-in replacement).

Notes

This PR is offered in good faith to the upstream repo — the same fix has been deployed in a community fork (pdurlej/Ice, "Fire from Ice") since 2026-05-24 and confirmed working by multiple users on macOS 26.4–26.5. Happy to iterate on the patch shape if a different approach is preferred.

Closes (or contributes toward closing): #744, #891, #913, #846, #818, #832, #872.

pdurlej added 2 commits May 26, 2026 00:48
Upstream PR jordanbaird#903 introduced MenuBarItemService.xpc with this line:

    listener = try XPCListener(service: name,
                               requirement: .isFromSameTeam()) { ... }

`.isFromSameTeam()` requires the listener and every peer to be signed
with the same Apple Team Identifier. That works for builds Jordan
produces from his Developer ID Application certificate. It does NOT
work for any ad-hoc-signed build (TeamIdentifier = empty), because
empty-vs-empty is never treated as a match — the listener rejects
every check-in attempt with "Bogus check-in attempt. Ignoring." and
"Dropping check-in message due to code signing requirement".

The visible symptom is the Menu Bar Layout settings pane spinning
forever on "Loading menu bar items…" — XPC never returns, so Ice
never gets the cached item snapshots. This is the same class of bug
reported in upstream issues jordanbaird#744 (46 reactions) and jordanbaird#891 (30 react-
ions), and it bites every community fork that ships without an Apple
Developer Program account — which is roughly every community fork.

This commit reads the running process's actual Team Identifier via
SecCodeCopySigningInformation; if it's nil (ad-hoc / unsigned), we
fall through to the no-requirement activation path. If it's set
(properly Developer-ID-signed build), behaviour is unchanged — the
strict same-team requirement still applies.

For our fire fork:
  - 0.11.13-fire.0..fire.1 (ad-hoc, this branch's defaults) → fixed.
  - 0.11.13-fire.2+ once signed with our Developer ID → unchanged,
    still uses .isFromSameTeam() because we'll have a team ID.

Also bumps MARKETING_VERSION 0.11.13-fire.1 → 0.11.13-fire.2 and
CURRENT_PROJECT_VERSION 1123 → 1124 so Sparkle in installed fire.1
recognizes this as a newer build and offers the update.
Companion to the listener-side fix in the previous commit. The
XPCSession client (Ice/MenuBar/MenuBarItems/MenuBarItemServiceConnection.swift)
also defaults to .isFromSameTeam() peer requirement, which silently
rejects ad-hoc-signed builds the same way the listener did.

The refactor introduces MenuBarItemService.ownTeamIdentifier() in the
shared layer so both sides query exactly the same predicate. Developer-
ID-signed builds keep strict same-team enforcement; ad-hoc community
builds skip both requirements (Listener accepts, Client sends).
chenhaozjnubit added a commit to chenhaozjnubit/Ice that referenced this pull request Sep 16, 2026
- 记录上游 PR jordanbaird#980 的来源、校验值与机制说明
- 记录已合入的提交 42a2316 与分支状态
- 确认 Xcode 27 / MacOSX27.sdk 为硬性要求(ScreenCapture.swift 用了
  macOS 27 专有的 SCScreenshotConfiguration / captureScreenshot(rect:))
- 记录编译后仍需处理 ad-hoc 签名的 XPC 对端校验(PR jordanbaird#950)与权限重授
- 移除误提交的探针编译产物 probe-menubar,并加入 .gitignore
chenhaozjnubit added a commit to chenhaozjnubit/Ice that referenced this pull request Sep 16, 2026
上游 PR jordanbaird#950(作者 pdurlej,open 未合并)的同内容移植。

问题:`.isFromSameTeam()` 在**没有 Team ID** 的进程上会静默拒绝所有对端。
任何社区自建包(含本次 ad-hoc 签名的构建,`TeamIdentifier=not set`)都会中招:
Ice 拒绝自己的助手服务,助手反过来拒绝 Ice,
`MenuBarItemManager.uncheckedCacheItems` 每几秒记一次 "Missing sourcePID",
Menu Bar Layout 面板永远停在 "Loading menu bar items…"。
上游同类 issue:jordanbaird#744(46👍) jordanbaird#891(30👍) jordanbaird#913 jordanbaird#846(27👍) jordanbaird#818 jordanbaird#832。

做法:新增 `MenuBarItemService.ownTeamIdentifier()`(经 SecStaticCode 读自身
Team ID,unsigned / ad-hoc / 读不到时返回 nil),XPC 两端——
`MenuBarItemService/Listener.swift` 的 listener 侧与
`Ice/MenuBar/MenuBarItems/MenuBarItemServiceConnection.swift` 的 client 侧——
都改为**仅在确实拿到 Team ID 时**才施加 `.isFromSameTeam()` 要求,两端谓词完全一致。
chenhaozjnubit added a commit to chenhaozjnubit/Ice that referenced this pull request Sep 16, 2026
上游 PR jordanbaird#950(作者 pdurlej,open 未合并)的同内容移植。

问题:`.isFromSameTeam()` 在**没有 Team ID** 的进程上会静默拒绝所有对端。
任何社区自建包(含本次 ad-hoc 签名的构建,`TeamIdentifier=not set`)都会中招:
Ice 拒绝自己的助手服务,助手反过来拒绝 Ice,
`MenuBarItemManager.uncheckedCacheItems` 每几秒记一次 "Missing sourcePID",
Menu Bar Layout 面板永远停在 "Loading menu bar items…"。
上游同类 issue:jordanbaird#744(46👍) jordanbaird#891(30👍) jordanbaird#913 jordanbaird#846(27👍) jordanbaird#818 jordanbaird#832。

做法:新增 `MenuBarItemService.ownTeamIdentifier()`(经 SecStaticCode 读自身
Team ID,unsigned / ad-hoc / 读不到时返回 nil),XPC 两端——
`MenuBarItemService/Listener.swift` 的 listener 侧与
`Ice/MenuBar/MenuBarItems/MenuBarItemServiceConnection.swift` 的 client 侧——
都改为**仅在确实拿到 Team ID 时**才施加 `.isFromSameTeam()` 要求,两端谓词完全一致。
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.

1 participant