Skip to content

iOS Simulator: sandboxed helper, Desktop zero-copy view, macOS test fixes - #139

Merged
shaohaozhi286 merged 10 commits into
masterfrom
claude/ios-simulator-hardening
Oct 16, 2026
Merged

shaohaozhi286 merged 10 commits into
masterfrom
claude/ios-simulator-hardening

Conversation

@shaohaozhi286

@shaohaozhi286 shaohaozhi286 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Finishes the iOS Simulator follow-ups and the macOS-only test failures found during v1.0.8.

What changes

  • Sandboxed helper. acecode-ios-sim now runs under an ACECode-authored Seatbelt profile (helper_sandbox.cpp, every path passed as a sandbox-exec -D parameter):
    • No IP networking.
    • No reading file contents under /Users, /Volumes or home, except the helper bundle, the selected Xcode, simulator data/logs and the simulator preference files.
    • Writes only to simulator data/logs and the temp/cache folders.
    • If sandbox-exec cannot apply the profile, the helper runs unconfined and status/Settings say why. ACECODE_IOS_SIM_SANDBOX=0 turns it off for diagnosis.
  • Zero-copy simulator view in ACECode Desktop (macOS).
    • The simulator's IOSurface is set as the contents of a click-through layer over the panel, so there is no readback, no JPEG encoding, and no Intel animation stall.
    • Desktop loads only the system CoreSimulator, through a new acecode_ios_sim_native static library shared with the helper. It never loads code from the web-supplied developer directory.
    • The panel switches the JPEG stream off with a new WebSocket {type:"frames"} message, or ?frames=0, and falls back automatically. Input still goes through the panel.
  • DTUHID, verified on Xcode 27. The dtuhidd message builders moved to the header-only dtuhid_messages.hpp, shared by the helper and unit tests. A new opt-in ios-simulator-live workflow runs scripts/ios_simulator/live_check.py on GitHub's xcode-27 runner. It builds the helper with clang++, boots a simulator and checks through the accessibility tree that input really takes effect.
    • Result: 16/16 on Xcode 27.0, iOS 27.0, CoreSimulator 1174.15, using the dtuhid transport. Taps, drags, typing and Home all work, as do orientation, the stream, the sandbox and the native view.
  • Orientation on Xcode 27 (found by the live run).
    • The CoreDevice reply format is now confirmed: displays[].currentOrientation = rotN.
    • Unknown values no longer read as portrait.
    • The provider connection is kept per device, and lookups refresh in the background instead of blocking input.
    • A timeout keeps the last good rotation.
    • The daemon allows 90 s for a cold first describe.
  • Version. Bumped to 1.0.9 (CMakeLists.txt, vcpkg.json).
  • Remote Web on macOS (bug fix). The proxy bound its upstream to 127.0.0.2, which macOS does not assign, so every proxied connection failed. It now falls back to a local non-loopback IPv4, which the daemon still treats as token-required.
  • macOS test fixes.
    • Concurrent claim workers use posix_spawn, because macOS serializes system().
    • The Crow shutdown test destroys the app.
    • The sandbox-policy test avoids autofs /home.
    • Browser-tool expectations now include macOS.
    • The settings label shrinks the value text instead of the label.
    • Fixed a dangling pointer in the channel log test.

Verification (Intel Mac, Xcode 26.6 green install, iOS 26.5)

  • Full unit suite: 6326 passed, 0 failed (previously 11 failures plus a crash on macOS).

  • Web: pnpm test (3215 passed), pnpm build, i18n catalog regenerated. All CI lint checks clean.

  • Every helper operation runs under the sandbox; the same profile refuses home reads, network access and home writes. IosSimulatorE2E.* passes and asserts the helper is sandboxed.

  • Native view:

    • An offscreen CARenderer render confirmed orientation and rotation direction.
    • The opt-in ios_simulator_view_mac_smoke passes on a booted simulator, checking IOSurface contents, geometry, mask, click-through, hide/show, unmount and the unknown-device error.
    • The panel was tested in a browser with a stubbed bridge: frames off/on, late socket, input mapping, fallback and unmount.
  • The WebSocket frames toggle was checked live against a daemon.

  • Xcode 27 live check (ios-simulator-live, xcode-27 runner): 16/16 passed, as listed above.

Not verified

  • Landscape orientation on Xcode 27: a simulator can't be rotated from CI. The rotN parse shares code with rot0, and older runtimes were verified in landscape locally.
  • The native view inside the full Desktop app. This session has no Screen Recording permission; the smoke test, offscreen render and stubbed-bridge test cover it.

🤖 Generated with Claude Code

haozhi shao and others added 10 commits October 16, 2026 12:55
…ixes

Sandbox the acecode-ios-sim helper with an ACECode-authored Seatbelt
profile (no IP networking, no reading personal files, writes only to
simulator data and temp folders). CFBundle must be able to list the
helper's ancestor directories and the profile follows the user-record
home, as CoreSimulator does. When sandbox-exec cannot apply the profile
the helper runs unconfined and status/settings say why.

Draw the simulator in ACECode Desktop on macOS natively: the simulator's
IOSurface becomes the contents of a click-through layer over the panel,
so frames skip readback and JPEG encoding. Desktop loads only the system
CoreSimulator through a static library shared with the helper. The panel
stops the JPEG stream with a new WebSocket frames message while the
native view renders and falls back when it cannot.

Move the dtuhidd message builders into a header shared by the helper and
unit tests. Live verification on Xcode 27 is still outstanding.

Fix the macOS-only unit failures: the remote Web proxy could not bind its
127.0.0.2 source address on macOS (remote Web never worked on Macs), and
several tests depended on Linux/Windows behaviour (serialized system(),
Crow shutdown race, autofs /home, browser tools, label width, a dangling
pointer).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Builds the helper, the Seatbelt argv printer and the native view smoke
with clang++ and drives a booted simulator: touch, drag, keyboard and
button input checked through the accessibility tree, screenshots, the
JPEG stream, sandbox denials and the Desktop native view. GitHub's
xcode-27 image (CoreSimulator 1155.4+) exercises the dtuhidd transport.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Xcode 27's display-info reply (verified on the xcode-27 runner) carries
displays[].currentOrientation = rot0/rot90/rot180/rot270. Anything else
now counts as no answer and falls back to Simulator.app's orientation,
and a provider that timed out is retried every 5 s instead of blocking
input for 2 s every 600 ms. The live check retries typing once when the
first tap only stopped a coasting list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a busy Mac the CoreDevice provider often misses a 2 s window, mostly
because every lookup opened a new guest connection. The connection is now
kept per device, the first lookup answers synchronously (5 s), later
lookups return the last answer at once and refresh in the background, and
a timed-out refresh keeps the last good rotation instead of dropping to
Simulator.app's window orientation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shaohaozhi286
shaohaozhi286 merged commit cf442ef into master Oct 16, 2026
4 checks passed
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