Skip to content

Scansv2#13

Open
pranavcodeant wants to merge 7 commits intomainfrom
scansv2
Open

Scansv2#13
pranavcodeant wants to merge 7 commits intomainfrom
scansv2

Conversation

@pranavcodeant
Copy link
Copy Markdown
Collaborator

@pranavcodeant pranavcodeant commented Apr 17, 2026

CodeAnt-AI Description

Add an interactive scans center for browsing repository scan results

What Changed

  • Adds a new scan-center command that guides users through connected organizations, repositories, scan history, and result types in one flow
  • Lets users view standard findings, advanced scan results, and dismissed alerts, with clear file, line, and issue details
  • Shows useful empty states and error messages when there are no connections, no repositories, no scan history, or a fetch fails
  • Keeps long lists usable with scrolling, paging, and back navigation throughout the scan browser

Impact

✅ Faster access to scan history
✅ Clearer review of security findings
✅ Restored dismissed alerts with saved context

🔄 Retrigger CodeAnt AI Review

Details

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 17, 2026

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Apr 17, 2026
@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 17, 2026

🏁 CodeAnt Quality Gate Results

Commit: 0d9fc5d2
Scan Time: 2026-04-20 11:53:21 UTC

✅ Overall Status: PASSED

Quality Gate Details

Quality Gate Status Details
Secrets ✅ PASSED 0 secrets found
Duplicate Code ✅ PASSED 1.8% duplicated

View Full Results

Comment thread src/scans/listRepos.js

if (response.repos) {
const sortedRepos = (response.repos || []).sort(
(a, b) => new Date(b.pushed_at) - new Date(a.pushed_at)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The date comparator subtracts new Date(...) values directly, which produces NaN for invalid or missing timestamps and makes sorting unreliable. Use parsed timestamps with a numeric fallback so repos are deterministically ordered even when pushed_at is absent. [logic error]

Severity Level: Major ⚠️
- ⚠️ listRepos may not sort repositories by latest push time.
- ⚠️ Repositories missing pushed_at can appear in inconsistent order.
- ⚠️ Downstream consumers relying on order get unreliable results.
Suggested change
(a, b) => new Date(b.pushed_at) - new Date(a.pushed_at)
(a, b) => (Date.parse(b.pushed_at) || 0) - (Date.parse(a.pushed_at) || 0)
Steps of Reproduction ✅
1. In a Node.js script, monkey-patch global `fetch` (used inside
`src/utils/fetchApi.js:4-25`) so that `response.json()` resolves to an object like `{
repos: [ { name: 'r1', full_name: 'org/r1', pushed_at: '2024-01-01T00:00:00Z' }, { name:
'r2', full_name: 'org/r2' }, { name: 'r3', full_name: 'org/r3', pushed_at:
'2024-02-01T00:00:00Z' } ] }`, where one repo lacks `pushed_at`.

2. Import `listRepos` from `src/scans/listRepos.js:13` in that script via `import {
listRepos } from './src/scans/listRepos.js';`.

3. Call `await listRepos('acme-org')`, which obtains the mocked response at
`src/scans/listRepos.js:15-17`, passes the `if (response.repos)` check at line 23, and
then sorts using `(response.repos || []).sort((a, b) => new Date(b.pushed_at) - new
Date(a.pushed_at))` at lines 24-26.

4. For the repo without `pushed_at`, `new Date(undefined)` yields an invalid Date whose
numeric value is `NaN`, so the comparator sometimes returns `NaN` instead of a
negative/zero/positive number; as a result, comparisons involving that repo treat it as
equal to others, and the final `sortedRepos` array returned at line 27 is not reliably
ordered by actual last push time, especially once multiple repos have missing or malformed
timestamps.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/listRepos.js
**Line:** 25:25
**Comment:**
	*Logic Error: The date comparator subtracts `new Date(...)` values directly, which produces `NaN` for invalid or missing timestamps and makes sorting unreliable. Use parsed timestamps with a numeric fallback so repos are deterministically ordered even when `pushed_at` is absent.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

const normalized = { ...item };
normalized.file_path = extractRelativeFilePath(item.file_path || item.path || item.filename || 'unknown');
normalized.line_number = item.line_number || item.start_line || item.line || 1;
normalized.file_line_range = [normalized.line_number];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The normalization logic always overwrites file_line_range with a single-line array, which drops valid multi-line ranges coming from scanners (especially IaC checks). Preserve the incoming range when present so callers can correctly display the full affected span. [logic error]

Severity Level: Major ⚠️
- ⚠️ Advanced IaC issues lose multi-line `file_line_range` spans.
- ⚠️ Downstream tools cannot show full misconfiguration blocks.
Suggested change
normalized.file_line_range = [normalized.line_number];
normalized.file_line_range =
Array.isArray(item.file_line_range) && item.file_line_range.length > 0
? item.file_line_range
: [normalized.line_number];
Steps of Reproduction ✅
1. Import and call `fetchIacResults(repo, commitId)` exported at
`src/scans/fetchAdvancedScanResults.js:318-319`, which internally calls
`fetchAdvancedScanResults(repo, commitId, ADVANCED_RESULT_TYPES.IAC)` at
`src/scans/fetchAdvancedScanResults.js:202-204`.

2. In `fetchAdvancedScanResults`, when `resultType === ADVANCED_RESULT_TYPES.IAC`, the
response from `/extension/scans2/fetch-advanced-results` is flattened in the IAC branch at
`src/scans/fetchAdvancedScanResults.js:241-270`; each failed check is turned into an
object with `file_line_range: check.file_line_range || [1]` at lines `253-254`, preserving
any multi-line ranges returned by the scanner.

3. After flattening, the code normalizes all items via
`resultsData.filter(Boolean).map((item) => normalizeAdvancedIssue(item, resultType))` at
`src/scans/fetchAdvancedScanResults.js:279-280`, which calls `normalizeAdvancedIssue`
defined at `src/scans/fetchAdvancedScanResults.js:147-192`.

4. Inside `normalizeAdvancedIssue`, the snippet at
`src/scans/fetchAdvancedScanResults.js:154-155` overwrites `file_line_range` with
`[normalized.line_number]`, so an IaC issue that originally had `file_line_range: [10,
20]` from the scanner is returned to callers with `file_line_range: [10]`, losing the
multi-line span; a future consumer that wants to highlight the full affected range
(similar to how `fetchScanResults` sets `file_line_range` at
`src/scans/fetchScanResults.js:92`) will only know about the first line.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/fetchAdvancedScanResults.js
**Line:** 155:155
**Comment:**
	*Logic Error: The normalization logic always overwrites `file_line_range` with a single-line array, which drops valid multi-line ranges coming from scanners (especially IaC checks). Preserve the incoming range when present so callers can correctly display the full affected span.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Comment on lines +50 to +51
reason_for_dismiss: dismissInfo.reason_for_dismiss || '',
comment_for_dismiss: dismissInfo.comment_for_dismiss || '',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: dismissInfo is used as an object without null checks, so a null/undefined entry in response.data will throw when accessing dismissal fields and fail the whole operation. Use optional access with defaults to avoid crashing on partial backend data. [null pointer]

Severity Level: Major ⚠️
- ❌ Dismissed alerts fetch fails on any null dismissal entry.
- ⚠️ All valid dismissed alerts lost due to single bad record.
Suggested change
reason_for_dismiss: dismissInfo.reason_for_dismiss || '',
comment_for_dismiss: dismissInfo.comment_for_dismiss || '',
reason_for_dismiss: dismissInfo?.reason_for_dismiss || '',
comment_for_dismiss: dismissInfo?.comment_for_dismiss || '',
Steps of Reproduction ✅
1. Any future caller (e.g. a scansv2 CLI flow) invokes `fetchDismissedAlerts(repo)`
defined in `src/scans/fetchDismissedAlerts.js:13`, which internally calls
`fetchApi('/extension/scans2/dismiss-alerts/get', 'POST', { repo, analysis_type })` at
lines 15–18.

2. The backend responds with JSON parsed by `fetchApi` (`src/utils/fetchApi.js:4–37`),
returning an object where `data` contains at least one entry whose value is `null` or
`undefined`, e.g. `{ "some/file.js||::||code||::||T1": null }`.

3. In `fetchDismissedAlerts`, the code at `src/scans/fetchDismissedAlerts.js:28–32`
executes `const dismissData = response.data || {};` and then `for (const [issueKey,
dismissInfo] of Object.entries(dismissData))`; for the malformed entry, `dismissInfo` is
`null`/`undefined`.

4. When constructing `dismissedAlerts.push({ ... })` at lines 43–52, accessing
`dismissInfo.reason_for_dismiss` and `dismissInfo.comment_for_dismiss` at lines 50–51
throws a `TypeError` ("Cannot read properties of null/undefined"), which is caught by the
`try/catch` at lines 14–57, causing the whole function to return `{ success: false, error:
error.message || 'Failed to fetch dismissed alerts' }` and preventing any dismissed alerts
from being returned.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/fetchDismissedAlerts.js
**Line:** 50:51
**Comment:**
	*Null Pointer: `dismissInfo` is used as an object without null checks, so a null/undefined entry in `response.data` will throw when accessing dismissal fields and fail the whole operation. Use optional access with defaults to avoid crashing on partial backend data.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 17, 2026

CodeAnt AI Incremental review completed.

@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 20, 2026

CodeAnt AI is running the review.

@codeant-ai codeant-ai bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Apr 20, 2026
@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 20, 2026

Sequence Diagram

This diagram shows how the new scans center validates the CLI connection, discovers repositories, and loads scan history and results (including advanced findings and dismissed alerts) for a selected repository and commit.

sequenceDiagram
    participant User
    participant ScansCenter
    participant CodeAntAPI

    User->>ScansCenter: Open scans center
    ScansCenter->>CodeAntAPI: Validate connection
    CodeAntAPI-->>ScansCenter: Return organizations and user email
    ScansCenter->>CodeAntAPI: List repositories for selected organization
    CodeAntAPI-->>ScansCenter: Return repository list

    User->>ScansCenter: Select repository and commit
    ScansCenter->>CodeAntAPI: Get scan history for repository
    CodeAntAPI-->>ScansCenter: Return scan runs
    ScansCenter->>CodeAntAPI: Fetch scan and advanced results for repo and commit
    ScansCenter->>CodeAntAPI: Fetch dismissed alerts for repo
    CodeAntAPI-->>ScansCenter: Return issues and dismissed alerts
Loading

Generated by CodeAnt AI

if (response.last_analysis_results !== undefined) {
return {
success: true,
repo: response.repo,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Returning repo: response.repo can produce undefined when the backend does not echo the repository name, which breaks the function's documented contract. Use the input repo as fallback to keep output stable. [possible bug]

Severity Level: Major ⚠️
- ⚠️ Scan history consumers may see missing repo identifier.
- ⚠️ Scans center history view could mislabel or lose repo context.
Suggested change
repo: response.repo,
repo: response.repo || repo,
Steps of Reproduction ✅
1. In a test harness, mock `fetchApi` from `src/utils/fetchApi.js:4` so that when
`getScanHistory` calls it with endpoint `/extension/scans2/get-scan-history`
(`src/scans/getScanHistory.js:16`), it resolves to `{ last_analysis_results: [], status:
'success' }` and does not include a `repo` property.

2. Import and call `getScanHistory('org/repo-name')` from `src/scans/getScanHistory.js:14`
with this mock in place.

3. The function passes the mock response through the `if (response.last_analysis_results
!== undefined)` branch at `src/scans/getScanHistory.js:22-27` and constructs the result
object using `repo: response.repo` at line 25.

4. Inspect the returned value and observe that `result.repo` is `undefined` despite the
JSDoc contract at `src/scans/getScanHistory.js:8-11` documenting `repo: "org/repo-name"`;
this breaks the documented output shape whenever the backend omits the `repo` field, which
is a realistic scenario since no other client code in this repo depends on the server
echoing the repo name and other scan endpoints (e.g. `fetchScanResults` at
`src/scans/fetchScanResults.js:54-99`) do not expose `repo` at all.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/getScanHistory.js
**Line:** 25:25
**Comment:**
	*Possible Bug: Returning `repo: response.repo` can produce `undefined` when the backend does not echo the repository name, which breaks the function's documented contract. Use the input `repo` as fallback to keep output stable.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

break;
case ADVANCED_RESULT_TYPES.DEAD_CODE:
normalized.check_name =
item.name || item.function_name || item.symbol_name || item.description || 'Unused code detected';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Dead-code entries generated by flattenDeadCode already include a specific check_name, but the dead-code normalization ignores that field and overwrites it with a generic fallback, causing issue names to lose important context. Preserve item.check_name during normalization. [logic error]

Severity Level: Major ⚠️
- ⚠️ Dead-code scan labels become generic or lose rule context.
- ⚠️ Scans UI may mislead users about unused items severity.
Suggested change
item.name || item.function_name || item.symbol_name || item.description || 'Unused code detected';
item.check_name || item.name || item.function_name || item.symbol_name || item.description || 'Unused code detected';
Steps of Reproduction ✅
1. In a consumer (CLI or UI), import `fetchDeadCodeResults` from
`src/scans/fetchAdvancedScanResults.js`, where it is exported at lines 321–322; Grep over
the repo shows no current internal callers, so this is a new public API intended for the
scans center.

2. Mock `fetchApi` (`src/utils/fetchApi.js:1–44`) so that `fetchAdvancedScanResults`
(defined at `src/scans/fetchAdvancedScanResults.js:202–307`) is invoked with `resultType =
'dead_code'` and returns `{ status: 'success', dead_code: { python_dead_code: [...],
js_dead_code: {...}, extra_dead_code: {...} } }` in the shape expected by
`flattenDeadCode` at lines 42–141.

3. When `fetchAdvancedScanResults` executes the dead-code branch at lines 228–231, it
calls `flattenDeadCode`, which emits flat issue objects with rich `check_name` values such
as `Unused ${issueType}: ${name}` (lines 67–77), `'Unused file'` (lines 85–93), `'Unused
export: ${exp.name}'` (lines 104–113), or Sonar-style descriptions from
`EXTRA_DEAD_CODE_MESSAGES` (lines 124–136).

4. The flat array is then normalized via `normalizeAdvancedIssue` at
`src/scans/fetchAdvancedScanResults.js:147–191`; in the `ADVANCED_RESULT_TYPES.DEAD_CODE`
case (lines 182–185), the statement `normalized.check_name = item.name ||
item.function_name || item.symbol_name || item.description || 'Unused code detected';`
overwrites the existing `item.check_name`, so callers of `fetchDeadCodeResults` see
generic labels like `'Unused code detected'` or bare symbol names instead of the more
descriptive dead-code messages produced by `flattenDeadCode`.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/fetchAdvancedScanResults.js
**Line:** 184:184
**Comment:**
	*Logic Error: Dead-code entries generated by `flattenDeadCode` already include a specific `check_name`, but the dead-code normalization ignores that field and overwrites it with a generic fallback, causing issue names to lose important context. Preserve `item.check_name` during normalization.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎


// Filter secrets false positives
if (resultType === ADVANCED_RESULT_TYPES.SECRETS) {
issues = issues.filter((issue) => issue.confidence_score?.toLowerCase() !== 'false_positive');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The secrets false-positive filter calls .toLowerCase() directly on confidence_score, which will throw at runtime when the backend sends a non-string value (for example numeric confidence). Normalize the value to a string before comparing. [type error]

Severity Level: Critical 🚨
- ❌ Secrets advanced scan crashes when confidence_score is non-string.
- ⚠️ Scans center cannot reliably display secrets findings and status.
Suggested change
issues = issues.filter((issue) => issue.confidence_score?.toLowerCase() !== 'false_positive');
issues = issues.filter((issue) => String(issue.confidence_score || '').toLowerCase() !== 'false_positive');
Steps of Reproduction ✅
1. In a Node test or REPL, import `fetchSecretsResults` from
`src/scans/fetchAdvancedScanResults.js` where it is exported at lines 315–316.

2. Mock `fetchApi` from `src/utils/fetchApi.js:1–44` so that `fetchAdvancedScanResults`
(defined at `src/scans/fetchAdvancedScanResults.js:202–307`) receives a JSON response like
`{ status: 'success', secrets: [ { file_path: 'foo.js', line_number: 10, confidence_score:
0.9 } ] }` when posting to `/extension/scans2/fetch-advanced-results`.

3. Call `await fetchSecretsResults('org/repo',
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')`; execution flows into the secrets branch at
`src/scans/fetchAdvancedScanResults.js:228–231`, sets `resultsData = response.secrets`,
builds the `issues` array via `normalizeAdvancedIssue` at lines 147–191, and then reaches
the secrets false-positive filter at lines 294–296.

4. At `src/scans/fetchAdvancedScanResults.js:295–296`, the expression
`issue.confidence_score?.toLowerCase() !== 'false_positive'` attempts to call
`.toLowerCase()` on the numeric `confidence_score` (0.9), causing a runtime `TypeError:
issue.confidence_score.toLowerCase is not a function` and making `fetchSecretsResults`
reject instead of returning scan results for the advanced secrets view.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/fetchAdvancedScanResults.js
**Line:** 296:296
**Comment:**
	*Type Error: The secrets false-positive filter calls `.toLowerCase()` directly on `confidence_score`, which will throw at runtime when the backend sends a non-string value (for example numeric confidence). Normalize the value to a string before comparing.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

Comment on lines +39 to +41
if (file_path.endsWith('/security_issues.json')) {
file_path = file_path.replace('/security_issues.json', '');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Dismissed alert paths are only stripped for /security_issues.json, but scan results support other suffixes too; this creates a path mismatch for anti-pattern/docstring/complex-function dismissals and prevents proper re-matching. Strip all known scan-result suffixes consistently. [logic error]

Severity Level: Critical 🚨
- ❌ Dismissed anti-pattern alerts fail to re-associate with issues.
- ❌ Dismissed docstring alerts fail to re-associate with issues.
- ❌ Dismissed complex-function alerts fail to re-associate with issues.
- ⚠️ Users see previously dismissed non-security findings as active again.
- ⚠️ Central scans center behavior inconsistent across different scan result types.
Suggested change
if (file_path.endsWith('/security_issues.json')) {
file_path = file_path.replace('/security_issues.json', '');
}
file_path = file_path.replace(/\/(security_issues|anti_patterns|docstring|complex_functions)\.json$/, '');
Steps of Reproduction ✅
1. A consumer of this package calls `fetchAntiPatternsResults(repo, commitId)` from
`src/scans/fetchScanResults.js:108-109`. This function delegates to `fetchScanResults()`
with `resultType = 'anti_patterns'`.

2. Inside `fetchScanResults()` (`src/scans/fetchScanResults.js:54-99`), each server path
key like `org/repo/<commit>/path/to/file.py/anti_patterns.json` is converted to a clean
`file_path` via `extractCleanPath(fullPath, commitId, fileSuffix)` (`lines 24-44`) using
`fileSuffix = RESULT_FILE_SUFFIXES[resultType]` (`lines 10-15`). For `anti_patterns`, this
strips the `/anti_patterns.json` suffix so issues are emitted with `file_path =
'path/to/file.py'`.

3. For the same repository and scan type, the consumer calls `fetchDismissedAlerts(repo,
'anti_patterns')` from `src/scans/fetchDismissedAlerts.js:13-18`. The server returns
dismissed-alert keys in the format described in the header comment (`lines 6-8`), where
the first segment is the same full scan-result path used in `fetchScanResults`.

4. In `fetchDismissedAlerts`, the code at `src/scans/fetchDismissedAlerts.js:31-48` splits
each `issueKey` and assigns `file_path = parts[0]`. It only strips `/security_issues.json`
when `file_path.endsWith('/security_issues.json')` (`lines 39-41`), leaving
`/anti_patterns.json`, `/docstring.json`, or `/complex_functions.json` intact for other
result types. As a result, dismissed alerts for anti-patterns/docstring/complex-functions
use `file_path` values like `path/to/file.py/anti_patterns.json`, which do not match the
normalized `file_path` values `path/to/file.py` produced by `fetchScanResults`. Any
downstream logic that matches issues and dismissals on `(file_path, test_id)` will fail to
re-associate dismissed alerts for these non-security scan types, even though the same
files/issues are involved.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scans/fetchDismissedAlerts.js
**Line:** 39:41
**Comment:**
	*Logic Error: Dismissed alert paths are only stripped for `/security_issues.json`, but scan results support other suffixes too; this creates a path mismatch for anti-pattern/docstring/complex-function dismissals and prevents proper re-matching. Strip all known scan-result suffixes consistently.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 20, 2026

CodeAnt AI finished running the review.

@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 20, 2026

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Apr 20, 2026
ce(Text, { color: 'gray' },
(issue.file_path || 'unknown') + (issue.line_number ? `:${issue.line_number}` : '')),
ce(Text, null,
issue.check_name || issue.issue_text || issue.message || '')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Dismissed-alert items from fetchDismissedAlerts do not provide check_name, issue_text, or message, so this renderer shows blank issue text. Add fallbacks for dismissed fields to avoid empty result rows. [logic error]

Severity Level: Major ⚠️
- ⚠️ Dismissed alerts list shows blank descriptions for each finding.
- ⚠️ Harder to understand which rule each dismissal corresponds to.
Suggested change
issue.check_name || issue.issue_text || issue.message || '')
issue.check_name || issue.issue_text || issue.message || issue.test_id || issue.type || issue.reason_for_dismiss || 'Dismissed finding')
Steps of Reproduction ✅
1. Run the CLI with the `scan-center` command defined in `src/index.js:21-26`, which
renders the `ScanCenter` component to browse scan results.

2. Select a connection and repository (handled by `validateConnectionOnMount` in
`src/scanCenter/validateConnectionOnMount.js:3-14` and
`handleSelectConnection`/`listRepos` in `src/scanCenter/handleSelectConnection.js:3-13`
and `src/scans/listRepos.js:13-27`), then choose a scan from the SELECT_SCAN view
(`src/components/ScanCenter.js:270-301`).

3. In the SELECT_RESULT_TYPE menu (`src/components/ScanCenter.js:304-321`), choose either
"Dismissed Alerts" or "Dismissed Secrets", whose result types are defined in
`RESULT_TYPES` at `src/components/ScanCenter.js:34-35` with values `dismissed_alerts` and
`dismissed_secrets`.

4. The selection triggers `handleSelectResultType`
(`src/scanCenter/handleSelectResultType.js:5-25`), which for these result types calls
`fetchDismissedAlerts` (`src/scans/fetchDismissedAlerts.js:13-55`) and wraps
`r.dismissedAlerts` into `res.issues`; each dismissed issue object only contains
`file_path`, `context_code_block`, `test_id`, `line_number`, `type`, `issue_key`,
`reason_for_dismiss`, and `comment_for_dismiss` (no `check_name`, `issue_text`, or
`message`), so when `ResultsView` renders rows at `src/components/ScanCenter.js:106-115`
the description `Text` uses `issue.check_name || issue.issue_text || issue.message || ''`
and resolves to an empty string for every dismissed finding, producing result rows with a
severity tag and file path but a blank description.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/components/ScanCenter.js
**Line:** 115:115
**Comment:**
	*Logic Error: Dismissed-alert items from `fetchDismissedAlerts` do not provide `check_name`, `issue_text`, or `message`, so this renderer shows blank issue text. Add fallbacks for dismissed fields to avoid empty result rows.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +6 to +7
setLoadingMsg(`Loading scan history for ${item.value.full_name}…`);
const res = await getScanHistory(item.value.full_name);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The repository identifier sent to getScanHistory assumes full_name always exists, but the UI allows selecting repos that may only have name. This can pass undefined to the API and fail loading scan history. [logic error]

Severity Level: Major ⚠️
- ❌ ScanCenter cannot load history for name-only repositories.
- ⚠️ Users blocked from viewing past scans for some repos.
Suggested change
setLoadingMsg(`Loading scan history for ${item.value.full_name}…`);
const res = await getScanHistory(item.value.full_name);
const repoFullName = item.value.full_name || item.value.name;
setLoadingMsg(`Loading scan history for ${repoFullName}…`);
const res = await getScanHistory(repoFullName);
Steps of Reproduction ✅
1. Run the CLI so it renders the ScanCenter component defined in
`src/components/ScanCenter.js:156-201`, which orchestrates the multi-step scan flow.

2. From the "Select a connection" step, pick any connection; `handleSelectConnection` at
`src/scanCenter/handleSelectConnection.js:3-13` calls `listRepos()`
(`src/scans/listRepos.js:13-27`) and stores `response.repos` into the `repos` state.

3. Ensure the backend returns at least one repository object where `name` is set but
`full_name` is absent (the UI is explicitly coded to allow this via `.filter((r) => r &&
(r.name || r.full_name))` and `label: r.name || r.full_name` in
`src/components/ScanCenter.js:248-253`). This repo shows up as a selectable item in the
"Select a repository" list with `value: r`.

4. Select that name-only repository in the "Select a repository" screen so `onSelect:
handleSelectRepo` at `src/components/ScanCenter.js:262-263` invokes `_handleSelectRepo`.
Inside `src/scanCenter/handleSelectRepo.js:3-7`, `setLoadingMsg` and `getScanHistory` both
read `item.value.full_name`, which is `undefined` for this repo, so `getScanHistory`
(`src/scans/getScanHistory.js:14-16`) posts `{ repo: undefined }` to
`/extension/scans2/get-scan-history` (even though the JSDoc at `getScanHistory.js:6`
states `repo` should be a full-name string). The request fails and `handleSelectRepo`
falls into the error branch at lines 8-11, showing `Failed to fetch scan history` instead
of loading history for that repository.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scanCenter/handleSelectRepo.js
**Line:** 6:7
**Comment:**
	*Logic Error: The repository identifier sent to `getScanHistory` assumes `full_name` always exists, but the UI allows selecting repos that may only have `name`. This can pass `undefined` to the API and fail loading scan history.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

return;
}
const history = res.scanHistory || [];
process.stderr.write('SCAN_HISTORY_SAMPLE: ' + JSON.stringify(history.slice(0, 15), null, 2) + '\n');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Writing raw scan history to stderr on every selection leaks potentially sensitive repository scan metadata and pollutes CLI output; this debug logging should be disabled by default. [security]

Severity Level: Major ⚠️
- ⚠️ Scan history metadata printed to stderr every repo selection.
- ⚠️ CI logs may leak repository scan context unintentionally.
Suggested change
process.stderr.write('SCAN_HISTORY_SAMPLE: ' + JSON.stringify(history.slice(0, 15), null, 2) + '\n');
if (process.env.CODEANT_DEBUG_SCAN_HISTORY === '1') {
process.stderr.write('SCAN_HISTORY_SAMPLE: ' + JSON.stringify(history.slice(0, 15), null, 2) + '\n');
}
Steps of Reproduction ✅
1. Start the CLI and navigate into the ScanCenter flow so that `ScanCenter` from
`src/components/ScanCenter.js:156-201` is active and repositories have been loaded into
state via `handleSelectConnection` and `listRepos`.

2. Reach the "Select a repository" step where `ScanCenter` builds items from the `repos`
state (`src/components/ScanCenter.js:248-255`) and wires `onSelect: handleSelectRepo`
(`ScanCenter.js:262-263`) to delegate repository selection.

3. Select any repository whose scan history can be fetched successfully. This calls
`_handleSelectRepo` from `src/scanCenter/handleSelectRepo.js:3-7`, which awaits
`getScanHistory(item.value.full_name)` and, on success, assigns `const history =
res.scanHistory || [];` at line 12.

4. On every such successful selection, the debug statement at
`src/scanCenter/handleSelectRepo.js:13` executes
`process.stderr.write('SCAN_HISTORY_SAMPLE: ' + JSON.stringify(history.slice(0, 15), null,
2) + '\n');`, unconditionally dumping up to 15 scan history entries (including repository
identifiers, branches, commit SHAs, and timestamps used later in `ScanCenter.js:271-286`)
to stderr, where they appear in user terminals or CI logs without any opt-in control.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/scanCenter/handleSelectRepo.js
**Line:** 13:13
**Comment:**
	*Security: Writing raw scan history to stderr on every selection leaks potentially sensitive repository scan metadata and pollutes CLI output; this debug logging should be disabled by default.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai
Copy link
Copy Markdown

codeant-ai bot commented Apr 20, 2026

CodeAnt AI Incremental review completed.

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

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant