Skip to content

fix: add error handling to GET /bugs/{id} and GET /bugs/search endpoints#44

Open
SatishKumar620 wants to merge 4 commits intoOWASP-BLT:mainfrom
SatishKumar620:fix/error-handling-bugs-get-endpoints
Open

fix: add error handling to GET /bugs/{id} and GET /bugs/search endpoints#44
SatishKumar620 wants to merge 4 commits intoOWASP-BLT:mainfrom
SatishKumar620:fix/error-handling-bugs-get-endpoints

Conversation

@SatishKumar620
Copy link
Contributor

@SatishKumar620 SatishKumar620 commented Mar 13, 2026

Problem

In src/handlers/bugs.py, the GET /bugs/{id} and GET /bugs/search
endpoints had bare await db.prepare() calls with no try/except block.
If D1 is unavailable or returns an unexpected error, these endpoints
would throw an unhandled exception and crash the worker instead of
returning a proper error response.

The POST /bugs handler already had correct error handling — this PR
makes GET /bugs/{id} and GET /bugs/search consistent with that pattern.

Fix

Wrapped all DB calls in both endpoints with try/except blocks that log
the error and return a 500 error_response, matching the existing
pattern in POST /bugs and handle_stats.

Closes #43

Summary by CodeRabbit

  • New Features

    • Bug detail view now includes associated screenshots for richer context.
  • Bug Fixes

    • Improved error handling for search and bug retrieval, returning consistent 500 responses on failure.
    • Added richer error logging to aid debugging and monitoring.

@owasp-blt
Copy link

owasp-blt bot commented Mar 13, 2026

📊 Monthly Leaderboard

Hi @SatishKumar620! Here's how you rank for March 2026:

Rank User Open PRs PRs (merged) PRs (closed) Reviews Comments Total
#19 @YasogaN 0 12 0 0 0 120
#20 @SatishKumar620 13 2 0 1 36 110
#21 @arnavkirti 5 2 12 20 2 105

Scoring this month (across OWASP-BLT org): Open PRs (+1 each), Merged PRs (+10), Closed (not merged) (−2), Reviews (+5; first two per PR in-month), Comments (+2, excludes CodeRabbit). Run /leaderboard on any issue or PR to see your rank!

@owasp-blt
Copy link

owasp-blt bot commented Mar 13, 2026

👋 Hi @SatishKumar620!

This pull request needs a peer review before it can be merged. Please request a review from a team member who is not:

  • The PR author
  • coderabbitai
  • copilot

Once a valid peer review is submitted, this check will pass automatically. Thank you!

⚠️ Peer review enforcement is active.

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

GET /bugs/search and GET /bugs/{id} in src/handlers/bugs.py now use try/except around DB operations, log errors, return standardized 500 responses on failure, and switch screenshot retrieval to the ORM while keeping tag retrieval via raw SQL.

Changes

Cohort / File(s) Summary
Bug handlers
src/handlers/bugs.py
Added BugScreenshot import; wrapped search and single-bug DB/ORM calls in try/except blocks with error logging and standardized 500 responses. Migrated screenshot retrieval to ORM; retained tags via raw SQL and converted results to expected format.
Models import surface
src/handlers/... (imports)
Expanded public imports to include BugScreenshot for screenshot ORM queries.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

quality: medium

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes a migration from raw SQL to ORM for the screenshots query, which aligns with maintainer feedback but extends beyond the original scope of issue #43 (error handling only). Consider separating the ORM migration work into a dedicated PR focused on that refactoring, keeping this PR focused solely on error handling to match issue #43 objectives.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding error handling to two specific endpoints.
Linked Issues check ✅ Passed The PR successfully implements error handling with try/except blocks around DB calls in both endpoints, matching the pattern in POST /bugs, logging errors, and returning 500 responses as required by issue #43.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@SatishKumar620
Copy link
Contributor Author

@coderabbitai Please assess the PR's completeness and merge readiness.

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat src/handlers/bugs.py

Length of output: 14272


@SatishKumar620: Here is a thorough assessment of PR #44.


✅ Merge Readiness Assessment

Goal Alignment

The PR fully addresses issue #43. Both GET /bugs/{id} and GET /bugs/search now follow the same try/except pattern as POST /bugs and handle_stats.


What's Done Well

Area Status
GET /bugs/search wrapped in try/except
GET /bugs/{id} wrapped in try/except
get_db_safe has its own isolated try/except
bug_id ValueError handled before DB try block
Error logging with logger.error(...)
500 error_response returned on failure
Pattern consistent with POST /bugs and GET /bugs list
No regressions to existing endpoints

Minor Pre-existing Observations (non-blocking, out of this PR's scope)

  1. Error detail leakage: All handlers — including the pre-existing POST /bugs — return str(e) directly in the error response body (e.g., f"Failed to search bugs: {str(e)}"). This can expose internal DB error messages to API clients. Consider a follow-up to return a generic message while logging the full exception internally.

  2. Hardcoded OFFSET 0 in search: The search SQL has LIMIT ? OFFSET 0 with no pagination support. This is pre-existing and out of scope for this PR.

  3. Single try block for three DB calls in GET /bugs/{id}: The main bug query, screenshots query, and tags query all share one except. If screenshots or tags fail after a valid bug is retrieved, the endpoint returns a 500 instead of a partial response. This is a pre-existing design choice and acceptable, but worth noting for future improvement.


Verdict

✅ The PR is complete and merge-ready. The core objective — consistent DB error handling across all bug endpoints — is fully achieved with no blocking issues. The observations above are pre-existing patterns not introduced by this PR and can be addressed in follow-up issues if desired.

@owasp-blt owasp-blt bot added has-peer-review PR has received peer review and removed needs-peer-review PR needs peer review labels Mar 13, 2026
@SatishKumar620
Copy link
Contributor Author

@Nachiket-Roy Thanks

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/handlers/bugs.py (2)

62-96: Error handling implementation looks good.

The try/except block correctly wraps the database operations, returns a generic error message to clients, and logs the full exception for debugging. This achieves the PR objective of consistent error handling.

One minor style improvement from static analysis:

💅 Minor: simplify f-string on line 95
         except Exception as e:
-            logger.error(f"Error searching bugs: {str(e)}")
+            logger.error(f"Error searching bugs: {e}")
             return error_response("Failed to search bugs. Please try again later.", status=500)

The str(e) call is redundant inside an f-string since it implicitly converts to string.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/handlers/bugs.py` around lines 62 - 96, The logger.error call in the
exception handler of the search routine uses an unnecessary str() inside an
f-string; update the exception logging in the except block (the logger.error in
the try/except around db.prepare in this file) to interpolate the exception
directly (e.g., use f"Error searching bugs: {e}") to simplify the f-string while
keeping the same message.

105-184: Error handling for GET /bugs/{id} is well implemented.

The try/except block properly covers all three database queries (main bug, screenshots, and tags). The approach of using a single try block is reasonable here - a partial response would add complexity, and a clean 500 error is appropriate when any part of the data retrieval fails.

Same minor style suggestion as the search endpoint:

💅 Minor: simplify f-string on line 183
         except Exception as e:
-            logger.error(f"Error fetching bug {bug_id}: {str(e)}")
+            logger.error(f"Error fetching bug {bug_id}: {e}")
             return error_response("Failed to fetch bug. Please try again later.", status=500)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/handlers/bugs.py` around lines 105 - 184, The except block uses an
f-string in logger.error; replace the f-string with structured logging
parameters to avoid string interpolation at call time—update the logger.error
call in the except Exception as e handler (the logger.error line inside the
try/except that references bug_id and e) to use logger.error("Error fetching bug
%s: %s", bug_id, e) or logger.exception("Error fetching bug %s", bug_id) so the
logger handles formatting and stack trace properly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/handlers/bugs.py`:
- Around line 62-96: The logger.error call in the exception handler of the
search routine uses an unnecessary str() inside an f-string; update the
exception logging in the except block (the logger.error in the try/except around
db.prepare in this file) to interpolate the exception directly (e.g., use
f"Error searching bugs: {e}") to simplify the f-string while keeping the same
message.
- Around line 105-184: The except block uses an f-string in logger.error;
replace the f-string with structured logging parameters to avoid string
interpolation at call time—update the logger.error call in the except Exception
as e handler (the logger.error line inside the try/except that references bug_id
and e) to use logger.error("Error fetching bug %s: %s", bug_id, e) or
logger.exception("Error fetching bug %s", bug_id) so the logger handles
formatting and stack trace properly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: OWASP-BLT/coderabbit/.coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 28abf3b4-6833-4cab-8cef-af4dd6fd6a97

📥 Commits

Reviewing files that changed from the base of the PR and between f37a9d6 and fca95b3.

📒 Files selected for processing (1)
  • src/handlers/bugs.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
tests/test_bugs.py (2)

110-116: Make the queryset mock chain more realistic.

filter() always returning the same mock_qs can hide chain-related bugs in pagination/filter composition. Returning a new queryset object per filter() call makes these tests stricter and closer to real ORM behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_bugs.py` around lines 110 - 116, The queryset mock in
_make_mock_bug_class currently returns the same mock_qs from filter(), which
hides chaining bugs; change filter on mock_qs to return a new queryset mock per
call (e.g., set mock_qs.filter.side_effect to a callable that creates and
returns a fresh MagicMock/qs with an AsyncMock count returning the same count),
and ensure mock_bug.objects still returns the initial mock_qs so callers can
start a chain while each subsequent .filter() yields an independent queryset
object.

289-295: Assert exact status filter arguments, not just “called”.

assert_called() can pass even if the wrong field/value is used. Assert the expected call payload to prevent false positives.

Precise assertion
-        mock_qs.filter.assert_called()
+        mock_qs.filter.assert_any_call(status="open")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_bugs.py` around lines 289 - 295, The test
test_status_filter_applied currently only checks mock_qs.filter.assert_called(),
which can miss incorrect arguments; update it to assert the exact filter payload
used by handle_bugs by replacing the call assertion with an exact argument
assertion on mock_qs.filter (e.g.,
mock_qs.filter.assert_called_once_with(status="open") or
mock_qs.filter.assert_called_once_with({"status": "open"}) depending on whether
handle_bugs calls filter with kwargs or a dict) so the test fails if the wrong
field or value is passed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_bugs.py`:
- Around line 297-303: The test declares mock_qs but doesn't use it, causing
RUF059; update test_non_digit_domain_ignored to use mock_qs to assert that
passing a non-digit "domain" does not add ORM filters: when patching
handlers.bugs.Bug with mock_bug and using mock_qs from
_make_mock_bug_class(count=0), assert that mock_qs.filter (or the equivalent
query-builder method exposed by mock_qs) was not called (or call_count == 0)
after calling handle_bugs with {"domain": "not-a-number"}, thereby both removing
the unused-variable warning and strengthening the assertion that handle_bugs
ignored the non-digit domain.
- Around line 12-30: The test currently mutates global interpreter state at
import time by inserting into sys.path and setting sys.modules (_MockResponse,
_mock_workers, Response entries) before importing handlers.bugs; change this to
a fixture-scoped setup that uses pytest's monkeypatch or
unittest.mock.patch.dict to temporarily set sys.path and sys.modules (including
providing a MockResponse class and a fake "workers", "libs", "libs.db", and
"models") and import handle_bugs inside that fixture so the patching is undone
after the test; update the test to reference the fixture when calling
handle_bugs and remove the top-level sys.path/sys.modules mutations from
tests/test_bugs.py.

---

Nitpick comments:
In `@tests/test_bugs.py`:
- Around line 110-116: The queryset mock in _make_mock_bug_class currently
returns the same mock_qs from filter(), which hides chaining bugs; change filter
on mock_qs to return a new queryset mock per call (e.g., set
mock_qs.filter.side_effect to a callable that creates and returns a fresh
MagicMock/qs with an AsyncMock count returning the same count), and ensure
mock_bug.objects still returns the initial mock_qs so callers can start a chain
while each subsequent .filter() yields an independent queryset object.
- Around line 289-295: The test test_status_filter_applied currently only checks
mock_qs.filter.assert_called(), which can miss incorrect arguments; update it to
assert the exact filter payload used by handle_bugs by replacing the call
assertion with an exact argument assertion on mock_qs.filter (e.g.,
mock_qs.filter.assert_called_once_with(status="open") or
mock_qs.filter.assert_called_once_with({"status": "open"}) depending on whether
handle_bugs calls filter with kwargs or a dict) so the test fails if the wrong
field or value is passed.
🪄 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: Repository: OWASP-BLT/coderabbit/.coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: b1a40c7a-afd7-4b6b-ae40-c7f55f446f65

📥 Commits

Reviewing files that changed from the base of the PR and between fca95b3 and c2c17c4.

📒 Files selected for processing (1)
  • tests/test_bugs.py

@SatishKumar620 SatishKumar620 force-pushed the fix/error-handling-bugs-get-endpoints branch from c2c17c4 to 4b68eb4 Compare March 13, 2026 14:29
@SatishKumar620
Copy link
Contributor Author

@coderabbitai Please assess the PR's completeness and merge readiness. It is ready to merged?

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Tip

For best results, initiate chat on the files or code changes.

@SatishKumar620: Yes, PR #44 is ready to be merged. My earlier assessment (above in this thread) still stands in full.

To summarize the verdict:

  • GET /bugs/{id} — wrapped in try/except, errors logged, 500 error_response returned
  • GET /bugs/search — same pattern applied
  • bug_id ValueError handled before the DB block
  • ✅ Consistent with the existing pattern in POST /bugs and handle_stats
  • ✅ No regressions to any other endpoint

The three minor observations noted (error detail leakage, hardcoded OFFSET 0, single try block for multiple DB calls in GET /bugs/{id}) are all pre-existing and outside the scope of this PR — none are blocking. The PR fully closes issue #43. You're good to go. 🚀

@SatishKumar620
Copy link
Contributor Author

@coderabbitai review again

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

@SatishKumar620 Sure! I'll kick off a fresh review of PR #44 right away.

✅ Actions performed

Full review triggered.

Copy link
Contributor

@DonnieBLT DonnieBLT left a comment

Choose a reason for hiding this comment

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

Please use the orm

@SatishKumar620
Copy link
Contributor Author

@DonnieBLT I checked the ORM and it currently only supports single-table queries, no JOIN support yet. The GET /bugs/{id} and search endpoints both need a LEFT JOIN with the domains table to return domain info.
Should I Extend src/libs/orm.py to support JOINs, then refactor the handlers to use it? In a new PR ?

@SatishKumar620
Copy link
Contributor Author

@coderabbitai Please assess the PR's completeness and merge readiness.

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat src/handlers/bugs.py

Length of output: 14300


@SatishKumar620: Here is the updated assessment based on the current state of src/handlers/bugs.py.


✅ Merge Readiness Assessment — PR #44 (Updated)

Goal Alignment

PR #44 fully addresses issue #43. Both GET /bugs/{id} and GET /bugs/search now follow the same try/except DB error-handling pattern as POST /bugs and handle_stats.


Checklist

Area Status
GET /bugs/search wrapped in try/except
GET /bugs/{id} wrapped in try/except
get_db_safe has its own isolated try/except
bug_id ValueError handled before DB try block
Error logging via logger.error(...)
500 error_response returned on failure
Pattern consistent with POST /bugs and GET /bugs list
No regressions to existing endpoints

Improvement Since Last Review

A previously noted concern — error detail leakage via str(e) in the response body — has been resolved for the two endpoints in scope:

  • GET /bugs/search now returns "Failed to search bugs. Please try again later."
  • GET /bugs/{id} now returns "Failed to fetch bug. Please try again later."

Regarding the ORM JOIN Discussion

Your note about extending src/libs/orm.py to support JOINs is a good idea for the future, but it is not a blocker here — both GET /bugs/search and GET /bugs/{id} already use raw SQL with LEFT JOIN domains d ON b.domain = d.id directly, so domain data is already returned correctly by this PR. The ORM extension would be a separate, independent improvement.


Verdict

✅ PR #44 is complete and merge-ready. All objectives from issue #43 are fully met. No blocking issues remain.

@SatishKumar620
Copy link
Contributor Author

@coderabbitai requested by maintainer to use orm so review pr again

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== src/handlers/bugs.py ==="
cat src/handlers/bugs.py

echo ""
echo "=== src/libs/orm.py ==="
cat src/libs/orm.py

Length of output: 30784


@SatishKumar620 I've reviewed the current state of both src/handlers/bugs.py and src/libs/orm.py in light of the maintainer's request to use the ORM. Here is the detailed assessment.


🔍 Review: ORM Migration Feasibility

The Core Blocker

The current QuerySet._build_select_sql() in src/libs/orm.py generates queries of the form:

SELECT ... FROM {table} [WHERE ...] [ORDER BY ...] [LIMIT ?] [OFFSET ?]

It has no JOIN support. This is the fundamental blocker — three of the four DB queries in the affected endpoints require a JOIN:

Query Table(s) JOIN? ORM Today?
GET /bugs/search — main fetch bugs b LEFT JOIN domains d
GET /bugs/{id} — main bug + domain bugs b LEFT JOIN domains d
GET /bugs/{id} — tags bug_tags bt JOIN tags t
GET /bugs/{id} — screenshots bug_screenshots (single table)

What Can Be Migrated Right Now (Partial)

Only the screenshots query is single-table and can use the ORM today:

# Before (raw SQL)
screenshots_result = await db.prepare('''
    SELECT id, image, created
    FROM bug_screenshots
    WHERE bug = ?
    ORDER BY created DESC
''').bind(bug_id).all()
screenshots_data = convert_d1_results(screenshots_result.results if hasattr(screenshots_result, 'results') else [])

# After (ORM) — requires a BugScreenshot model with table_name = "bug_screenshots"
screenshots_data = await BugScreenshot.objects(db).filter(bug=bug_id).order_by('-created').values('id', 'image', 'created').all()

But the main bug, domain, and tags queries cannot be migrated without ORM extension.


Path Forward

Your earlier suggestion was exactly right. The recommended approach is:

  1. New PR first: Extend src/libs/orm.py to support LEFT JOINs (e.g., a .join(table, on="...") chainable method), following the same safe-identifier-validation pattern already in place.
  2. Then refactor GET /bugs/{id} and GET /bugs/search (and the list endpoint, which has the same gap) to use the extended ORM.

Note that GET /bugs (list) has the exact same limitation — it already uses Bug.objects(db) for count() but falls back to a raw SQL JOIN for the actual fetch. So the ORM extension would benefit all three endpoints.


Current PR Status

The error-handling objective (issue #43) is fully and correctly implemented. However, as long as the maintainer requires ORM usage, this PR cannot be merged as-is because the JOIN queries remain as raw SQL.

Recommended next steps:

  • Open a new PR to add JOIN support to src/libs/orm.py
  • Once merged, refactor this PR's endpoints (and the list endpoint) to use the ORM
  • Then this PR can be re-evaluated for merge

Would you like me to open a follow-up issue to track the ORM JOIN extension work?


📝 Learnings were identified and not saved (knowledge base disabled). Enable

@DonnieBLT
Copy link
Contributor

Yes, please update it to support joins.

- Wrap bare db.prepare() calls in try/except for GET /bugs/{id} and
  GET /bugs/search, consistent with POST /bugs error handling pattern
- Return generic messages in 500 responses instead of raw str(e)

Closes OWASP-BLT#43
…ition

- Replace GET /bugs/{id} main query with ORM JOIN on domains table
- Replace screenshots fetch with BugScreenshot.objects(db) ORM call
- Keep search as raw SQL — ORM does not support OR conditions
- Add comment explaining why raw SQL is retained for search

Addresses DonnieBLT feedback on PR OWASP-BLT#44
@SatishKumar620 SatishKumar620 force-pushed the fix/error-handling-bugs-get-endpoints branch from 4b68eb4 to f25ac88 Compare March 15, 2026 19:04
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/handlers/bugs.py`:
- Around line 91-143: Define and validate bug_id before entering the DB/try
block and return a 400 error for invalid values: extract the path parameter into
bug_id (e.g., convert to int or validate UUID as appropriate) at the start of
the handler, check it's present and valid and call error_response("Invalid bug
id", status=400) if not; then proceed to use that validated bug_id in
Bug.objects, BugScreenshot.objects, the raw SQL bind, and in the except block
(so the except no longer risks referencing an undefined variable).
🪄 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: Repository: OWASP-BLT/coderabbit/.coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 50a26756-814f-4759-a65a-c0ac23612720

📥 Commits

Reviewing files that changed from the base of the PR and between 4b68eb4 and f25ac88.

📒 Files selected for processing (1)
  • src/handlers/bugs.py

@SatishKumar620
Copy link
Contributor Author

@coderabbitai Please assess the PR's completeness and merge readiness. It is ready to merged?

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== src/handlers/bugs.py ==="
cat src/handlers/bugs.py

echo ""
echo "=== src/libs/orm.py ==="
cat src/libs/orm.py

Length of output: 33670


@SatishKumar620 I've reviewed the current state of both src/handlers/bugs.py and src/libs/orm.py. Great progress — the ORM now has proper JOIN support and GET /bugs/{id} has been migrated to use it. However, there is one blocking bug before this can be merged.


🚧 Blocking Issue: Ambiguous Column in .filter(id=bug_id) with JOIN

In GET /bugs/{id}, this code:

Bug.objects(db)
    .join("domains", on="bugs.domain=domains.id", join_type="LEFT")
    .filter(id=bug_id)   # ← generates: WHERE id = ?
    ...

generates the SQL fragment WHERE id = ?. Since both bugs and domains have an id column, D1/SQLite will raise:

ambiguous column name: id

Fix: qualify the filter with the table name. The ORM's _validate_identifier already handles dotted identifiers like bugs.id, so this works:

Bug.objects(db)
    .join("domains", on="bugs.domain=domains.id", join_type="LEFT")
    .filter(**{"bugs.id": bug_id})   # generates: WHERE bugs.id = ?
    ...

Updated Merge Readiness Checklist

Area Status
ORM .join() support implemented
GET /bugs/{id} main fetch uses ORM with JOIN
GET /bugs/{id} screenshots use ORM
GET /bugs/search raw SQL — justified (ORM lacks OR support)
Tags raw SQL — justified (no BugTag model)
All error handling with try/except + logger.error
Generic 500 error messages (no str(e) leakage)
filter(id=bug_id) ambiguous column with JOIN ❌ Blocking

Once that single line is updated to filter(**{"bugs.id": bug_id}), the PR will be ready to merge.

@SatishKumar620
Copy link
Contributor Author

@coderabbitai Please assess the PR's completeness and merge readiness. It is ready to merged?

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== src/handlers/bugs.py ==="
cat src/handlers/bugs.py

echo ""
echo "=== src/libs/orm.py ==="
cat src/libs/orm.py

Length of output: 33682


@SatishKumar620 Good news — the previously flagged blocking issue (ambiguous id column) has been fixed correctly with filter(**{"bugs.id": bug_id}) ✅. However, a new blocking bug has been introduced by the ORM migration in GET /bugs/{id}.


🚧 New Blocking Issue: AS Aliases in .values() Fail Validation

The values() call in GET /bugs/{id} uses aliased column names:

.values(
    "bugs.id", "bugs.url", ...,
    "domains.id as domain_id",      # ← contains a space
    "domains.name as domain_name",  # ← contains a space
    "domains.url as domain_url",    # ← contains a space
    "domains.logo as domain_logo"   # ← contains a space
)

Each field is passed through _validate_identifier() in src/libs/orm.py:

_SAFE_IDENT_CHARS = frozenset("abcdefghijklmnopqrstuvwxyz0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ")

def _validate_identifier(name: str) -> str:
    for part in name.split("."):
        if not part or not all(c in _SAFE_IDENT_CHARS for c in part):
            raise ValueError(...)

For "domains.id as domain_id":

  • .split(".")["domains", "id as domain_id"]
  • "id as domain_id" contains spaces, which are not in _SAFE_IDENT_CHARSValueError raised

This ValueError will be caught by the outer try/except and every call to GET /bugs/{id} for a valid bug ID will return a 500 error at runtime.


Fix Options

Option A — Extend _validate_identifier / values() to support AS aliases (requires ORM change):

def _validate_identifier(name: str) -> str:
    # Support "table.col AS alias" or "table.col as alias"
    parts = name.split()
    if len(parts) == 3 and parts[1].lower() == "as":
        col_part, alias_part = parts[0], parts[2]
        _validate_plain_identifier(col_part)
        _validate_plain_identifier(alias_part)
        return name
    _validate_plain_identifier(name)
    return name

Option B — Rename aliased fields post-query (no ORM change, handler-only fix):

Use unaliased .values() calls and rename the conflicting fields manually after fetching:

bug_data = await (
    Bug.objects(db)
    .join("domains", on="bugs.domain=domains.id", join_type="LEFT")
    .filter(**{"bugs.id": bug_id})
    .values(
        "bugs.id", "bugs.url", ...,
        "domains.id",    "domains.name",
        "domains.url",   "domains.logo"
    )
    .first()
)
# Rename to avoid collision with bugs.id
if bug_data:
    bug_data["domain_id"]   = bug_data.pop("id", None)  # domains.id shadows bugs.id — needs care
    ...

⚠️ Note: Option B is tricky because both bugs.id and domains.id would be returned as "id" by SQLite, causing one to shadow the other. Option A is the cleaner fix and makes the ORM more generally useful.


Updated Checklist

Area Status
GET /bugs/search wrapped in try/except
GET /bugs/{id} wrapped in try/except
bug_id ValueError handled before DB block
Error logging via logger.error(...)
Generic 500 error messages (no str(e) leakage)
ORM JOIN support implemented
filter(id=bug_id) ambiguous column — previously fixed
values() with AS aliases raises ValueError at runtime Blocking

Once the aliased column issue is resolved (by extending _validate_identifier in the ORM to accept col AS alias syntax, or restructuring the values() call), the PR will be ready to merge.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Title: Missing error handling in GET /bugs/{id} and GET /bugs/search endpoints

4 participants