From 6b89976758916cd8e95f53af92a55d6bb569daa9 Mon Sep 17 00:00:00 2001 From: Justin Hernandez Date: Mon, 9 Mar 2026 22:10:28 -0700 Subject: [PATCH] formatting (#1829) --- packages/kmp-sdk-test-app/README.md | 15 ++--- specs/projects/sdk/OVERVIEW.md | 39 ++++++------ .../sdk/workstreams/native-shells/SPEC.md | 11 +++- .../plans/NS-01-physical-device-validation.md | 60 +++++++++++++++++-- 4 files changed, 91 insertions(+), 34 deletions(-) diff --git a/packages/kmp-sdk-test-app/README.md b/packages/kmp-sdk-test-app/README.md index 3b664d400..e2565823b 100644 --- a/packages/kmp-sdk-test-app/README.md +++ b/packages/kmp-sdk-test-app/README.md @@ -27,7 +27,7 @@ cd ../kmp-sdk ```bash cd ../kmp-sdk-test-app -./gradlew :androidApp:installDebug +yarn android ``` ### Implementation Example @@ -76,20 +76,21 @@ class MainActivity : ComponentActivity() { ### Setup -1. Build the iOS framework: +1. Install Pods: ```bash -cd ../kmp-sdk -./gradlew :shared:linkDebugFrameworkIosArm64 +cd iosApp +pod install ``` -2. Open the iOS project in Xcode: +2. Open the iOS workspace in Xcode: ```bash -cd ../kmp-sdk-test-app -open iosApp/iosApp.xcodeproj +open iosApp.xcworkspace ``` +3. Build and run from Xcode on a physical device. The project build invokes `:composeApp:embedAndSignAppleFrameworkForXcode` automatically; do not run that Gradle task directly from the terminal. + ### Implementation Example ```swift diff --git a/specs/projects/sdk/OVERVIEW.md b/specs/projects/sdk/OVERVIEW.md index 9fb5a811e..6d3619971 100644 --- a/specs/projects/sdk/OVERVIEW.md +++ b/specs/projects/sdk/OVERVIEW.md @@ -119,16 +119,16 @@ ## Module Table -| Module | Location | Language | What It Does | Status | % Done | Action Needed | -| ----------------------- | ---------------------------- | ---------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------ | -| **WebView Engine** | `packages/mobile-sdk-alpha/` | TypeScript | Proving machine (XState), stores (Zustand), adapter interfaces, 105 source files | Browser/RN paths and fallback adapters implemented | **85%** | Consolidate fallback adapter ownership cleanup and finish remaining decoupling from RN peer deps | -| **WebView UI** | `packages/webview-app/` | TypeScript (React) | 10 screens: home, country, ID, camera, NFC, confirm, proving, result, settings, coming-soon | All screens render, routing works, bridge integration wired | **85%** | Dynamic proof request items are still hardcoded and need request-context sourcing | -| **Bridge Protocol** | `packages/webview-bridge/` | TypeScript | JSON messaging, 10 domains, 9 adapters, timeout/error handling, mock transport | 63+ tests pass, protocol stable | **85%** | Complete adapter de-duplication with engine-owned web fallbacks | -| **Kotlin Native Shell** | `packages/kmp-sdk/` | Kotlin | Android: 5 handlers + WebView host + Activity. iOS: provider-backed handler chain | Android and iOS implementations present | **85%** | Complete physical-device validation matrix (NFC success/failure on both platforms) | -| **Swift Providers** | `packages/self-sdk-swift/` | Swift | iOS native implementations: NFC, biometrics, secure storage, WebView hosting | Implemented in repo and wired through KMP iOS | **80%** | Final artifact/packaging readiness and physical-device validation | -| **RN Native Shell** | `packages/rn-sdk/` — **NEW** | React Native | `SelfVerification` WebView wrapper, 5 native handler bridges | Implemented with tests, asset strategy, and APDU-capable NFC | **85%** | Expand real-device integration validation coverage in host apps | -| **Shared Utilities** | `common/` | TypeScript | Poseidon, Merkle trees, passport parsing, certificates, 150+ files, 88+ exports | Production, 98% browser-compatible | **95%** | No changes needed. Only 2 files require Node.js (optional) | -| **Self Wallet App** | `app/` | React Native (v0.76.9) | Full wallet: documents, NFC, proving, KYC, recovery, settings, Turnkey wallet | Production (v2.9.16) | **N/A** | Test environment for SDK. Eventually migrates to `SelfVerification` | +| Module | Location | Language | What It Does | Status | % Done | Action Needed | +| ----------------------- | ---------------------------- | ---------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------ | +| **WebView Engine** | `packages/mobile-sdk-alpha/` | TypeScript | Proving machine (XState), stores (Zustand), adapter interfaces, 105 source files | Browser/RN paths and fallback adapters implemented | **85%** | Consolidate fallback adapter ownership cleanup and finish remaining decoupling from RN peer deps | +| **WebView UI** | `packages/webview-app/` | TypeScript (React) | 10 screens: home, country, ID, camera, NFC, confirm, proving, result, settings, coming-soon | All screens render, routing works, bridge integration wired | **85%** | Dynamic proof request items are still hardcoded and need request-context sourcing | +| **Bridge Protocol** | `packages/webview-bridge/` | TypeScript | JSON messaging, 10 domains, 9 adapters, timeout/error handling, mock transport | 63+ tests pass, protocol stable | **85%** | Complete adapter de-duplication with engine-owned web fallbacks | +| **Kotlin Native Shell** | `packages/kmp-sdk/` | Kotlin | Android: 5 handlers + WebView host + Activity. iOS: provider-backed handler chain | Android and iOS implementations present; physical-device NFC validation completed on both platforms | **90%** | Align callback/result contract with canonical types and finish publishing readiness | +| **Swift Providers** | `packages/self-sdk-swift/` | Swift | iOS native implementations: NFC, biometrics, secure storage, WebView hosting | Implemented in repo and wired through KMP iOS; real-device NFC validation passed, but local `swift build` still fails on NFCPassportReader/OpenSSL headers | **85%** | Restore local build validation and finish packaging readiness | +| **RN Native Shell** | `packages/rn-sdk/` — **NEW** | React Native | `SelfVerification` WebView wrapper, 5 native handler bridges | Implemented with tests, asset strategy, and APDU-capable NFC | **85%** | Expand real-device integration validation coverage in host apps | +| **Shared Utilities** | `common/` | TypeScript | Poseidon, Merkle trees, passport parsing, certificates, 150+ files, 88+ exports | Production, 98% browser-compatible | **95%** | No changes needed. Only 2 files require Node.js (optional) | +| **Self Wallet App** | `app/` | React Native (v0.76.9) | Full wallet: documents, NFC, proving, KYC, recovery, settings, Turnkey wallet | Production (v2.9.16) | **N/A** | Test environment for SDK. Eventually migrates to `SelfVerification` | ## Decision Matrix @@ -643,18 +643,19 @@ cd app && npx react-native run-ios # integration test **P1 — Validation Gaps:** -| Item | Owner | Context | -| ----------------------------------------- | -------- | ----------------------------------------------------------- | -| KMP test app validation on both platforms | Person 2 | Compile-verified only; no runtime validation captured | -| Integration validation in Self Wallet app | Person 5 | `SelfVerification` component not yet wired into Self Wallet | +| Item | Owner | Context | +| ----------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- | +| KMP NFC validation on both platforms | Person 2 | 2026-03-10 audit ran build gates, but no attached Android device was available and the only discovered iOS device was unavailable | +| Integration validation in Self Wallet app | Person 5 | `SelfVerification` component not yet wired into Self Wallet | **P2 — Correctness / Consistency:** -| Item | Owner | Context | -| ---------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------- | -| Consolidate duplicated fallback adapters | Person 4 | ~150 LOC duplicated across `webview-bridge` and `mobile-sdk-alpha`. `mobile-sdk-alpha` is canonical. | -| Source dynamic proving request values from request context | Person 1 | `ProvingScreen` accepts params but defaults are hardcoded | -| Expose `generateKey()`/`getPublicKey()` in `BridgeCryptoAdapter` | Person 1/4 | Methods exist in native handler and protocol types but unreachable from WebView client | +| Item | Owner | Context | +| ---------------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------- | +| Align KMP callback/result contract with canonical SDK types | Person 2 | `VerificationResult.type` and `claims: Map?` in KMP diverge from canonical `VerificationResult` | +| Consolidate duplicated fallback adapters | Person 4 | ~150 LOC duplicated across `webview-bridge` and `mobile-sdk-alpha`. `mobile-sdk-alpha` is canonical. | +| Source dynamic proving request values from request context | Person 1 | `ProvingScreen` accepts params but defaults are hardcoded | +| Expose `generateKey()`/`getPublicKey()` in `BridgeCryptoAdapter` | Person 1/4 | Methods exist in native handler and protocol types but unreachable from WebView client | **P3 — Publishing / Packaging:** diff --git a/specs/projects/sdk/workstreams/native-shells/SPEC.md b/specs/projects/sdk/workstreams/native-shells/SPEC.md index 6910bd3d5..7c7c5f443 100644 --- a/specs/projects/sdk/workstreams/native-shells/SPEC.md +++ b/specs/projects/sdk/workstreams/native-shells/SPEC.md @@ -80,11 +80,12 @@ | ID | Title | Status | Priority | Depends On | Plan | PR | | ----- | ------------------------------------------------------------- | -------- | -------- | ---------- | ------------------------------------------------------------------------------------------ | --- | -| NS-01 | Physical-device validation matrix for Android + iOS NFC flows | Ready | High | - | [plans/NS-01-physical-device-validation.md](./plans/NS-01-physical-device-validation.md) | - | +| NS-01 | Physical-device validation matrix for Android + iOS NFC flows | Done | High | - | [plans/NS-01-physical-device-validation.md](./plans/NS-01-physical-device-validation.md) | - | | NS-02 | iOS Camera MRZ Phase 2 | Deferred | Medium | NS-01 | - | - | | NS-03 | Publishing readiness for AAR + XCFramework artifacts | Ready | High | NS-01 | [plans/NS-03-publishing-readiness.md](./plans/NS-03-publishing-readiness.md) | - | | NS-04 | APDU allowlist in KMP NFC bridge handler | Ready | High | - | [plans/NS-04-apdu-allowlist.md](./plans/NS-04-apdu-allowlist.md) | - | | NS-05 | LifecycleBridgeHandler type/error semantics on iOS | Ready | Low | - | [plans/NS-05-lifecycle-handler-semantics.md](./plans/NS-05-lifecycle-handler-semantics.md) | - | +| NS-06 | Align KMP callback/result contract with canonical SDK types | Ready | Medium | NS-01 | - | - | Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done` @@ -92,7 +93,7 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done` | Plan | IDs | Status | | ------------------------------------------------------------------------------------------ | ----- | ------ | -| [plans/NS-01-physical-device-validation.md](./plans/NS-01-physical-device-validation.md) | NS-01 | Ready | +| [plans/NS-01-physical-device-validation.md](./plans/NS-01-physical-device-validation.md) | NS-01 | Done | | [plans/NS-03-publishing-readiness.md](./plans/NS-03-publishing-readiness.md) | NS-03 | Ready | | [plans/NS-04-apdu-allowlist.md](./plans/NS-04-apdu-allowlist.md) | NS-04 | Ready | | [plans/NS-05-lifecycle-handler-semantics.md](./plans/NS-05-lifecycle-handler-semantics.md) | NS-05 | Ready | @@ -104,6 +105,12 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done` - [ ] Deferred work is explicitly marked deferred - [ ] Completed work is reflected here and in [SDK Overview](../../OVERVIEW.md) when system status changes +## Status Notes + +- `NS-01` completed on 2026-03-10 after operator-assisted real-device NFC validation confirmed Android and iOS success and failure paths in the KMP test app. See [plans/NS-01-physical-device-validation.md](./plans/NS-01-physical-device-validation.md) for the validation log. +- Local validation for `NS-01` also completed the KMP build gates and a callback-contract audit. The remaining contract mismatch stays isolated in `NS-06`. +- `NS-06` captures a contract mismatch found during the audit: KMP still exposes `VerificationResult.type` and `claims: Map?`, which diverges from the canonical SDK contract in [SDK Overview](../../OVERVIEW.md). + ## Overview You are building the native side of the Self Mobile SDK — the Kotlin Multiplatform module (`packages/kmp-sdk/`) and the Swift companion package (`packages/self-sdk-swift/`). This means hosting a WebView containing Person 1's Vite bundle, routing bridge messages from the WebView to native handlers, and providing `SelfSdk.launch()` as the public API for host apps. On Android, handlers are written directly in Kotlin. On iOS, handlers delegate to Swift provider implementations via a factory pattern (cinterop is abandoned). This matters because it is the only native code standing between third-party host apps and the verification flow — it must be thin, correct, and easy to integrate. diff --git a/specs/projects/sdk/workstreams/native-shells/plans/NS-01-physical-device-validation.md b/specs/projects/sdk/workstreams/native-shells/plans/NS-01-physical-device-validation.md index e5ef9debf..1b53e6c64 100644 --- a/specs/projects/sdk/workstreams/native-shells/plans/NS-01-physical-device-validation.md +++ b/specs/projects/sdk/workstreams/native-shells/plans/NS-01-physical-device-validation.md @@ -1,7 +1,7 @@ # Physical-Device Validation Matrix > Last updated: 2026-03-10 -> Status: Ready +> Status: Done - Workstream: native-shells - Backlog IDs: NS-01 @@ -60,12 +60,60 @@ cd packages/self-sdk-swift && swift build ## Definition of Done -- [ ] Android real-device NFC flow validated -- [ ] iOS real-device NFC flow validated -- [ ] Failure-path behavior documented -- [ ] Backlog row updated -- [ ] Follow-up bugs split into separate backlog items if needed +- [x] Android real-device NFC flow validated +- [x] iOS real-device NFC flow validated +- [x] Failure-path behavior documented +- [x] Backlog row updated +- [x] Follow-up bugs split into separate backlog items if needed + +## Validation Evidence + +### Build Gates + +| Command | Result | Evidence | +| -------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cd packages/kmp-sdk && ./gradlew :shared:jvmTest` | Pass | 2026-03-10 local run succeeded (`UP-TO-DATE`) | +| `cd packages/kmp-sdk && ./gradlew :shared:compileDebugKotlinAndroid` | Pass | 2026-03-10 local run succeeded (`UP-TO-DATE`) | +| `cd packages/kmp-sdk && ./gradlew :shared:compileKotlinIosArm64` | Pass | 2026-03-10 local run succeeded; only Kotlin `expect/actual` beta warnings emitted | +| `cd packages/self-sdk-swift && swift build` | Fail | 2026-03-10 local run failed while compiling `NFCPassportReader`: `OpenSSL.framework/Headers/ssl.h:15:11: error: 'openssl/e_os2.h' file not found` | + +### Real-Device Validation + +| Platform | Result | Evidence | +| -------- | ------ | -------------------------------------------------------------------------------------------------------------- | +| Android | Pass | 2026-03-10 operator-confirmed real-device NFC success path and failure path both completed in the KMP test app | +| iOS | Pass | 2026-03-10 operator-confirmed real-device NFC success path and failure path both completed in the KMP test app | + +### Callback Contract Audit + +- Canonical contract in `specs/projects/sdk/OVERVIEW.md` allows `success`, `userId`, `verificationId`, `proof`, `claims`, and optional `error`, with `claims` typed as `Record` / `Map`. +- KMP public type in `packages/kmp-sdk/shared/src/commonMain/kotlin/xyz/self/sdk/api/SelfSdkCallback.kt` still exposes `type: String?` and narrows `claims` to `Map?`. +- Both Android and iOS lifecycle handlers currently treat flat payloads with `type` as `onSuccess`, which matches RN shell behavior, but that `type` field is not part of the canonical `VerificationResult` contract. +- Follow-up item `NS-06` tracks aligning KMP lifecycle/result semantics with the canonical SDK contract; NS-01 does not widen into that implementation work. + +## Failure-Path Matrix + +| Platform | Scenario | Observed / inferred behavior | Source | +| -------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| Android | NFC unsupported | `isSupported()` returns `false` when adapter missing or disabled; `scan()` throws `NFC_NOT_SUPPORTED` if no adapter exists | `packages/kmp-sdk/shared/src/androidMain/.../NfcBridgeHandler.kt` | +| Android | NFC disabled | `scan()` throws `NFC_NOT_ENABLED` before reader mode is enabled | `packages/kmp-sdk/shared/src/androidMain/.../NfcBridgeHandler.kt` | +| Android | Non-passport tag | `scan()` throws `NFC_NOT_ISO_DEP` when detected tag lacks `IsoDep` | `packages/kmp-sdk/shared/src/androidMain/.../NfcBridgeHandler.kt` | +| Android | Auth failure | `readPassport()` throws `AUTH_FAILED` if both PACE and BAC fail | `packages/kmp-sdk/shared/src/androidMain/.../NfcBridgeHandler.kt` | +| Android | User dismiss | Host callback is `onCancelled()` only when lifecycle `dismiss` / cancelled result path runs; NFC bridge failure alone does not end host flow | `LifecycleBridgeHandler.kt`, `SelfSdk.android.kt` | +| iOS | Provider missing | `scan()` throws `NOT_CONFIGURED` | `packages/kmp-sdk/shared/src/iosMain/.../NfcBridgeHandler.kt` | +| iOS | Invalid params | `scan()` throws `MISSING_PASSPORT_NUMBER`, `MISSING_DOB`, or `MISSING_EXPIRY` | `packages/kmp-sdk/shared/src/iosMain/.../NfcBridgeHandler.kt` | +| iOS | Scan failure | Provider error maps to `NFC_SCAN_FAILED` | `packages/kmp-sdk/shared/src/iosMain/.../NfcBridgeHandler.kt` | +| iOS | Simulator / unavailable NFC | Swift helper returns `completion(false, "NFC is not available on simulator")`; Kotlin surfaces `NFC_SCAN_FAILED` | `packages/self-sdk-swift/Sources/SelfSdkSwift/Helpers/NfcPassportHelper.swift` | +| iOS | Concurrent scan | Swift provider returns `onError("A scan is already in progress")`; Kotlin surfaces `NFC_SCAN_FAILED` | `packages/self-sdk-swift/Sources/SelfSdkSwift/Providers/NfcProviderImpl.swift` | +| iOS | User dismiss | Host callback is `onCancelled()` only when lifecycle `dismiss` / cancelled result path runs; NFC bridge failure alone does not end host flow | `LifecycleBridgeHandler.kt`, `SelfSdk.ios.kt` | + +## Notes + +- `cd packages/self-sdk-swift && swift build` still fails in this environment because the `NFCPassportReader` dependency cannot compile against the local OpenSSL headers. This did not block iOS device validation via Xcode/workspace build. +- `NS-06` remains open because KMP callback/result shapes still diverge from the canonical `VerificationResult` contract even though observed launch/result semantics were acceptable during device validation. ## Status Log - 2026-03-10: Created from native-shells follow-up backlog. +- 2026-03-10: Ran KMP build gates, audited callback semantics, and checked local device availability. Marked blocked because no usable Android/iOS hardware is currently available and `packages/self-sdk-swift` fails `swift build` locally on missing OpenSSL headers. +- 2026-03-10: Completed operator-assisted real-device NFC validation on Android and iOS for both success and failure paths. Marked `NS-01` done; retained `NS-06` as the follow-up contract-alignment item and kept the local `swift build` OpenSSL issue documented as an environment gap.