Skip to content

Develop#4

Merged
7amed3li merged 5 commits into
mainfrom
develop
May 4, 2026
Merged

Develop#4
7amed3li merged 5 commits into
mainfrom
develop

Conversation

@7amed3li
Copy link
Copy Markdown
Owner

@7amed3li 7amed3li commented May 4, 2026


Summary by cubic

Adds end‑to‑end scan progress tracking and a cancel action so users can monitor progress and stop pending or running scans. The worker writes progress to the DB, and the UI shows a determinate/indeterminate bar with percent or “ANALYZING…”, plus a cancel button with loading state.

  • New Features

    • Backend: added Scan.progress (0–100) and POST /scans/:id/cancel to cancel PENDING/QUEUED/RUNNING; sets status CANCELED and completedAt.
    • Worker: syncs progress to the DB throughout (starting at 10) and finalizes with COMPLETED + progress: 100.
    • Frontend: scanApi.cancel(id) with mutation that invalidates the list; progress bar switches between indeterminate and percent with a label; CANCELED icon/color; cancel button for PENDING/RUNNING with spinner and disabled state.
  • Migration

    • Run Prisma migration to add progress to Scan and regenerate the client.
    • Update any references from STOPPED to CANCELED.

Written for commit 841f15f. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

New Features

  • Users can now cancel running or pending scans, providing greater control over execution and workflow management
  • Real-time progress tracking is now displayed for active scans with animated visual feedback and status indicators
  • Enhanced scan status displays with improved terminology and updated color-coding for better clarity and visibility

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

Added scan progress tracking and cancellation capability across the backend and frontend. The Prisma schema now includes a progress field; the SQL injection orchestrator persists progress checkpoints; a new cancellation service and API endpoint allow users to stop running or queued scans; the frontend displays progress and provides a cancel button.

Changes

Scan Progress Tracking & Cancellation

Layer / File(s) Summary
Data Shape
backend/prisma/schema.prisma, frontend/src/entities/scan/model/types.ts
Prisma Scan model adds progress: Int @default(0). Frontend Scan interface adds optional progress?: number field; ScanStatus enum replaces 'STOPPED' with 'CANCELED'.
Core Service Logic
backend/src/services/scans.ts
New cancelScan(userId, scanId) service verifies ownership via getScanById, then transitions scans in RUNNING/QUEUED/PENDING to CANCELED and sets completedAt.
Progress Persistence
backend/src/worker/sqli/orchestrator.ts
SQL injection orchestrator now syncs scan progress to database after Wave 1 (progress 10) and after each subsequent wave parameter; final completion sets progress: 100 in Prisma update rather than separate job.updateProgress call.
API/Controller Layer
backend/src/controllers/scans.ts, backend/src/routes/scans.ts
New cancelScan controller validates id parameter, delegates to service, returns 200 response. New authenticated POST /scans/{id}/cancel route with Swagger documentation wired to controller.
Frontend API & UI
frontend/src/entities/scan/api/scanApi.ts, frontend/src/pages/scans/ui/Page.tsx
Frontend scanApi.cancel(id) method POSTs to /scans/{id}/cancel. Scans page integrates cancelMutation via React Query, invalidates scan list on success. Status rendering adds CANCELED state with StopCircle icon; progress bar renders indeterminate for RUNNING scans without progress data, else determined; RUNNING/PENDING rows show cancel button with loading spinner during mutation.

Sequence Diagram

sequenceDiagram
    actor User
    participant Frontend as Frontend UI
    participant API as Backend API
    participant Service as Scan Service
    participant DB as Prisma DB
    
    User->>Frontend: Clicks cancel button on<br/>RUNNING or PENDING scan
    Frontend->>API: POST /scans/{id}/cancel
    API->>Service: cancelScan(userId, scanId)
    Service->>DB: getScanById (verify ownership)
    DB-->>Service: Scan record
    alt Scan is RUNNING/QUEUED/PENDING
        Service->>DB: update(status=CANCELED,<br/>completedAt=now)
        DB-->>Service: Updated scan
    end
    Service-->>API: true
    API-->>Frontend: 200 OK
    Frontend->>Frontend: Invalidate ['scans']<br/>query via React Query
    Frontend->>Frontend: Refetch and<br/>re-render scan list
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Poem

🐰 A cancel button hops to life,
Progress bars dance without strife,
Scans now pause at user's call,
CANCELED states, that's best of all! 🚫✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Develop' is vague and generic, failing to describe the substantial changes across multiple files including scan progress tracking, cancellation functionality, and UI updates. Use a descriptive title that captures the main change, such as 'Add scan cancellation and progress tracking' or 'Implement scan cancellation with database progress persistence'.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

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.

Copy link
Copy Markdown

@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

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/pages/scans/ui/Page.tsx (1)

42-60: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle QUEUED scans in the UI.

The backend now creates scans in QUEUED, but these branches still treat that state as unknown/default and only expose cancel for RUNNING/PENDING. That means a freshly queued scan will show the restart path and cannot be canceled from the UI.

Please add QUEUED to the shared scan status contract and include it in the status helpers and action column.

♻️ Suggested fixes
   switch (status) {
     case 'RUNNING': return 'text-cyber-green';
     case 'PENDING': return 'text-blue-400';
+    case 'QUEUED': return 'text-blue-400';
     case 'COMPLETED': return 'text-purple-400';
     case 'FAILED': return 'text-cyber-red';
     case 'CANCELED': return 'text-white/40';
-                  ) : scan.status === 'RUNNING' || scan.status === 'PENDING' ? (
+                  ) : scan.status === 'RUNNING' || scan.status === 'PENDING' || scan.status === 'QUEUED' ? (

Also applies to: 170-188

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

In `@frontend/src/pages/scans/ui/Page.tsx` around lines 42 - 60, Add the new
QUEUED scan state to the status contract and UI helpers: update the shared
ScanStatus type/enum to include 'QUEUED', then add a 'QUEUED' case in
getStatusColor (choose an appropriate CSS class, e.g., same as PENDING or
RUNNING) and in getStatusIcon (pick a suitable icon like Clock or Activity).
Also update the action column logic (the component that decides cancel/restart
buttons around the branch that currently checks for 'RUNNING'/'PENDING') to
treat 'QUEUED' as cancelable (same behavior as PENDING), ensuring queued scans
show the proper status color, icon, and expose the cancel action instead of a
restart.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/src/services/scans.ts`:
- Around line 184-205: Make the cancellation atomic and job-aware by replacing
the read-then-update pattern in cancelScan with a conditional single-step update
(e.g., use prisma.scan.update or updateMany with a where that includes id:
scanId and status in ['RUNNING','QUEUED','PENDING'] and set status to
ScanStatus.CANCELED and completedAt); after the conditional update, check
whether any row was changed and, if so, use the scan.jobId (or the field that
stores BullMQ job id on the Scan) to locate the BullMQ job via the Queue API
(e.g., queue.getJob(jobId)) and remove/discard/fail it so the worker stops,
returning false if no row was updated; keep worker logic to re-check scan status
before completing work.

In `@frontend/src/entities/scan/model/types.ts`:
- Around line 3-9: The Scan interface currently declares progress as optional;
change the Scan type definition so the progress property is required (remove the
optional modifier from progress) so progress: number; in the Scan interface
(frontend/src/entities/scan/model/types.ts, symbol: Scan) and update any usages
that defensively check for undefined to rely on a numeric value instead (e.g.,
callers that treat 0 vs missing).

---

Outside diff comments:
In `@frontend/src/pages/scans/ui/Page.tsx`:
- Around line 42-60: Add the new QUEUED scan state to the status contract and UI
helpers: update the shared ScanStatus type/enum to include 'QUEUED', then add a
'QUEUED' case in getStatusColor (choose an appropriate CSS class, e.g., same as
PENDING or RUNNING) and in getStatusIcon (pick a suitable icon like Clock or
Activity). Also update the action column logic (the component that decides
cancel/restart buttons around the branch that currently checks for
'RUNNING'/'PENDING') to treat 'QUEUED' as cancelable (same behavior as PENDING),
ensuring queued scans show the proper status color, icon, and expose the cancel
action instead of a restart.
🪄 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: 6dd0c440-9d90-4cb0-98ce-0669a47e63a9

📥 Commits

Reviewing files that changed from the base of the PR and between 6f80b44 and f598d1a.

📒 Files selected for processing (8)
  • backend/prisma/schema.prisma
  • backend/src/controllers/scans.ts
  • backend/src/routes/scans.ts
  • backend/src/services/scans.ts
  • backend/src/worker/sqli/orchestrator.ts
  • frontend/src/entities/scan/api/scanApi.ts
  • frontend/src/entities/scan/model/types.ts
  • frontend/src/pages/scans/ui/Page.tsx

Comment on lines +184 to 205
export const cancelScan = async (userId: string, scanId: string) => {
// 1. التأكد من وجود الفحص وصلاحيات المستخدم
const scan = await getScanById(userId, scanId);

// 2. تحديث الحالة فقط إذا كانت RUNNING أو QUEUED أو PENDING
const activeStatuses = ['RUNNING', 'QUEUED', 'PENDING'];
if (activeStatuses.includes(scan.status)) {
await prisma.scan.update({
where: { id: scanId },
data: {
status: ScanStatus.CANCELED,
completedAt: new Date() // نعتبره مكتملاً (متوقفاً) لتسجيل الوقت
}
});

// ملاحظة: إيقاف الـ Job الفعلي من BullMQ يتطلب معرف JobId.
// في هذه المرحلة، نكتفي بتحديث حالة قاعدة البيانات.
// الـ Worker يجب أن يتحقق من حالة الفحص في قاعدة البيانات قبل الاستمرار.
}

return true;
}; No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Cancellation needs to be atomic and job-aware.

The current read-then-update flow leaves a TOCTOU window, and the BullMQ job is never removed or stopped. A scan can still finish after cancellation and be written back as COMPLETED, which makes the cancel action look successful while the work keeps running.

Please make the state transition conditional in one step and coordinate queue removal or an early worker exit before returning success.

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

In `@backend/src/services/scans.ts` around lines 184 - 205, Make the cancellation
atomic and job-aware by replacing the read-then-update pattern in cancelScan
with a conditional single-step update (e.g., use prisma.scan.update or
updateMany with a where that includes id: scanId and status in
['RUNNING','QUEUED','PENDING'] and set status to ScanStatus.CANCELED and
completedAt); after the conditional update, check whether any row was changed
and, if so, use the scan.jobId (or the field that stores BullMQ job id on the
Scan) to locate the BullMQ job via the Queue API (e.g., queue.getJob(jobId)) and
remove/discard/fail it so the worker stops, returning false if no row was
updated; keep worker logic to re-check scan status before completing work.

Comment on lines 3 to 9
export interface Scan {
id: string;
status: ScanStatus;
progress?: number; // 🆕 نسبة التقدم (0-100)
startedAt: string | null;
completedAt: string | null;
createdAt: string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make progress required.

The backend now guarantees a numeric progress value for every scan, so keeping this optional only forces consumers into undefined/falsy handling and makes 0% indistinguishable from missing data.

♻️ Suggested tweak
 export interface Scan {
   id: string;
   status: ScanStatus;
-  progress?: number; // 🆕 نسبة التقدم (0-100)
+  progress: number; // 0-100
   startedAt: string | null;
   completedAt: string | null;
   createdAt: string;
📝 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.

Suggested change
export interface Scan {
id: string;
status: ScanStatus;
progress?: number; // 🆕 نسبة التقدم (0-100)
startedAt: string | null;
completedAt: string | null;
createdAt: string;
export interface Scan {
id: string;
status: ScanStatus;
progress: number; // 0-100
startedAt: string | null;
completedAt: string | null;
createdAt: string;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/entities/scan/model/types.ts` around lines 3 - 9, The Scan
interface currently declares progress as optional; change the Scan type
definition so the progress property is required (remove the optional modifier
from progress) so progress: number; in the Scan interface
(frontend/src/entities/scan/model/types.ts, symbol: Scan) and update any usages
that defensively check for undefined to rely on a numeric value instead (e.g.,
callers that treat 0 vs missing).

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 8 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/src/services/scans.ts">

<violation number="1" location="backend/src/services/scans.ts:191">
P1: Make the cancel update atomic by enforcing allowed statuses in the database write condition; the current read-then-update flow can overwrite a status changed concurrently.</violation>
</file>

<file name="backend/src/worker/sqli/orchestrator.ts">

<violation number="1" location="backend/src/worker/sqli/orchestrator.ts:112">
P2: The final completion write unconditionally sets `progress: 100` without the stale-client fallback used above, so schema/client drift can cause successful scans to be marked as FAILED at the very end.</violation>
</file>

<file name="frontend/src/pages/scans/ui/Page.tsx">

<violation number="1" location="frontend/src/pages/scans/ui/Page.tsx:139">
P2: `!scan.progress` treats a valid `0` progress as missing, so 0% running scans are shown as indeterminate.</violation>

<violation number="2" location="frontend/src/pages/scans/ui/Page.tsx:157">
P2: The progress label can show `0%` for completed scans, which conflicts with the 100% completed bar state.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread backend/src/services/scans.ts Outdated
where: { id: scanId },
data: {
status: 'COMPLETED',
progress: 100, // 🆕 تأكيد الوصول لـ 100%
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The final completion write unconditionally sets progress: 100 without the stale-client fallback used above, so schema/client drift can cause successful scans to be marked as FAILED at the very end.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/src/worker/sqli/orchestrator.ts, line 112:

<comment>The final completion write unconditionally sets `progress: 100` without the stale-client fallback used above, so schema/client drift can cause successful scans to be marked as FAILED at the very end.</comment>

<file context>
@@ -84,12 +101,15 @@ export async function runSqliScan(job: Job, prisma: PrismaClient): Promise<void>
             where: { id: scanId },
             data: { 
                 status: 'COMPLETED', 
+                progress: 100, // 🆕 تأكيد الوصول لـ 100%
                 completedAt: new Date(),
                 // يمكن إضافة حقل لعدد النتائج إذا كان مدعوماً في قاعدة البيانات
</file context>

Comment thread frontend/src/pages/scans/ui/Page.tsx Outdated
Comment thread frontend/src/pages/scans/ui/Page.tsx Outdated
7amed3li and others added 3 commits May 4, 2026 11:49
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/src/services/scans.ts">

<violation number="1" location="backend/src/services/scans.ts:191">
P2: The BullMQ job is never removed or signaled to stop after marking the scan as `CANCELED`. The worker will continue processing and could overwrite the status back to `COMPLETED` when it finishes, making the cancel appear successful while work continues. Consider storing the BullMQ job ID on the scan record and calling `job.remove()` or using the `AbortSignal`-based cancellation pattern here, or at minimum ensure the worker checks the DB status before writing terminal states.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

// 2. تحديث الحالة فقط إذا كانت RUNNING أو QUEUED أو PENDING
const activeStatuses = ['RUNNING', 'QUEUED', 'PENDING'];
if (activeStatuses.includes(scan.status)) {
await prisma.scan.updateMany({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The BullMQ job is never removed or signaled to stop after marking the scan as CANCELED. The worker will continue processing and could overwrite the status back to COMPLETED when it finishes, making the cancel appear successful while work continues. Consider storing the BullMQ job ID on the scan record and calling job.remove() or using the AbortSignal-based cancellation pattern here, or at minimum ensure the worker checks the DB status before writing terminal states.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/src/services/scans.ts, line 191:

<comment>The BullMQ job is never removed or signaled to stop after marking the scan as `CANCELED`. The worker will continue processing and could overwrite the status back to `COMPLETED` when it finishes, making the cancel appear successful while work continues. Consider storing the BullMQ job ID on the scan record and calling `job.remove()` or using the `AbortSignal`-based cancellation pattern here, or at minimum ensure the worker checks the DB status before writing terminal states.</comment>

<file context>
@@ -188,14 +188,16 @@ export const cancelScan = async (userId: string, scanId: string) => {
-        await prisma.scan.update({
-            where: { id: scanId },
-            data: { 
+        await prisma.scan.updateMany({
+            where: {
+                id: scanId,
</file context>

Tip: Review your code locally with the cubic CLI to iterate faster.

@7amed3li 7amed3li merged commit 021023f into main May 4, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant