fix(recaptcha): address review items for requestHooks bridging - #127
Conversation
- Add AppCheckRecaptchaProvider as dependency to AppCheckCoreUnitObjC and add an Objective-C bridging test constructing GACRecaptchaProvider with request hooks. - Define invalidRequestHook (3002) message code in AppCheckCoreErrors and use it when logging rejected hooks. - Add CHANGELOG entry for GACRecaptchaProvider requestHooks bridging fix. - Format doc-comment parameters across AppCheckRecaptchaProvider convenience initializers.
…atalyst and CocoaPods
Signed-off-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com>
Signed-off-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com>
|
Merging. Can resolve any feedback in additional PRs/commits. |
|
For the record, these are just nits, and may be addressed in a cleanup task later: Review: #127 — "fix(recaptcha): address review items for requestHooks bridging"PR: google/app-check#127 · Review history:
VerdictApprove, with one nit worth a follow-up line and one open question that predates this PR's mechanics.
-if (TARGET_OS_IOS || TARGET_OS_VISION) && !TARGET_OS_MACCATALYST
+#if SWIFT_PACKAGE && (TARGET_OS_IOS || TARGET_OS_VISION) && !TARGET_OS_MACCATALYSTThat single line clears B1 (bare CI now proves it rather than predicting it
The 🟡 New nit —
|
1731eb32 |
3f95be91 (head) |
|
|---|---|---|
@import AppCheckRecaptchaProvider; |
#if SWIFT_PACKAGE && … |
#if SWIFT_PACKAGE && … |
testRecaptchaProviderRequestHooksBridging |
#if (TARGET_OS_IOS || TARGET_OS_VISION) && !TARGET_OS_MACCATALYST |
#if SWIFT_PACKAGE && … |
Only the import needs SWIFT_PACKAGE, because only SwiftPM has a separate module. The test compiles fine under CocoaPods: AppCheckRecaptchaProvider.swift:15 puts only import AppCheckCore behind #if SWIFT_PACKAGE — the @objc(GACRecaptchaProvider) class itself is unconditional, and the podspec compiles it into the AppCheckCore module on iOS, so @import AppCheckCore; already reaches it.
Net effect: the reCAPTCHA bridging test no longer exists on the CocoaPods leg. The green pod_lib_lint (ios) therefore proves the file builds there, not that the test ran there — and CocoaPods is the build system where module and access-level differences have actually bitten this branch before (af0bc656). Dropping SWIFT_PACKAGE && from the test guard alone recovers that coverage.
Not worth blocking on; worth a one-line follow-up.
🟡 Q1 — still open: can the new test fail against the bug?
Unchanged through all three passes, and now the only substantive item left.
RecaptchaEnterpriseSDKLoader resolves its classes with NSClassFromString("RecaptchaEnterprise.RCARecaptcha"), and RecaptchaEnterprise is not linked into the test target — the package depends on RecaptchaInterop, the protocol shim, not the SDK. So the initializer takes its first branch:
guard let sdk = RecaptchaEnterpriseSDKLoader(customAction: actionName) else {
return nil // ← before `requestHooks` is ever read
}The test detects a reverted signature only if the typed-array trap fires in the @objc thunk during argument bridging, rather than on first element access. I argued thunk-time in #126: the thunk must produce Array<Element> where Element is a function type, which is neither a class, an ObjC existential, nor _ObjectiveCBridgeable, so the conversion cannot be verbatim and must be eager. The author's doc comment on testRequestHooksBridging states the opposite — "bridging is lazy, so the element cast is forced on first access." Both cannot hold, and a green CI run says nothing either way, because the bug is not present to be caught.
One experiment settles it. Revert the reCAPTCHA parameter to [@convention(block) (NSMutableURLRequest) -> Void]? locally and run the test:
- Crashes → the test is sound, one of the two comments is wrong, and the thunk-time behaviour belongs in this test's doc comment.
- Passes → the test is inert and needs to reach the array, via a stubbed loader or by exercising the provider's forwarding into
_GACAppCheckAPIService.
Carried nits
- The test has no assertion and no comment saying why. Its entire signal is "does not crash." In a PR that exists because an earlier test could not fail for its own regression, an assertion-free body with no explanation is the shape of thing a later cleanup deletes. Resolving Q1 gives you exactly the sentence to put there.
- Changelog comma splice — "…now accepts
NSArray<id> */[Any]?fixing an@objcargument bridging trap…" wants a comma before fixing.
Summary
| Items addressed (F1, F2, F4, F5) | ✅ All four |
B1 — missing # |
✅ Fixed in 3f95be91 |
| B2 — CocoaPods module | ✅ Fixed in 3f95be91, confirmed by pod_lib_lint (ios) |
@available removal |
✅ Safe, confirmed by warnings-as-errors |
| Test runs under CocoaPods | 🟡 No — over-gated on SWIFT_PACKAGE |
| New test is load-bearing | ❓ Q1 — unresolved |
| Message code work | ✅ Exceeded the ask |
Mergeable as-is. Q1 is the one thing I would want answered before treating this test as protection rather than decoration — and it is a five-minute local experiment, not a code change.
Addresses #126 (review)