Repository navigation
Add native Bank and Location verification support - #60
Merged
Merged
Conversation
…h (continuation of DID-5770) Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
…h (continuation of DID-5770) Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
…h (continuation of DID-5770) Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
…h (continuation of DID-5770) Opened by a BotInc run. Delivery follows the workflow's review and merge policy.
This was referenced Oct 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prepare the React Native wrapper for native Bank and Location verification through the existing entry points. Configure optional Location support, add English and Spanish iOS purpose strings in both examples, and preserve the native
retryBlockedcallback in JavaScript. Native builds retain the source checkout path through Turbo, and the iOS Location setting participates in the build cache key.Native dependency: a single immutable source pin to the native SDK repository's integration branch (the branch name is in
package.json), which stacks the open native Bank and Location pull requests at their 2026-10-08T07:49Z (Bank) and 07:59Z (Location) states. The pinned revision88259c3b2ac57520ead46579ee7c1fb56686cdb1equals that branch's head, re-verified in this pass by remote reference and by the integration pull request's head. The native Bank step, Location and Bank fallback pull requests have since received correction commits that are not part of the stack and therefore not in the pin; the precise list is below, for routing to the owning native packages. The pin moves to the released native version before the stacked push and package release. Released-binary CI checks compatibility only; those binaries do not provide the new steps.Acceptance: NOT-READY. The consumed native revision still fails the visual gate against the frozen design boards. This wrapper renders none of those screens, and this revision's only source change is the Android bridge's diagnostic logging, which no screen shows, so it claims no visual fix; the corrections below are owned by the native SDK packages and the integration branch. Re-review of the unchanged pin cannot clear the visual gate. Once the integration branch carries the native head revisions below (plus the one item no native head carries yet, the Bank step-specific Spanish attribution string), this side moves the pin to the new integration head and re-runs the full visual matrix.
Missing from the consumed native revision
Behavioural list, measured at 390x844 against the frozen boards in light, dark and Spanish, each traced to the native revision that corrects it. None of the cited native revisions is an ancestor of the pinned revision; the stack predates them. Native Android Bank step head:
977a74266c81231eed7e99144741088579bc3d71. That same content is now also published as a single squashed commit off the native base at7a22ab291c32def75ac49014945b79fb8937a976; both revisions have the byte-identical root treebb0300745e0aa4969a99bd5a4af1e4b0cace36b9, so they are two open publications of one Android Bank step, not two variants. Stack exactly one of them, either is equivalent, and do not stack both. Native Android Bank fallbacks head:2f1804c7db0cf98b00646ff084abee93ff2f26bc(a parallel branch off the native base, not stacked on the step head; it carries the same Bank visual corrections plus the fallback states). Native Android Location head:a3c2a152d31e772301b13e1967304981f82b9962. Native iOS Bank fallbacks head:da8154635d67cc4f6d50e67af91fbad2b5dd1023.No iOS Location routing is required. The pinned revision's iOS Location surface is content-identical to the open iOS Location head
a1a50a2c4e9fc253dd064e313da17f4a20676590: the diff overios/sdk/didit-sdk/Sources/Features/Location,ios/sdk/Location,ios/sdk/didit-sdk/Sources/Core/Utils/GeolocationManager.swift, both Location test files andios/sdk/tests/test_location_privacy.pyis empty. The pin is therefore already current for iOS Location, and the routing action this list asks for is Android-only (Bank step, Bank fallbacks, Location) plus the iOS Bank fallbacks head. Every pixel-measured deviation below comes from the Android captures, because iOS cannot be compiled or captured in this Linux sandbox; the iOS items are stated from source, not from a render.50853e1a146a2f64b1e503a84f8ff570d7743619:BankStepView.ktrenders the shared header insideBankScreenContainerwithModifier.padding(horizontal = 4.dp).offset(y = 16.dp).50853e1(atextStyleparameter onPrimaryButton.ktandSecondaryButton.kt) and977a742(BankFootersuppliesboardText(17.sp, 20.74.sp, (-0.84).sp, FontWeight.Medium)with a measured label height).7d977b10eb9021999ff4f16715739257db90f836(buttonStyle()with the same board metrics inLocationStepView.kt, passed to the footer buttons).7d977b1.PoweredByViewgainstext,textStyleandtextColorparameters; the footer passeslocation_secured_by, a new string in every locale (Spanish "Protegido por"), atboardText(12.sp, 18.sp)in surface1 at 40 percent.50853e1(PoweredByViewgainstextStyleandtextColor; the bank footer passes the board metrics).977a742, at its squashed republication7a22ab2and at the Bank fallbacks head2f1804cthe footer still renderscommon_powered_by("Desarrollado por" in Spanish) because theirPoweredByViewcall passes styles but no step-specifictext; re-verified at all three this pass, wherePoweredByView.kttakes onlymodifier,textStyleandtextColorand itsTextreadsstringResource(R.string.common_powered_by), and nosecured_bystring exists in the Android resources. Note also that the native heads extendPoweredByView.ktdifferently (Location addstext; Bank adds onlytextStyleandtextColor), so re-stacking must join both signatures and add a Bank step-specific secured-by string. This is the single item on this list that no native head carries, so it is the only one that needs new native work rather than stacking.android/sdk/src/main/res/font/directory at all.50853e1:res/font/bank_regular.ttf,bank_medium.ttf,bank_semibold.ttf,bank_bold.ttfplusres/raw/bank_font_license.txt, wired asBANK_FONTthroughboardTextinBankComponents.kt.7d977b1:res/font/location_inter_regular.ttf,location_inter_medium.ttf,location_inter_semibold.ttf, wired asLOCATION_FONTthroughboardTextinLocationStepView.kt.BankScreenenum has no close-match, micro-deposit, amounts or statement member).2f1804c(a parallel branch off the native base, not stacked on the Bank step head): theBankScreenenum gainsCLOSE_MATCH,MICRODEPOSIT,AMOUNTSandSTATEMENT, with newBankFallback.kt,BankFallbackApi.kt,ui/BankFallbackScreens.kt,ui/BankInput.ktandui/BankStatementScreen.ktplus screenshot coverage. The fallbacks are gated on the backend offering each method (onUnsupportedon a 404), so the screens are built and render only when the backend enables them. This head also carries the same Bank visual corrections as the step head (bundled Inter fonts,BankScreenContainerwith the 16 dp board offset, board button type style,PoweredByViewstyle parameters), so for Android Bank it is effectively a superset of the step head977a742.da81546:BankFallbackAPI.swift,BankFallbackInputs.swift,Views/BankFallbackViews.swiftandViews/BankStatementView.swift.977a742(BankStepView.kt), which predates the fallbacks work; the fallbacks head2f1804csupersedes it with the real screens. Whether the backend now offers close-match, micro-deposit and statement is a separate backend-contract question for the owning backend package; the native screens exist and only need stacking. Routing action: stack the Android and iOS Bank fallbacks heads (reconciling the Android fallbacks head with the Android Bank step head, since the fallbacks branch is a parallel superset), not confirm-or-close a scope gap.Also at the Location head but not in the pin:
b0e5be078a46ed3638a832581fdc21d9baf9af45(AppLogo.ktmeasures logo contrast as displayed, composited over the page),aa319fd1b1a32f110aa5489130bbc279216f7001(a StepRecovery session fence; not visual) anda3c2a152(documentation only: README and CHANGELOG). The Android Bank step, Android Bank fallbacks and Location heads all regenerate their committed screenshot baselines to the corrected UI, so the pin's baselines still encode the pre-correction rendering.Verification in this pass
Every exit status below was read from the owning command.
yarn lint,yarn typecheck: exit 0.yarn test --maxWorkers=2: exit 0.Test Suites: 11 passed, 11 total;Tests: 92 passed, 92 total.yarn prepare,git diff --check: exit 0; the working tree is clean and currentmainis already an ancestor.BUILD SUCCESSFUL in 6m 17s, 58 suites and 490 tests with 0 failures (Bank 170, Location 101), including the JVM screenshot tests. The 60 fresh Location captures reproduce the committed captures and the 63 Bank baselines compare clean.yarn turbo run build:androidexit 0,BUILD SUCCESSFUL in 7m 18s. Expo Android example:./gradlew :app:assembleDebugexit 0,BUILD SUCCESSFUL in 12m 20s. Both merged manifests carry foreground fine and coarse location plus optional location hardware, with no background location permission. Every native artefact resolved from the local source repository; the built bundle contains 172 Bank and 108 Location classes.yarn lint,yarn typecheck,yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. The Android native build script now reports the intended missing-pin error instead of a type error when no source pin is configured, for example after the release moves to versioned binaries. Currentmainremains an ancestor, and the pinned revision still equals the native integration branch head, re-verified by remote reference.yarn lint,yarn typecheck,yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. Currentmain(9d50600) remains an ancestor; no base merge was needed. The pin was re-verified equal to the integration branch head and to the integration pull request's head by remote reference, and the native correction commits listed above were confirmed absent from it by ancestry check and by content (nores/font/directory, nolocation_secured_by, parameterlessPoweredByView()calls, no header offset inBankStepView.kt).FAIL: NOT-READY. Passing screenshot regression tests do not establish parity.yarn lint,yarn typecheck,yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests; the working tree is clean and currentmain(9d50600) remains an ancestor, so the code head is unchanged. The pin was re-verified equal to the native integration branch head and to the integration pull request's head by remote reference; the native Android Bank step head977a74266c81231eed7e99144741088579bc3d71is unchanged, the Location head advanced toa3c2a152d31e772301b13e1967304981f82b9962(a documentation-only delta over the previously citedaa319fd1), and the Android Bank fallbacks head2f1804c7db0cf98b00646ff084abee93ff2f26bcand iOS Bank fallbacks headda8154635d67cc4f6d50e67af91fbad2b5dd1023all remain diverged from the pin (none is an ancestor); the pin still has nores/font/directory and nolocation_secured_bystring. All 22 embedded proof URLs were re-fetched: each returns HTTP 200 with PNG content byte-identical (sha256) to the local capture. The pixel matrix was recomputed from exactly the published files: all six percentages reproduce to the third decimal and all six published overlays are pixel-identical (max channel delta 0) to the recomputed overlays.a3c2a152(the extra commit overaa319fd1is documentation only), and item 5 now traces the Bank fallback states to the Android fallbacks head2f1804cand the iOS fallbacks headda81546, which implement them; the earlier "not corrected at any native head" claim was wrong and is withdrawn. Confirmed by source at each head: the fallbacks head carriesCLOSE_MATCH/MICRODEPOSIT/AMOUNTS/STATEMENTplus the same Bank visual corrections, and no Android head carries a Bank step-specific Spanish attribution string. Reproduced the gate independently this pass: rendered all six boards fresh from the frozen canvas (renderer exit 0, owned server stopped and reaped), extracted the six native captures fresh from the pin bygit archive(Bank 585x1266 downsampled to 390x844 with Lanczos, Location native 390x844), and ran the pixel diff in a fresh environment. My six renders are pixel-identical (max channel delta 0) to the published design references, my six pin captures are pixel-identical to the published native captures, and the diff reproduces all six percentages to three decimals (5.815, 6.337, 6.519, 6.690, 8.002, 7.482), 0 of 6 states identical.yarn lint,yarn typecheck,yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. No wrapper source changed and the pin did not move, so the visual gate stays NOT-READY; this pass corrects the routing list the recorded decision makes the routing mechanism.88259c3b2ac57520ead46579ee7c1fb56686cdb1, committed 2026-10-08T08:25:12Z, so the integration branch has not moved and no compliant pin move exists. Re-verified by ancestry check that all six cited native heads remain diverged from the pin. Re-verified the pin's content by source: zero files underandroid/sdk/src/main/res/font/, nolocation_secured_byin the Android resources,HEADER_HEIGHT = 36.dpinBankComponents.kt, a parameterlessPoweredByView()atBankComponents.kt:264, and aBankScreenenum that ends atRESULTwith no close-match, micro-deposit, amounts or statement member. Two precision defects found and corrected in the list above. First, the Android Bank step content is now published twice, as977a742and as a single squashed commit7a22ab291c32def75ac49014945b79fb8937a976; both have the identical root treebb0300745e0aa4969a99bd5a4af1e4b0cace36b9, verified by tree comparison and by an empty diff between the two revisions, so the list now names both and says to stack exactly one. Second, the list cited no iOS Location head and so implied iOS Location might need routing; measured this pass, the pin's iOS Location surface is content-identical to the open iOS Location heada1a50a2c4e9fc253dd064e313da17f4a20676590(empty diff over the Location sources, the Location privacy manifest,GeolocationManager.swift, both Location test files andtest_location_privacy.py), so the list now states that the routing ask is Android-only plus the iOS Bank fallbacks head. Item 3's Bank Spanish attribution string was re-verified absent at all three Android Bank heads. All 22 embedded proof URLs were re-fetched: each returns HTTP 200 once GitHub's/raw/redirect is followed, with a valid PNG body.yarn lint,yarn typecheck,yarn test --maxWorkers=2: exit 0; 11 suites, 92 tests. Currentmain(9d50600) remains an ancestor and the working tree is clean, so the code head is unchanged. This pass did not re-run the pixel matrix: the pinned revision is byte-identical to the one the previous pass reproduced independently and the review round reproduced again, the boards are frozen, and the diff is deterministic over those two inputs, so a third run could only restate 5.815, 6.337, 6.519, 6.690, 8.002 and 7.482. No wrapper source changed and the pin did not move, so the visual gate stays NOT-READY; this pass narrows and corrects the routing list that the recorded decision makes the routing mechanism.yarn lint,yarn typecheck,yarn test --maxWorkers=2: exit 0;Test Suites: 12 passed, 12 total,Tests: 105 passed, 105 total, the new logging guard adding one suite and 13 tests.yarn prepareandgit diff --check: exit 0. Currentmain(9d50600) remains an ancestor and the pin did not move, re-verified equal to the native integration branch head88259c3b2ac57520ead46579ee7c1fb56686cdb1by remote reference this pass. No JDK, Android SDK or Gradle exists in this Linux sandbox, so the module cannot be compiled here; two partial substitutes were run instead. The two new helpers and every call-site form they now receive, including the nullable throwable, the default parameter and both::class.simpleNametemplates, were compiled with Kotlin 2.0.21, the version this module pins, against anandroid.util.Logstub carrying the real Android signatures and aBuildConfigstub: exit 0, no warnings. The whole module was then parsed by the same compiler: zero syntax errors, and its error profile is identical tomain's apart from the absent React Native, native SDK and coroutines classpath. The full module compile against the pinned native source is still unverified here and lands with CI's Android compatibility job.Diagnostic logging
The Android bridge logged data a release build must never log.
android/src/main/java/com/sdkreactnative/SdkReactNativeModule.ktprinted the first 8 characters of the session token together with the verification config, and the workflow entry point printed the workflow identifier,vendorData,metadata,contactDetails,expectedDetailsand the config on one line, plus the parsedConfigurationand, from the SDK error state, the native error message. All 16 call sites used plainLog.dandLog.ewith no build-type check, and the library's release build type setsminifyEnabled false, so nothing stripped them: a release build wrote a credential prefix and personal data to logcat.This revision removes the token and every personal-data field from those logs entirely and routes the remaining diagnostics through two private helpers gated on
BuildConfig.DEBUG, so a release build emits nothing from this module.startVerificationentrystartVerification: startedstartVerificationWithWorkflowentry, 2 callsvendorData,metadata,contactDetails,expectedDetails, configstartVerificationWithWorkflow: startedConfigurationSDK entered Error stateThe gate removes release-build crash diagnostics from this module. That is deliberate:
loggingEnabledin the verification config stays the supported diagnostic channel and is documented in the README.Guard:
src/__tests__/android-logging-privacy.test.tsreads every Kotlin and Java file underandroid/srcand every Swift and Objective-C file underios, and fails when a log call interpolates a token,vendorData,metadata,contactDetails,expectedDetails, the config or configuration, a session identifier or the native error message, and when a call that reaches the platform logger directly sits outside aBuildConfig.DEBUGgate, or outside a#if DEBUGregion in an Apple source. Six negative controls assert that the checker rejects the exact log this revision removed, rejects personal data placed behind the gate, rejects an ungated structural log and rejects a helper that reaches the logger without a gate, so the guard is not vacuous.Reproduced before fixing: with the pre-revision module restored, the guard exits 1 and names all 16 offending call sites, among them
line 49: logs token,line 83: logs vendorData,line 84: logs contactDetails,line 54: logs configurationandline 140: logs state.message. With the fix in place it passes.Both example apps in this repository already default their session token fields to empty, so no demo credential ships in either.
Routing to the native packages, where source is read-only on this side: at the pinned revision
88259c3b,ios/example/verify-sdk/ContentView.swift:111still defaults its demosessionTokento a 12-character hard-coded value. It needs an obvious placeholder. The value is not reproduced here.Visual proof
The images are hosted in this repository on the branch
proof/bank-location-visual-matrix(commit28df9e63153dfc040952feb6476b849534dd5f56); every embedded URL was verified to return HTTP 200 byte-identical to the local capture. Per state and theme: the design reference render of the end-user verification preview (phone 390x844, bare frame), the native Android screen compiled from the pinned native source revision, and the pixel-diff overlay (red = differing pixels, any channel over 24), plus 2x close-ups of the progress bar offset and the Spanish footer string. All captures use static sample data: no personal, provider, credential or token content. Bank native captures were produced at 1.5x density by the committed native screenshot tests and normalized to 390x844 with Lanczos; Location native captures are the committed native 390x844 screenshot-test captures at the pin. This revision changed no rendered surface, its only source change being the Android bridge's diagnostic logging, and did not move the pin, so the native captures remain both the before and the after state.Bank consent, light
Bank consent, dark
Bank consent, Spanish
Location intro, light
Location intro, dark
Location intro, Spanish
Measured deviations (close-ups, 2x)
Progress bar: the reference places it 16 px below the top inset; the native screen draws it at the top inset.
Spanish footer attribution: the reference reads "Protegido por"; the native screen reads "Desarrollado por" in the caption style at the secondary colour.
Still required on a Mac and on devices
Regenerate both CocoaPods lockfiles against the pinned source (neither Xcode nor CocoaPods exists in the Linux build sandbox; no checksum was fabricated), build both iOS examples, run the native-result bridge XCTests including
retryBlockedagainst source and released binaries, and capture the real English and Spanish when-in-use and temporary precise-location prompts in both examples. Authenticated Bank return and cancellation, and physical-device Location flows (denial, approximate grant, Settings return, precise-location retry) remain unverified; the supervisor runs them locally at review.Public metadata
Title and body describe the change in public terms only; the proof images are hosted in this public repository and every embedded link resolves to it. The final squash message must stay public-safe. Editing metadata cannot erase earlier disclosure.