Repository navigation
Add zig-ctap2 test execution to fork CI - #1947
Jesssullivan wants to merge 73 commits into
Conversation
Implement full WebAuthn support via JS bridge + AuthenticationServices, enabling hardware security key (YubiKey) and passkey authentication in the cmux browser for GSuite, GitHub, GitLab, etc. - WebAuthnBridgeJavaScript: intercepts navigator.credentials.create/get, serializes ArrayBuffer↔base64url, constructs spec-compliant clientDataJSON and PublicKeyCredential response objects - WebAuthnCoordinator: native bridge using ASAuthorizationController with both SecurityKey and Platform credential providers, state machine, origin validation, exhaustive error mapping - Integrated into BrowserPanel.bindWebView and BrowserPopupWindowController so WebAuthn works in both main browser and popup OAuth flows - Added com.apple.developer.web-browser.public-key-credential entitlement - Created cmux.embedded.entitlements for CLI/helper (narrow, no passkey) - Fixed codesign order in release/nightly/build scripts: sign app --deep first, then re-sign embedded binaries with narrow entitlements - Added NSBluetoothAlwaysUsageDescription for cross-device passkey flows Addresses #124, manaflow-ai#1278. Supersedes approach from manaflow-ai#1021, manaflow-ai#1823.
Fork-only infrastructure for lab testing of FIDO2/WebAuthn work. Not intended for upstream. - Trans flag gradient app icon (AppIcon-Fork) with "LAB" banner to visually distinguish fork builds from upstream cmux - generate_fork_icon.py: recolors debug icon banner to trans gradient (light blue #5BCEFA → pink #F5A9B8 → white → pink → blue) - fork-ci.yml: build validation for macOS .app, Linux daemon, nix flake - fork-release.yml: multi-platform release workflow producing: - macOS DMG (.app bundle with LAB branding) - Linux cmuxd binaries (amd64, arm64) - DEB packages (Debian/Ubuntu) - RPM packages (RHEL/Fedora) - flake.nix: Nix flake for darwin .app packaging and dev shell
Add fork CI, packaging, and trans-themed LAB branding
Add WebAuthn/FIDO2/YubiKey passthrough for browser panel
Fix fork CI: remove cmuxd refs, fix hashFiles glob
Fix fork CI: use macos-15 runner for SDK compatibility
Fix fork CI: native xcframework target, skip macOS app
Fix fork CI: symlink GhosttyKit.xcframework to repo root
Fix fork CI: debug xcframework path, fix cache key
Fix fork release: dynamic xcframework discovery + build diagnostics
The setup-zig action's cache causes zig to skip producing output artifacts (zig-out/lib/GhosttyKit.xcframework) because it thinks the build is up-to-date from cached intermediate objects. Disable the zig cache and clean zig-out before building.
Fix fork CI: disable zig cache to ensure xcframework output
Fix fork CI: use universal xcframework target
Building GhosttyKit from source fails on GitHub-hosted runners due to Xcode/libtool compatibility issues. Upstream builds it on custom warp runners and publishes to manaflow-ai/ghostty releases. Download the pre-built xcframework instead — much faster and reliable.
Fix fork CI: download pre-built GhosttyKit from upstream
Fix fork CI: cmux-LAB (no space) avoids xcodebuild bundle conflicts
The trans icon (AppIcon-Fork) is sufficient to differentiate fork builds. Overriding PRODUCT_NAME causes 'Multiple commands produce' errors because multiple Xcode targets produce the same .bundle.
Fix fork CI: don't override PRODUCT_NAME
.preferSignInWithApple and .deviceNotConfiguredForPasskeyCreation are only available in newer SDKs (macOS 26+). Use @unknown default to handle them portably.
Fix WebAuthn: remove SDK-version-dependent error cases
Fix fork CI: install zig for CLI helper build
Wire zig-ctap2 for direct USB HID FIDO2 (no Apple entitlements needed)
Fix CTAP2 Swift compilation errors
Fix remaining nonisolated static methods
Fix libctap2: native arch build, add ARCHS=arm64 to xcodebuild
Fix WKWebView reply serialization
Update zig-ctap2: IOKit write fix + IOReturn diagnostic
Update zig-ctap2 submodule + header
IOHIDDeviceSetReport returns kIOReturnNotPermitted (0xe00002cd) under hardened runtime without this entitlement. Required for direct CTAP2 communication with security keys over USB HID via IOKit.
Add USB device entitlement for FIDO2 HID
Update zig-ctap2: raw IOKit constants
Fix IOKit device lifecycle crash
Update zig-ctap2: fix CFRetain
Run unit and property-based tests for the ctap2 library before building cmux, so test failures surface early in CI.
|
@Jesssullivan is attempting to deploy a commit to the Manaflow Team on Vercel. A member of the Team first needs to authorize it. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (10)
📒 Files selected for processing (23)
📝 WalkthroughWalkthroughIntroduces WebAuthn/FIDO2 support for cmux by adding a JavaScript bridge and native WebAuthnCoordinator that intercepts web credential APIs, integrating with a CTAP2 C library via USB HID. Includes new fork-specific CI/release workflows, updated code signing with split entitlements, icon generation, and Nix flake configuration. Changes
Sequence DiagramssequenceDiagram
participant JS as JavaScript<br/>(Web Page)
participant Bridge as WebAuthn Bridge<br/>(JavaScript)
participant Coordinator as WebAuthnCoordinator<br/>(`@MainActor`)
participant CTAP2 as CTAP2 Library<br/>(C via Zig)
participant HID as USB HID<br/>(Security Key)
JS->>Bridge: navigator.credentials.create(options)
activate Bridge
Bridge->>Bridge: Validate & serialize options
Bridge->>Coordinator: postMessage({type: "create", options, origin})
deactivate Bridge
activate Coordinator
Coordinator->>Coordinator: Validate origin against webView URL
Coordinator->>Coordinator: Parse challenge, rp, user, pubKeyCredParams
Coordinator->>Coordinator: Generate clientDataJSON & SHA-256 hash
Coordinator->>CTAP2: ctap2_make_credential(client_data_hash, ..., allow_list, result_buf)
deactivate Coordinator
activate CTAP2
CTAP2->>HID: Send CTAP2 request (USB HID)
activate HID
HID->>HID: User performs authentication gesture
HID-->>CTAP2: Return credential response
deactivate HID
CTAP2->>CTAP2: Parse CBOR response, extract credentialID, attestationObject
CTAP2-->>Coordinator: credentialID, attestationObject (raw bytes)
deactivate CTAP2
activate Coordinator
Coordinator->>Coordinator: Decode CBOR, base64url-encode fields
Coordinator-->>Bridge: {credentialID, attestationObject, type, transports}
deactivate Coordinator
Bridge->>Bridge: Transform to PublicKeyCredential
Bridge-->>JS: Resolve promise with credential
sequenceDiagram
participant JS as JavaScript<br/>(Web Page)
participant Bridge as WebAuthn Bridge<br/>(JavaScript)
participant Coordinator as WebAuthnCoordinator<br/>(`@MainActor`)
participant CTAP2 as CTAP2 Library<br/>(C via Zig)
participant HID as USB HID<br/>(Security Key)
JS->>Bridge: navigator.credentials.get({publicKey: options})
activate Bridge
Bridge->>Bridge: Serialize challenge, rpId, allowCredentials
Bridge->>Coordinator: postMessage({type: "get", options, origin})
deactivate Bridge
activate Coordinator
Coordinator->>Coordinator: Validate origin
Coordinator->>Coordinator: Parse challenge, rpId, allowCredentials array
Coordinator->>Coordinator: Generate clientDataJSON & SHA-256 hash
Coordinator->>CTAP2: ctap2_get_assertion(client_data_hash, rp_id, allow_list, result_buf)
deactivate Coordinator
activate CTAP2
CTAP2->>HID: Send CTAP2 get_assertion request (USB HID)
activate HID
HID->>HID: User performs verification gesture
HID-->>CTAP2: Return assertion response
deactivate HID
CTAP2->>CTAP2: Parse CBOR response, extract credentialID, authenticatorData, signature
CTAP2-->>Coordinator: credentialID, authenticatorData, signature (raw bytes)
deactivate CTAP2
activate Coordinator
Coordinator->>Coordinator: Decode CBOR, base64url-encode fields
Coordinator-->>Bridge: {credentialID, authenticatorData, signature, type}
deactivate Coordinator
Bridge->>Bridge: Transform to PublicKeyCredential
Bridge-->>JS: Resolve promise with credential
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Important Merge conflicts detected (Beta)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip You can disable poems in the walkthrough.Disable the |
Greptile SummaryThis PR adds FIDO2/WebAuthn hardware security key support to cmux, wiring a new Key findings:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Page as Web Page (JS)
participant Bridge as WebAuthnBridgeJavaScript
participant Coord as WebAuthnCoordinator (Swift)
participant CTAP2 as libctap2 (C / USB HID)
participant Key as FIDO2 Security Key
Page->>Bridge: navigator.credentials.create(options)
Bridge->>Bridge: serializeCreateOptions(publicKey)
Bridge->>Coord: postMessage {type:"create", options, origin}
Coord->>Coord: validateOrigin(origin)
Coord->>Coord: buildClientDataJSON → SHA-256 hash
Coord->>CTAP2: ctap2_make_credential(...) [ctap2Queue]
CTAP2->>Key: CTAP2 MakeCredential over USB HID
Key-->>CTAP2: CBOR attestation response
CTAP2-->>Coord: raw bytes (status + CBOR)
Coord->>Coord: parseCBORMap → extract credentialID, attestationObject
Coord-->>Bridge: {credentialID, attestationObject, transports}
Bridge->>Bridge: buildRegistrationResponse(nativeResult, challenge, origin)
Bridge-->>Page: PublicKeyCredential object
Page->>Bridge: navigator.credentials.get(options)
Bridge->>Bridge: serializeGetOptions(publicKey)
Bridge->>Coord: postMessage {type:"get", options, origin}
Coord->>Coord: validateOrigin(origin)
Coord->>Coord: buildClientDataJSON → SHA-256 hash
Coord->>CTAP2: ctap2_get_assertion(...) [ctap2Queue]
CTAP2->>Key: CTAP2 GetAssertion over USB HID
Key-->>CTAP2: CBOR assertion response
CTAP2-->>Coord: raw bytes (status + CBOR)
Coord->>Coord: parseCBORMap → credentialID, authData, signature
Coord-->>Bridge: {credentialID, authenticatorData, signature, userHandle}
Bridge->>Bridge: buildAssertionResponse(nativeResult, challenge, origin)
Bridge-->>Page: PublicKeyCredential object
Reviews (1): Last reviewed commit: "Add zig-ctap2 test execution to fork CI" | Re-trigger Greptile |
There was a problem hiding this comment.
14 issues found across 33 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="Sources/Panels/BrowserPanel.swift">
<violation number="1" location="Sources/Panels/BrowserPanel.swift:2472">
P2: Main-frame-only injection disables iframe focus tracking, so address-bar focus restore will not work for inputs inside iframes that previously relayed state via postMessage.</violation>
</file>
<file name="cmux.entitlements">
<violation number="1" location="cmux.entitlements:20">
P1: Hardcoded `com.apple.application-identifier` uses a bundle/team string that does not match project bundle identifiers, creating a real signing/entitlement mismatch risk.</violation>
</file>
<file name="ctap2.h">
<violation number="1" location="ctap2.h:82">
P2: `ctap2_debug_last_ioreturn` is declared outside both the include guard and `extern "C"`, creating inconsistent header behavior and potential C++ linkage/name-mangling mismatch.</violation>
</file>
<file name="Sources/Panels/WebAuthnBridgeJavaScript.swift">
<violation number="1" location="Sources/Panels/WebAuthnBridgeJavaScript.swift:285">
P2: Platform authenticator availability is hardcoded to true, causing inaccurate feature detection and potentially incorrect RP authentication flows.</violation>
</file>
<file name=".github/workflows/nightly.yml">
<violation number="1" location=".github/workflows/nightly.yml:377">
P1: App bundle is deep-signed before embedded binaries are re-signed, but there is no final top-level re-sign; this can invalidate the outer app signature/seal.</violation>
</file>
<file name="Sources/Panels/WebAuthnCoordinator.swift">
<violation number="1" location="Sources/Panels/WebAuthnCoordinator.swift:163">
P2: Cancellation does not stop in-flight CTAP2 work. The async completion always replies and resets state without verifying that the operation is still current, so a canceled ceremony can later reply again and force state back to idle even if a new operation is running.</violation>
</file>
<file name=".github/workflows/fork-release.yml">
<violation number="1" location=".github/workflows/fork-release.yml:22">
P1: Manual dispatch accepts a release tag input but checkout is not pinned to it, so artifacts may be built from the wrong commit.</violation>
<violation number="2" location=".github/workflows/fork-release.yml:167">
P1: Manual dispatch `tag` input is effectively ignored by preferring `GITHUB_REF_NAME`, which can publish/update the wrong release tag.</violation>
</file>
<file name=".github/workflows/fork-ci.yml">
<violation number="1" location=".github/workflows/fork-ci.yml:41">
P1: Workflow consumes a downloaded prebuilt binary artifact without integrity verification before extraction and use.</violation>
<violation number="2" location=".github/workflows/fork-ci.yml:84">
P2: Third-party GitHub Action is referenced with a mutable ref (@main/@v2) instead of an immutable commit SHA, which allows supply‑chain drift in CI.</violation>
</file>
<file name="flake.nix">
<violation number="1" location="flake.nix:30">
P2: cmux-darwin assumes a prebuilt .app inside build/ (ignored by .gitignore) and exits 1 when missing, which makes flake/Nix builds non-reproducible and likely to fail in CI because the source snapshot won’t include those artifacts.</violation>
<violation number="2" location="flake.nix:59">
P2: `cmux-rpm` does not include Zig as a build input, so `cmuxd` is usually not built and the install phase silently skips it, producing a package without the daemon.</violation>
</file>
<file name="scripts/generate_fork_icon.py">
<violation number="1" location="scripts/generate_fork_icon.py:113">
P2: Text segmentation uses a near-white threshold after introducing a white gradient stripe, so non-text pixels are treated as text and LAB replacement bounds/font sizing can be wrong.</violation>
<violation number="2" location="scripts/generate_fork_icon.py:174">
P2: Missing source icons are silently skipped but Contents.json still lists all filenames, which can leave the appiconset referencing files that were never generated and cause asset catalog validation errors.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Disregard, accidental remote push.
Summary by cubic
Adds
zig build testandzig build test-pbtfor thevendor/ctap2library to Fork CI so CTAP2 regressions fail fast before Xcode builds. Tests run after buildinglibctap2.aand exposingctap2.h, and before Debug/Release app builds on macOS-15.New Features
vendor/ctap2, runs unit and property tests, then builds cmux (Debug and Release).flake.nix) to validate the dev shell and flake config.Bug Fixes
cmux.embedded.entitlements, then re-sign the app bundle to refresh the seal.Written for commit 7ecb250. Summary will update on new commits.
Summary by CodeRabbit
Release Notes
New Features
Localization
Chores