Skip to content

feat(api): add runtime request validation for all API endpoints#65

Merged
Flamki merged 4 commits into
Flamki:masterfrom
supremeproton01:feature/runtime-request-validation
Jun 8, 2026
Merged

feat(api): add runtime request validation for all API endpoints#65
Flamki merged 4 commits into
Flamki:masterfrom
supremeproton01:feature/runtime-request-validation

Conversation

@supremeproton01

@supremeproton01 supremeproton01 commented May 30, 2026

Copy link
Copy Markdown

closes #9

Summary

hooked into API routes so invalid input returns structured 400 errors.
validated request data and enforce non-negative/finite budgets plus text length limits.
cover validation failures for major routes.

Validation

  • Ran relevant local command(s)
  • Verified no secrets were added
  • Updated docs if behavior changed

Checklist

  • No .env or private keys committed
  • No sensitive data in screenshots/logs
  • README.md and examples still accurate

Summary by CodeRabbit

  • New Features

    • Applied robust request validation to premium, orchestrator, and wallet endpoints to sanitize and standardize inputs.
  • Bug Fixes

    • Error responses now include detailed field-level validation information when available to clarify input issues.
  • Tests

    • Added comprehensive validation tests covering premium, wallet, orchestrator, and API key scenarios.
  • Chores

    • Updated test scripts to add a dedicated validation test command and run validation checks during test runs.

@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

@supremeproton01 is attempting to deploy a commit to the flamki's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 263c6fbd-dd48-4e2e-b208-68c49fd785a8

📥 Commits

Reviewing files that changed from the base of the PR and between e047f96 and c6fc4d2.

📒 Files selected for processing (3)
  • package.json
  • src/middleware/errorHandler.js
  • src/server.js

📝 Walkthrough

Walkthrough

Adds request validators and Express middleware, wires them into premium/orchestrate/wallet routes, updates the error handler to include validation details, and adds unit tests and package.json test scripts for the validation suite.

Changes

Request Validation Infrastructure

Layer / File(s) Summary
Validation foundations and error handling
src/requestValidation.js (lines 1-71,73-145,147-150,251-260), src/middleware/errorHandler.js (lines 79-82)
Core constants, validationError, assertStringField, assertBudget, assertApiKey, collectValidationError, and named exports added; errorHandler now includes details when present.
Validation middleware implementations
src/requestValidation.js (lines 152-249)
validatePremiumQuery, validateOrchestrate, validateWalletTransactions, and validateConfigApiKey implemented; they sanitize inputs, aggregate field errors, and populate req.validated.
Endpoint middleware wiring and request consumption
src/server.js (lines 165-219,284-288,326,423-426)
Import validation middleware and attach to premium endpoints, GET/POST /api/orchestrate, and /api/wallet/transactions; handlers now read sanitized values from req.validated (some handlers still retain fallback parsing).
Validation middleware test suite
tests/api.validation.test.js (lines 1-80)
New tests covering orchestrate, premium query, wallet transactions, and config API key validation, asserting error structure and req.validated on success.
Test script configuration updates
package.json (lines 15-16)
test script updated to run settlement-header and API validation tests; test:validation added to run API validation tests alone.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Server
  participant validatePremiumQuery
  participant validateOrchestrate
  participant validateWalletTransactions
  participant RequestValidator
  participant ErrorHandler
  Client->>Server: HTTP request to premium/orchestrate/wallet
  Server->>validatePremiumQuery: invoke (premium routes)
  Server->>validateOrchestrate: invoke (orchestrate)
  Server->>validateWalletTransactions: invoke (wallet)
  validatePremiumQuery->>RequestValidator: validate topic/text/prompt
  validateOrchestrate->>RequestValidator: validate task and budget
  validateWalletTransactions->>RequestValidator: validate address
  RequestValidator-->>validatePremiumQuery: {valid, value|error}
  RequestValidator-->>validateOrchestrate: {valid, value|error}
  RequestValidator-->>validateWalletTransactions: {valid, value|error}
  validatePremiumQuery->>Server: attach req.validated or next(err)
  validateOrchestrate->>Server: attach req.validated or next(err)
  validateWalletTransactions->>Server: attach req.validated or next(err)
  Server->>ErrorHandler: next(err) when validation fails
  ErrorHandler-->>Client: JSON error response (includes details)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Flamki/stellarmind#74: Modifies /api/premium/* route wiring and may overlap with the validatePremiumQuery integration in this PR.

Poem

🐰 I trim each field and keep it neat,
Errors bring details, tidy and complete,
Middleware hops inputs into place,
Tests give every route a gentle chase,
The rabbit cheers — validation's sweet.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description addresses the primary changes (validation middleware, error handling, test coverage) but all validation checklist items remain unchecked, indicating incomplete verification before submission. Check off validation checklist items after confirming local tests pass, no secrets exist, and documentation is updated if needed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding runtime request validation for all API endpoints, which matches the changeset's core objective.
Linked Issues check ✅ Passed The PR implements all core requirements: runtime validation across endpoints [#9], structured 400 error responses with details enrichment, budget bounds enforcement (non-negative/finite), text length guards, and unit test coverage for validation failures.
Out of Scope Changes check ✅ Passed All changes directly support the validation objectives: new requestValidation module, middleware integration, errorHandler enrichment for details, test coverage, and package.json script updates are all in-scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/server.js

Parsing error: Identifier 'task' has already been declared


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@drips-wave

drips-wave Bot commented May 30, 2026

Copy link
Copy Markdown

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server.js (1)

164-172: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

summarize ignores the validated value and reads raw req.query.text.

Unlike the other premium endpoints (research/analyze/code) which now consume req.validated, this handler still reads req.query.text on Line 166. That bypasses the trimming/normalization done by validatePremiumQuery and is inconsistent with the PR's stated behavior of reading from req.validated.

🐛 Proposed fix
-    const text = req.query.text || 'Please provide text to summarize via ?text= parameter';
+    const text = req.validated.text;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 164 - 172, The summarize route handler is still
reading raw req.query.text instead of using the validated value from the
validatePremiumQuery middleware; update the GET /api/premium/summarize handler
to use req.validated.text (and fall back to the existing placeholder only if
undefined) for the variables passed to broadcast and runSummary and for any
cost/logging; ensure all references to the input in this handler (broadcast
input, runSummary call, resultPreview) use req.validated.text to match the other
premium endpoints and preserve trimming/normalization performed by
validatePremiumQuery.
🧹 Nitpick comments (1)
src/requestValidation.js (1)

147-150: ⚡ Quick win

collectValidationError is unused dead code.

None of the middleware call this helper (they invoke assertStringField/assertBudget directly), and it isn't exported. It looks like a leftover from an intended refactor. Either route the validators through it for consistency or remove it.

♻️ Proposed removal
-function collectValidationError(name, validator, value, options) {
-  const result = validator(name, value, options);
-  return result.valid ? { valid: true, value: result.value } : { valid: false, error: result.error };
-}
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/requestValidation.js` around lines 147 - 150, The function
collectValidationError is dead code; remove its declaration to avoid unused code
bloat and either (A) delete the collectValidationError function entirely from
src/requestValidation.js, or (B) if you prefer the refactor, update middleware
to call collectValidationError from assertStringField and assertBudget (replace
their direct validation calls with collectValidationError(name, validator,
value, options) and adapt return shapes accordingly); after making the change,
run tests/linters to ensure no remaining references to collectValidationError
remain and adjust any callsites to match the returned {valid, value, error}
shape if you chose the refactor path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/server.js`:
- Around line 164-172: The summarize route handler is still reading raw
req.query.text instead of using the validated value from the
validatePremiumQuery middleware; update the GET /api/premium/summarize handler
to use req.validated.text (and fall back to the existing placeholder only if
undefined) for the variables passed to broadcast and runSummary and for any
cost/logging; ensure all references to the input in this handler (broadcast
input, runSummary call, resultPreview) use req.validated.text to match the other
premium endpoints and preserve trimming/normalization performed by
validatePremiumQuery.

---

Nitpick comments:
In `@src/requestValidation.js`:
- Around line 147-150: The function collectValidationError is dead code; remove
its declaration to avoid unused code bloat and either (A) delete the
collectValidationError function entirely from src/requestValidation.js, or (B)
if you prefer the refactor, update middleware to call collectValidationError
from assertStringField and assertBudget (replace their direct validation calls
with collectValidationError(name, validator, value, options) and adapt return
shapes accordingly); after making the change, run tests/linters to ensure no
remaining references to collectValidationError remain and adjust any callsites
to match the returned {valid, value, error} shape if you chose the refactor
path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 55fa3ed9-4e10-4412-9ae1-3f7824179071

📥 Commits

Reviewing files that changed from the base of the PR and between a85d2a7 and 9c3d9b0.

📒 Files selected for processing (5)
  • package.json
  • src/middleware/errorHandler.js
  • src/requestValidation.js
  • src/server.js
  • tests/api.validation.test.js

@Flamki

Flamki commented May 30, 2026

Copy link
Copy Markdown
Owner

@supremeproton01 can you plz resolve conflict

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/server.js (3)

398-410: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Inline API-key check bypasses the structured validator and can 500 on non-string input.

This route replaces validateConfigApiKey (still imported on Line 14, now unused) with an inline startsWith check. Two concerns:

  1. It diverges from the PR's goal of consistent structured 400 validation payloads — validateConfigApiKey emits validationError(..., 'INVALID_API_KEY') with structured details, while this path emits a plain Error.
  2. If apiKey is a truthy non-string (e.g. a JSON number), apiKey.startsWith throws TypeError, surfacing as a 500 rather than a structured 400.

Also note the AI summary claims POST /api/config/apikey is unchanged in this diff, which is inconsistent with these added lines.

🛡️ Proposed fix (reuse the validator)
-app.post('/api/config/apikey', apikeyLimiter, (req, res, next) => {
-  const { apiKey } = req.body;
-  if (!apiKey || !apiKey.startsWith('sk-ant-')) {
-    const err = new Error('Invalid API key. Must start with sk-ant-');
-    err.status = 400;
-    err.code = 'INVALID_API_KEY';
-    return next(err);
-  }
+app.post('/api/config/apikey', apikeyLimiter, validateConfigApiKey, (req, res, next) => {
+  const { apiKey } = req.validated;
   // Security: Log only that a key was updated, never log the key itself
   console.log('  🔑 API key updated (ephemeral, session-only)');
   setApiKey(apiKey);
   res.json({ success: true, masked: `sk-ant-...${apiKey.slice(-6)}` });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 398 - 410, Replace the inline startsWith check in
the POST /api/config/apikey handler with the existing validateConfigApiKey
validator so you emit the same structured 400 responses (use validationError
with code 'INVALID_API_KEY') and avoid TypeError on non-strings; specifically,
call validateConfigApiKey (or run its validation logic) against req.body.apiKey
before calling setApiKey, ensure any validation failure is passed to next(...)
as the structured validation error, never log the raw key (keep the existing
console message), and return the masked key in the same response shape after
successful setApiKey.

165-177: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Read text from req.validated, not req.query.

Unlike the sibling routes (research/analyze/code read req.validated.topic/prompt), this handler reads the raw req.query.text on Line 167, bypassing the sanitized value produced by validatePremiumQuery. This also contradicts the AI summary, which states summarize reads text from req.validated.

🐛 Proposed fix
-    const text = req.query.text || 'Please provide text to summarize via ?text= parameter';
+    const text = req.validated.text;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 165 - 177, The route handler for GET
/api/premium/summarize is reading raw req.query.text instead of the sanitized
value set by validatePremiumQuery; update the handler to use req.validated.text
(with the same fallback message if necessary) wherever text is used — i.e.,
assign const text = req.validated.text || 'Please provide text to summarize via
?text= parameter', use that text for broadcast input truncation, pass it to
runSummary, and include it in response/broadcast logic; reference the
validatePremiumQuery middleware, the route handler function
(app.get('/api/premium/summarize', ...)), and runSummary/priceInfo usage to
locate and modify the code.

249-268: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Re-add orchestrateLimiter to /api/orchestrate routes

orchestrateLimiter is imported and defined, but it isn’t attached to either POST or GET /api/orchestrate (both currently use only validateOrchestrate), leaving the expensive orchestrate() endpoint unrate-limited and the import effectively unused.

🛡️ Proposed fix (re-add limiter)
-app.post('/api/orchestrate', validateOrchestrate, async (req, res, next) => {
+app.post('/api/orchestrate', orchestrateLimiter, validateOrchestrate, async (req, res, next) => {
   try {
     const { task, budget } = req.validated;
     const result = await orchestrate(task, budget, broadcast);
     res.json(result);
   } catch (err) {
     next(err);
   }
 });
 
 // Also support GET for easy testing
-app.get('/api/orchestrate', validateOrchestrate, async (req, res, next) => {
+app.get('/api/orchestrate', orchestrateLimiter, validateOrchestrate, async (req, res, next) => {
   try {
     const { task, budget } = req.validated;
     const result = await orchestrate(task, budget, broadcast);
     res.json(result);
   } catch (err) {
     next(err);
   }
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 249 - 268, The POST and GET /api/orchestrate
handlers are missing the imported orchestrateLimiter middleware, leaving the
expensive orchestrate() endpoint unrate-limited; update both route registrations
to include orchestrateLimiter (e.g., add orchestrateLimiter before
validateOrchestrate) so that requests pass through the limiter before
validateOrchestrate and the orchestrate(task, budget, broadcast) call; ensure
you reference the existing symbols orchestrateLimiter, validateOrchestrate, and
orchestrate when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/server.js`:
- Around line 398-410: Replace the inline startsWith check in the POST
/api/config/apikey handler with the existing validateConfigApiKey validator so
you emit the same structured 400 responses (use validationError with code
'INVALID_API_KEY') and avoid TypeError on non-strings; specifically, call
validateConfigApiKey (or run its validation logic) against req.body.apiKey
before calling setApiKey, ensure any validation failure is passed to next(...)
as the structured validation error, never log the raw key (keep the existing
console message), and return the masked key in the same response shape after
successful setApiKey.
- Around line 165-177: The route handler for GET /api/premium/summarize is
reading raw req.query.text instead of the sanitized value set by
validatePremiumQuery; update the handler to use req.validated.text (with the
same fallback message if necessary) wherever text is used — i.e., assign const
text = req.validated.text || 'Please provide text to summarize via ?text=
parameter', use that text for broadcast input truncation, pass it to runSummary,
and include it in response/broadcast logic; reference the validatePremiumQuery
middleware, the route handler function (app.get('/api/premium/summarize', ...)),
and runSummary/priceInfo usage to locate and modify the code.
- Around line 249-268: The POST and GET /api/orchestrate handlers are missing
the imported orchestrateLimiter middleware, leaving the expensive orchestrate()
endpoint unrate-limited; update both route registrations to include
orchestrateLimiter (e.g., add orchestrateLimiter before validateOrchestrate) so
that requests pass through the limiter before validateOrchestrate and the
orchestrate(task, budget, broadcast) call; ensure you reference the existing
symbols orchestrateLimiter, validateOrchestrate, and orchestrate when making the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 13ed0ade-4449-44d9-bf0a-87bad20ac580

📥 Commits

Reviewing files that changed from the base of the PR and between 9c3d9b0 and e047f96.

📒 Files selected for processing (1)
  • src/server.js

@supremeproton01

Copy link
Copy Markdown
Author

@supremeproton01 can you plz resolve conflict

done chief @Flamki

@Flamki

Flamki commented Jun 3, 2026

Copy link
Copy Markdown
Owner

@supremeproton01 its look like there is still some conflicts

@supremeproton01

Copy link
Copy Markdown
Author

@supremeproton01 its look like there is still some conflicts

fixed conflicts @Flamki

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server.js (1)

179-181: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handler bypasses validated text value.

validatePremiumQuery sanitizes and validates text into req.validated.text, but this handler reads from req.query.text directly. This defeats the length guards and trimming applied by the validator, and is inconsistent with the other premium endpoints.

🐛 Proposed fix
 app.get('/api/premium/summarize', validatePremiumQuery, async (req, res, next) => {
   try {
-    const text = req.query.text || 'Please provide text to summarize via ?text= parameter';
+    const text = req.validated.text;
     const priceInfo = pricingConfig.getEndpointInfo('GET /api/premium/summarize');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 179 - 181, The route handler registered with
app.get('/api/premium/summarize', validatePremiumQuery, ...) is incorrectly
reading raw input from req.query.text and bypasses the validator; change the
handler to use the validated and sanitized value req.validated.text (instead of
req.query.text) so the length trimming and guards applied by
validatePremiumQuery are respected—remove the fallback default text or keep only
as a debug fallback after checking req.validated.text is missing, and update any
downstream uses of the local text variable accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 15-21: There are duplicate "test" script keys in package.json so
the first one (running tests/api.validation.test.js) is ignored; update the
single "test" script (the "test" key) to run both desired tests (e.g., chain
node src/agents/settlement-header.test.js && node tests/api.validation.test.js
&& node tests/premium-endpoints.integration.test.js) or keep "test" for the
default suite and ensure "test:validation" is referenced/used in CI; modify the
"test" entry (script name "test") to include api.validation.test.js so
validation tests are executed.

In `@src/middleware/errorHandler.js`:
- Around line 79-81: The statement assigning err.details to body.details in the
errorHandler (the block that checks Array.isArray(err.details) &&
err.details.length > 0) contains a trailing semicolon that violates Prettier;
remove the semicolon after the body.details assignment so the line ends without
a semicolon and run the project's formatter/linter to ensure style compliance.

In `@src/server.js`:
- Around line 423-428: In the '/api/wallet/transactions' route handler (the
async function registered with app.get and middleware
validateWalletTransactions) remove the duplicate declaration "const address"
that comes from req.query and keep the single declaration that reads from
req.validated?.address || config.orchestratorAddress || config.serverAddress;
ensure you delete the second "const address = req.query.address..." line and its
redundant null-check so the handler consistently uses the validated address
fallback (req.validated?.address then config.orchestratorAddress then
config.serverAddress) and returns an empty array if that single address is
falsy.
- Around line 20-25: Add missing imports for the validation middleware functions
used in route definitions: import validatePremiumQuery, validateOrchestrate, and
validateWalletTransactions into the top of src/server.js alongside other
middleware imports (so the route handlers referencing validatePremiumQuery,
validateOrchestrate, and validateWalletTransactions no longer throw
ReferenceError). Ensure you import the exact exported names from the modules
that define them (the validation middleware file(s)) and include them in the
same import block as requestId/requestLogger/errorHandler or the appropriate
middleware import so the symbols are available where routes are registered.
- Around line 326-329: The route handler for app.get('/api/orchestrate') is
ignoring the middleware-validated values by reading directly from req.query with
fallbacks; update the handler to use the values attached by validateOrchestrate
(e.g., use req.validated.task and req.validated.budget or whatever property
validateOrchestrate populates) instead of using req.query.task || 'Research AI
payments' and parseFloat(req.query.budget) || 0.15, and remove the fallback
defaults so the handler relies on the middleware-validated task and budget (use
the budget value as-is or coerce safely with Number() if needed).
- Around line 284-319: In the app.post('/api/orchestrate' ...) handler remove
the stale duplicate extraction and manual validation that pull { task, budget }
from req.body and re-parse budget (the redeclared "{ task, budget } = req.body",
the missing-task check and the parseFloat(... || 0.15)" fallback), and also
remove the premature orchestrate call that runs before the run is created;
instead use the values from req.validated (const { task, budget } =
req.validated), compute budgetNum from that validated budget (or rely on the
middleware) and call orchestrate only once with runBroadcast so
runHistoryStore.createRun, runBroadcast, runHistoryStore.completeRun/failRun and
result.runId all operate on the validated inputs.

---

Outside diff comments:
In `@src/server.js`:
- Around line 179-181: The route handler registered with
app.get('/api/premium/summarize', validatePremiumQuery, ...) is incorrectly
reading raw input from req.query.text and bypasses the validator; change the
handler to use the validated and sanitized value req.validated.text (instead of
req.query.text) so the length trimming and guards applied by
validatePremiumQuery are respected—remove the fallback default text or keep only
as a debug fallback after checking req.validated.text is missing, and update any
downstream uses of the local text variable accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 263c6fbd-dd48-4e2e-b208-68c49fd785a8

📥 Commits

Reviewing files that changed from the base of the PR and between e047f96 and c6fc4d2.

📒 Files selected for processing (3)
  • package.json
  • src/middleware/errorHandler.js
  • src/server.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server.js (1)

179-181: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handler bypasses validated text value.

validatePremiumQuery sanitizes and validates text into req.validated.text, but this handler reads from req.query.text directly. This defeats the length guards and trimming applied by the validator, and is inconsistent with the other premium endpoints.

🐛 Proposed fix
 app.get('/api/premium/summarize', validatePremiumQuery, async (req, res, next) => {
   try {
-    const text = req.query.text || 'Please provide text to summarize via ?text= parameter';
+    const text = req.validated.text;
     const priceInfo = pricingConfig.getEndpointInfo('GET /api/premium/summarize');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 179 - 181, The route handler registered with
app.get('/api/premium/summarize', validatePremiumQuery, ...) is incorrectly
reading raw input from req.query.text and bypasses the validator; change the
handler to use the validated and sanitized value req.validated.text (instead of
req.query.text) so the length trimming and guards applied by
validatePremiumQuery are respected—remove the fallback default text or keep only
as a debug fallback after checking req.validated.text is missing, and update any
downstream uses of the local text variable accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 15-21: There are duplicate "test" script keys in package.json so
the first one (running tests/api.validation.test.js) is ignored; update the
single "test" script (the "test" key) to run both desired tests (e.g., chain
node src/agents/settlement-header.test.js && node tests/api.validation.test.js
&& node tests/premium-endpoints.integration.test.js) or keep "test" for the
default suite and ensure "test:validation" is referenced/used in CI; modify the
"test" entry (script name "test") to include api.validation.test.js so
validation tests are executed.

In `@src/middleware/errorHandler.js`:
- Around line 79-81: The statement assigning err.details to body.details in the
errorHandler (the block that checks Array.isArray(err.details) &&
err.details.length > 0) contains a trailing semicolon that violates Prettier;
remove the semicolon after the body.details assignment so the line ends without
a semicolon and run the project's formatter/linter to ensure style compliance.

In `@src/server.js`:
- Around line 423-428: In the '/api/wallet/transactions' route handler (the
async function registered with app.get and middleware
validateWalletTransactions) remove the duplicate declaration "const address"
that comes from req.query and keep the single declaration that reads from
req.validated?.address || config.orchestratorAddress || config.serverAddress;
ensure you delete the second "const address = req.query.address..." line and its
redundant null-check so the handler consistently uses the validated address
fallback (req.validated?.address then config.orchestratorAddress then
config.serverAddress) and returns an empty array if that single address is
falsy.
- Around line 20-25: Add missing imports for the validation middleware functions
used in route definitions: import validatePremiumQuery, validateOrchestrate, and
validateWalletTransactions into the top of src/server.js alongside other
middleware imports (so the route handlers referencing validatePremiumQuery,
validateOrchestrate, and validateWalletTransactions no longer throw
ReferenceError). Ensure you import the exact exported names from the modules
that define them (the validation middleware file(s)) and include them in the
same import block as requestId/requestLogger/errorHandler or the appropriate
middleware import so the symbols are available where routes are registered.
- Around line 326-329: The route handler for app.get('/api/orchestrate') is
ignoring the middleware-validated values by reading directly from req.query with
fallbacks; update the handler to use the values attached by validateOrchestrate
(e.g., use req.validated.task and req.validated.budget or whatever property
validateOrchestrate populates) instead of using req.query.task || 'Research AI
payments' and parseFloat(req.query.budget) || 0.15, and remove the fallback
defaults so the handler relies on the middleware-validated task and budget (use
the budget value as-is or coerce safely with Number() if needed).
- Around line 284-319: In the app.post('/api/orchestrate' ...) handler remove
the stale duplicate extraction and manual validation that pull { task, budget }
from req.body and re-parse budget (the redeclared "{ task, budget } = req.body",
the missing-task check and the parseFloat(... || 0.15)" fallback), and also
remove the premature orchestrate call that runs before the run is created;
instead use the values from req.validated (const { task, budget } =
req.validated), compute budgetNum from that validated budget (or rely on the
middleware) and call orchestrate only once with runBroadcast so
runHistoryStore.createRun, runBroadcast, runHistoryStore.completeRun/failRun and
result.runId all operate on the validated inputs.

---

Outside diff comments:
In `@src/server.js`:
- Around line 179-181: The route handler registered with
app.get('/api/premium/summarize', validatePremiumQuery, ...) is incorrectly
reading raw input from req.query.text and bypasses the validator; change the
handler to use the validated and sanitized value req.validated.text (instead of
req.query.text) so the length trimming and guards applied by
validatePremiumQuery are respected—remove the fallback default text or keep only
as a debug fallback after checking req.validated.text is missing, and update any
downstream uses of the local text variable accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 263c6fbd-dd48-4e2e-b208-68c49fd785a8

📥 Commits

Reviewing files that changed from the base of the PR and between e047f96 and c6fc4d2.

📒 Files selected for processing (3)
  • package.json
  • src/middleware/errorHandler.js
  • src/server.js
🛑 Comments failed to post (6)
package.json (1)

15-21: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Duplicate "test" script key causes validation tests to be skipped.

The scripts object contains two "test" keys (lines 15 and 21). In JSON, duplicate keys are invalid, and parsers will use only the last occurrence. As a result, npm test will execute premium-endpoints.integration.test.js (line 21) instead of api.validation.test.js (line 15), which contradicts the PR objective of adding runtime request validation test coverage.

🔧 Proposed fix to remove the duplicate and keep the validation tests
     "test": "node src/agents/settlement-header.test.js && node tests/api.validation.test.js",
     "test:validation": "node tests/api.validation.test.js",
     "lint": "eslint . --ext .js,.mjs,.cjs",
     "lint:fix": "eslint . --ext .js,.mjs,.cjs --fix",
     "format": "prettier --write \"**/*.{js,md,html,yaml,yml}\"",
     "format:check": "prettier --check \"**/*.{js,md,html,yaml,yml}\"",
-    "test": "node src/agents/settlement-header.test.js && node tests/premium-endpoints.integration.test.js",
     "test:parser": "node src/agents/settlement-header.test.js",
     "test:premium": "node tests/premium-endpoints.integration.test.js",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    "test": "node src/agents/settlement-header.test.js && node tests/api.validation.test.js",
    "test:validation": "node tests/api.validation.test.js",
    "lint": "eslint . --ext .js,.mjs,.cjs",
    "lint:fix": "eslint . --ext .js,.mjs,.cjs --fix",
    "format": "prettier --write \"**/*.{js,md,html,yaml,yml}\"",
    "format:check": "prettier --check \"**/*.{js,md,html,yaml,yml}\"",
🧰 Tools
🪛 Biome (2.4.16)

[error] 15-15: The key test was already declared.

(lint/suspicious/noDuplicateObjectKeys)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 15 - 21, There are duplicate "test" script keys in
package.json so the first one (running tests/api.validation.test.js) is ignored;
update the single "test" script (the "test" key) to run both desired tests
(e.g., chain node src/agents/settlement-header.test.js && node
tests/api.validation.test.js && node
tests/premium-endpoints.integration.test.js) or keep "test" for the default
suite and ensure "test:validation" is referenced/used in CI; modify the "test"
entry (script name "test") to include api.validation.test.js so validation tests
are executed.
src/middleware/errorHandler.js (1)

79-81: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove trailing semicolon on line 80.

The semicolon violates the Prettier code style configured for this project.

🎨 Proposed fix
 if (Array.isArray(err.details) && err.details.length > 0) {
-  body.details = err.details;
+  body.details = err.details
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  if (Array.isArray(err.details) && err.details.length > 0) {
    body.details = err.details
  }
🧰 Tools
🪛 ESLint

[error] 80-80: Delete ;

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/middleware/errorHandler.js` around lines 79 - 81, The statement assigning
err.details to body.details in the errorHandler (the block that checks
Array.isArray(err.details) && err.details.length > 0) contains a trailing
semicolon that violates Prettier; remove the semicolon after the body.details
assignment so the line ends without a semicolon and run the project's
formatter/linter to ensure style compliance.
src/server.js (4)

20-25: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing imports for validation middleware functions.

validatePremiumQuery, validateOrchestrate, and validateWalletTransactions are used in route definitions but are never imported. This will cause a ReferenceError at runtime.

🐛 Proposed fix to add missing imports
 import { requestId, requestLogger, errorHandler } from './middleware/errorHandler.js'
 import { orchestrateLimiter, apikeyLimiter } from './middleware/rateLimiter.js'
 import { logger } from './logger.js'
 import { adminAuth } from './middleware/auth.js'
+import {
+  validatePremiumQuery,
+  validateOrchestrate,
+  validateWalletTransactions,
+} from './requestValidation.js'
 import { registerPremiumRoutes } from './routes/premium-routes.js'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

import { requestId, requestLogger, errorHandler } from './middleware/errorHandler.js'
import { orchestrateLimiter, apikeyLimiter } from './middleware/rateLimiter.js'
import { logger } from './logger.js'
import { adminAuth } from './middleware/auth.js'
import {
  validatePremiumQuery,
  validateOrchestrate,
  validateWalletTransactions,
} from './requestValidation.js'
import { registerPremiumRoutes } from './routes/premium-routes.js'
import { createRunHistoryStore } from './storage/run-history.js'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 20 - 25, Add missing imports for the validation
middleware functions used in route definitions: import validatePremiumQuery,
validateOrchestrate, and validateWalletTransactions into the top of
src/server.js alongside other middleware imports (so the route handlers
referencing validatePremiumQuery, validateOrchestrate, and
validateWalletTransactions no longer throw ReferenceError). Ensure you import
the exact exported names from the modules that define them (the validation
middleware file(s)) and include them in the same import block as
requestId/requestLogger/errorHandler or the appropriate middleware import so the
symbols are available where routes are registered.

284-319: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Duplicate extraction overwrites validated values and bypasses middleware validation.

Lines 286-287 correctly extract from req.validated and call orchestrate, but lines 288-295 then shadow those variables by re-extracting from req.body. This completely bypasses the validation middleware:

  1. validateOrchestrate rejects negative/NaN budgets and missing tasks
  2. Line 288 re-declares { task, budget } from raw req.body, shadowing line 286
  3. Line 295 re-parses budget with || 0.15 fallback that accepts negative values the middleware would reject

This appears to be leftover code from before the middleware was added. Remove the redundant extraction and manual validation.

🐛 Proposed fix: remove duplicate extraction and manual validation
 app.post('/api/orchestrate', validateOrchestrate, async (req, res, next) => {
   try {
     const { task, budget } = req.validated;
-    const result = await orchestrate(task, budget, broadcast);
-    const { task, budget } = req.body;
-    if (!task) {
-      const err = new Error('Missing "task" in request body')
-      err.status = 400
-      err.code = 'MISSING_FIELD'
-      return next(err)
-    }
-    const budgetNum = parseFloat(budget) || 0.15
     const run = await runHistoryStore.createRun({
       task,
-      budget: budgetNum,
+      budget,
       source: 'POST /api/orchestrate',
     })
     const runBroadcast = (event) => {
       const eventWithRun = { ...event, runId: run.id }
       broadcast(eventWithRun)
       runHistoryStore.appendEvent(run.id, eventWithRun).catch((persistErr) => {
         logger.warn('run_history_append_failed', { runId: run.id, error: persistErr.message })
       })
     }

     let result
     try {
-      result = await orchestrate(task, budgetNum, runBroadcast, { correlationId: req.requestId })
+      result = await orchestrate(task, budget, runBroadcast, { correlationId: req.requestId })
       await runHistoryStore.completeRun(run.id, result)
     } catch (err) {
       await runHistoryStore.failRun(run.id, err)
       throw err
     }

     result.runId = run.id
     res.json(result)
   } catch (err) {
     next(err)
   }
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 284 - 319, In the app.post('/api/orchestrate'
...) handler remove the stale duplicate extraction and manual validation that
pull { task, budget } from req.body and re-parse budget (the redeclared "{ task,
budget } = req.body", the missing-task check and the parseFloat(... || 0.15)"
fallback), and also remove the premature orchestrate call that runs before the
run is created; instead use the values from req.validated (const { task, budget
} = req.validated), compute budgetNum from that validated budget (or rely on the
middleware) and call orchestrate only once with runBroadcast so
runHistoryStore.createRun, runBroadcast, runHistoryStore.completeRun/failRun and
result.runId all operate on the validated inputs.

326-329: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handler bypasses validated values from middleware.

validateOrchestrate middleware requires task and rejects negative/NaN budgets, but the handler reads from req.query with fallbacks that defeat this validation:

  • Line 328: Falls back to 'Research AI payments' if task missing (middleware already rejects missing task)
  • Line 329: Uses parseFloat(...) || 0.15 which would accept negative budgets the middleware rejects
🐛 Proposed fix
 app.get('/api/orchestrate', validateOrchestrate, async (req, res, next) => {
   try {
-    const task = req.query.task || 'Research AI payments'
-    const budget = parseFloat(req.query.budget) || 0.15
+    const { task, budget } = req.validated;
     const run = await runHistoryStore.createRun({
       task,
       budget,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 326 - 329, The route handler for
app.get('/api/orchestrate') is ignoring the middleware-validated values by
reading directly from req.query with fallbacks; update the handler to use the
values attached by validateOrchestrate (e.g., use req.validated.task and
req.validated.budget or whatever property validateOrchestrate populates) instead
of using req.query.task || 'Research AI payments' and
parseFloat(req.query.budget) || 0.15, and remove the fallback defaults so the
handler relies on the middleware-validated task and budget (use the budget value
as-is or coerce safely with Number() if needed).

423-428: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Duplicate const address declarations will cause a syntax error.

Lines 425 and 427 both declare const address in the same scope. This is a syntax error that will crash at startup. This appears to be an incomplete merge where both the validated and non-validated versions of the code were left in.

Remove lines 427-428 and use the validated address from line 425.

🐛 Proposed fix
 app.get('/api/wallet/transactions', validateWalletTransactions, async (req, res, next) => {
   try {
     const address = req.validated?.address || config.orchestratorAddress || config.serverAddress;
     if (!address) return res.json([]);
-    const address = req.query.address || config.orchestratorAddress || config.serverAddress
-    if (!address) return res.json([])

     // 1. Validate & clamp "limit"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

app.get('/api/wallet/transactions', validateWalletTransactions, async (req, res, next) => {
  try {
    const address = req.validated?.address || config.orchestratorAddress || config.serverAddress;
    if (!address) return res.json([]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.js` around lines 423 - 428, In the '/api/wallet/transactions'
route handler (the async function registered with app.get and middleware
validateWalletTransactions) remove the duplicate declaration "const address"
that comes from req.query and keep the single declaration that reads from
req.validated?.address || config.orchestratorAddress || config.serverAddress;
ensure you delete the second "const address = req.query.address..." line and its
redundant null-check so the handler consistently uses the validated address
fallback (req.validated?.address then config.orchestratorAddress then
config.serverAddress) and returns an empty array if that single address is
falsy.

@Flamki Flamki merged commit d9b9c79 into Flamki:master Jun 8, 2026
1 check failed
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.

Add runtime request validation for all API endpoints

2 participants