fix(appstore): drop winit's private blur call that App Review refused

- App Review's automated check rejected the first submission for importing the private `CGSSetWindowBackgroundBlurRadius`. winit's macOS backend calls it for window blur, and the import stays in the binary although no window here asks for blur.
- Every winit crate is now patched to grmrgecko/winit, which is libcosmic's pinned revision with the private calls removed and blur doing nothing on macOS. The fork has to move whenever the libcosmic revision does.
- The App Store bundle is no longer signed when either executable imports a private window server symbol, so a dependency update cannot bring one back unnoticed.
- The `com.apple.security.network.server` entitlement, which the same check questioned, stays: network ports bind UDP and take incoming sessions. R-110 records the answer given to App Review.
This commit is contained in:
James Coleman 2026-10-03 09:39:12 -05:00
parent f250678dd6
commit 9eede3b366
6 changed files with 82 additions and 14 deletions

24
Cargo.lock generated
View file

@ -1882,7 +1882,7 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]] [[package]]
name = "dpi" name = "dpi"
version = "0.1.2" version = "0.1.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
[[package]] [[package]]
name = "drm" name = "drm"
@ -7793,7 +7793,7 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]] [[package]]
name = "winit" name = "winit"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"cfg_aliases", "cfg_aliases",
@ -7819,7 +7819,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-android" name = "winit-android"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"android-activity", "android-activity",
"bitflags 2.13.2", "bitflags 2.13.2",
@ -7834,7 +7834,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-appkit" name = "winit-appkit"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"block2 0.6.2", "block2 0.6.2",
@ -7856,7 +7856,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-common" name = "winit-common"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"memmap2 0.9.11", "memmap2 0.9.11",
"objc2 0.6.4", "objc2 0.6.4",
@ -7871,7 +7871,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-core" name = "winit-core"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"cursor-icon", "cursor-icon",
@ -7885,7 +7885,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-orbital" name = "winit-orbital"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"dpi", "dpi",
@ -7901,7 +7901,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-uikit" name = "winit-uikit"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"block2 0.6.2", "block2 0.6.2",
@ -7921,7 +7921,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-wayland" name = "winit-wayland"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"ahash", "ahash",
"bitflags 2.13.2", "bitflags 2.13.2",
@ -7947,7 +7947,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-web" name = "winit-web"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"atomic-waker", "atomic-waker",
"bitflags 2.13.2", "bitflags 2.13.2",
@ -7969,7 +7969,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-win32" name = "winit-win32"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"cursor-icon", "cursor-icon",
@ -7985,7 +7985,7 @@ dependencies = [
[[package]] [[package]]
name = "winit-x11" name = "winit-x11"
version = "0.31.0-beta.2" version = "0.31.0-beta.2"
source = "git+https://github.com/pop-os/winit.git?rev=9567503#9567503d34130113e36b0167a2b8829c3756e429" source = "git+https://github.com/grmrgecko/winit?rev=2b36ab9e35cdf59916d1ceef1b49fc8169266ae8#2b36ab9e35cdf59916d1ceef1b49fc8169266ae8"
dependencies = [ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"bytemuck", "bytemuck",

View file

@ -135,6 +135,23 @@ integer_division = "warn"
[patch.crates-io] [patch.crates-io]
btleplug = { git = "https://github.com/grmrgecko/btleplug", rev = "3a9da4bd65697593d127c124cf332b835d240802" } btleplug = { git = "https://github.com/grmrgecko/btleplug", rev = "3a9da4bd65697593d127c124cf332b835d240802" }
# winit's macOS backend imports the private CGSSetWindowBackgroundBlurRadius for window blur, which
# the Mac App Store rejects in any binary that links it (research R-110). The fork is libcosmic's
# pinned revision with that call removed. Every winit crate is listed so that all of them come from
# one source; move the fork along with the libcosmic revision in crates/gui/Cargo.toml.
[patch."https://github.com/pop-os/winit.git"]
winit = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-android = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-appkit = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-common = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-core = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-orbital = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-uikit = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-wayland = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-web = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-win32 = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
winit-x11 = { git = "https://github.com/grmrgecko/winit", rev = "2b36ab9e35cdf59916d1ceef1b49fc8169266ae8" }
# Dependencies build without debug info in dev and test builds. Each of the workspace's test # Dependencies build without debug info in dev and test builds. Each of the workspace's test
# binaries otherwise links libcosmic's debug info, which made relinking after a one-line change # binaries otherwise links libcosmic's debug info, which made relinking after a one-line change
# take about two minutes on the development Mac instead of about ten seconds. The workspace's own # take about two minutes on the development Mac instead of about ten seconds. The workspace's own

View file

@ -102,6 +102,16 @@ if [ -n "$helper" ]; then
identity=${MIDI_HARBOR_SIGNING_IDENTITY:--} identity=${MIDI_HARBOR_SIGNING_IDENTITY:--}
fi fi
# Refuse private window server calls: App Review rejects a binary that so much as imports
# one, and a dependency's macOS backend brought one in before (research R-110).
for executable in midi-harbor midi-harbor-daemon; do
private=$(nm -u -arch all "$app/Contents/MacOS/$executable" | grep '_CGS[A-Z]' | sort -u)
if [ -n "$private" ]; then
echo "$executable imports private APIs the App Store rejects:" $private >&2
exit 1
fi
done
# Sign, with no extended attributes: App Store Connect refuses a package holding a file # Sign, with no extended attributes: App Store Connect refuses a package holding a file
# marked with com.apple.quarantine, as a downloaded profile is (research R-103). # marked with com.apple.quarantine, as a downloaded profile is (research R-103).
xattr -cr "$app" xattr -cr "$app"

View file

@ -57,3 +57,43 @@ quarantine.
**Not checked**: an upload after the quarantine fix; the expanded package carries no attribute but **Not checked**: an upload after the quarantine fix; the expanded package carries no attribute but
`com.apple.provenance`. `com.apple.provenance`.
---
## R-110: What App Review's automated check refused
**Status**: **VERIFIED** (2026-10-03) locally; resubmitted the same day, verdict pending. Built as T255.
The first submission came back with two automated messages before any person reviewed it.
**The private API was winit's.** The check named `_CGSSetWindowBackgroundBlurRadius`. Nothing in
this project calls it: winit's macOS backend does, in `set_blur`, with `CGSMainConnectionID`
beside it, and libcosmic's iced pins `pop-os/winit` at `9567503`. No window here asks for blur,
but the linker keeps the import whether or not the call is reached, and the check reads imports.
winit 0.30.13 and the fork's other revisions in the cargo cache carry the same call, so no
update removes it.
**Decision**: `grmrgecko/winit`, branch `no-private-blur`, is `9567503` with the two declarations
removed and `set_blur` doing nothing on macOS. The root `Cargo.toml` patches every winit crate to
it, since patching `winit-appkit` alone would leave two copies of `winit-core`. It moves with the
libcosmic revision. The direct-download build takes the same patch, having no use for blur
either. `bundle.sh` now refuses to sign an App Store bundle whose executables import any `_CGS`
followed by a capital, the prefix of the window server's private calls; the public
`CGShieldingWindowLevel` does not match.
**The server entitlement stays.** The second message said `com.apple.security.network.server` had
no matching functionality. It has: each network port binds UDP ports and takes session
invitations from other machines (R-097). The helper does the listening and carries only the
sandbox and inherit, which is the likely reason the check saw none, though Apple does not say.
The answer is a reply and a note in App Review Information describing RTP-MIDI and how to see a
port from Audio MIDI Setup on another Mac, not a change to the build.
**Evidence**, `make appstore` on the development Mac:
- Before, `nm -u` on the full binary listed `_CGSMainConnectionID` and
`_CGSSetWindowBackgroundBlurRadius` for both architectures; the headless binary listed neither.
- After, `nm -u -arch arm64` and `-arch x86_64` list no `_CGS` private symbol in either
executable, and `strings` finds no `CGSSetWindowBackgroundBlurRadius` in the app.
- `codesign --verify --deep --strict` passes on the bundle.
**Not checked**: App Review's verdict on the rebuilt package, and its answer to the reply.

View file

@ -3,3 +3,4 @@
Tasks by their numbers in the project-wide sequence, which continues across every spec. Tasks by their numbers in the project-wide sequence, which continues across every spec.
- [x] T245 Build the App Store package with `make appstore`, per FR-S01 to FR-S03 — done: with `.signing/app-store.provisionprofile`, `bundle.sh --helper` embeds the profile, adds its App ID and team to the app's entitlements after checking the App ID is the bundle's, signs both executables with the keychain's Apple Distribution identity, sets the build number to the time in UTC and `ITSAppUsesNonExemptEncryption` to false, and wraps the app in a package signed with Mac Installer Distribution; without a profile it builds as before. Checked on the owner's Mac (R-103); not unit tested, since it is a build script. - [x] T245 Build the App Store package with `make appstore`, per FR-S01 to FR-S03 — done: with `.signing/app-store.provisionprofile`, `bundle.sh --helper` embeds the profile, adds its App ID and team to the app's entitlements after checking the App ID is the bundle's, signs both executables with the keychain's Apple Distribution identity, sets the build number to the time in UTC and `ITSAppUsesNonExemptEncryption` to false, and wraps the app in a package signed with Mac Installer Distribution; without a profile it builds as before. Checked on the owner's Mac (R-103); not unit tested, since it is a build script.
- [x] T255 Remove what App Review's automated check refused (R-110) — done: every winit crate is patched to `grmrgecko/winit`, which drops the private `CGSSetWindowBackgroundBlurRadius` call, and `bundle.sh` refuses an App Store bundle whose executables import a private window server symbol. Checked with `nm -u` on both architectures of both executables; not unit tested, since it is a dependency patch and a build script. The server entitlement is kept and answered in App Review Information.

View file

@ -137,8 +137,8 @@ exception is 014, whose task list started again at T001: its T001 to T034 are ci
- **Requirements**: FR-S01, FR-S02, FR-S03 - **Requirements**: FR-S01, FR-S02, FR-S03
- **Success criteria**: SC-S01 - **Success criteria**: SC-S01
- **Research**: R-103 - **Research**: R-103, R-110
- **Tasks**: T245 - **Tasks**: T245, T255
### 017-appimage ### 017-appimage