Skip to content

test(billing): map Soroban error categories to HTTP statuses (#1311) - #1408

Open
legend-esc wants to merge 1 commit into
CalloraOrg:mainfrom
legend-esc:feat/1311-soroban-error-category-http-mapping
Open

legend-esc wants to merge 1 commit into
CalloraOrg:mainfrom
legend-esc:feat/1311-soroban-error-category-http-mapping

Conversation

@legend-esc

Copy link
Copy Markdown

Summary

Closes #1311

Adds comprehensive tests for the SorobanRpcError category → HTTP status
mapping in POST /api/billing/deduct, covering every documented category
and the unknown-error fallthrough. No running Soroban node is required.

Changes

jest.env-setup.cjs (restored)

Deleted in a prior commit (599ab6e) but still required by jest.config.cjs.
Without it, src/config/env.ts fails Zod validation and calls process.exit(1)
before any test runs. Added string guards for boolean-default env vars
(TRUST_FORWARDED_USER_ID, SOROBAN_RPC_ENABLED, etc.) that leak as JS
booleans across Jest workers and cause re-validation failures on the next
module load.

package.json (restored)

Also deleted in the same commit.

src/routes/billing/deduct.test.ts (rewritten)

  • Auth: switched from x-user-id header (requires TRUST_FORWARDED_USER_ID=true
    • gateway signature, not set in CI) to JWT Bearer tokens, consistent with
      tests/helpers/jwt.ts and jest.setup.ts.
  • Injection strategy: mock BillingService at the class level so
    createRouteBillingService() inside the route returns a controlled fake —
    no Soroban node, no DB, no network.

Criteria → tests mapping

Criterion Test(s)
INSUFFICIENT_BALANCE → 402 / INSUFFICIENT_BALANCE INSUFFICIENT_BALANCE suite × 3
TIMEOUT → 504 / SOROBAN_RPC_TIMEOUT TIMEOUT suite × 3
CONTRACT_ERROR → 502 / SOROBAN_RPC_ERROR CONTRACT_ERROR suite × 3
NETWORK_ERROR → 502 / SOROBAN_RPC_ERROR NETWORK_ERROR suite × 3
Unknown error → 500 / INTERNAL_SERVER_ERROR, no internal leak unknown error suite × 4
Simulation diagnostics redacted in 502 body simulationDetails suite × 7
Successful deduction → 200 with payload successful deduction suite × 2

Security / failure-mode handling

  • No internal leak: the 500 tests assert res.body.error.message ===
    'Internal server error' and that the raw exception message and stack do
    not appear in the response body (enforced by errorHandler →
    safePublicMessage() in src/errors/errorEnvelopePolicy.ts).
  • Simulation redaction: sensitive fields matching
    /(address|account|balance|secret|key|xdr|hash|signature|source|destination|contract)/i
    are replaced with [REDACTED] by redactSimulationDetails(). Tests assert
    that raw Stellar addresses/keys from the fixture do not appear in the
    response while non-sensitive fields (errorCode, errorMessage) survive.

Tested with

npm test -- src/routes/billing/deduct.test.ts

31 tests, 0 failures.

…Org#1311)

Add comprehensive tests for SorobanRpcError category → HTTP status
mapping in the deduct route, covering all documented categories and
the unknown-error fallthrough.

Changes:
- Restore jest.env-setup.cjs (deleted in 599ab6e), which jest.config.cjs
  requires; add string guards for boolean-default env vars that leak
  across Jest workers and cause Zod re-validation failures
- Restore package.json (also deleted in 599ab6e)
- Rewrite deduct.test.ts:
  - Switch auth from x-user-id header to JWT Bearer tokens so tests
    do not depend on TRUST_FORWARDED_USER_ID being enabled
  - Mock BillingService at the class level to inject fake deduct()
    behaviour without a running Soroban node
  - Assert each SorobanRpcError category yields its documented status
    and error code:
      INSUFFICIENT_BALANCE → 402 / INSUFFICIENT_BALANCE
      TIMEOUT             → 504 / SOROBAN_RPC_TIMEOUT
      CONTRACT_ERROR      → 502 / SOROBAN_RPC_ERROR
      NETWORK_ERROR       → 502 / SOROBAN_RPC_ERROR
  - Assert unknown (non-SorobanRpcError) errors reach errorHandler
    as 500 / INTERNAL_SERVER_ERROR without leaking message or stack
  - Assert simulation-failure path (SorobanRpcError with
    simulationDetails) returns 502 / SIMULATION_FAILED with redacted
    diagnostics: sensitive address/key/xdr fields replaced with
    [REDACTED], events collapsed to eventCount, footprint to
    footprintPresent

Closes CalloraOrg#1311
@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

@legend-esc Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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.

Map Soroban error categories to deduct HTTP statuses

1 participant