Skip to content

fix: security headers (Helmet), Soroban fee from simulation, cache stampede, forced shutdown timeout - #256

Merged
DeFiVC merged 1 commit into
ChainLearnOfficial:mainfrom
codemagician1949:feat/helmet-fee-stampede-shutdown-216-217-218-220
Jul 29, 2026
Merged

fix: security headers (Helmet), Soroban fee from simulation, cache stampede, forced shutdown timeout#256
DeFiVC merged 1 commit into
ChainLearnOfficial:mainfrom
codemagician1949:feat/helmet-fee-stampede-shutdown-216-217-218-220

Conversation

@codemagician1949

Copy link
Copy Markdown
Contributor

Summary

  • No security headers (Helmet) -- missing OWASP protections #220 — Security headers (Helmet/OWASP): Registered @fastify/helmet with a restrictive OWASP-aligned configuration: CSP with default-src 'none', HSTS 1 year + includeSubDomains + preload, X-Frame-Options: DENY, noSniff, xssFilter, hidePoweredBy. Added @fastify/helmet ^13.0.1 to package.json dependencies.

  • Fee not computed from Soroban simulation -- transactions may fail on-chain #218 — Fee from Soroban simulation: invokeContract was building transactions with the hardcoded BASE_FEE (100 stroops), causing on-chain failures when Soroban resource fees exceeded that amount. Now: (1) simulate with a throw-away transaction; (2) extract minResourceFee from the success response; (3) compute totalFee = BASE_FEE + minResourceFee × 1.2 (20 % buffer for fee-market fluctuations); (4) rebuild the transaction with the computed fee before calling assembleTransaction.

  • Cache stampede (thundering herd) -- no protection on cache miss #217 — Cache stampede / thundering herd: Added cacheGetOrSet<T>() to src/cache/index.ts. On a cache miss, exactly one concurrent caller executes fetchFn and populates the cache; all other callers for the same key await the same in-flight Promise stored in an in-process Map. The promise is removed from the map in a finally block so a failed fetch doesn't permanently block future requests.

  • No forced shutdown timeout -- process hangs if DB/Redis stuck #216 — Forced shutdown timeout: The shutdown handler now starts a 10 s setTimeout (with .unref() so it doesn't keep the event loop alive on its own) that calls process.exit(1) if graceful shutdown has not completed. clearTimeout is called if shutdown finishes normally so production restarts remain clean.

Test plan

  • curl -I /health — response includes Strict-Transport-Security, X-Content-Type-Options: nosniff, Content-Security-Policy, X-Frame-Options: DENY
  • Inspect invokeContract logs — fee logged should be BASE_FEE + minResourceFee×1.2, not 100
  • Simulate 50 concurrent requests to a cached endpoint with an empty cache — DB/service should be called exactly once per key
  • kill -SIGTERM <pid> while DB is unreachable — process exits within 10 s with code 1 instead of hanging

Closes #220
Closes #218
Closes #217
Closes #216

…hutdown timeout

- ChainLearnOfficial#220: Register @fastify/helmet with OWASP-aligned defaults: restrictive CSP
  (default-src/script-src/object-src/frame-ancestors all 'none'), HSTS 1 yr +
  includeSubDomains + preload, X-Frame-Options DENY, noSniff, xssFilter,
  hidePoweredBy; add @fastify/helmet ^13.0.1 to dependencies
- ChainLearnOfficial#218: Compute Soroban transaction fee from simulateTransaction result instead
  of hardcoding BASE_FEE. Extracts minResourceFee from the success response,
  adds a 20 % buffer on the resource portion, and rebuilds the transaction with
  the computed total before assembleTransaction — prevents on-chain fee failures
- ChainLearnOfficial#217: Add cacheGetOrSet() to src/cache/index.ts with thundering-herd
  protection. On a cache miss, exactly one caller fetches from the source; all
  other concurrent callers for the same key await the same in-flight promise via
  an in-process Map, eliminating the cache stampede
- ChainLearnOfficial#216: Add a 10 s forced-exit timer (unref'd) at the start of the shutdown
  handler so the process cannot hang indefinitely when DB or Redis is stuck;
  timer is cancelled if graceful shutdown completes within the window

Closes ChainLearnOfficial#220
Closes ChainLearnOfficial#218
Closes ChainLearnOfficial#217
Closes ChainLearnOfficial#216
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@codemagician1949 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

@DeFiVC
DeFiVC merged commit 726e8c2 into ChainLearnOfficial:main Jul 29, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants