diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index c7f10ccf0cff..d3ebbe8a8619 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -372,13 +372,15 @@ jobs: do CLI_PATH="$APP_PATH/Contents/Resources/bin/cmux" HELPER_PATH="$APP_PATH/Contents/Resources/bin/ghostty" + # Sign app bundle first (--deep signs all nested content with full entitlements), + # then re-sign embedded binaries with narrower entitlements. + /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$APP_ENTITLEMENTS" --deep "$APP_PATH" if [ -f "$CLI_PATH" ]; then /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$CLI_PATH" fi if [ -f "$HELPER_PATH" ]; then /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$HELPER_PATH" fi - /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$APP_ENTITLEMENTS" --deep "$APP_PATH" /usr/bin/codesign --verify --deep --strict --verbose=2 "$APP_PATH" done diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28eabb2f3736..3fb4cf5e5368 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -238,13 +238,15 @@ jobs: EMBEDDED_ENTITLEMENTS="cmux.embedded.entitlements" CLI_PATH="$APP_PATH/Contents/Resources/bin/cmux" HELPER_PATH="$APP_PATH/Contents/Resources/bin/ghostty" + # Sign app bundle first (--deep signs all nested content with full entitlements), + # then re-sign embedded binaries with narrower entitlements. + /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$APP_ENTITLEMENTS" --deep "$APP_PATH" if [ -f "$CLI_PATH" ]; then /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$CLI_PATH" fi if [ -f "$HELPER_PATH" ]; then /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$HELPER_PATH" fi - /usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$APP_ENTITLEMENTS" --deep "$APP_PATH" /usr/bin/codesign --verify --deep --strict --verbose=2 "$APP_PATH" - name: Notarize app diff --git a/Sources/Panels/BrowserPanel.swift b/Sources/Panels/BrowserPanel.swift index d7554d23a2dd..fff7aa833f11 100644 --- a/Sources/Panels/BrowserPanel.swift +++ b/Sources/Panels/BrowserPanel.swift @@ -1755,6 +1755,7 @@ private struct BrowserPasskeyAuthorizationReply { } } +@available(macOS 15.0, *) @MainActor private final class BrowserPasskeyAuthorizationCoordinator: NSObject, WKScriptMessageHandlerWithReply { weak var panel: BrowserPanel? @@ -1972,6 +1973,7 @@ final class BrowserPanel: Panel, ObservableObject { /// Popup windows owned by this panel (for lifecycle cleanup) private var popupControllers: [BrowserPopupWindowController] = [] + @available(macOS 15.0, *) private lazy var passkeyAuthorizationCoordinator = BrowserPasskeyAuthorizationCoordinator(panel: self) static let telemetryHookBootstrapScriptSource = """ @@ -2935,6 +2937,7 @@ final class BrowserPanel: Panel, ObservableObject { } func configurePasskeyAuthorizationBridge(on configuration: WKWebViewConfiguration) { + guard #available(macOS 15.0, *) else { return } let userContentController = configuration.userContentController if !userContentController.userScripts.contains(where: { $0.source == Self.passkeyAuthorizationBootstrapScriptSource }) { userContentController.addUserScript( diff --git a/Sources/Panels/BrowserPopupWindowController.swift b/Sources/Panels/BrowserPopupWindowController.swift index b3ad28e2f4de..9fb6790cbdb1 100644 --- a/Sources/Panels/BrowserPopupWindowController.swift +++ b/Sources/Panels/BrowserPopupWindowController.swift @@ -298,7 +298,6 @@ final class BrowserPopupWindowController: NSObject, NSWindowDelegate { #endif return nil } - openerPanel?.configurePasskeyAuthorizationBridge(on: configuration) let child = BrowserPopupWindowController( configuration: configuration, windowFeatures: windowFeatures, diff --git a/scripts/build-sign-upload.sh b/scripts/build-sign-upload.sh index 53939df29559..ff929425d1a2 100755 --- a/scripts/build-sign-upload.sh +++ b/scripts/build-sign-upload.sh @@ -94,13 +94,16 @@ echo "Sparkle keys injected" # --- Codesign --- echo "Codesigning..." CLI_PATH="$APP_PATH/Contents/Resources/bin/cmux" +# Sign app bundle first (--deep signs all nested content with full entitlements), +# then re-sign embedded binaries with narrower entitlements so they don't inherit +# the restricted public-key-credential entitlement. +/usr/bin/codesign --force --options runtime --timestamp --sign "$SIGN_HASH" --entitlements "$APP_ENTITLEMENTS" --deep "$APP_PATH" if [ -f "$CLI_PATH" ]; then /usr/bin/codesign --force --options runtime --timestamp --sign "$SIGN_HASH" --entitlements "$EMBEDDED_ENTITLEMENTS" "$CLI_PATH" fi if [ -f "$HELPER_PATH" ]; then /usr/bin/codesign --force --options runtime --timestamp --sign "$SIGN_HASH" --entitlements "$EMBEDDED_ENTITLEMENTS" "$HELPER_PATH" fi -/usr/bin/codesign --force --options runtime --timestamp --sign "$SIGN_HASH" --entitlements "$APP_ENTITLEMENTS" --deep "$APP_PATH" /usr/bin/codesign --verify --deep --strict --verbose=2 "$APP_PATH" echo "Codesign verified"