Native Swift/SwiftUI rewrite (1.0.0) - #13
Merged
Merged
Conversation
…ts, native usbmuxd/lockdown stack - ToolkitCore: OSLog categories, ToolkitError, central CommandRunner (argv-only, timeouts, cancellation, bounded output, minimal environment), secure file IO, sanitizer, operation journal, plist/JSON value types - DeviceKit: device models with plain-language field explanations, CoreDevice (devicectl JSON) client with actionable error interpretation, simctl client, usbmuxd client with event-driven Listen, lockdown client with TLS (swift-nio-ssl) and device-certificate pinning, DeviceSession with UDID identity verification - Tests: 51 tests including an end-to-end fake usbmuxd/lockdownd server
…e-insensitive filesystems
…tics, installation proxy, image mounter, misagent, SpringBoard, notifications, AFC, MobileBackup2 Each service is exercised end to end against the fake usbmuxd/lockdownd server, including path-traversal rejection in MobileBackup2 and clean end-of-stream handling. Adds CoreDevice/simctl parser fixtures and exact integer JSON values (ECIDs).
… Matrix, Evidence Capture, and external tool adapters Shared DeviceTestSupport target provides the fake usbmuxd/lockdownd device to all tests.
…le, compatibility history, and demo mode
…al-simulator end-to-end test
- Replace split views in Actions and Tool Reference with fixed list + flexible detail - Location Lab switches between two columns and one based on measured width - Pages and the sidebar list have zero ideal height so no page can grow the window (Live Logs previously forced 1207pt of content into a 700pt window) - Live Logs uses fixed single-line rows in a lazy stack with a bottom scroll anchor and a detail strip for the selected line - Demo Mode banner only when the demo device is selected; launch flags parsed as -flag YES|NO pairs - Simulators show their model identifier and host architecture - Screenshot harness: -populate-demo, -select-booted-simulator, -start-simulator-log, -only, -dump-views, overflow detection, hard timeout, plain sidebar while capturing - Replace Python-era screenshots with captures of the Swift app hideouts.io
- Actions › Packet capture: records com.apple.pcapd for a fixed time into a new .pcap file (native, no Xcode), reports packet count and SHA-256, keeps a valid partial file on failure. Restores the standalone pcap command the Python app had. - Tested end to end against the fake device, including refusal to overwrite. - Fix an unused-result warning in the Bonjour browser that only appeared on a clean build. - Treat Swift warnings as errors in the app and UI-test targets. hideouts.io
- README: capabilities, screenshots, requirements with a with/without-Xcode feature table, installation and verification, first steps, workspaces, confirmation levels, idt, security and privacy, troubleshooting, building from source, status and known limitations. - docs/: plain Markdown (architecture, safety, troubleshooting, release verification, physical-device test protocol) with an index; the mkdocs site, its stylesheet, requirements, workflow, and the superseded Python audit removed. - SECURITY, SUPPORT, CONTRIBUTING, SOURCE_AVAILABILITY, THIRD_PARTY_NOTICES (swift-nio, swift-nio-ssl/BoringSSL, swift-argument-parser and their dependencies; pymobiledevice3, PySide6, Nuitka, go-ios, ipsw removed), CITATION 1.0.0, issue and PR templates, CODEOWNERS, Dependabot (swift and github-actions). hideouts.io
…able
The summary row showed the full reason sentence in about 110 pt, so it was
always truncated ("The macOS devic…"). It now shows "Unavailable" and keeps
the full reason in the tooltip and the accessibility label. Verified by
rendering at 900x560 with discovery disabled.
hideouts.io
- CI (macos-26): swift build/test with warnings as errors and an idt smoke test; app build-for-testing, UI tests, and a layout check of every page at 1180x700 and 900x560; the opt-in real-simulator end-to-end test; and an unpublished release packaging run. - Release on v* tags: tests, then scripts/build-release.sh; checksums are re-verified, build provenance and the SPDX SBOM are attested, and the GitHub release is created. - CodeQL for Swift (manual build of the package and app); dependency review kept. The Python CI, frozen-bundle smoke, and per-architecture release workflows are removed. - scripts/build-release.sh: universal Release archive, idt in Contents/MacOS, dependency LICENSE/NOTICE files and the SBOM in Contents/Resources/Licenses, ad-hoc signing with the hardened runtime, verification (signature, runtime flag, both architectures, versions, no Python), ditto ZIP, SHA256SUMS, and re-verification from the ZIP. - scripts/generate-sbom.swift: SPDX 2.3 from Package.resolved. - scripts/ci-select-xcode.sh: picks Xcode through DEVELOPER_DIR (no sudo). - scripts/check-layout.sh: the layout check used by CI and contributors. hideouts.io
- MIGRATION.md §2: every feature row now has a status (verified end to end, fake-device/recorded-output only pending hardware, replaced, not migrated); install, uninstall, and crash-report rows corrected to the mechanisms the code actually uses. - §5: test inventory (145 package tests, real-simulator end-to-end run, UI tests pending CI), GUI layout verification, release packaging, and an explicit "not tested on hardware" physical-device record. - §6: why Safari tab listing, Bluetooth HCI capture, DVT file listing, and iOS 16 developer-image mounting are not in 1.0, the alternatives investigated, and whether native implementations are possible; the remaining verification gaps and behaviour changes from 0.3.x. - Add a fake-device test for springboardservices, the one lockdown service client that had none. hideouts.io
The Swift app, idt, and their tests replace every Python component (MIGRATION.md §2; 145 package tests and the real-simulator end-to-end test pass). Removed: - ios_developer_toolkit/ (PySide6 app, pymobiledevice3 wrappers, go-ios and ipsw adapters) and python-tests/ - pyproject.toml, requirements/, packaging/, macos/, script/ - the Nuitka release script and Python verification/licensing scripts The logo and world map were already carried over byte-for-byte into the Swift targets. .gitignore drops Python, venv, Nuitka, and mkdocs entries and keeps the private device-data patterns. A case-insensitive search for go-ios|goios|blacktop|ipsw|pymobiledevice3| PySide|python now finds only migration history, the optional user-installed UFADE and MVT tools (which are Python programs themselves), and guards that keep the removed tools and Python out of the app. hideouts.io
…n CI The UI-test target was never compiled by a plain `xcodebuild build`, so 78 actor-isolation warnings (XCUIApplication is main-actor isolated) went unnoticed; Swift does not promote these to errors under SWIFT_TREAT_WARNINGS_AS_ERRORS. The test class is now @mainactor with async setUp/tearDown, and build-for-testing is warning-free. CI now also fails when the app/UI-test build log has any Swift warning outside dependency checkouts (checked against the old log: 78 hits; fixed: 0). hideouts.io
Without Xcode (verified with DEVELOPER_DIR pointing at the Command Line Tools), every route was reported as "The installed devicectl does not offer this command". The check now probes the developer tools first and reports "Xcode is not installed or not selected … Install Xcode and open it once" (or the tool's own failure when Xcode is present), skipping the 27 help invocations that cannot succeed. idt toolchain still exits 2. hideouts.io
Found while reviewing the unified log: - Default command display names (logged publicly) were the tool plus its first three arguments, so `simctl boot <UDID>` put a UDID in the public log. They now stop at the first argument that is not a plain subcommand word, so UDIDs, paths, URLs, options, and values never appear. - Error descriptions (which can contain file paths) in the process runner, usbmuxd listener, and evidence finalization are now private; the error kind stays public. - Operation titles (which can contain app and file names) are now private. hideouts.io
MIGRATION.md §5.5: fresh-clone build and tests (147 pass), clean Xcode build, every screen rendered, no Python required, idt devices/toolchain, real-simulator end-to-end test, no-Xcode / no-usbmuxd / no-device states, unified log review, default window size, README cross-check, and the fixes each check led to. Physical devices remain untested: none was connected. hideouts.io
The first local UI-test run (6 of 7 passed) failed testDemoActionsAreBlockedWithExplanation: the "action-<id>" identifier on a row container was copied onto the title, summary, and risk icon, so the click matched three elements, and VoiceOver read each row as three items. Rows are now one element with the action title as label, the risk (and availability) as value, and the summary as hint. The device header and Demo Mode banner combine their children for the same reason. Builds warning-free and the layout check passes; the UI-test re-run could not complete here because other apps' windows covered the test window. hideouts.io
All 7 XCUITest smoke tests now pass locally: 6 in the first run, and the Actions-row test (plus the two other tests touched by the accessibility fix) in the re-run. hideouts.io
hideouts.io
The Python app mounted developer images through pymobiledevice3; the Swift
app could only ask Xcode's devicectl to do it. This restores the capability
without pymobiledevice3, go-ios, or ipsw:
- DeviceKit/DeveloperImage:
- ImageMounter: full com.apple.mobile.mobile_image_mounter client
(LookupImage, CopyDevices, QueryNonce, QueryPersonalizationIdentifiers,
QueryPersonalizationManifest, ReceiveBytes upload, MountImage with trust
cache, UnmountImage for /System/Developer and /Developer) with error
classification into plain-language messages.
- DeveloperImageLibrary: Xcode's installed image
(/Library/Developer/DeveloperDiskImages/iOS_DDI), user folders (Xcode
Restore layout or flat Image.dmg layout), legacy DeveloperDiskImage.dmg +
.signature by exact iOS major.minor; build-identity selection by chip
and board; validated reads (regular files, size limits).
- ImagePersonalization: the Apple TSS request pymobiledevice3/Xcode send
(identifiers, nonce, trusted manifest entries, restore-request rules),
HTTPS transport behind a protocol, reply parsing with clear errors.
- DeveloperImageManager: device facts (iOS version, build, model,
architecture, chip, board, Developer Mode), a pure evaluator for the
states not required / mounted / available / personalization required /
missing / incompatible / blocked / failed, mount (no remount when
mounted; reuses a personalization the device already holds; Xcode's
device service or the built-in client), and unmount.
- App: a Developer image card on the Device page (state, explanation, next
step, details, mount/unmount with device-bound confirmation that states
what is sent to Apple, mechanism choice, image folders); checked
automatically when a device is shown.
- Readiness Check, Actions (status/mount/unmount), and `idt ddi
status|mount|unmount` use the new manager; `idt ddi prepare` stays as an
alias.
- Screenshot harness: -scroll-fraction to render cards below the fold.
- Tests: 14 new tests including end-to-end personalized and legacy mounts
against a stateful fake image mounter, a UI test for the card, and a test
that parses the image Xcode installed on this Mac.
hideouts.io
- README: Developer images section (states, personalized vs legacy images, where images come from, what personalization sends to Apple, mount mechanisms) with a screenshot of the Device page card; with/without-Xcode table, first steps, idt examples, troubleshooting, privacy note, and status updated. - SECURITY: the one place the app's own code uses the internet (personalization, after confirmation). - docs: architecture (DeveloperImage module and its isolation of the private service), troubleshooting rows, physical-device protocol Stage 3 steps for every image state and both mechanisms, safety wording. - MIGRATION: feature rows 4–6, §6 no longer lists iOS 16 image mounting as missing, §8.3 what was implemented per gap, §8.4 verification and the hardware checks still open, test counts (161 package tests). hideouts.io
With Rosetta 2 installed, the Intel slices were exercised: the release script's check ran the Intel idt; the Intel idt listed devices, found all 27 Xcode routes, and reported developer-image status; the Intel app rendered every page at both window sizes; and all 161 package tests pass built for x86_64 and run with `arch -x86_64 xctest` (SwiftPM's test helper is arm64-only). CONTRIBUTING documents the recipe. Verified under Rosetta on Apple silicon, not on Intel hardware. hideouts.io
Swift 6.3 infers `optional.map { Array($0.utf8) + [0] } ?? []` as `[Any]?`
(Swift 6.4 infers `[UInt8]`), which broke the DeviceKitTests build on the
macos-26 runner. Annotate the two byte arrays explicitly.
hideouts.io
On the CI runner the first `simctl launch` after `simctl boot` timed out after 60 s: `simctl boot` returns while iOS is still starting. Starting a simulator now uses `simctl bootstatus <udid> -b`, which boots if needed and returns once boot (and any data migration) has completed; the Start simulator action and the end-to-end test both use it. Launch timeout raised to 120 s. The Toolchain Check now also verifies `simctl bootstatus -b`. hideouts.io
- The real-simulator test now compiles a minimal iOS-simulator app with Xcode's swiftc (through CommandRunner), signs it ad hoc, then installs, lists, launches, and uninstalls it; `simctl install` was previously covered only by argument tests. - MIGRATION.md: all 8 UI tests (including the developer-image card) pass in CI; CI's first runs and the two fixes they led to; the simulator-install gap is closed. hideouts.io
MIGRATION.md §9: every preset, workspace control and workflow, CLI option, evidence snapshot, readiness row, profile field, and shortcut of 0.3.4 classified against the Swift app, with a prioritized list of 13 gaps. hideouts.io
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
The Xcode 26.6 CI runner exposed three environment assumptions: - Developer-image tests found real legacy images from the runner's older Xcode installs. Host image locations are now injectable (DeveloperImageHostLocations) and the tests use empty ones; user-chosen image folders now take precedence over Xcode-discovered images. A new test validates real legacy images when the machine has them. - Xcode 26.6's devicectl lacks `device simulate location`, the screenshot `--destination` option, `device process openURL`, and `profile list --type`. devicectl syntax errors now become "The installed Xcode's device tool does not support this command" with an update/Toolchain Check hint, and the Toolchain Check reports these routes as "Needs a newer Xcode" (idt toolchain exits 0 for them). CI prints the runner's devicectl syntax for the affected commands. - The real-simulator test hit its 5-minute limit on a cold CI boot: limit raised to 20 minutes, job timeout to 45, and the test logs step timings. hideouts.io
0.3.x listed processes over lockdown (`processes ps`), but 1.0 needed Xcode's devicectl. The os_trace_relay client now issues `PidList` (one leading byte, a big-endian length, then a plist mapping pids to process names); the Running processes action and the evidence snapshot use it over USB, and fall back to devicectl only for network-only devices. Tests: reply parsing (missing payload, unnamed and non-numeric entries), the action against the fake device, the evidence snapshot now succeeding without Xcode, and readiness treating the action as ready without Xcode. Not yet verified on a physical device. hideouts.io
0.3.x listed configuration profiles over lockdown (`profile list`), but 1.0 needed Xcode's devicectl, whose `profile list --type` is also missing in Xcode 26. A read-only MCInstall client (`GetProfileList`: ordered identifiers, metadata, active state) now serves the Configuration profiles action and the evidence snapshot over USB; devicectl remains the route for network-only devices. Also fixes "1 processes"/"1 profiles" wording. Tests: reply parsing (ordering, missing entries, errors), the action and the evidence snapshot against the fake device. Not yet verified on a physical device. hideouts.io
0.3.x listed inspectable Safari tabs and web views (`webinspector opened-tabs`); 1.0 had marked this "not migrated". A native com.apple.webinspector client now implements the WebKit remote-inspector handshake and listing (`_rpc_reportIdentifier:`, `_rpc_getConnected Applications:`, `_rpc_forwardGetListing:` → application and page reports), keeping only titles, addresses, page kinds, and app names. The device drops refused sessions without a reason (Web Inspector off, a session started within ~10 s of the previous one, or still booting), so refusals are retried until a deadline and then explained with the exact setting to turn on. - Action "Safari and web view tabs"; Readiness row "Safari Web Inspector" (short probe; "not answering" is attention, not a failure). - Tests: a reusable fake webinspectord (Tests/DeviceTestSupport), listing after a retried refusal, the refusal explanation, listing-state rules (listings replace pages, disconnects remove apps), the action and the readiness row. - Opening a URL through Web Inspector (automation) remains out of scope; Open URL uses CoreDevice. Not yet verified on a physical device. hideouts.io
0.3.x captured Bluetooth HCI traffic (`btlogger`); 1.0 had marked it "not migrated". A native com.apple.bluetooth.BTPacketLogger client reads the stream (2-byte little-endian length per record, zero-length keep-alives) of Apple PacketLogger records and writes them back to back as a `.pklg` file, which PacketLogger and Wireshark open (0.3.x wrote pcapng). - Action "Bluetooth capture" (duration, new `.pklg` file, SHA-256, packet counts by type); a missing logging profile or an empty capture is explained in plain language. - Tests: record parsing, keep-alives, byte-exact `.pklg` output, hash and per-type counts, desynchronized streams, the missing-service explanation, and the action with and without packets. Not yet verified on a physical device. hideouts.io
- The fake device now writes the usbmux Result and installs its TLS handler in the same event-loop tick, so a client's ClientHello can no longer arrive before the handler and stall the handshake (intermittent timeout in opensServicesWithAndWithoutTLS on CI). - build-release.sh shows the compiler errors and the log tail when the universal idt build fails, instead of only "Build failed". - open-url validates its URL parameter on its own rather than reading it from the combined parameters, so no other parameter's value can reach the URL handed to the device. hideouts.io
Device › Reconnect a Device… (also on the Connection diagnostics and No-device cards) lists the 0.3.x reconnect steps and then watches discovery for 30 seconds. It reports when a trusted device arrives, when a device arrives but still needs Trust, or when nothing appears, with the next step for each. Discovery is event-driven, so nothing is polled or restarted, and the boundary is stated: no sudo, no pairing-record deletion, no service restarts, no device changes. The screenshot harness can render the sheet (-show-sheet reconnect), select a USB device (-select-physical-device YES), and always exits even if a sheet blocks termination. hideouts.io
…pass RealDeviceTests (IDT_DEVICE_TESTS=1) checks the native protocol layer against a connected iPhone or iPad without changing it: lockdown values, process list, configuration and provisioning profiles, installed apps, diagnostics, mounted images, the developer-image evaluation, the Bluetooth logger, syslog, Unified Logging, and packet capture. MIGRATION.md §5.4 records the results on an iPhone 17 Pro on iOS 26.3.1 (locked, Developer Mode off). The GUI protocol and anything that changes the device are still untested on hardware. hideouts.io
The 0.3.x name of --include-unified-logs is accepted as a hidden alias so existing collection scripts keep working. hideouts.io
The 0.3.x DVT reachability row is replaced by “Instruments (xctrace)”, read from `xcrun xctrace list devices`: ready when Instruments lists the device or simulator as available, needs attention when it is listed offline (Developer Mode off, locked, or not yet prepared by Xcode) or not listed, blocked without Xcode. The Instruments recording action now waits for this row, so its readiness shortcut points at the real prerequisite. hideouts.io
The row's state already reads “Needs attention”; a blocked image (for example Developer Mode off) now shows only the reason. hideouts.io
…arity gap G6) Profiles now carry the Actions category, the selected action, and the developer-image mount mechanism, and Settings › Profiles imports files exported by the 0.3.x Python app (schema 1). Those are checked as strictly as 0.3.x checked them and translated: workspace names, Command Center presets to their replacement actions (MIGRATION.md §9.1), ddi_source to the built-in mounter (nothing is downloaded), and DVT OSLog to Unified Logging. The import preview lists each translation. The test fixture was written by 0.3.4's own exporter. The Actions page's category and selection moved into the app model, so profiles and the command palette can open a specific action. hideouts.io
Location Lab › Route gets 0.3.x's “Add Current Coordinate”: the validated latitude and longitude are appended as the last waypoint, and any built GPX route is discarded so it cannot be saved out of date. hideouts.io
Live Logs › Findings gets 0.3.x's “Copy Register”: the capture facts and every finding as Markdown, the same text as the evidence bundle's investigation report, available while the capture is still running. hideouts.io
…G11) Help › Keyboard Shortcuts (⌘/) lists every shortcut, generated from the same workspace order as the ⌘1–⌘9 menu items. View › Previous and Next Workspace (⌥⌘← / ⌥⌘→) step through the sidebar, wrapping around, and the standard sidebar commands (⌃⌘S) are now in the View menu. The screenshot harness can render the reference (-show-sheet shortcuts). hideouts.io
- Every action and Evidence Capture show what the latest Readiness Check says about their prerequisites, with Run Readiness Check, Check Again, and Open Readiness Check. An evidence collection needs a trusted connection, plus Xcode's device service when it includes a screenshot. - Tool Reference › “Use in Advanced Mode” opens Advanced Mode with the selected devicectl command filled in; nothing runs until Run, and Advanced Mode's own policy still classifies and confirms it. - Advanced Mode is presented from the main window, keeps its command line between openings, and can be rendered by the screenshot harness. hideouts.io
- Rename Sources/idt/main.swift to IDT.swift: Swift 6.3 rejects @main in a file named main.swift when building the universal release binary. - A tool probe that times out is reported as “did not answer in time” (Readiness: needs attention; Toolchain Check: run again), not as a missing Xcode, and the probe waits up to 45 seconds. On a busy CI runner that had just booted a simulator, the 20-second probe timed out and the simulator test saw “Xcode is not installed”. - Coordinate parameters are range-checked in a separate helper so that coordinate data shares no flow path with the URL parameter (CodeQL cleartext-transmission alert on open-url). hideouts.io
After validation, External Tools › UFADE says whether the checkout's ufade_developer submodule is populated. When it is not, it explains that logical acquisitions still work but UFADE's Developer Options may be limited, and gives the command to populate it. hideouts.io
Test counts, the first hardware pass, CI fixes, the migration log, and the audit outcome, including what is intentionally excluded and why. hideouts.io
…itive) CodeQL's cleartext-logging query treats any property named like a certificate as sensitive, so printing the number of developer certificates in `idt inspect-ipa` was flagged. The property is now `allowedSignerCount`; the JSON key stays `developerCertificateCount`, so `idt inspect-ipa --json` output is unchanged (tested). hideouts.io
…device data - The Readiness row for the developer image uses the image check's own advice, so with Developer Mode off it says to turn Developer Mode on instead of the generic “Mount Developer Image” (found on the iPhone). - The screenshot harness can run the Readiness Check and load the app list for the selected device before rendering (-load-device-data YES, read-only). - MIGRATION.md §5.4: the app's pages rendered with a real iPhone. hideouts.io
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.
Summary
Replaces the Python / PySide6 /
pymobiledevice3application (0.3.x) with a native Swift/SwiftUI macOS app and theidtcommand-line tool (1.0.0). The feature-by-feature record — audit, mapping, test results, known limitations — is in MIGRATION.md.devicectl),simctl, andxctraceare used for developer services, simulators, and Instruments.DeveloperDiskImage.dmgmounting on iOS 16 and earlier, unmount, and plain-language errors — natively or throughdevicectl. See MIGRATION.md §8.sudo; device-bound typed confirmations; owner-only, no-overwrite file writes; identifiers kept out of public unified-log fields.scripts/build-release.shproduces a universal (arm64 + x86_64), ad-hoc-signed, hardened-runtime ZIP with bundled licenses, an SPDX SBOM, and SHA256SUMS. New workflows: CI (package tests, app build with a zero-warning check, UI tests, layout check at both window sizes, real-simulator test, release packaging), tagged releases with attestations, CodeQL for Swift, dependency review; Dependabot for Swift and GitHub Actions.Verification
-warnings-as-errors, also when built for x86_64 and run under Rosetta 2.IDT_SIMULATOR_TESTS=1) passes.xcodebuildhas zero warnings; every page renders at 1180×700 and 900×560 without clipping.Not yet verified
macos-26; if its Xcode is too old for the code, set theXCODE_VERSIONrepository variable.testDeveloperImageCardShowsStateAndBlocksDemoMounthas not run yet (it runs in CI).Behaviour changes for 0.3.x users
pymobiledevice3presets; Advanced Mode runsdevicectl.