Repository navigation
pi/hitl: Mac mini iOS+C6 HITL bench — darwin runner, headless signing, sshd lockout fix - #189
Merged
Merged
Conversation
Contributor
|
…, sshd fix
Stands up the reservation daemon on a Mac mini for the iOS+C6 bench (Phase D):
a nix-darwin module (hitl-darwin.nix) that adds a launchd `hitl-reserved --runner
darwin` on :8087, a scoped sshd user, and the iOS toolbox — no container; each
reservation is a scoped SSH grant into the shared `hitl` user, driving the iPhone
(devicectl/usbmux) and the C6 (esptool over /dev/cu.usbmodem*) host-native.
* Pin hitl-reserve -> 085532e5 (hitl-reserve#7, the --runner darwin backend) in
both consumers: MODULE.bazel (@hitl_reserve) + pi/hitl/flake.nix (+ flake.lock).
* hitl-darwin.nix: the additive module. CRITICAL sshd fix — PermitUserEnvironment
is GLOBAL, not inside the Match block: sshd rejects that directive within a
Match and then fails to parse the whole config, dropping every connection
before the banner (a full ssh lockout). It's the one directive that can't be
scoped; validated with `sshd -t`. Documents the headless code-signing secret
seam (HITL_SIGN_* dedicated keychain + HITL_ASC_* App Store Connect API key,
injected via the daemon user's root-owned ~/.ssh/environment, never in-repo).
* catalog-mac.json: one ios-phone unit (iPhone + its own C6), hardware filled
from the live Mac (C6 port /dev/cu.usbmodem*, iPhone UDID); the sim/second-C6
unit dropped until a second C6 is attached.
* ios_build_server.py device-build: gated preamble unlocks the dedicated signing
keychain (HITL_SIGN_*) and, for a paid team, passes the App Store Connect API
key (HITL_ASC_*) to xcodebuild -allowProvisioningUpdates so the dev cert +
provisioning profile are created/renewed FULLY HEADLESS. No-op for local GUI
dev (vars unset).
Verified on the live Mac: nix-darwin system builds; daemon advertises the
ios-phone unit on :8087; the C6 flashes host-native (esptool flash_id);
end-to-end signed device build SUCCEEDS via the ASC API key (dev profile
auto-created + iPhone registered). Remaining for a green on-device journey is the
phone staying unlocked (DDI mount) — tracked separately; the harness path is proven.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fughilli
force-pushed
the
claude/mac-ios-bench-deploy
branch
from
September 25, 2026 03:35
8530762 to
9fe0359
Compare
This was referenced Sep 25, 2026
fughilli
pushed a commit
that referenced
this pull request
Oct 3, 2026
…discovery The Mac iOS bench (#189) stood up the reservation daemon, signing and a bare app install, but the app-driver JOURNEY lane could not actually run on a real iPhone: a native Capacitor WKWebView loads the bundled web/dist at capacitor://localhost/ with no query string, so the `?driver=…&ble=real` seam (web/src/ui/app/main.ts) — which starts the journeys — was unreachable. And the iOS client posted to a build server that doesn't exist (:8765 /device-*?url=) instead of the real tools/ios_build_server.py (:8099 /run?task=…). Drive the iPhone the SAME way as Android by pointing Capacitor's server.url at the station-served app URL (which carries the query) so the WKWebView loads it over the LAN and enters driver mode; native BLE keeps bridging through the Capacitor Improv plugin. - web/capacitor.config.ts: set server.url from CAP_SERVER_URL when present (unset = load the bundle, as before). - tools/ios_build_server.py: accept a `server_url` param on /run and pass it as CAP_SERVER_URL into the task env so `cap sync` bakes it (env only, never argv; validated to an http(s) URL). - pi/hitl/phone/phone_target.py: IosBuildClient now hits the real /run?task= endpoint on :8099; the iOS targets thread the app URL through server_url on a cap-sync→build→install→launch chain (not a devicectl launch url=, which can't open a URL on a real device). Default bundle id fixed to dev.splanc.app. - pi/hitl/phone/launcher.py: serve the app on 0.0.0.0 so an off-box phone can fetch it (+ SO_REUSEADDR); the returned base stays loopback for the browser lane. - web/ios-config/apply.sh: NSAllowsLocalNetworking so ATS permits cleartext to the LAN station + device (narrower than arbitrary loads; App-Store-acceptable). Dynamic C6 serial-port discovery (owner requirement — never hardcode the renumbering /dev/cu.usbmodem*): pi/hitl/harness/serial_discovery.py resolves the port from the stable USB identity (Espressif VID 0x303a), matching the reserved board by its HITL_ADAPTER_SERIAL when several C6s are attached. Reusable on the Mac bench and the Linux rigs; a py_binary CLI prints the path for `esptool --port "$(…)"`. Pure selection logic is dependency-injected and unit-tested without pyserial/hardware. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stands up the reservation daemon on a Mac mini for the iOS+C6 bench (Phase D). Rebuilt clean off current main (the WiFi fix #190 + screen-off #191 that this branch previously overlapped are already merged).
085532e5(hitl-reserve#7, the--runner darwinbackend) in both consumers:MODULE.bazel+pi/hitl/flake.nix(+flake.lock, re-locked via nix).hitl-darwin.nix— the additive nix-darwin module (launchdhitl-reserved --runner darwinon :8087, scoped sshd user, iOS toolbox). CRITICAL sshd fix:PermitUserEnvironmentis now GLOBAL, not inside theMatchblock — sshd rejects it within a Match and then fails to parse the whole config, dropping every connection before the banner (a full ssh lockout). Validated withsshd -t. Documents the headless code-signing secret seam (HITL_SIGN_*dedicated keychain +HITL_ASC_*App Store Connect API key, injected via the daemon user's root-owned~/.ssh/environment, never in-repo).catalog-mac.json— oneios-phoneunit (iPhone + its own C6), filled from the live Mac.ios_build_server.pydevice-build — gated preamble unlocks the dedicated signing keychain and, for a paid team, passes the ASC API key toxcodebuild -allowProvisioningUpdatesso the dev cert + profile are created/renewed fully headless. No-op for local GUI dev.Verified live: nix-darwin system builds; daemon advertises
ios-phoneon :8087; C6 flashes host-native; end-to-end signed device build SUCCEEDS via the ASC API key (dev profile auto-created + iPhone registered). Remaining for a green on-device journey is the phone staying unlocked (DDI mount) — the harness path is proven.HITL flake on the prior run was the usual netstack flake (video_stream/map_upload/led_capture 1/2), orthogonal to these Mac-only changes.
🤖 Generated with Claude Code