Skip to content

fix(upi): M4.3.2 financial integrity remediation for PR #31 - #32

Open
Satelink-Protocol wants to merge 1 commit into
feature/m4-3-1-review-remediationfrom
feature/m4-3-2-financial-integrity
Open

Satelink-Protocol wants to merge 1 commit into
feature/m4-3-1-review-remediationfrom
feature/m4-3-2-financial-integrity

Conversation

@Satelink-Protocol

Copy link
Copy Markdown
Contributor

Summary of Changes — NIGHTLIFEZ M4.3.2 Final Independent Review Corrections for PR #31

This pull request implements the financial-integrity corrections required by the independent owner review of PR #31 (feature/m4-3-1-review-remediation), addressing merchant identity fail-closed enforcement, secure manual refund reconciliation authorization, and refund state transition integrity.

1. Fail-Closed Merchant Identity & Currency Invariance

  • Eliminated Permissive Logic: Replaced !merchantId || !payment.merchant_id || merchantId === payment.merchant_id with strict fail-closed checks across lib/services/upi-payments.js.
  • Three-Way Merchant Verification: applySuccessfulUpiPayment strictly enforces that:
    • Verified gateway merchantId is non-empty.
    • Stored intent payment.merchant_id is non-empty.
    • Server-configured adapter adapter.merchantId is non-empty.
    • All three values are strictly equal (merchantId === payment.merchant_id && merchantId === expectedConfiguredMerchantId).
    • Mismatch or absence records immutable audit log with specific failure reasons: missing_verified_merchant_id, missing_stored_merchant_id, missing_configured_merchant_id, or merchant_mismatch.
  • Strict Currency Invariance: Missing or empty currency cannot bypass INR enforcement. Payment payload currency and stored payment.currency must both strictly equal 'INR'.
  • Adapter Level Fail-Closed:
    • PhonePeAdapter: Constructor asserts merchantId. getPaymentStatus validates and returns verified merchantId and currency: 'INR'. verifyWebhook rejects missing configured merchantId, missing payload merchantId, and mismatched merchantId (WebhookSignatureError).
    • MockUpiAdapter: Constructor accepts merchantId. getPaymentStatus returns merchantId and currency: 'INR'. verifyWebhook strictly requires matching configured merchantId.
  • Creation Validation: createUpiPaymentIntent asserts server-configured adapter merchant identity exists before inserting payment intent row.

2. Secure Manual Refund Reconciliation

  • Removed Fabricated References: Eliminated auto-generated MANUAL-... placeholder references.
  • Server-Side Authorization: verifyFinanceAuthorization validates against the authenticated server-side session (admin_users table). Only active super_admin or finance roles may perform manual reconciliation. Caller-supplied actor strings or unauthorized roles (e.g. support) are rejected (403 unauthorized_finance_role).
  • External Bank Reference Requirement: Mandatory verifiable external refund reference (e.g. bank UTR, PG refund ARN) validated by isValidExternalRefundRef(ref):
    • Minimum 6 characters.
    • Strictly rejects missing, empty, or placeholder patterns (MANUAL, DUMMY, TEST, PLACEHOLDER, NONE, NULL, NA, TEMP, REFUND, PENDING, UNKNOWN, SAMPLE, VOID, XXX).
    • Rejects single-character repetitions (000000, XXXXXX) and trivial sequences (123456, abcdef).
  • Mandatory Evidence Reference & Documented Reason:
    • isValidEvidenceRef(evidenceRef) requires verified ticket/receipt reference (min 4 characters, non-placeholder).
    • isValidReconciliationReason(reason) requires documented justification (min 10 characters, non-placeholder).
  • Concurrency & Idempotency: Pessimistic row locking (SELECT ... FOR UPDATE) prevents concurrent operator race conditions or double reconciliation. Repeated reconciliation on already-refunded payment returns existing state safely.
  • Immutable Ledger: Records authenticated actor, timestamp, reference, and evidence reference into payment_audits and audit_log.
  • CBS Limitation Documented: Clarified in docs/UPI_SECURITY_AUDIT.md and docs/UPI_PROVIDER_READINESS.md that minimal reference-based reconciliation does not interface with Core Banking System (CBS) host-to-host APIs.

3. Refund State Transitions & Side Effects

  • Verified both succeeded and refund_pending enter refund workflow.
  • Provider Initiation vs. Completion: Provider pending responses leave payment in refund_pending without marking refunded.
  • Recoverability: Failed provider refunds remain recoverable in failed status.
  • Side Effect Gating: Booking status changes to refunded, Telegram invite link revocation, chat kicks, and member notifications execute strictly upon confirmed refund (status === 'refunded'). Pending or failed refunds trigger no side effects.

Verification Results

  • Unit & Integration Tests: TEST_DATABASE_URL=postgres://localhost:5432/sm_test node --test test/upi-checkout.test.js → 33/33 tests passed (100%).
  • Full Test Suite: TEST_DATABASE_URL=postgres://localhost:5432/sm_test npm test → 466 passed, 2 skipped, 0 failed across all 26 test files.
  • Linter: npm run lint → 140/140 files clean (0 errors).
  • E2E Test Suite: npx playwright test → 157 passed, 11 skipped, 0 failed across 168 tests (100% clean).

Absolute Compliance Confirmation

…nt identity, secure manual refund reconciliation & state transition verification
@vercel

vercel Bot commented Nov 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
strangersmeetup Ready Ready Preview Nov 4, 2026 9:00am UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant