fix: security headers (Helmet), Soroban fee from simulation, cache stampede, forced shutdown timeout - #256
Merged
DeFiVC merged 1 commit intoJul 29, 2026
Conversation
…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
|
@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! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
No security headers (Helmet) -- missing OWASP protections #220 — Security headers (Helmet/OWASP): Registered
@fastify/helmetwith a restrictive OWASP-aligned configuration: CSP withdefault-src 'none', HSTS 1 year +includeSubDomains+preload,X-Frame-Options: DENY,noSniff,xssFilter,hidePoweredBy. Added@fastify/helmet ^13.0.1topackage.jsondependencies.Fee not computed from Soroban simulation -- transactions may fail on-chain #218 — Fee from Soroban simulation:
invokeContractwas building transactions with the hardcodedBASE_FEE(100 stroops), causing on-chain failures when Soroban resource fees exceeded that amount. Now: (1) simulate with a throw-away transaction; (2) extractminResourceFeefrom the success response; (3) computetotalFee = BASE_FEE + minResourceFee × 1.2(20 % buffer for fee-market fluctuations); (4) rebuild the transaction with the computed fee before callingassembleTransaction.Cache stampede (thundering herd) -- no protection on cache miss #217 — Cache stampede / thundering herd: Added
cacheGetOrSet<T>()tosrc/cache/index.ts. On a cache miss, exactly one concurrent caller executesfetchFnand populates the cache; all other callers for the same key await the same in-flightPromisestored in an in-processMap. The promise is removed from the map in afinallyblock 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
shutdownhandler now starts a 10 ssetTimeout(with.unref()so it doesn't keep the event loop alive on its own) that callsprocess.exit(1)if graceful shutdown has not completed.clearTimeoutis called if shutdown finishes normally so production restarts remain clean.Test plan
curl -I /health— response includesStrict-Transport-Security,X-Content-Type-Options: nosniff,Content-Security-Policy,X-Frame-Options: DENYinvokeContractlogs — fee logged should beBASE_FEE + minResourceFee×1.2, not100kill -SIGTERM <pid>while DB is unreachable — process exits within 10 s with code 1 instead of hangingCloses #220
Closes #218
Closes #217
Closes #216