Inspect is split into these layers:
Apps/iOS/: iOS app shellApps/macOS/: macOS app shellExtensions/Action/: iOS action/share extensionExtensions/ActionShared/: shared action-extension supportExtensions/SafariWeb/: Safari web extension for iOS and macOSExtensions/MacShare/: macOS share extensionPackages/InspectCore/: shared Swift models, feature UI, logging, and storesExtensions/PacketTunnel/: iOS/macOS packet tunnel wrapper and Rust bridgeRust/tunnel-core/: Rust forwarding core
flowchart LR
classDef app fill:#f4d35e,stroke:#7a5c00,color:#1f1f1f,stroke-width:2px;
classDef extension fill:#ee964b,stroke:#8a3b12,color:#1f1f1f,stroke-width:2px;
classDef shared fill:#7bdff2,stroke:#155e75,color:#0b1f2a,stroke-width:2px;
classDef tunnel fill:#b8f2e6,stroke:#1d6f5f,color:#12302a,stroke-width:2px;
classDef rust fill:#cdb4db,stroke:#6b4c7a,color:#23182a,stroke-width:2px;
A["iOS App"] --> B["InspectCore"]
M["macOS App"] --> B
E["iOS Action Extension"] --> B
S["Safari Web Extension"] --> B
X["macOS Share Extension"] --> B
A --> T["PacketTunnelExtension"]
T --> R["Rust tunnel-core"]
- The app, Safari extension, or share extension resolves a host or URL.
TLSInspectoropens a direct TLS connection.- The result is normalized into
TLSInspectionReport. - Shared feature UI renders summary cards and certificate detail.
- Safari popup asks the native handler to inspect the active tab URL.
- The extension returns a compact summary payload for the popup.
Open Full Detailssaves the report into the shared app group.- The app opens through
inspect://certificate-detail?...and shows Swift certificate detail.
- Safari or another host app shares a page or URL to
Inspect Certificate. - The share extension extracts the URL.
- The extension runs
TLSInspector, stores the report in the app group, and queues a pending handoff token. - The mac app activates, consumes that pending report, and opens certificate detail in the existing window.
LiveMonitorManagerstarts the packet tunnel.InspectPacketTunnelExtensionconfigures the tunnel and launches the forwarding engine.tunnel-coreruns on top oftun2proxyand passively observes TLS traffic.- Observations are written back into the shared app group feed and log.
InspectionMonitorStoreaggregates those observations into hosts and latest reports.
Common commands:
just generate
just rust test
just rust tun2proxy-harness
just test-ios-sim
just run-ios-device
just run-mac
just testflight-dry-run
just app-store-screenshotsNotes:
project.ymlis the source of truth. Regenerate the Xcode project withxcodegen generate.- Prefer
xcodebuild ... | xcbeautifyfor local and CI output. - The packet tunnel extension links the Rust static library directly;
InspectCoredoes not link Rust. - Shared logs are written through the app group and surfaced in-app under Settings diagnostics.
- Xcode 16 or newer
- iOS 18 SDK
- XcodeGen
xcbeautify
Today:
- TCP/TLS live monitoring works on device.
- Passive SNI and certificate-chain capture work for the current TCP path.
- UDP forwarding exists in
tun2proxy, but Inspect does not yet surface UDP observations. - QUIC/HTTP3 certificate capture is not implemented.
The main release entry point is:
just testflightOne-time setup:
cp project.local.yml.example project.local.yml
cp .env.example .envFor local Xcode signing, set your DEVELOPMENT_TEAM and INSPECT_APP_GROUP_IDENTIFIER in project.local.yml. The generate script merges that file into project.yml so the generated project gets automatic signing target attributes as well as build settings.
Required .env values:
ASC_APP_IDAPP_STORE_CONNECT_KEY_IDAPP_STORE_CONNECT_ISSUER_IDAPP_STORE_CONNECT_KEY_PATH
If the current App Store Connect app already has the repo's CURRENT_PROJECT_VERSION, set TESTFLIGHT_BUILD_NUMBER before uploading.
Useful variants:
just testflight-build
just testflight-dry-runNotes:
just testflightregeneratesInspect.xcodeprojwith XcodeGen before archiving.- The archive/export flow uses automatic signing and
-allowProvisioningUpdatesby default. just testflight-buildstops after producing the exported artifact inbuild/testflight/.
Capture screenshots locally:
just app-store-screenshotsThat uses the built-in INSPECT_SCREENSHOT_SCENARIO launch mode and writes output under build/app-store-screenshots/output/.
To upload screenshots:
./scripts/app_store_screenshots.sh upload <VERSION_LOCALIZATION_ID>Or capture and upload in one pass:
./scripts/app_store_screenshots.sh capture-upload <VERSION_LOCALIZATION_ID>