Skip to content

Commit 0bf7db8

Browse files
authored
Merge pull request #17 from CodeAnt-AI/login
scan center
2 parents 2b5e998 + b385654 commit 0bf7db8

12 files changed

Lines changed: 69 additions & 82 deletions

File tree

changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## [0.4.10] - 04/05/2026
4+
- Scans filtering added
5+
36
## [0.4.9] - 29/05/2026
47
- Login Url
58

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeant-cli",
3-
"version": "0.4.9",
3+
"version": "0.4.10",
44
"description": "Code review CLI tool",
55
"type": "module",
66
"bin": {

src/commands/scans/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ export default function registerScansCommands(program, { runCmd }) {
7171
.option('--severity <list>', 'Filter by severity (e.g. critical,high)')
7272
.option('--path <glob>', 'Filter by file path glob')
7373
.option('--check <regex>', 'Filter by check ID or name (regex)')
74-
.option('--include-dismissed', 'Include dismissed findings (excluded by default)')
74+
.option('--filter-dismissed', 'Exclude dismissed findings (default: false)')
75+
.option('--no-false-positives', 'Exclude false positives (default: included)')
7576
.option('--format <fmt>', 'Output format: json|sarif|csv|md|table (default: json)', 'json')
7677
.option('--output <path>', 'Write output to file instead of stdout')
7778
.option('--fields <list>', 'Project findings to subset of fields (comma-separated)')
@@ -96,7 +97,8 @@ export default function registerScansCommands(program, { runCmd }) {
9697
severity: opts.severity,
9798
path: opts.path,
9899
check: opts.check,
99-
includeDismissed: opts.includeDismissed || false,
100+
filterDismissed: opts.filterDismissed || false,
101+
includeFalsePositives: opts.falsePositives ?? true,
100102
format: opts.format,
101103
output: opts.output,
102104
fields: opts.fields,

src/commands/scans/lib/filters.js

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,22 @@
11
import { minimatch } from 'minimatch';
2-
import { isDismissed, findDismissMatch } from './dismissMatch.js';
32
import { normalizeSeverity } from './normalize.js';
43

5-
const SEV_RANK = { critical: 5, high: 4, medium: 3, low: 2, info: 1, unknown: 0 };
6-
74
/**
8-
* Apply all filters to findings in-place (returns new array).
5+
* Apply client-side filters to findings (returns new array).
6+
* Dismissed / false-positive filtering is handled exclusively by the backend.
97
*
108
* @param {Array} findings - NormalizedFinding[]
119
* @param {object} opts
12-
* @param {string[]|null} opts.severity - allowed severity levels (e.g. ['critical','high'])
13-
* @param {string|null} opts.pathGlob - minimatch glob for file_path
10+
* @param {string[]|null} opts.severity - allowed severity levels (e.g. ['critical','high'])
11+
* @param {string|null} opts.pathGlob - minimatch glob for file_path
1412
* @param {string|null} opts.checkRegex - regex applied to check_id + check_name
15-
* @param {Array} opts.dismissedAlerts - from fetchDismissedAlerts()
16-
* @param {boolean} opts.includeDismissed
17-
* @returns {Array} filtered NormalizedFinding[] (dismissed field annotated)
13+
* @returns {Array} filtered NormalizedFinding[]
1814
*/
1915
export function applyFilters(findings, {
2016
severity = null,
2117
pathGlob = null,
2218
checkRegex = null,
23-
dismissedAlerts = [],
24-
includeDismissed = false,
2519
} = {}) {
26-
// Pre-compile regex — strip Python/PCRE inline flag (?i) and fold into JS flag
2720
let checkRe = null;
2821
if (checkRegex) {
2922
try {
@@ -37,35 +30,15 @@ export function applyFilters(findings, {
3730
}
3831
}
3932

40-
// Severity set
4133
const sevSet = severity && severity.length > 0
4234
? new Set(severity.map((s) => normalizeSeverity(s)))
4335
: null;
4436

4537
const result = [];
4638
for (const f of findings) {
47-
// Annotate dismiss status
48-
const match = findDismissMatch(f, dismissedAlerts);
49-
f.dismissed = match !== null;
50-
if (match) {
51-
f.dismiss_info = {
52-
reason: match.reason_for_dismiss || null,
53-
comment: match.comment_for_dismiss || null,
54-
};
55-
}
56-
57-
// Filter dismissed
58-
if (f.dismissed && !includeDismissed) continue;
59-
60-
// Filter by severity
6139
if (sevSet && !sevSet.has(f.severity)) continue;
62-
63-
// Filter by path glob
6440
if (pathGlob && !minimatch(f.file_path, pathGlob, { matchBase: true })) continue;
65-
66-
// Filter by check regex
6741
if (checkRe && !checkRe.test(f.check_id) && !checkRe.test(f.check_name)) continue;
68-
6942
result.push(f);
7043
}
7144
return result;

src/commands/scans/lib/normalize.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,6 @@ export function normalizeIssue(issue, category) {
106106
cve: cve ? String(cve) : null,
107107
package: packageInfo,
108108
metadata,
109-
dismissed: false,
110-
dismiss_info: null,
111109
};
112110
}
113111

src/commands/scans/results.js

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { paginate } from './lib/paginate.js';
77
import { emit } from './lib/emit.js';
88
import { progress, logError } from './lib/log.js';
99
import { FORMATTERS } from './formatters/index.js';
10-
import { fetchDismissedAlerts } from '../../scans/fetchDismissedAlerts.js';
1110

1211
/**
1312
* codeant scans results — full orchestration.
@@ -23,7 +22,8 @@ export async function runResults(opts = {}) {
2322
severity,
2423
path: pathGlob,
2524
check: checkRegex,
26-
includeDismissed = false,
25+
filterDismissed = false,
26+
includeFalsePositives = true,
2727
format = 'json',
2828
output: outputPath = null,
2929
fields = null,
@@ -53,16 +53,12 @@ export async function runResults(opts = {}) {
5353
// 2. Parse types
5454
const categories = parseTypes(types);
5555

56-
// 3. Fetch in parallel + dismissed alerts
56+
// 3. Fetch in parallel
5757
progress(`fetching ${categories.map((c) => c.key).join(', ')}…`);
58-
const [settled, dismissedResult] = await Promise.all([
59-
Promise.allSettled(categories.map((c) => c.fetcher(repo, scanMeta.commit_id))),
60-
includeDismissed
61-
? Promise.resolve({ success: true, dismissedAlerts: [] })
62-
: fetchDismissedAlerts(repo, 'security'),
63-
]);
64-
65-
const dismissedAlerts = dismissedResult.success ? (dismissedResult.dismissedAlerts ?? []) : [];
58+
const fetchOpts = { filterDismissed, includeFalsePositives };
59+
const settled = await Promise.allSettled(
60+
categories.map((c) => c.fetcher(repo, scanMeta.commit_id, fetchOpts))
61+
);
6662

6763
// 4. Collect findings + errors
6864
const allFindings = [];
@@ -100,8 +96,6 @@ export async function runResults(opts = {}) {
10096
severity: severityList,
10197
pathGlob: pathGlob || null,
10298
checkRegex: checkRegex || null,
103-
dismissedAlerts,
104-
includeDismissed,
10599
});
106100

107101
// 6. Sort
@@ -115,7 +109,8 @@ export async function runResults(opts = {}) {
115109
severity: severityList,
116110
path: pathGlob || null,
117111
check: checkRegex || null,
118-
include_dismissed: includeDismissed,
112+
filter_dismissed: filterDismissed,
113+
include_false_positives: includeFalsePositives,
119114
};
120115

121116
// Rebuild summary from all filtered (pre-page) findings

src/components/ScanCenter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ function ErrorView({ message, onBack, canGoBack }) {
153153

154154
// ─── Main ScanCenter ─────────────────────────────────────────────────────────
155155

156-
export default function ScanCenter() {
156+
export default function ScanCenter({ filterDismissed = false, includeFalsePositives = true }) {
157157
const { exit } = useApp();
158158

159159
const [step, setStep] = useState(STEPS.LOADING);
@@ -198,7 +198,7 @@ export default function ScanCenter() {
198198

199199
// ── Step 5: result type selected → fetch exactly one endpoint ──
200200
const handleSelectResultType = (item) =>
201-
_handleSelectResultType({ STEPS, item, selectedRepo, selectedScan, setSelectedResultType, setStep, setLoadingMsg, setError, setResults });
201+
_handleSelectResultType({ STEPS, item, selectedRepo, selectedScan, setSelectedResultType, setStep, setLoadingMsg, setError, setResults, filterDismissed, includeFalsePositives });
202202

203203
// ── Back navigation ──
204204
const goBack = {

src/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,13 @@ program
211211
program
212212
.command('scan-center')
213213
.description('Browse scan results interactively')
214-
.action(() => {
215-
render(React.createElement(ScanCenter));
214+
.option('--filter-dismissed', 'Exclude dismissed alerts from results (default: false)')
215+
.option('--no-false-positives', 'Exclude false positives from results (default: included)')
216+
.action((options) => {
217+
render(React.createElement(ScanCenter, {
218+
filterDismissed: options.filterDismissed ?? false,
219+
includeFalsePositives: options.falsePositives ?? true,
220+
}));
216221
});
217222

218223
program

src/scanCenter/handleSelectResultType.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@ import { fetchScanResults } from '../scans/fetchScanResults.js';
22
import { fetchAdvancedScanResults } from '../scans/fetchAdvancedScanResults.js';
33
import { fetchDismissedAlerts } from '../scans/fetchDismissedAlerts.js';
44

5-
export async function handleSelectResultType({ STEPS, item, selectedRepo, selectedScan, setSelectedResultType, setStep, setLoadingMsg, setError, setResults }) {
5+
export async function handleSelectResultType({ STEPS, item, selectedRepo, selectedScan, setSelectedResultType, setStep, setLoadingMsg, setError, setResults, filterDismissed = false, includeFalsePositives = true }) {
66
const rt = item.value;
77
setSelectedResultType(rt);
88
setStep(STEPS.LOADING);
99
setLoadingMsg(`Fetching ${item.label}…`);
1010

1111
const repo = selectedRepo.full_name;
1212
const commitId = selectedScan.commitId;
13+
const fetchOpts = { filterDismissed, includeFalsePositives };
1314
let res;
1415

1516
if (rt.kind === 'basic') {
16-
res = await fetchScanResults(repo, commitId, rt.value);
17+
res = await fetchScanResults(repo, commitId, rt.value, fetchOpts);
1718
} else if (rt.kind === 'advanced') {
18-
res = await fetchAdvancedScanResults(repo, commitId, rt.value);
19+
res = await fetchAdvancedScanResults(repo, commitId, rt.value, fetchOpts);
1920
} else if (rt.value === 'dismissed_alerts') {
2021
const r = await fetchDismissedAlerts(repo, 'security');
2122
res = r.success ? { success: true, issues: r.dismissedAlerts } : r;

0 commit comments

Comments
 (0)