Skip to content

Centralize Swift checkout message ingress validation - #644

Open
markmur wants to merge 5 commits into
mainfrom
swift-message-rejection-lifecycle
Open

Centralize Swift checkout message ingress validation#644
markmur wants to merge 5 commits into
mainfrom
swift-message-rejection-lifecycle

Conversation

@markmur

@markmur markmur commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What changes are you making?

This PR explores a warning-and-drop alternative to the diagnostics subscription approach in #642 and #643. It removes onMessageRejected from Configuration without adding another consumer callback surface.

Incoming WebKit messages now pass through an internal CheckoutMessageIngressPolicy before reaching the checkout protocol client:

let incomingMessage = IncomingCheckoutMessage(
  isMainFrame: messageIsMainFrame(message),
  resolveOrigin: { self.messageOrigin(message) },
  resolveRequestURL: { self.messageRequestURL(message) }
)

switch ingressPolicy.evaluate(incomingMessage) {
case .accepted:
  protocolBridge.receive(message: body)
case let .rejected(rejection):
  // Rejected messages are untrusted input, not checkout lifecycle failures. Warn and
  // drop them without allowing unrelated page activity to terminate a healthy checkout.
  OSLogger.shared.warn(
    "Rejected checkout message from \(rejection.origin): \(rejection.reason.logDescription)"
  )
  return
}

The policy owns the transport admission decision using WebKit's authenticated source origin and frame metadata. This keeps trust evaluation at the native WebView boundary and ensures the protocol client only receives admitted checkout messages.

Rejection behavior

A rejected message means that specific input was not trusted. It does not mean the checkout session failed: checkout may be displaying an external surface that also posts messages, and unrelated page activity must not be able to terminate an otherwise healthy checkout. The rejection branch logs the warning inline and returns before protocol processing begins.

  • Rejected child-frame, origin, and explicit-port-zero messages are logged at warning level and dropped.
  • Rejected messages never reach the checkout protocol client.
  • Rejection does not transition PreloadState to .failed or evict the preload.
  • Rejection does not create a CheckoutError or call .onFail / checkoutDidFail(error:).
  • The rejection model remains internal because this approach does not expose a public diagnostics stream.

Consumer API

Consumers only configure the origins they trust. The existing lifecycle APIs remain reserved for actual checkout failures:

ShopifyCheckoutKit.configure {
  $0.allowedMessageOrigins = [
    "https://checkout.example.com",
    "https://*.example.com",
  ]
  $0.logLevel = .warn
}

There is no message-rejection subscription in this approach. Consumers that need structured rejection telemetry can compare this PR with the diagnostics API in #642.

React Native consumer API

This approach adds no React Native event or callback. Rejected native messages are warning-logged and dropped; they do not dispatch onFail:

checkoutKit.present(checkoutUrl, {
  onFail(error) {
    // Called for checkout lifecycle failures, not rejected messages.
    reportCheckoutFailure(error);
  },
});

Before you merge

Important

  • I've added tests to support my implementation
  • I have read and agree with the Contribution Guidelines
  • I have read and agree with the Code of Conduct
  • I've updated the relevant platform README (platforms/swift/README.md and/or platforms/android/README.md)

@github-actions github-actions Bot added the #gsd:50662 Rebase Checkout Kit on UCP label Aug 14, 2026

markmur commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@markmur markmur changed the title Route Swift message rejection through lifecycle failures Centralize Swift checkout message ingress validation Aug 14, 2026
@markmur
markmur force-pushed the swift-message-rejection-lifecycle branch from 63d2a15 to ac84d8f Compare August 14, 2026 11:44
@markmur
markmur marked this pull request as ready for review August 14, 2026 11:47
@markmur
markmur requested a review from a team as a code owner August 14, 2026 11:47
@bitrise

bitrise Bot commented Aug 14, 2026

Copy link
Copy Markdown

Install this build

Open Tophat, select your target device, then click Install. Links open on the Mac running Tophat.

SDK Install
Swift Install with Tophat

Checkout Kit E2E results

Status Suite Target Platform OS version tag Device
swift-ios swift ios latest iPhone 15
iOS 27 Beta

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

#gsd:50662 Rebase Checkout Kit on UCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant