Skip to content

Release to Staging - 2025-12-16#1516

Merged
transphorm merged 12 commits intostagingfrom
release/staging-2025-12-16
Dec 17, 2025
Merged

Release to Staging - 2025-12-16#1516
transphorm merged 12 commits intostagingfrom
release/staging-2025-12-16

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Dec 16, 2025

🚀 Weekly Release to Staging

Release Date: December 16, 2025
Release Branch: release/staging-2025-12-16

This automated PR promotes a snapshot of dev to staging for testing.

What's Included

All commits merged to dev up to the branch creation time.

Note: This PR uses a dedicated release branch, so new commits to dev will NOT automatically appear here.

Review Checklist

  • All CI checks pass
  • Code review completed
  • QA team notified
  • Ready to merge to staging environment

Next Steps

After merging, the staging environment will be updated. A production release PR will be created on Sunday.


This PR was automatically created by the Release Calendar workflow on December 16, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added back navigation button on QR code scanner for easier navigation
    • Dynamic scan prompts adapted to your document type
    • Document expiration validation prevents operations on expired documents
  • Improvements

    • Conditional route visibility based on available documents
    • Updated app branding to "Self.xyz Mobile App"
  • Bug Fixes

    • Removed "Need Help?" button from error screen

✏️ Tip: You can customize this high-level summary in your review settings.

seshanthS and others added 11 commits December 15, 2025 13:06
* Disable Verify button for expired documents

* coderabbit feedbacks
Update build numbers and deployment timestamps after successful deployment.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* Add back navigation to QR scanner view

* linting

* remove custom hook. use default package
* fix sentry replays

* clean up comments
* Fix paste button on recovery screen

* Improve recovery paste button accessibility

* recovery screen bugfix

* simplify fix. remove pressable logic
* Hide document-only settings without documents

* revert document info screen changes, rely on hiding option from settings view

* agent feedback

* hide settings options that depend on having a document
* Update document scan prompt

* formatting

* fix scan instruction location

* use helper for title text
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Walkthrough

This PR consolidates document attribute extraction into a centralized utility module, implements document expiration validation during verification, migrates custom hooks to library implementations, refactors navigation to use reset-based state management for deeplinks, and introduces conditional routing based on document availability. Version numbers are bumped and configuration/constants are updated.

Changes

Cohort / File(s) Change Summary
Project Metadata
app/README.md, app/version.json
Updated app title from "OpenPassport App" to "Self.xyz Mobile App"; bumped iOS build 193→194 and Android build 125→126 with updated timestamps.
Utility Module Creation
app/src/utils/documentAttributes.ts
New centralized module for document attribute extraction, expiration checks, date formatting, and scan prompts; exports DocumentAttributes interface and utilities for Aadhaar, MRZ/Passport, and generic document processing.
Document Attribute Refactoring
app/src/components/homescreen/IdCard.tsx
Replaced inline attribute extraction logic with imports from documentAttributes utilities; removed per-type helper functions; delegated document processing to shared utilities.
Document Expiration Feature
app/src/screens/verification/ProveScreen.tsx, packages/mobile-sdk-alpha/src/components/buttons/HeldPrimaryButtonProveScreen.tsx
Integrated document expiration check in ProveScreen effect; gates store initialization and auto-scroll on expiration status; extended HeldPrimaryButtonProveScreen with isDocumentExpired prop to display "Document expired" and block ready state transitions.
Navigation & Deeplinks
app/src/navigation/deeplinks.ts, app/tests/src/navigation/deeplinks.test.ts
Replaced push-based navigation with reset-based state management (navigationRef.reset with createDeeplinkNavigationState) for Prove screen routing; updated corresponding test assertions.
Navigation Screen Options
app/src/navigation/verification.ts
Added gestureEnabled: false to ProofRequestStatus, Prove, and QRCodeViewFinder screens to disable gesture-based back navigation.
QR Code Scanner UI
app/src/screens/verification/QRCodeViewFinderScreen.tsx
Added safe-area-aware NavBar.Container with back navigation control; integrated haptic feedback on back action; imported NavBar components and buttonTap utility.
Safe Area Insets Migration
app/src/hooks/useSafeAreaInsets.ts (removed), app/src/screens/account/settings/ShowRecoveryPhraseScreen.tsx, app/src/screens/documents/selection/CountryPickerScreen.tsx
Deleted custom useSafeAreaInsets hook that applied platform-specific minimum insets; migrated usages to react-native-safe-area-context library implementation.
Configuration
app/src/config/sentry.ts
Added mobileReplayIntegration import and enabled replay with maskAllText: true, maskAllImages: false, maskAllVectors: false.
Conditional Document-Based Routing
app/src/screens/account/settings/SettingsScreen.tsx
Added stateful logic to load document catalog via usePassport; filters document-dependent routes from screenRoutes based on hasRealDocument availability; includes error logging for catalog load/validation failures.
Paste Validation Relaxation
app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx
Replaced ethers.Mnemonic.isValidMnemonic validation with non-empty clipboard check in onPaste handler (bugfix comment added).
Document Scanning Prompts
app/src/screens/documents/scanning/DocumentCameraScreen.tsx, app/src/screens/documents/selection/DocumentOnboardingScreen.tsx
Imported getDocumentScanPrompt and useSelfClient; replaced static "Scan your ID" text with dynamic prompts based on selectedDocumentType from MRZ store.
Onboarding State Sync
packages/mobile-sdk-alpha/src/flows/onboarding/id-selection-screen.tsx
Updated MRZ state with selected documentType via selfClient.getMRZState().update() before emitting DOCUMENT_TYPE_SELECTED event.
Onboarding UI Updates
packages/mobile-sdk-alpha/src/flows/onboarding/country-picker-screen.tsx
Added showInfoIcon={false} to CountryPickerUI component.
Aadhaar Error Screen
app/src/screens/documents/aadhaar/AadhaarUploadErrorScreen.tsx
Removed SecondaryButton import and commented out "Need Help?" button rendering; PrimaryButton "Try Again" remains.
Dependencies
app/package.json, packages/mobile-sdk-alpha/package.json
Bumped @selfxyz/euclid from ^0.6.0 to ^0.6.1 in both packages.
Constants & Utilities
common/src/constants/constants.ts, common/src/utils/aadhaar/utils.ts
Updated PCR0_MANAGER_ADDRESS to 0xE36d4EE5Fd3916e703A46C21Bb3837dB7680C8B8; changed timestamp parsing in returnNewDateString to interpret input as milliseconds (+timestamp) instead of seconds (+timestamp \* 1000).

Sequence Diagram(s)

sequenceDiagram
    participant ProveScreen
    participant useEffect
    participant loadSelectedDocument
    participant checkDocumentExpiration
    participant provingStore
    participant HeldPrimaryButtonProveScreen
    participant UI

    ProveScreen->>useEffect: sessionId changes
    useEffect->>loadSelectedDocument: retrieve document
    loadSelectedDocument-->>useEffect: document loaded
    useEffect->>checkDocumentExpiration: check expiry date
    checkDocumentExpiration-->>useEffect: isExpired boolean
    
    alt Document Not Expired
        useEffect->>provingStore: init(selfClient, 'disclose')
        provingStore-->>useEffect: store initialized
        useEffect->>HeldPrimaryButtonProveScreen: pass isDocumentExpired=false
        HeldPrimaryButtonProveScreen->>UI: render ready to prove
    else Document Expired
        useEffect->>HeldPrimaryButtonProveScreen: pass isDocumentExpired=true
        HeldPrimaryButtonProveScreen->>UI: render "Document expired"
        HeldPrimaryButtonProveScreen->>UI: block ready state transition
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Document expiration integration: Review logic in ProveScreen.tsx effect and HeldPrimaryButtonProveScreen state machine; verify guard conditions prevent initialization with expired documents and that UI correctly reflects expiration status.
  • Navigation state reset: Verify deeplink handling correctly uses reset-based navigation vs. push; ensure test assertions match new behavior and navigation stack ends at Prove with correct parent context.
  • Utility centralization: Validate documentAttributes.ts handles Aadhaar, MRZ/Passport, and edge cases; confirm refactored IdCard.tsx and related components correctly use extracted utilities without behavioral changes.
  • Conditional routing logic: Verify SettingsScreen document catalog loading, null-state handling, and route filtering logic functions correctly when documents are unavailable.
  • Timestamp parsing change: Confirm milliseconds-as-epoch interpretation in aadhaar/utils.ts is intentional and aligns with backend Aadhaar data format.

Possibly related PRs

Poem

🔐 Documents now expire with grace,
Reset flows take deeplinks to their place,
Utilities centralized, clean and lean,
Safe insets migrate to libraries serene,
Self.xyz rises—verification refined! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Release to Staging - 2025-12-16' is a generic release identifier that does not meaningfully describe the technical changes in the changeset. Consider using a more descriptive title that highlights key changes, such as 'Release: Add document expiration checks and refactor document utilities' or a similar summary of primary changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch release/staging-2025-12-16

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

* Improve prove deeplink navigation

* fix tests
@transphorm
Copy link
Member

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx (1)

62-65: Missing user feedback on validation failure.

When mnemonic validation fails, the function silently returns without providing any user feedback. The user will see the loading state briefly disappear with no explanation of why the recovery failed. This creates a confusing experience, especially now that invalid mnemonics can be pasted into the text area.

As per coding guidelines: "Provide user-friendly error messages in UI and error handlers."

Consider adding an error state and displaying a message to the user when validation fails:

+  const [error, setError] = useState<string>();
+
   const restoreAccount = useCallback(async () => {
     try {
+      setError(undefined);
       setRestoring(true);
       const slimMnemonic = mnemonic?.trim();
       if (!slimMnemonic || !ethers.Mnemonic.isValidMnemonic(slimMnemonic)) {
+        setError('Invalid recovery phrase. Please check and try again.');
         setRestoring(false);
         return;
       }

Then display the error message in the UI below the text area or as a toast notification.

common/src/utils/aadhaar/utils.ts (1)

400-418: Improve type safety and add documentation.

The timestamp parameter is typed as string? but is coerced to a number without validation. Consider:

  • Document the expected timestamp format (milliseconds since epoch)
  • Use number type instead of string, or add explicit parsing with validation
  • Document the IST offset behavior

Apply this diff to improve type safety:

-export function returnNewDateString(timestamp?: string): string {
-  const newDate = timestamp ? new Date(+timestamp) : new Date();
+/**
+ * Generates a date string in IST timezone formatted as YYYYMMDDHHmmssSSS
+ * @param timestampMs - Optional timestamp in milliseconds since epoch (UTC)
+ * @returns Formatted date string in IST timezone
+ */
+export function returnNewDateString(timestampMs?: number): string {
+  const newDate = timestampMs ? new Date(timestampMs) : new Date();
♻️ Duplicate comments (1)
packages/mobile-sdk-alpha/package.json (1)

154-154: Verify the @selfxyz/euclid version update.

Same verification needed as in app/package.json for version ^0.6.1.

🧹 Nitpick comments (5)
app/src/screens/account/settings/SettingsScreen.tsx (1)

165-178: Log the error for better observability.

The catch block swallows the error without logging it. When catalog loading fails, you'll have no diagnostic information about the cause (network failure, permission issue, etc.).

Apply this diff to improve error logging:

-    } catch {
-      console.warn('SettingsScreen: failed to load document catalog');
+    } catch (error) {
+      console.warn('SettingsScreen: failed to load document catalog', error);
       setHasRealDocument(false);
     }
common/src/utils/aadhaar/utils.ts (1)

401-401: Remove: breaking change claim is incorrect; timestamp format is already milliseconds in actual usage.

Line 401's change from +timestamp * 1000 to +timestamp is not a breaking change. The actual caller at common/src/utils/passports/genMockIdDoc.ts:84 already passes new Date().getTime().toString(), which is in milliseconds—matching the new code's expectation.

However, address compliance violations:

  • Lines 405-407: Applies IST offset (+5:30) to UTC timestamps. Per compliance guidelines, use UTC timestamps only for verification operations.
  • Lines 408-415: Returns custom format (YYYYMMDDHHMMSSMMM) instead of ISO 8601 (YYYY-MM-DD).
packages/mobile-sdk-alpha/src/components/buttons/HeldPrimaryButtonProveScreen.tsx (1)

215-215: Consider disabling the button when document is expired.

Currently isDisabled only checks !state.matches('ready'), but when isDocumentExpired is true, the button shows "Document expired" yet may still appear interactive. Consider updating the disabled logic:

-  const isDisabled = !state.matches('ready');
+  const isDisabled = !state.matches('ready') || isDocumentExpired;

This provides better UX by making the button visually non-interactive when the document is expired.

app/src/screens/documents/aadhaar/AadhaarUploadErrorScreen.tsx (1)

11-11: Consider alternative user assistance path.

The "Need Help?" button has been removed, leaving users with only a "Try Again" option when encountering Aadhaar upload errors. While the TODO comment suggests the help functionality was incomplete, removing user assistance without an alternative path may impact user experience, especially for error recovery scenarios.

If help functionality is deferred, consider:

  • Adding a link or guidance in the error description text
  • Implementing a lightweight in-app help modal
  • Providing documentation links for common error scenarios

Also applies to: 98-107

app/src/utils/documentAttributes.ts (1)

13-17: Remove misplaced JSDoc comment.

The JSDoc comment describes "Gets the scan prompt for a document type" but precedes the DocumentAttributes interface definition. This comment belongs to the getDocumentScanPrompt function at line 221 or should be removed here.

Apply this diff to remove the misplaced comment:

-/**
- * Gets the scan prompt for a document type.
- * @param documentType - Document type code ('p' = Passport, 'i' = ID card, 'a' = Aadhaar)
- * @returns Scan prompt text
- */
 export interface DocumentAttributes {

Comment on lines +168 to +172
mobileReplayIntegration({
maskAllText: true,
maskAllImages: false,
maskAllVectors: false,
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider masking images and vectors for PII protection.

While maskAllText: true protects text-based PII, maskAllImages: false and maskAllVectors: false could expose sensitive information in this identity verification app. Document photos, passport images, and ID scans may be captured in session replays.

Consider updating to:

maskAllText: true,
maskAllImages: true,
maskAllVectors: true,

As per coding guidelines: "NEVER log sensitive data including PII (names, DOB, passport numbers, addresses), credentials, tokens, API keys, private keys, or session identifiers."

🤖 Prompt for AI Agents
In app/src/config/sentry.ts around lines 168 to 172, the mobileReplayIntegration
currently masks text but leaves images and vectors unmasked; update the
integration options to set maskAllImages: true and maskAllVectors: true so that
images and vector data (e.g., document photos, passport scans) are redacted
during session replay, and run a quick local build/format to ensure no lint
errors after the change.

Comment on lines +51 to +52
// bugfix: perform a simple clipboard check; ethers.Mnemonic.isValidMnemonic doesn't work
if (clipboard) {
Copy link
Contributor

@coderabbitai coderabbitai bot Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find the file
find . -name "RecoverWithPhraseScreen.tsx" -type f 2>/dev/null | head -5

Repository: selfxyz/self

Length of output: 118


🏁 Script executed:

#!/bin/bash
# Find and examine the RecoverWithPhraseScreen.tsx file
if [ -f "app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx" ]; then
  echo "=== File found, examining content ==="
  cat -n "app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx" | sed -n '40,80p'
  echo ""
  echo "=== Around line 62 ==="
  cat -n "app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx" | sed -n '55,70p'
  echo ""
  echo "=== Around line 190-200 (button state) ==="
  cat -n "app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx" | sed -n '190,210p'
fi

Repository: selfxyz/self

Length of output: 3099


🏁 Script executed:

#!/bin/bash
# Search for all isValidMnemonic usages in the file
rg -n "isValidMnemonic" app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx -A 2 -B 2

Repository: selfxyz/self

Length of output: 530


🏁 Script executed:

#!/bin/bash
# Get file size and total lines
wc -l app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx

Repository: selfxyz/self

Length of output: 120


Misleading comment and inconsistent validation logic in recovery flow.

The comment at line 51 states that ethers.Mnemonic.isValidMnemonic "doesn't work," yet this same function is still used for validation at line 62 in restoreAccount. The actual issue is that validation was removed from the onPaste handler (only checks if clipboard is non-empty), but validation still occurs when the user presses Continue. However, when validation fails at lines 62-65, there's no user feedback—the function silently returns.

This creates poor UX in a security-sensitive recovery flow: users can paste an invalid mnemonic and only discover the error after pressing Continue, with no indication of what went wrong.

Clarify the comment to reflect the intentional UX change (e.g., "Allow pasting any text; validation occurs on Continue button press") and add user-facing error feedback when validation fails.

🤖 Prompt for AI Agents
In app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx around lines
51-52 and 62-65, update the misleading comment and add user-facing feedback for
failed mnemonic validation: change the comment at line 51 to something like
"Allow pasting any text; validation is performed on Continue" so it reflects
intent, keep the onPaste handler accepting any non-empty clipboard text, and in
restoreAccount replace the silent return on invalid mnemonic with explicit user
feedback (e.g., set an error state/validation message or show an alert/toast)
that explains the mnemonic is invalid so the user knows why recovery failed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't work as a gate. we should allow users to paste whatever they want. i tried pasting a real recovery phrase and it wouldn't allow me to do so

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@transphorm, thank you for the clarification! That makes sense—if isValidMnemonic was producing false negatives and blocking valid recovery phrases, removing it from the paste gate is the right fix. Allowing users to paste any content and validating only when they press Continue is a good approach.

One suggestion: when validation does fail at line 62 (in restoreAccount), the function silently returns without feedback. Consider adding a user-facing error message (e.g., a toast or alert stating "Invalid recovery phrase") so users understand why the recovery didn't proceed. This would improve the UX in the security-sensitive recovery flow.


✏️ Learnings added
Learnt from: transphorm
Repo: selfxyz/self PR: 1516
File: app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx:51-52
Timestamp: 2025-12-17T15:27:34.682Z
Learning: In app/src/screens/account/recovery/RecoverWithPhraseScreen.tsx, ethers.Mnemonic.isValidMnemonic should not be used as a gate for pasting recovery phrases because it produces false negatives and rejects valid mnemonics. Allow users to paste any clipboard content; validation should only occur when the user attempts to restore the account.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@transphorm transphorm merged commit f1bddc1 into staging Dec 17, 2025
42 checks passed
@transphorm transphorm deleted the release/staging-2025-12-16 branch December 17, 2025 15:27
@coderabbitai coderabbitai bot mentioned this pull request Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants