✨ server: integrate sardine#594
Conversation
🦋 Changeset detectedLatest commit: ddc66a8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Summary of ChangesHello @cruzdanilo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces the integration of the Sardine fraud detection platform into the server-side application. The primary goal is to enhance security and mitigate fraud by performing real-time risk assessments at critical user touchpoints, such as account creation, card provisioning, and identity verification via Persona. This involves setting up necessary API credentials, expanding data collection from Persona, and implementing calls to Sardine's API to evaluate customer risk levels, with the capability to prevent high-risk actions. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request integrates the Sardine fraud detection service into the application. Key changes include adding Sardine API key and URL environment variables, creating a new sardine.ts utility for API interactions with valibot schemas, and incorporating Sardine customer calls at critical points: user signup, Persona inquiry approval, and card issuance. The Persona integration was expanded to collect more detailed customer data for Sardine. Testing mocks were also updated to accommodate the new service. Review comments address an incorrect Basic authentication header format for Sardine, the need for the request utility to handle empty API responses gracefully by returning undefined, the brittleness of hardcoded string mappings for annualSalary and expectedMonthlyVolume in the Persona hook, and an incomplete mock for the Sardine feedback function in tests.
There was a problem hiding this comment.
This PR is being reviewed by Cursor Bugbot
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
There was a problem hiding this comment.
Code Review
This pull request integrates Sardine for risk assessment across several key user flows. A new Sardine client is introduced with strict schemas, and it's wired into credential creation, Persona KYC hooks, and card issuance. The changes are well-structured, with corresponding updates to configuration and tests. My review includes a few suggestions to improve robustness, maintainability, and test correctness. I've identified a critical issue in the response handling of the new Sardine client, a potential availability risk due to a very short timeout, and some opportunities for code refinement and fixing incorrect test mocks.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #594 +/- ##
==========================================
+ Coverage 46.02% 48.51% +2.49%
==========================================
Files 40 41 +1
Lines 6584 6985 +401
Branches 478 501 +23
==========================================
+ Hits 3030 3389 +359
- Misses 3537 3579 +42
Partials 17 17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@sentry review |
|
@sentry review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request integrates Sardine for risk evaluation and event tracking. I've identified a critical authentication issue in the new Sardine client, a brittle data mapping in the Persona webhook handler, and an issue with handling empty API responses from Sardine. The latter is particularly important as unexpected empty responses from external systems should be treated as errors, aligning with our guideline for handling missing expected data. Addressing these issues will significantly improve the correctness and robustness of the integration.
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a Sardine HTTP client and env vars, wires Sardine calls (customer / feedback / risk) into persona verification, card issuance, and credential creation, updates persona payload and span attributes, and provides Vitest mocks and test updates. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Server
participant Sardine
participant Database
Client->>Server: Submit persona / create card / create credential
activate Server
Note over Server: Extract/enrich payload (contact, address, demographics)\nset span attributes (exa.*)
Server->>Sardine: customer(flow, customer, transaction) [async / fire-and-forget in some paths]
activate Sardine
Sardine-->>Server: {status, level, sessionKey, score}
deactivate Sardine
alt level == "very_high"
Server-->>Client: 200 { code: "very high risk" }
else
Server->>Database: persist user / card / credential
activate Database
Database-->>Server: success
deactivate Database
Server-->>Client: 200 { success payload }
end
deactivate Server
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (10)
.changeset/forty-ads-lie.md.do/app.yamlserver/api/card.tsserver/hooks/persona.tsserver/script/openapi.tsserver/test/hooks/persona.test.tsserver/test/mocks/sardine.tsserver/utils/createCredential.tsserver/utils/sardine.tsserver/vitest.config.mts
🧰 Additional context used
🧬 Code graph analysis (4)
server/api/card.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/utils/createCredential.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/hooks/persona.ts (1)
server/utils/sardine.ts (2)
risk(36-38)customer(30-32)
server/utils/sardine.ts (1)
server/instrument.cjs (1)
domain(1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (20)
server/script/openapi.ts (1)
26-27: LGTM!The Sardine environment variables follow the established pattern for OpenAPI spec generation.
server/vitest.config.mts (1)
30-31: LGTM!The Sardine environment variables are correctly configured for the test environment.
server/test/hooks/persona.test.ts (2)
16-16: LGTM!The import of the Sardine utility module is correctly placed for test mocking.
37-41: LGTM!The Sardine mock is properly configured with the required response fields (sessionKey, status, level) to exercise the test path.
.do/app.yaml (1)
137-143: LGTM!The Sardine environment variables follow the established pattern: API key is correctly marked as SECRET with encrypted fallback, and the API URL is provided as a plain value.
server/utils/createCredential.ts (2)
16-16: LGTM!The import of the Sardine customer function is correctly placed.
61-63: credentialId is an Ethereum address, not PII, and is appropriate for Sardine tracking.Ethereum addresses are public blockchain identifiers validated by
isAddress(), not personally identifiable information. They're standard identifiers used by fraud detection services for blockchain-based applications. The fire-and-forget pattern with error capture is correctly implemented—timeouts won't impact credential creation completion since errors are caught and logged without blocking the user flow.Likely an incorrect or invalid review comment.
server/api/card.ts (2)
34-34: LGTM!The import of the Sardine customer function is correctly placed.
369-384: Verify card data sharing with Sardine complies with security and compliance requirements.This code sends card details (last4, expiry dates, card ID hash) to the external Sardine service. The codebase schema defines
customer.type: "customer"as a valid value among 17 documented types, so that field is correctly populated. However, Sardine's public API documentation does not mention thecustomer.typefield, suggesting either a private API variation or an undocumented feature—confirm this matches the actual Sardine endpoint being called.Ensure this data sharing:
- Complies with PCI-DSS and your security policies
- Is covered by your data processing agreement with Sardine
- Is disclosed in your privacy policy
The fire-and-forget pattern with error capture is appropriate for this telemetry use case.
server/utils/sardine.ts (6)
24-28: LGTM - Environment setup is correctly validated at module load.The early validation ensures the module fails fast if required configuration is missing, preventing runtime surprises.
30-38: LGTM - Well-structured public API with appropriate timeouts.The API surface is clean with properly typed inputs via
InferInput<typeof Schema>.
40-65: LGTM - Robust request handling with proper timeout and validation.The implementation correctly:
- Uses
AbortSignal.timeout()for cancellation- Throws on empty responses (as discussed in past reviews)
- Validates responses against schemas
265-296: LGTM - Feedback schema with proper dynamic defaults.All timestamp and UUID defaults correctly use arrow functions to ensure fresh values per request.
298-337: LGTM - Clean terminal type transformation with safe fallback.The transform elegantly maps terminal type codes to semantic values, with an appropriate "unspecified" fallback for unknown codes.
339-346: LGTM - Response schema correctly defined.server/hooks/persona.ts (5)
59-79: LGTM - Payload schema expanded to support Sardine customer data.The additional fields (name parts, address, contact info) are properly typed with appropriate nullable constraints matching the Persona API structure.
205-212: Verify: Fail-open risk assessment allows user creation when Sardine is unavailable.If the Sardine
customer()call throws (network failure, timeout, etc.), the error is logged but user creation proceeds. This is resilient but means users can be onboarded without risk evaluation when Sardine is down.Confirm this fail-open behavior is intentional for your risk tolerance. If blocking is required when risk cannot be assessed, consider returning early with an appropriate response code.
155-155: LGTM - Span attributes correctly replace setContext for better Sentry integration.
209-212: Confirm: Onlyvery_highrisk level blocks user creation.Risk levels
high,medium,low, andunknownwill all proceed to user creation. Verify this threshold aligns with your risk policy. Ifstatus: "Timeout"responses should also be blocked or flagged separately, additional handling may be needed.
225-229: LGTM - User creation and credential update flow is correct.The pandaId is properly persisted and recorded in the span for observability.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (10)
.changeset/forty-ads-lie.md.do/app.yamlserver/api/card.tsserver/hooks/persona.tsserver/script/openapi.tsserver/test/hooks/persona.test.tsserver/test/mocks/sardine.tsserver/utils/createCredential.tsserver/utils/sardine.tsserver/vitest.config.mts
🧰 Additional context used
🧬 Code graph analysis (4)
server/utils/createCredential.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/api/card.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/hooks/persona.ts (1)
server/utils/sardine.ts (2)
risk(36-38)customer(30-32)
server/utils/sardine.ts (3)
src/utils/accountClient.ts (1)
request(146-185)server/utils/alchemy.ts (1)
headers(10-10)server/instrument.cjs (1)
domain(1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (16)
server/script/openapi.ts (1)
26-27: LGTM: Environment variables follow established patterns.The addition of SARDINE_API_KEY and SARDINE_API_URL for OpenAPI spec generation is consistent with how other external services are configured in this script.
server/utils/createCredential.ts (2)
61-63: Verify credentialId is appropriate to send to external service.The customer call sends
credentialIdas the customer identifier to Sardine (an external risk evaluation service). Ensure this doesn't violate privacy policies or expose sensitive user data to third parties.Consider whether you should use a different identifier (like a hashed version or account address) or verify that credentialId is already anonymized/appropriate for external sharing.
61-63: Fire-and-forget pattern is appropriate here.The Sardine customer call is correctly implemented as fire-and-forget within Promise.all, ensuring signup tracking doesn't block credential creation. Error handling via captureException with error level is appropriate.
server/vitest.config.mts (1)
30-31: LGTM: Test environment variables configured correctly.The Sardine environment variables are properly configured for the test environment, following the same pattern as other external service configurations.
server/test/hooks/persona.test.ts (1)
37-41: LGTM: Sardine mock properly integrated into test.The test correctly mocks the
sardine.customercall with appropriate return values (sessionKey, status, level) that align with the CustomerResponse schema. This ensures the test can verify the integration without making actual external API calls..do/app.yaml (1)
137-143: LGTM: Sardine environment variables properly configured with security best practices.The configuration correctly:
- Marks SARDINE_API_KEY as SECRET type
- Uses encrypted secret fallback pattern (ENCRYPTED_SARDINE_API_KEY || SARDINE_API_KEY)
- Configures SARDINE_API_URL as RUN_TIME scope (appropriate for non-sensitive data)
- Follows established patterns for other external service integrations
server/api/card.ts (1)
369-384: Fire-and-forget pattern appropriately used.The Sardine customer call is correctly implemented as fire-and-forget, ensuring risk tracking doesn't block the card creation response. Error handling via captureException with error level is appropriate.
server/test/mocks/sardine.ts (1)
3-8: LGTM: Mock implementations align with Sardine schemas.The mock correctly:
- Preserves original module exports while overriding test-specific functions
- Returns schema-compliant values with proper capitalization ("Success")
- Provides all required fields (sessionKey, status, level for customer; status for feedback; amlLevel, level, sessionKey, status for risk)
Based on past review comments, the status capitalization issue was already addressed.
server/utils/sardine.ts (4)
1-28: LGTM - Environment checks and configuration.The module-level guards ensure required environment variables are present at startup, preventing runtime failures. The Base64 encoding of the API key for Basic auth is appropriate given the clarified format.
40-65: LGTM - Request helper with proper error handling.The generic request function correctly:
- Builds headers with auth and request ID
- Handles timeouts via
AbortSignal.timeout()- Throws on non-2xx responses with useful context
- Throws on empty response bodies (addressing prior feedback)
- Parses and validates responses against the provided schema
265-294: Schema defaults correctly use factory functions.The
FeedbackRequestschema properly uses arrow functions foridandtimeMillisdefaults (lines 273, 275, 288, 290), ensuring fresh UUIDs and timestamps per request rather than stale values from module load time. This addresses the prior feedback.
298-337: Well-structured RiskRequest with terminal type enrichment.The
RiskRequestschema includes atransformstep that maps raw terminal type codes to human-readable type/operator pairs. The fallback to "unspecified" handles unknown codes gracefully.server/hooks/persona.ts (4)
59-79: LGTM - Expanded payload schema captures necessary customer data.The additional fields (contact info, address details, demographics) enable rich customer profiles for Sardine risk evaluation. The
nullable()wrappers appropriately handle optional middle name and street2.
154-159: LGTM - Consistent span attribute usage.The refactor from
setContexttogetActiveSpan()?.setAttributealigns with the Sentry best practice of using span attributes for request-scoped data.
225-229: LGTM - Proper completion of user creation flow.The database update and span attribute assignment correctly finalize the persona inquiry handling.
162-212: Sardine integration with resilient error handling.The implementation correctly:
- Builds a comprehensive customer payload with income, address, and tags
- Uses
.catch()to capture errors without blocking the flow- Sets span attributes for observability (risk level and score)
- Blocks only on
very_highrisk with a retriable 200 responseOne consideration: if the Sardine call fails (network issues, timeouts),
riskwill beundefinedand the user creation proceeds. This is a deliberate resilience choice, but consider logging atwarninglevel instead oferrorto better reflect that this is graceful degradation rather than a critical failure.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (10)
.changeset/forty-ads-lie.md.do/app.yamlserver/api/card.tsserver/hooks/persona.tsserver/script/openapi.tsserver/test/hooks/persona.test.tsserver/test/mocks/sardine.tsserver/utils/createCredential.tsserver/utils/sardine.tsserver/vitest.config.mts
🧰 Additional context used
🧬 Code graph analysis (4)
server/utils/createCredential.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/api/card.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/utils/sardine.ts (1)
server/instrument.cjs (1)
domain(1-1)
server/hooks/persona.ts (1)
server/utils/sardine.ts (2)
risk(36-38)customer(30-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (21)
server/script/openapi.ts (1)
26-27: LGTM!The Sardine environment variables follow the established pattern for OpenAPI generation.
.changeset/forty-ads-lie.md (1)
1-5: LGTM!Standard changeset format for the Sardine integration.
.do/app.yaml (1)
137-143: LGTM!The Sardine environment variables are correctly configured with appropriate secret handling, following the same pattern as other API credentials.
server/vitest.config.mts (1)
30-31: LGTM!Test environment variables for Sardine are properly configured and consistent with other test setup.
server/utils/sardine.ts (6)
24-28: LGTM!Environment variable validation ensures required Sardine configuration is present at startup.
30-38: LGTM!The three exported functions provide a clean API for Sardine integration with appropriate timeout defaults (note: the 500ms timeout for
risk()is intentional for time-constrained authorization flows).
40-65: LGTM!The request helper properly handles timeouts, error responses, and empty response bodies (throwing an error since 204 is not expected from these Sardine endpoints).
246-263: LGTM!CustomerResponse schema correctly models the risk assessment response with level and optional risk details.
265-294: LGTM!FeedbackRequest schema properly models authorization and settlement feedback with appropriate status enums.
298-337: LGTM!RiskRequest schema includes a clever transform that maps terminal type codes to standardized type/operator pairs for Sardine's API.
server/test/hooks/persona.test.ts (2)
16-16: LGTM!Importing the Sardine module enables proper mocking in tests.
37-41: LGTM!The mock properly simulates a successful Sardine customer response with all required fields.
server/utils/createCredential.ts (2)
16-16: LGTM!Import enables Sardine customer tracking during credential creation.
61-63: LGTM!The Sardine customer call runs in parallel with other credential setup tasks and errors are captured without blocking the main flow. The minimal payload (flow and customer ID) is appropriate for signup tracking.
server/api/card.ts (2)
34-34: LGTM!Import enables Sardine customer tracking for card issuance events.
369-384: LGTM!The Sardine customer call appropriately tracks card issuance with minimal card metadata (last4, expiry, hash). The fire-and-forget pattern with error logging ensures the main card creation flow isn't blocked. Compliance aspects (DPA, privacy policy, user consent) were confirmed in previous review.
server/test/mocks/sardine.ts (1)
3-8: LGTM! Mock implementation correctly matches Sardine response schemas.The mock properly returns all required fields with valid enum values. Previous schema mismatch issues have been resolved.
server/hooks/persona.ts (4)
2-2: LGTM! Import changes support Sentry span refactor and Sardine integration.The shift from
setContexttogetActiveSpanwith attributes is appropriate, and thecustomerimport enables risk evaluation.Also applies to: 26-26
59-80: LGTM! Schema expansion provides complete identity data for Sardine risk evaluation.The new required fields (emailAddress, phoneNumber, birthdate, name components, address details) enable comprehensive customer profiling. Validation will appropriately reject incomplete Persona payloads.
162-212: Verify fail-open behavior is intentional for risk evaluation.The Sardine
customer()call uses.catch()that captures exceptions without rethrowing (lines 205-207). This means if Sardine fails (network error, timeout, API error),riskbecomesundefined, theif (risk)check on line 209 is skipped, and the flow proceeds to user creation on line 215 without risk evaluation.This fail-open behavior allows legitimate users through if Sardine is unavailable, but also permits potentially risky users to bypass risk checks during Sardine outages.
Confirm this is the intended security/reliability trade-off. If risk evaluation is critical, consider fail-closed behavior (return early on Sardine errors) or additional safeguards.
155-155: LGTM! Span attribute updates align with Sentry observability pattern.The refactor from
setContextto span attributes (lines 155, 227) properly associates inquiry and panda IDs with the active span. Minor note: line 227 usessetAttributes(plural) while line 155 usessetAttribute(singular), but both are valid.Also applies to: 227-227
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (10)
.changeset/forty-ads-lie.md.do/app.yamlserver/api/card.tsserver/hooks/persona.tsserver/script/openapi.tsserver/test/hooks/persona.test.tsserver/test/mocks/sardine.tsserver/utils/createCredential.tsserver/utils/sardine.tsserver/vitest.config.mts
🧰 Additional context used
🧬 Code graph analysis (2)
server/utils/createCredential.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
server/api/card.ts (1)
server/utils/sardine.ts (1)
customer(30-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (14)
.do/app.yaml (1)
137-143: LGTM! Environment variable configuration follows established patterns.The Sardine API key and URL are properly configured with appropriate scopes and security settings, consistent with other service integrations in this file.
server/script/openapi.ts (1)
26-27: LGTM! Environment initialization follows the existing pattern.The Sardine API key and URL are initialized consistently with other service configurations in this file.
server/test/hooks/persona.test.ts (2)
16-16: LGTM! Sardine utility import enables proper test mocking.The import is necessary to support mocking of Sardine calls in the test scenarios.
37-41: LGTM! Sardine mock provides correct response shape.The mock return value includes all required fields (sessionKey, status, level) and matches the CustomerResponse schema expectations.
server/utils/createCredential.ts (2)
16-16: LGTM! Import enables Sardine integration for signup flow.The customer function import is correctly placed and necessary for the signup event tracking.
61-63: No changes needed. The schema defines thecustomer.typefield as optional, not required. The implementation in createCredential.ts correctly passes only the requiredidfield, which is valid. The different customer object shapes across calls reflect intentional flow-specific requirements—thesignupflow doesn't need thetypefield, while other flows likecard.issuedandaccount_updateoptionally include it. Both patterns are correct per the schema.server/api/card.ts (2)
34-34: LGTM! Import enables Sardine integration for card issuance flow.The customer function import is correctly placed and necessary for the payment method link event tracking.
369-384: LGTM! Sardine integration for card issuance is properly implemented.The fire-and-forget pattern with error handling is appropriate for this non-critical tracking call. The transaction payload includes only necessary card metadata (no full PAN), and past review comments confirm that DPA, privacy policy, and user consent coverage are in place.
server/vitest.config.mts (1)
30-31: LGTM! Test environment configuration is correct.The Sardine environment variables are properly configured for test execution, consistent with the OpenAPI script configuration.
server/test/mocks/sardine.ts (1)
1-8: LGTM! Sardine mock properly implements all required response fields.The mock correctly returns response shapes that match the Sardine API schemas, including proper enum capitalization (e.g., "Success" not "success"). Past review feedback has been addressed.
server/utils/sardine.ts (1)
1-346: LGTM! Past issues have been addressed.All previously flagged concerns have been resolved:
- Schema defaults now properly use factory functions (
() => Date.now(),() => crypto.randomUUID())billingAddress.regionCodeandbillingAddress.companyare now optional, consistent withcustomer.address- Empty response handling is appropriate for these endpoints
- Request timeout and error handling are well-structured
The Sardine client implementation follows best practices with strict schema validation, proper timeout handling, and clean separation of concerns.
server/hooks/persona.ts (3)
155-156: Good use of span attributes for tracing.The migration from
setContexttogetActiveSpan()?.setAttribute()for tracking inquiry and panda IDs aligns with modern OpenTelemetry best practices and provides better distributed tracing support.
209-211: Risk-based blocking correctly implemented.The early return on
very_highrisk level with a 200 status prevents user creation while signaling to the webhook sender not to retry. This correctly implements the risk-based blocking requirement.
162-163: Clarify the flow type for Persona identity verification.The flow type is set to
"account_update"for a Persona inquiry approval event. While both"account_update"and"identity_verification"are valid schema options (server/utils/sardine.ts lines 71-87),"identity_verification"appears more semantically appropriate since this webhook represents a completed identity verification/KYC approval from Persona. Consider whether the current choice is intentional or if"identity_verification"better represents this flow.
closes #480
Note
Integrates Sardine risk evaluation and event tracking into key user flows.
utils/sardine.tsclient (customer,feedback, defaultrisk) with strict schemas and request handlinghooks/persona.ts): enriches payload, callscustomerfor risk; annotates spans; blocks onvery_highrisk; minor Sentry context refactorapi/card.ts): after creating a card, sends Sardinecustomerevent with card payment method metadatautils/createCredential.ts): sends Sardinecustomerevent on signupSARDINE_API_KEYandSARDINE_API_URLto runtime env, OpenAPI script, and Vitest configWritten by Cursor Bugbot for commit 378de8d. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Enhancements
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.