Skip to content

feat(backend): harden and instrument SEP-0001 generator, add relay integration/stress suite, retry idempotency Redis calls with backoff - #1603

Open
Y33t-dev wants to merge 1 commit into
emdevelopa:mainfrom
Y33t-dev:feature/be-sep0001-hardening-relay-test-suite-idempotency-retry
Open

Y33t-dev wants to merge 1 commit into
emdevelopa:mainfrom
Y33t-dev:feature/be-sep0001-hardening-relay-test-suite-idempotency-retry

Conversation

@Y33t-dev

Copy link
Copy Markdown

Summary

#1457 - Payload sanitization and strict validation for the SEP-0001 Stellar Info Generator

  • TOML escaping now covers every control character (\r, \t, \b, \f, plus \uXXXX for the rest). Before, only \n was escaped, so a raw \r or other control character in a merchant field could break the document. Tests try quote, CRLF, table-header, NUL and backslash breakouts and assert that the key set never changes.
  • business_name: bidi override characters (used for visual spoofing) are stripped, the value is trimmed, and it is capped at 256 code points. Non-string or empty values fall back to the default name.
  • ACCOUNTS and SIGNING_KEY must be valid Stellar public keys, including the StrKey checksum.
  • A secret seed configured as SIGNING_KEY is never published. Before, the generator would put an S... seed into a public file. It is now refused and logged without its value, and an alert fires.
  • Emails are validated. Merchant homepage/logo URLs must be https with no credentials. Server URLs must be https (http is allowed only for localhost). An invalid optional field is omitted and reported. An invalid TRANSFER_SERVER / network passphrase raises a typed Sep0001ConfigError, and the route turns that into a generic 500 without exposing configuration.
  • validateStellarToml: required keys must start a line, raw control characters are rejected, and the document is capped at the 100 KB SEP-0001 limit.
  • Route:
    • merchant_id must be a single UUID, otherwise 400 without a database query. Repeated params and object injection are covered.
    • console.error replaced with the structured logger.
    • Adds Access-Control-Allow-Origin: * (required by SEP-0001 for browser wallets) and X-Content-Type-Options: nosniff.
  • New generateStellarTomlReport() returns { toml, rejections }. generateStellarToml() keeps its signature and return type.

#1458 - Prometheus alert metrics and health telemetry for the SEP-0001 generator

  • New src/lib/sep0001-telemetry.js with its own registry, merged into GET /metrics:
    • sep0001_requests_total{outcome}
    • sep0001_generation_duration_seconds{outcome}
    • sep0001_document_size_bytes
    • sep0001_rejected_fields_total{field,reason}
    • sep0001_health_state
    • sep0001_error_ratio
    • sep0001_last_success_timestamp_seconds
  • All label values come from fixed sets; unknown values map to other / generation_error.
  • Rolling-window health monitor (constant memory). Unhealthy when the server error ratio is at least 0.25; degraded when it is at least 0.05 or when a secret SIGNING_KEY was refused. 400/404 do not count. Thresholds are configurable through SEP0001_* env vars.
  • New GET /health/sep0001 endpoint (503 only when unhealthy). /health also reports services.sep0001_generator, informational only.
  • Alert rules: backend/docs/alerts/sep0001-generator.rules.yml (unhealthy, degraded, secret signing key refused, invalid configuration, merchant data rejected).

#1456 - Integration and stress test suite for the WebSocket Relay Service

  • websocket-relay.integration.test.js wires the real security, query, recovery and metrics modules into a relay worker. It covers:
    • the handshake: origin allow-list, HS256-pinned JWT, and rejection of alg: none, HS512, expired and wrong-secret tokens
    • frame size limits; stripping of unknown and __proto__ fields
    • parameterised batch insert and FIFO dequeue
    • delivery through the circuit breaker; complete/fail transitions; dead-lettering
    • HALF_OPEN recovery with DLQ replay
    • database failure wrapping and pagination clamps
    • reconnect backoff and audit log integrity
  • websocket-relay.stress.test.js:
    • 50 concurrent consumers drain 2,000 events, each claimed exactly once
    • interleaved latency never double-claims
    • 1,000-row single-statement insert
    • 10,000 frames sanitized; oversized-frame floods; byte-accurate multi-byte size checks
    • 1,000 concurrent fast-fails on an open circuit; 10,000 mixed breaker outcomes
    • 10,000-entry DLQ drained in FIFO order
    • 200 concurrent reconnect loops stay under the delay cap
  • New tests/helpers/fake-relay-db.js interprets the exact SQL from websocket-relay-queries.js, applying each statement atomically to mirror FOR UPDATE SKIP LOCKED.
  • Source fix found by the suite: auditRelayEvent() spread caller metadata after audit/ts/event, so metadata could forge those fields. Metadata is now spread first.
  • Docs: backend/docs/WEBSOCKET_RELAY_TESTING.md.

#1464 - Automated retry with exponential backoff in the Idempotency Key Manager

  • New src/lib/idempotency-retry.js: withIdempotencyRetry() with capped exponential backoff and +/-20% jitter, a total latency budget, and env-configurable bounds (IDEMPOTENCY_REDIS_MAX_RETRIES 2, _RETRY_BASE_MS 25, _RETRY_MAX_MS 250, _RETRY_BUDGET_MS 500, all clamped).
  • Only transient errors are retried: socket/connect timeouts, ECONNRESET and similar, and the replies LOADING/BUSY/TRYAGAIN/READONLY/MASTERDOWN/CLUSTERDOWN. A closed client, auth errors, WRONGTYPE and corrupt JSON fail immediately.
  • Wired into the middleware's cache read (get), the background cache write (set, which never delays the response) and lookupIdempotentResponse (lookup).
  • Final-failure behaviour is unchanged: the read fails open, the write is logged, and lookup propagates the error.
  • Metrics: idempotency_redis_operations_total{operation,outcome}, idempotency_redis_retries_total{operation}, idempotency_redis_retry_delay_seconds{operation}, merged into GET /metrics.
  • Docs: backend/docs/IDEMPOTENCY_KEY_MANAGER.md.

Notes

  • Changed test fixtures:
    • sep0001-generator.test.js and sep0001-generator.integration.test.js used the example accounts GBUQWP3B... and GCEZWKCA..., which fail the StrKey checksum. With strict validation they would be omitted from ACCOUNTS, so they were replaced with valid deterministic keys.
    • The integration test that asserted a secret seed (SCZANGBA...) is published as SIGNING_KEY was replaced with two tests: a public key is published, and a secret seed is not.
    • The 10,000-character name stress test now asserts truncation to 256 characters instead of the full name being published.
    • The guide's example account was updated to match.
  • Behaviour changes:
    • Invalid merchant fields are omitted instead of published.
    • A non-UUID merchant_id returns 400 instead of reaching the database.
    • A non-https public TRANSFER_SERVER_URL / API_BASE_URL returns 500 (http still works for localhost).
    • stellar.toml responses gain CORS and nosniff headers.
    • Idempotency Redis failures can add up to IDEMPOTENCY_REDIS_RETRY_BUDGET_MS (default 500 ms) of latency before failing open.
  • Assumption ([Backend] Add comprehensive integration and stress test suite for WebSocket Relay Service #1456): the issue asks for a test suite, so source changes are limited to the audit-log fix the suite exposed and the reusable fake DB helper.
  • Follow-up, not changed here: the [ORG] keys (name, contact, support, homepage, logo) do not match the SEP-0001 spec (ORG_NAME, ORG_OFFICIAL_EMAIL, ORG_SUPPORT_EMAIL, ORG_URL, ORG_LOGO). They were kept for backwards compatibility.
  • Security notes:
    • stellar.toml can no longer leak a secret seed or carry injected TOML keys.
    • Metric labels cannot be inflated by request data.
    • The health and metrics endpoints contain no merchant ids or key material.
    • Audit lines cannot be forged through metadata.
  • Test output: to be attached after running the commands below.

closes #1458
closes #1457
closes #1456
closes #1464

@vercel

vercel Bot commented Oct 16, 2026

Copy link
Copy Markdown

@noevidence1017 is attempting to deploy a commit to the Emmanuel's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Oct 16, 2026

Copy link
Copy Markdown

@Y33t-dev 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

@gitguardian

gitguardian Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
- - Generic High Entropy Secret bdb6388 backend/src/lib/sep0001-generator.sanitization.test.js View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

…tegration/stress suite, retry idempotency Redis calls with backoff
@Y33t-dev
Y33t-dev force-pushed the feature/be-sep0001-hardening-relay-test-suite-idempotency-retry branch from 81c412f to bdb6388 Compare October 16, 2026 11:59

This branch has not been deployed

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