Conversation
📝 WalkthroughWalkthroughThis pull request establishes the initial backend infrastructure for a Node.js/Express API serving bug bounty management features. It introduces server configuration, MongoDB connection setup, a Mongoose Bug model, REST route handlers with CRUD operations, centralized error handling, and project metadata updates. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (3)
core-services/routes/bugsRoutes.js (1)
5-13: Optional: chain handlers on the samerouter.route()and renamedeleteBugs.Each path currently calls
router.route(...)twice. You can collapse the duplication, anddeleteBugsdeletes a single bug by:id, so the plural name is misleading — preferdeleteBugfor consistency withgetBug/updateBug.Proposed refactor
-const {getBugs,createBug,getBug,updateBug,deleteBugs} = require('../controllers/bugController'); - -router.route('/').get(getBugs); - -router.route('/').post(createBug); - -router.route('/:id').get(getBug); - -router.route('/:id').put(updateBug); - -router.route('/:id').delete(deleteBugs); +const {getBugs, createBug, getBug, updateBug, deleteBug} = require('../controllers/bugController'); + +router.route('/').get(getBugs).post(createBug); +router.route('/:id').get(getBug).put(updateBug).delete(deleteBug);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-services/routes/bugsRoutes.js` around lines 5 - 13, Routes are duplicated by calling router.route('/') and router.route('/:id') twice and the delete handler is misnamed; consolidate handlers by chaining methods on the same router.route call (e.g., router.route('/').get(getBugs).post(createBug) and router.route('/:id').get(getBug).put(updateBug).delete(deleteBug)) and rename the exported/defined handler function from deleteBugs to deleteBug (update any imports/exports/usages accordingly) so naming matches getBug/updateBug and avoids duplicate route declarations.core-services/controllers/bugController.js (1)
76-87: RenamedeleteBugs→deleteBug(single-resource handler).The route is
DELETE /api/bugs/:idand the handler deletes exactly one document, but the exported name is plural, which is inconsistent withgetBug/updateBugand misleading at call sites. Rename here and inroutes/bugsRoutes.jsand the module exports.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-services/controllers/bugController.js` around lines 76 - 87, Rename the exported handler function deleteBugs to deleteBug to match single-resource semantics and naming of getBug/updateBug: change the function name declaration from deleteBugs to deleteBug, update all imports/usages where the route registers the handler (the route that currently references deleteBugs) to use deleteBug, and update the module exports to export deleteBug instead of deleteBugs; ensure no other references to deleteBugs remain.core-services/Models/bug.js (1)
5-27: Add bounds and URL validation for public input fields.
title,description,techStack,tags, and GitHub metadata are user-controlled and currently unbounded. Add reasonablemaxlength/array limits and URL validation forrepoUrl/issueUrlto reduce abuse and bad links entering the database.Also applies to: 63-69
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-services/Models/bug.js` around lines 5 - 27, The schema fields title, description, techStack, tags (and GitHub fields repoUrl/issueUrl) are currently unbounded; add sensible limits and URL validation: set maxlength on title (e.g., 200) and description (e.g., 2000), enforce array-size limits on techStack and tags with a validator (e.g., max 20 items) and set per-item maxlength (e.g., 50), and add URL validation for repoUrl and issueUrl using either a regex match or validator.isURL in their schema definitions (with an appropriate error message). Update the model entries for title, description, techStack, tags, repoUrl and issueUrl to include these maxlength/validate constraints so bad or overly large inputs are rejected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@core-services/config/dbConnection.js`:
- Around line 14-18: The catch block for mongoose.connect currently uses
console.log(err) and doesn't handle later connection events; change
console.log(err) to console.error(err) in the existing catch so the initial
handshake error goes to stderr, and add listeners on mongoose.connection (e.g.,
mongoose.connection.on('error', handler) and
mongoose.connection.on('disconnected', handler)) to log runtime connection
errors/disconnects and exit or trigger reconnection logic as appropriate so the
process does not silently run with a broken DB; locate the existing
mongoose.connect call and the catch block and attach the connection listeners
there (use the same logging mechanism, e.g., console.error or your
processLogger, and call process.exit(1) or other cleanup inside the handlers).
In `@core-services/controllers/bugController.js`:
- Around line 40-49: Validate req.params.id with mongoose.Types.ObjectId.isValid
before calling Bug.findById in getBug, updateBug, and deleteBugs; if the id is
invalid, set an appropriate status (e.g., res.status(404) or 400) and throw a
new Error ('Bug not found' or 'Invalid id') so the errorHandler gets the status,
and only call Bug.findById when the id is valid to avoid Mongoose CastError.
- Around line 55-70: In updateBug, avoid mass-assignment and the redundant
pre-fetch: build a whitelist object from req.body containing only allowed
updatable fields (e.g., title, description, reward, tags — explicitly exclude
status, ownerId, isAbusive, isRewardLocked, refundProcessed and any keys
starting with $), then call Bug.findByIdAndUpdate(req.params.id,
whitelistObject, { new: true, runValidators: true, context: 'query' }) and check
the returned updatedBug for null to return 404; remove the initial Bug.findById
call and ensure validators are enforced by passing runValidators: true (and
context: 'query' if using mongoose validators that need it).
In `@core-services/middleware/errorHandler.js`:
- Around line 1-32: The errorHandler middleware currently lets unmapped errors
hang, leaks stacks, and never explicitly sets the HTTP status; update the
errorHandler function to: determine the statusCode as res.statusCode &&
res.statusCode !== 200 ? res.statusCode : constants.SERVER_ERROR (so unmapped
errors become 500), create a lookup map (e.g., statusTitles = {
[constants.VALIDATION_ERROR]: 'Validation Failed', ... }) instead of the switch,
call res.status(statusCode) before sending a response, and send res.json with {
title: statusTitles[statusCode] || 'Error', message: err.message,
...(process.env.NODE_ENV !== 'production' && { stackTrace: err.stack }) } so
stack traces are only included outside production and every path returns a JSON
response; keep the middleware signature errorHandler(err, req, res, next) and
ensure the default path returns a 500 JSON response instead of logging and
falling through.
In `@core-services/Models/bug.js`:
- Around line 40-83: The updateBug handler currently passes req.body straight
into findByIdAndUpdate, allowing clients to change protected server-controlled
fields; update the updateBug function to mirror createBug's allowlist pattern:
build an updates object by extracting only permitted mutable fields from
req.body (e.g., title, description, github.repoUrl, github.filePath,
github.issueUrl, deadline, reward-related editable fields) and explicitly
exclude server-controlled fields such as status, acceptedSolutionId,
isRewardLocked, isAbusive, refundProcessed, ownerId, solutionCount before
calling Bug.findByIdAndUpdate; ensure you still call findByIdAndUpdate with {
new: true, runValidators: true } so validation and return of the updated
document continue to work.
- Around line 47-52: The ownerId field is optional in the Bug schema and
createBug doesn't set it from the authenticated user, allowing orphaned bugs;
update the Bug model's ownerId schema (symbol: ownerId) to include required:
true and keep the ObjectId ref to "User", and then modify the createBug
controller (symbol: createBug) to source ownerId from the authenticated request
context (e.g., req.user.id or req.user._id) instead of the request body—also
remove ownerId from the destructured body fields ({title, description, deadline,
reward}) so persisted bugs always have a validated owner reference for
authorization and listing.
- Around line 58-62: The solutionCount schema field lacks a minimum constraint
allowing negative values; update the solutionCount definition in Models/bug.js
(field name: solutionCount) to include a Mongoose validation of min: 0 (and keep
default: 0) so any direct updates (e.g., via updateBug) will be rejected if
negative; ensure the schema change is saved and tests/requests that set
solutionCount < 0 now fail validation.
In `@core-services/server.js`:
- Around line 7-18: Await the connectDb() promise before starting the HTTP
server and add graceful shutdown handlers: call await connectDb() inside an
async init function (or top-level promise handling) and only then call server =
app.listen(...); wrap connectDb() in try/catch so on failure you log the error
and exit with non-zero status; register SIGINT/SIGTERM handlers that close the
HTTP server (server.close()) and the DB connection (e.g.,
mongoose.connection.close() or a provided disconnect function) and then exit
cleanly; keep existing symbols (connectDb, app.listen, errorHandler, router) and
ensure server variable is stored so the shutdown handlers can close it.
---
Nitpick comments:
In `@core-services/controllers/bugController.js`:
- Around line 76-87: Rename the exported handler function deleteBugs to
deleteBug to match single-resource semantics and naming of getBug/updateBug:
change the function name declaration from deleteBugs to deleteBug, update all
imports/usages where the route registers the handler (the route that currently
references deleteBugs) to use deleteBug, and update the module exports to export
deleteBug instead of deleteBugs; ensure no other references to deleteBugs
remain.
In `@core-services/Models/bug.js`:
- Around line 5-27: The schema fields title, description, techStack, tags (and
GitHub fields repoUrl/issueUrl) are currently unbounded; add sensible limits and
URL validation: set maxlength on title (e.g., 200) and description (e.g., 2000),
enforce array-size limits on techStack and tags with a validator (e.g., max 20
items) and set per-item maxlength (e.g., 50), and add URL validation for repoUrl
and issueUrl using either a regex match or validator.isURL in their schema
definitions (with an appropriate error message). Update the model entries for
title, description, techStack, tags, repoUrl and issueUrl to include these
maxlength/validate constraints so bad or overly large inputs are rejected.
In `@core-services/routes/bugsRoutes.js`:
- Around line 5-13: Routes are duplicated by calling router.route('/') and
router.route('/:id') twice and the delete handler is misnamed; consolidate
handlers by chaining methods on the same router.route call (e.g.,
router.route('/').get(getBugs).post(createBug) and
router.route('/:id').get(getBug).put(updateBug).delete(deleteBug)) and rename
the exported/defined handler function from deleteBugs to deleteBug (update any
imports/exports/usages accordingly) so naming matches getBug/updateBug and
avoids duplicate route declarations.
🪄 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: c9f9ba99-b3e0-4888-9f39-bfdcc5e7ab51
⛔ Files ignored due to path filters (1)
core-services/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
core-services/.gitignorecore-services/Models/bug.jscore-services/config/dbConnection.jscore-services/constants.jscore-services/controllers/bugController.jscore-services/middleware/errorHandler.jscore-services/package.jsoncore-services/routes/bugsRoutes.jscore-services/server.js
| catch (err) | ||
| { | ||
| console.log(err); | ||
| process.exit(1); | ||
| } |
There was a problem hiding this comment.
Log errors to stderr and add disconnect handling.
Two minor concerns:
console.log(err)writes DB connection failure to stdout; useconsole.errorso errors land in the proper stream.mongoose.connectonly rejects on the initial handshake. Later disconnects, auth failures, or topology errors won't hit thiscatch. Attach listeners onmongoose.connection(error,disconnected) to surface runtime issues; otherwise the process will silently run with a broken DB while Mongoose buffers (and eventually times out) every query.
Proposed fix
catch (err)
{
- console.log(err);
+ console.error('Database connection failed:', err);
process.exit(1);
}
};
+
+mongoose.connection.on('error', (err) => console.error('Mongoose error:', err));
+mongoose.connection.on('disconnected', () => console.warn('Mongoose disconnected'));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/config/dbConnection.js` around lines 14 - 18, The catch block
for mongoose.connect currently uses console.log(err) and doesn't handle later
connection events; change console.log(err) to console.error(err) in the existing
catch so the initial handshake error goes to stderr, and add listeners on
mongoose.connection (e.g., mongoose.connection.on('error', handler) and
mongoose.connection.on('disconnected', handler)) to log runtime connection
errors/disconnects and exit or trigger reconnection logic as appropriate so the
process does not silently run with a broken DB; locate the existing
mongoose.connect call and the catch block and attach the connection listeners
there (use the same logging mechanism, e.g., console.error or your
processLogger, and call process.exit(1) or other cleanup inside the handlers).
| const getBug = asyncHandler(async (req, res) => | ||
| { | ||
| const bug = await Bug.findById(req.params.id); | ||
| if(!bug) | ||
| { | ||
| res.status(404); | ||
| throw new Error('Bug not found'); | ||
| } | ||
| res.status(200).json(bug); | ||
| }); |
There was a problem hiding this comment.
Validate req.params.id as an ObjectId before findById.
getBug, updateBug, and deleteBugs all pass req.params.id straight into Bug.findById. If the caller sends something that isn't a 24-char hex string (e.g. /api/bugs/foo), Mongoose throws a CastError before your if (!bug) guard runs — res.status(...) was never set, so with the current errorHandler the default branch hits and the request hangs (see the errorHandler comment). Validate up front and return a proper 404/400.
Proposed fix (apply in getBug, updateBug, deleteBugs)
const mongoose = require('mongoose');
...
const getBug = asyncHandler(async (req, res) =>
{
+ if (!mongoose.isValidObjectId(req.params.id))
+ {
+ res.status(404);
+ throw new Error('Bug not found');
+ }
const bug = await Bug.findById(req.params.id);
if(!bug)
{
res.status(404);
throw new Error('Bug not found');
}
res.status(200).json(bug);
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/controllers/bugController.js` around lines 40 - 49, Validate
req.params.id with mongoose.Types.ObjectId.isValid before calling Bug.findById
in getBug, updateBug, and deleteBugs; if the id is invalid, set an appropriate
status (e.g., res.status(404) or 400) and throw a new Error ('Bug not found' or
'Invalid id') so the errorHandler gets the status, and only call Bug.findById
when the id is valid to avoid Mongoose CastError.
| const updateBug = asyncHandler(async(req, res) => | ||
| { | ||
| const bug = await Bug.findById(req.params.id); | ||
| if(!bug) | ||
| { | ||
| res.status(404); | ||
| throw new Error('Bug not found'); | ||
| } | ||
| const updatedBug = await Bug.findByIdAndUpdate( | ||
| req.params.id, | ||
| req.body, | ||
| {new: true} | ||
| ); | ||
|
|
||
| res.status(200).json(updatedBug); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
mongoose 9 findByIdAndUpdate runValidators default behavior
💡 Result:
In Mongoose 9, the default behavior of Model.findByIdAndUpdate regarding runValidators is false. Update validators, including those triggered by runValidators: true, are off by default for findByIdAndUpdate and similar update operations. You must explicitly set { runValidators: true } in the options to enable validation on updates. This has been consistent across Mongoose versions, including 9.x, with no changes noted in the 9.0 changelog or migration guides.
Citations:
- 1: https://mongoosejs.com/docs/validation.html
- 2: Configuration to make runValidators default to true? Automattic/mongoose#6578
- 3: http://mongoosejs.com/docs/api/model.html
- 4: https://mongoosejs.com/docs/api/query.html
🏁 Script executed:
# Find the Bug model/schema definition
fd -t f Bug -i | grep -E '\.(js|ts)$'Repository: call-0f-code/Bug-Graveyard
Length of output: 207
🏁 Script executed:
# Also search for Bug schema/model definition in common patterns
rg "const Bug|export.*Bug|mongoose.model.*Bug" -t js -t ts -A 5Repository: call-0f-code/Bug-Graveyard
Length of output: 595
🏁 Script executed:
# Check the Bug schema definition in the Models directory (since that's what the controller imports)
cat -n core-services/Models/bug.jsRepository: call-0f-code/Bug-Graveyard
Length of output: 2130
🏁 Script executed:
# Also check the src models version to see if there are differences
cat -n core-services/src/models/Bug.jsRepository: call-0f-code/Bug-Graveyard
Length of output: 1892
🏁 Script executed:
# Let's check the full updateBug function and surrounding context
sed -n '45,90p' core-services/controllers/bugController.jsRepository: call-0f-code/Bug-Graveyard
Length of output: 979
🏁 Script executed:
# Also check if there are any other update operations or patterns in the controller
rg "findByIdAndUpdate|findOneAndUpdate" core-services/controllers/bugController.js -A 10 -B 2Repository: call-0f-code/Bug-Graveyard
Length of output: 332
Harden updateBug: whitelist fields, run validators, drop redundant fetch.
Three issues here:
-
Mass assignment / NoSQL injection risk. Passing
req.bodydirectly tofindByIdAndUpdatelets a client set arbitrary fields or inject Mongo operators (e.g.{"$rename": {...}}). The schema includes sensitive fields (status,ownerId,isAbusive,isRewardLocked,refundProcessed) that should never be client-editable. Pick the allowed fields explicitly. -
Schema validators don't run by default on
findByIdAndUpdate. PassrunValidators: trueso required rules ontitle,description,rewardand themin: 1constraint onrewardare enforced on updates. -
The preceding
findByIdis redundant —findByIdAndUpdatealready returnsnullif no document matches, so you can check the result instead and save a round trip.
Proposed fix
-const updateBug = asyncHandler(async(req, res) =>
-{
- const bug = await Bug.findById(req.params.id);
- if(!bug)
- {
- res.status(404);
- throw new Error('Bug not found');
- }
- const updatedBug = await Bug.findByIdAndUpdate(
- req.params.id,
- req.body,
- {new: true}
- );
-
- res.status(200).json(updatedBug);
-});
+const updateBug = asyncHandler(async (req, res) =>
+{
+ const { title, description, deadline, reward } = req.body;
+ const updates = { title, description, deadline, reward };
+ Object.keys(updates).forEach(k => updates[k] === undefined && delete updates[k]);
+
+ const updatedBug = await Bug.findByIdAndUpdate(
+ req.params.id,
+ updates,
+ { new: true, runValidators: true }
+ );
+ if (!updatedBug)
+ {
+ res.status(404);
+ throw new Error('Bug not found');
+ }
+ res.status(200).json(updatedBug);
+});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/controllers/bugController.js` around lines 55 - 70, In
updateBug, avoid mass-assignment and the redundant pre-fetch: build a whitelist
object from req.body containing only allowed updatable fields (e.g., title,
description, reward, tags — explicitly exclude status, ownerId, isAbusive,
isRewardLocked, refundProcessed and any keys starting with $), then call
Bug.findByIdAndUpdate(req.params.id, whitelistObject, { new: true,
runValidators: true, context: 'query' }) and check the returned updatedBug for
null to return 404; remove the initial Bug.findById call and ensure validators
are enforced by passing runValidators: true (and context: 'query' if using
mongoose validators that need it).
| const{constants} = require('../constants'); | ||
| const errorHandler = (err,req,res,next) => | ||
| { | ||
| const statusCode = res.statusCode ? res.statusCode: 500; | ||
|
|
||
| switch (statusCode) | ||
| { | ||
| case constants.VALIDATION_ERROR: | ||
| res.json({title: "Validation Failed",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.NOT_FOUND: | ||
| res.json({title: "Not Found",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.UNAUTHORIZED: | ||
| res.json({title: "Not Authorized",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.FORBIDDEN: | ||
| res.json({title: "Forbidden",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| case constants.SERVER_ERROR: | ||
| res.json({title: "Server Error",message: err.message,stackTrace: err.stack}); | ||
| break; | ||
|
|
||
| default: | ||
| console.log('No Error'); | ||
| break; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Critical: unmapped errors leave the request hanging; stack traces leak to clients.
Several problems on this hot path:
- Request hang on any unmapped error. In Express,
res.statusCodedefaults to200. So if any handler throws without first callingres.status(400|401|403|404|500)(e.g. a MongooseCastErrorfrom an invalid:idingetBug/updateBug/deleteBugs, a schema validation failure increateBug, a DB timeout, a thrownTypeError, etc.),statusCodebecomes200, falls through todefault, logs"No Error", and never sends a response — the client hangs until its socket timeout. This will bite you the first time anyone hits/api/bugs/not-an-object-id. - Status on the wire is never explicitly set. The middleware should call
res.status(statusCode)beforeres.json(...)so the HTTP status matches the payload regardless of what the controller set. err.stackis returned in the response body. That's an information-disclosure issue in production; gate it onNODE_ENV !== 'production'.- The
switchon constants is verbose and duplicated — a lookup table is clearer and removes the risk of forgetting abreak.
Proposed fix
-const{constants} = require('../constants');
-const errorHandler = (err,req,res,next) =>
-{
- const statusCode = res.statusCode ? res.statusCode: 500;
-
- switch (statusCode)
- {
- case constants.VALIDATION_ERROR:
- res.json({title: "Validation Failed",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.NOT_FOUND:
- res.json({title: "Not Found",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.UNAUTHORIZED:
- res.json({title: "Not Authorized",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.FORBIDDEN:
- res.json({title: "Forbidden",message: err.message,stackTrace: err.stack});
- break;
-
- case constants.SERVER_ERROR:
- res.json({title: "Server Error",message: err.message,stackTrace: err.stack});
- break;
-
- default:
- console.log('No Error');
- break;
- }
-};
+const { constants } = require('../constants');
+
+const TITLES = {
+ [constants.VALIDATION_ERROR]: 'Validation Failed',
+ [constants.NOT_FOUND]: 'Not Found',
+ [constants.UNAUTHORIZED]: 'Not Authorized',
+ [constants.FORBIDDEN]: 'Forbidden',
+ [constants.SERVER_ERROR]: 'Server Error',
+};
+
+const errorHandler = (err, req, res, next) => {
+ // If no explicit error status was set by the controller, treat as 500.
+ const statusCode =
+ res.statusCode && res.statusCode !== 200 ? res.statusCode : 500;
+
+ res.status(statusCode).json({
+ title: TITLES[statusCode] || 'Error',
+ message: err.message,
+ ...(process.env.NODE_ENV !== 'production' && { stackTrace: err.stack }),
+ });
+};
module.exports = errorHandler;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/middleware/errorHandler.js` around lines 1 - 32, The
errorHandler middleware currently lets unmapped errors hang, leaks stacks, and
never explicitly sets the HTTP status; update the errorHandler function to:
determine the statusCode as res.statusCode && res.statusCode !== 200 ?
res.statusCode : constants.SERVER_ERROR (so unmapped errors become 500), create
a lookup map (e.g., statusTitles = { [constants.VALIDATION_ERROR]: 'Validation
Failed', ... }) instead of the switch, call res.status(statusCode) before
sending a response, and send res.json with { title: statusTitles[statusCode] ||
'Error', message: err.message, ...(process.env.NODE_ENV !== 'production' && {
stackTrace: err.stack }) } so stack traces are only included outside production
and every path returns a JSON response; keep the middleware signature
errorHandler(err, req, res, next) and ensure the default path returns a 500 JSON
response instead of logging and falling through.
| status: | ||
| { | ||
| type: String, | ||
| enum: ["OPEN", "SOLVED", "CLOSED"], | ||
| default: "OPEN", | ||
| index: true | ||
| }, | ||
| ownerId: | ||
| { | ||
| type: mongoose.Schema.Types.ObjectId, | ||
| ref: "User", | ||
| index: true | ||
| }, | ||
| acceptedSolutionId: | ||
| { | ||
| type: mongoose.Schema.Types.ObjectId, | ||
| ref: "Solution" | ||
| }, | ||
| solutionCount: | ||
| { | ||
| type: Number, | ||
| default: 0 | ||
| }, | ||
| github: | ||
| { | ||
| repoUrl: String, | ||
| filePath: String, | ||
| issueUrl: String | ||
| }, | ||
| deadline: Date, | ||
| isRewardLocked: | ||
| { | ||
| type: Boolean, | ||
| default: true | ||
| }, | ||
| isAbusive: | ||
| { | ||
| type: Boolean, | ||
| default: false | ||
| }, | ||
| refundProcessed: | ||
| { | ||
| type: Boolean, | ||
| default: false |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Inspect Bug write paths for raw request-body persistence.
# Expected: Bug.create/findByIdAndUpdate should use an explicit allowlist DTO, not req.body directly.
rg -n -C4 'Bug\.(create|findByIdAndUpdate|findOneAndUpdate|updateOne)\s*\(|req\.body' --iglob '*.js'Repository: call-0f-code/Bug-Graveyard
Length of output: 1981
🏁 Script executed:
#!/bin/bash
# In bugController.js updateBug function, replace req.body with explicit field allowlist
# Example: const {title, description, reward} = req.body; then pass {title, description, reward} to findByIdAndUpdateRepository: call-0f-code/Bug-Graveyard
Length of output: 52
Fix the update handler to whitelist mutable fields.
While createBug correctly whitelists fields before creation, the updateBug handler passes req.body directly to findByIdAndUpdate, allowing users to modify protected fields. Extract allowed fields from the request body before the update call, mirroring the allowlist pattern already used in create.
Fields like status, acceptedSolutionId, isRewardLocked, isAbusive, and refundProcessed must remain server-controlled and are vulnerable in the current update path.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/Models/bug.js` around lines 40 - 83, The updateBug handler
currently passes req.body straight into findByIdAndUpdate, allowing clients to
change protected server-controlled fields; update the updateBug function to
mirror createBug's allowlist pattern: build an updates object by extracting only
permitted mutable fields from req.body (e.g., title, description,
github.repoUrl, github.filePath, github.issueUrl, deadline, reward-related
editable fields) and explicitly exclude server-controlled fields such as status,
acceptedSolutionId, isRewardLocked, isAbusive, refundProcessed, ownerId,
solutionCount before calling Bug.findByIdAndUpdate; ensure you still call
findByIdAndUpdate with { new: true, runValidators: true } so validation and
return of the updated document continue to work.
| ownerId: | ||
| { | ||
| type: mongoose.Schema.Types.ObjectId, | ||
| ref: "User", | ||
| index: true | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "*bugController*" -o -name "*bug.js" | grep -E "\.(js|ts)$"Repository: call-0f-code/Bug-Graveyard
Length of output: 144
🏁 Script executed:
cd core-services && git ls-files | grep -i bug | head -20Repository: call-0f-code/Bug-Graveyard
Length of output: 151
🏁 Script executed:
cat -n core-services/Models/bug.jsRepository: call-0f-code/Bug-Graveyard
Length of output: 2130
🏁 Script executed:
cat -n core-services/controllers/bugController.js 2>/dev/null || echo "File not found in expected location"Repository: call-0f-code/Bug-Graveyard
Length of output: 2728
Require ownerId for created bugs.
The ownerId field is currently optional, and the controller's createBug function (line 21) does not set this value from the authenticated user—it only extracts {title, description, deadline, reward} from the request. This allows bugs to be persisted with a null ownerId, creating orphan records that cannot be reliably authorized, listed by owner, or refunded. The schema must enforce required: true, and the controller must source ownerId from the authenticated request context rather than the request body.
🛡️ Proposed schema change
ownerId:
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
+ required: true,
index: true
},📝 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.
| ownerId: | |
| { | |
| type: mongoose.Schema.Types.ObjectId, | |
| ref: "User", | |
| index: true | |
| }, | |
| ownerId: | |
| { | |
| type: mongoose.Schema.Types.ObjectId, | |
| ref: "User", | |
| required: true, | |
| index: true | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/Models/bug.js` around lines 47 - 52, The ownerId field is
optional in the Bug schema and createBug doesn't set it from the authenticated
user, allowing orphaned bugs; update the Bug model's ownerId schema (symbol:
ownerId) to include required: true and keep the ObjectId ref to "User", and then
modify the createBug controller (symbol: createBug) to source ownerId from the
authenticated request context (e.g., req.user.id or req.user._id) instead of the
request body—also remove ownerId from the destructured body fields ({title,
description, deadline, reward}) so persisted bugs always have a validated owner
reference for authorization and listing.
| solutionCount: | ||
| { | ||
| type: Number, | ||
| default: 0 | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd core-services && cat -n Models/bug.js | head -80Repository: call-0f-code/Bug-Graveyard
Length of output: 1925
🏁 Script executed:
cd core-services && rg "solutionCount" --type js -B 2 -A 2Repository: call-0f-code/Bug-Graveyard
Length of output: 384
🏁 Script executed:
cd core-services && rg "\$inc|solutionCount\s*[:=]|updateOne|updateMany|findByIdAndUpdate" --type js -B 2 -A 2 | head -100Repository: call-0f-code/Bug-Graveyard
Length of output: 673
🏁 Script executed:
cd core-services && find . -name "*[Ss]olution*" -type f | grep -E "\.(js|ts)$"Repository: call-0f-code/Bug-Graveyard
Length of output: 94
🏁 Script executed:
cd core-services && cat src/models/Solution.js && echo "---" && find . -name "*[Ss]olution*[Cc]ontroller*" -type fRepository: call-0f-code/Bug-Graveyard
Length of output: 887
🏁 Script executed:
cd core-services && find . -type f -name "*.js" -exec rg -l "new Solution|solution.*save|solutionCount.*\+|\$inc.*solutionCount" {} \; | head -10Repository: call-0f-code/Bug-Graveyard
Length of output: 52
🏁 Script executed:
cd core-services && rg "solution|Solution" --type js -i | grep -i "controller\|route" | head -20Repository: call-0f-code/Bug-Graveyard
Length of output: 52
🏁 Script executed:
cd core-services && ls -la controllers/ && ls -la src/controllers/ 2>/dev/null || echo "src/controllers not found"Repository: call-0f-code/Bug-Graveyard
Length of output: 419
🏁 Script executed:
cd core-services && cat -n controllers/bugController.jsRepository: call-0f-code/Bug-Graveyard
Length of output: 2728
🏁 Script executed:
cd core-services && find . -name "*route*" -type f && find . -name "*middleware*" -type fRepository: call-0f-code/Bug-Graveyard
Length of output: 52
🏁 Script executed:
cd core-services && rg -i "bug|solution" --type js | grep -i "increment\|decrement\|add\|remove" | head -20Repository: call-0f-code/Bug-Graveyard
Length of output: 52
Add minimum value validation to prevent negative solutionCount.
The updateBug controller allows direct updates to solutionCount via request body, making it possible to set negative values. A min: 0 validation constraint should be added to the schema to prevent invalid counter states that could corrupt listing/sorting logic.
Proposed validation
solutionCount:
{
type: Number,
- default: 0
+ default: 0,
+ min: 0
},🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/Models/bug.js` around lines 58 - 62, The solutionCount schema
field lacks a minimum constraint allowing negative values; update the
solutionCount definition in Models/bug.js (field name: solutionCount) to include
a Mongoose validation of min: 0 (and keep default: 0) so any direct updates
(e.g., via updateBug) will be rejected if negative; ensure the schema change is
saved and tests/requests that set solutionCount < 0 now fail validation.
| connectDb(); | ||
| const app = express(); | ||
|
|
||
| const port = process.env.PORT || 5000; | ||
|
|
||
| app.use(express.json()); | ||
| app.use('/api/bugs',router); | ||
| app.use(errorHandler); | ||
|
|
||
| app.listen(port, () => { | ||
| console.log('server running on port', port); | ||
| }); No newline at end of file |
There was a problem hiding this comment.
Await connectDb() and add graceful shutdown.
connectDb() returns a promise but is called fire-and-forget, so app.listen starts before the DB connection is established. Mongoose buffers commands briefly, but if the initial connect fails, process.exit(1) runs while the HTTP server is already accepting traffic — first requests may 500 or hang. Start the listener only after the DB is ready, and register termination handlers so containers/orchestrators can stop the process cleanly.
Proposed fix
-connectDb();
-const app = express();
+const app = express();
const port = process.env.PORT || 5000;
app.use(express.json());
app.use('/api/bugs',router);
app.use(errorHandler);
-app.listen(port, () => {
- console.log('server running on port', port);
-});
+connectDb().then(() => {
+ const server = app.listen(port, () => {
+ console.log('server running on port', port);
+ });
+ const shutdown = () => server.close(() => process.exit(0));
+ process.on('SIGTERM', shutdown);
+ process.on('SIGINT', shutdown);
+});📝 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.
| connectDb(); | |
| const app = express(); | |
| const port = process.env.PORT || 5000; | |
| app.use(express.json()); | |
| app.use('/api/bugs',router); | |
| app.use(errorHandler); | |
| app.listen(port, () => { | |
| console.log('server running on port', port); | |
| }); | |
| const app = express(); | |
| const port = process.env.PORT || 5000; | |
| app.use(express.json()); | |
| app.use('/api/bugs',router); | |
| app.use(errorHandler); | |
| connectDb().then(() => { | |
| const server = app.listen(port, () => { | |
| console.log('server running on port', port); | |
| }); | |
| const shutdown = () => server.close(() => process.exit(0)); | |
| process.on('SIGTERM', shutdown); | |
| process.on('SIGINT', shutdown); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@core-services/server.js` around lines 7 - 18, Await the connectDb() promise
before starting the HTTP server and add graceful shutdown handlers: call await
connectDb() inside an async init function (or top-level promise handling) and
only then call server = app.listen(...); wrap connectDb() in try/catch so on
failure you log the error and exit with non-zero status; register SIGINT/SIGTERM
handlers that close the HTTP server (server.close()) and the DB connection
(e.g., mongoose.connection.close() or a provided disconnect function) and then
exit cleanly; keep existing symbols (connectDb, app.listen, errorHandler,
router) and ensure server variable is stored so the shutdown handlers can close
it.
Added CRUD routes for bugs (GET, POST, PUT, DELETE)
Connected to MongoDB using Mongoose
Summary by CodeRabbit
Release Notes
New Features
Chores