Skip to content

Commit 9f46bdc

Browse files
Merge pull request #13 from Corgea/improved_devx
Improve scanning uncommited files experience
2 parents 1947bf2 + d815a44 commit 9f46bdc

File tree

16 files changed

+1007
-18
lines changed

16 files changed

+1007
-18
lines changed

package-lock.json

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

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Corgea",
44
"publisher": "Corgea",
55
"description": "Corgea helps you automatically fix insecure code.",
6-
"version": "1.3.0",
6+
"version": "1.4.0",
77
"icon": "images/logo.png",
88
"engines": {
99
"vscode": "^1.50.0"
@@ -121,6 +121,7 @@
121121
"axios": "^1.6.8",
122122
"diff": "^5.2.0",
123123
"extract-zip": "^2.0.1",
124+
"minimatch": "^9.0.3",
124125
"pug": "^3.0.3",
125126
"react": "^18.2.0",
126127
"react-dom": "^18.2.0",

src/config/constants.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// File exclusion patterns for security scanning
2+
// These patterns match files that should be ignored during security analysis
3+
export const FILE_EXCLUDE_PATTERNS = [
4+
"**/tests/**",
5+
"**/.corgea/**",
6+
"**/test/**",
7+
"**/spec/**",
8+
"**/specs/**",
9+
"**/node_modules/**",
10+
"**/tmp/**",
11+
"**/migrations/**",
12+
"**/python*/site-packages/**",
13+
"**/*.mmdb",
14+
"**/*.css",
15+
"**/*.less",
16+
"**/*.scss",
17+
"**/*.map",
18+
"**/*.env",
19+
"**/*.sh",
20+
"**/.vs/**",
21+
"**/.vscode/**",
22+
"**/.idea/**",
23+
];
24+
25+
// Application constants
26+
export const APP_NAME = "Corgea";
27+
export const TERMINAL_NAME = "Corgea";
28+
29+
// UI Constants
30+
export const MODAL_ANIMATION_DURATION = 300;
31+
export const BUTTON_HOVER_TRANSITION = "0.2s";
32+
33+
// File status types
34+
export const FILE_STATUS = {
35+
MODIFIED: 'modified',
36+
UNTRACKED: 'untracked',
37+
DELETED: 'deleted',
38+
STAGED: 'staged'
39+
} as const;
40+
41+
// Scan stages
42+
export const SCAN_STAGES = {
43+
INIT: 'init',
44+
PACKAGE: 'package',
45+
UPLOAD: 'upload',
46+
SCAN: 'scan',
47+
COMPLETED: 'completed',
48+
CANCELLED: 'cancelled'
49+
} as const;

src/providers/vulnerabilitiesWebviewProvider.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,41 @@ export default class VulnerabilitiesWebviewProvider implements vscode.WebviewVie
8585
console.log('Auto refresh toggle clicked from webview');
8686
await this.toggleAutoRefresh();
8787
break;
88+
case "getUncommittedFiles":
89+
console.log('Get uncommitted files requested from webview', data.includeIgnored ? 'including ignored files' : 'excluding ignored files');
90+
const uncommittedFiles = await scanningService.getUncommittedFiles(data.includeIgnored || false);
91+
this._view?.webview.postMessage({
92+
type: 'uncommittedFilesResponse',
93+
files: uncommittedFiles
94+
});
95+
break;
96+
case "scanUncommittedFiles":
97+
console.log('Scan uncommitted files button clicked from webview');
98+
vscode.commands.executeCommand("corgea.scan-uncommitted");
99+
break;
100+
case "clearScanState":
101+
console.log('Clear scan state requested from webview');
102+
// Reset scan state and exit scanning mode
103+
this._scanState = {
104+
isScanning: false,
105+
progress: [],
106+
output: [],
107+
stages: {
108+
init: false,
109+
package: false,
110+
upload: false,
111+
scan: false
112+
}
113+
};
114+
this._isInScanningMode = false;
115+
this._view?.webview.postMessage({
116+
type: 'exitScanningMode'
117+
});
118+
this._view?.webview.postMessage({
119+
type: 'scanStateUpdate',
120+
scanState: this._scanState
121+
});
122+
break;
88123
default:
89124
console.log('Unknown message type:', data.type);
90125
}

src/services/scanningService.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ export default class scanningService {
6969
await scanningService.scanProject(false);
7070
}
7171

72+
public static async getUncommittedFiles(includeIgnored: boolean = false): Promise<any[]> {
73+
try {
74+
const workspacePath = WorkspaceManager.getWorkspaceFolder()?.uri?.fsPath;
75+
if (!workspacePath) {
76+
console.log('No workspace path found');
77+
return [];
78+
}
79+
80+
console.log(`Getting uncommitted files from ${workspacePath}, includeIgnored: ${includeIgnored}`);
81+
const GitManager = (await import("../utils/gitManager")).default;
82+
const uncommittedFiles = await GitManager.getUncommittedFiles(workspacePath, includeIgnored);
83+
console.log(`Found ${uncommittedFiles.length} uncommitted files`);
84+
return uncommittedFiles;
85+
} catch (error) {
86+
console.error('Error getting uncommitted files:', error);
87+
return [];
88+
}
89+
}
90+
7291
/*
7392
Scan cammand should only scan changed files unless the projecty doesnt have any previous scan results
7493
Options to be (forced full scan)

src/utils/gitManager.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,34 @@
11
const simpleGit = require("simple-git");
2+
const minimatch = require("minimatch");
3+
import { FILE_EXCLUDE_PATTERNS } from "../config/constants";
4+
5+
export interface UncommittedFile {
6+
path: string;
7+
status: string; // 'modified', 'added', 'deleted', etc.
8+
}
29

310
export default class GitManager {
11+
private static isFileExcluded(filePath: string, excludePatterns: string[] = FILE_EXCLUDE_PATTERNS): boolean {
12+
return excludePatterns.some(pattern => {
13+
try {
14+
// Normalize the file path to use forward slashes
15+
const normalizedPath = filePath.replace(/\\/g, '/');
16+
const result = minimatch(normalizedPath, pattern, {
17+
matchBase: true,
18+
dot: true,
19+
nocase: true // Case insensitive matching for Windows
20+
});
21+
if (result) {
22+
console.log(`File ${normalizedPath} matched pattern ${pattern}`);
23+
}
24+
return result;
25+
} catch (error) {
26+
console.warn(`Invalid glob pattern: ${pattern}`, error);
27+
return false;
28+
}
29+
});
30+
}
31+
432
public static async getRemoteUrls(folderPath: string): Promise<string[]> {
533
try {
634
const git = simpleGit(folderPath);
@@ -13,4 +41,48 @@ export default class GitManager {
1341
}
1442
return [];
1543
}
44+
45+
public static async getUncommittedFiles(folderPath: string, includeIgnored: boolean = false): Promise<UncommittedFile[]> {
46+
try {
47+
const git = simpleGit(folderPath);
48+
const status = await git.status();
49+
50+
const uncommittedFiles: UncommittedFile[] = [];
51+
52+
// Helper function to add files if they're not excluded
53+
const addFileIfNotExcluded = (file: string, fileStatus: string) => {
54+
const isExcluded = this.isFileExcluded(file);
55+
console.log(`Processing file: ${file}, excluded: ${isExcluded}, includeIgnored: ${includeIgnored}`);
56+
57+
if (includeIgnored || !isExcluded) {
58+
uncommittedFiles.push({ path: file, status: fileStatus });
59+
}
60+
};
61+
62+
// Add modified files
63+
status.modified.forEach((file: string) => {
64+
addFileIfNotExcluded(file, 'modified');
65+
});
66+
67+
// Add new files
68+
status.not_added.forEach((file: string) => {
69+
addFileIfNotExcluded(file, 'untracked');
70+
});
71+
72+
// Add deleted files
73+
status.deleted.forEach((file: string) => {
74+
addFileIfNotExcluded(file, 'deleted');
75+
});
76+
77+
// Add staged files
78+
status.staged.forEach((file: string) => {
79+
addFileIfNotExcluded(file, 'staged');
80+
});
81+
82+
return uncommittedFiles;
83+
} catch (error) {
84+
console.error('Error getting uncommitted files:', error);
85+
return [];
86+
}
87+
}
1688
}

src/views/components/ScanningCompleted/ScanningCompleted.css

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,47 @@
1818
.completed-actions {
1919
display: flex;
2020
justify-content: center;
21-
gap: 10px;
21+
gap: 12px;
2222
flex-wrap: wrap;
2323
}
24+
25+
.btn {
26+
padding: 10px 20px;
27+
border: none;
28+
border-radius: 4px;
29+
cursor: pointer;
30+
font-size: 13px;
31+
font-weight: 500;
32+
transition: all 0.2s;
33+
display: flex;
34+
align-items: center;
35+
justify-content: center;
36+
gap: 6px;
37+
}
38+
39+
.btn-primary {
40+
background: var(--vscode-button-background);
41+
color: var(--vscode-button-foreground);
42+
}
43+
44+
.btn-primary:hover {
45+
background: var(--vscode-button-hoverBackground);
46+
}
47+
48+
.btn-secondary {
49+
background: var(--vscode-button-secondaryBackground);
50+
color: var(--vscode-button-secondaryForeground);
51+
border: 1px solid var(--vscode-button-border);
52+
}
53+
54+
.btn-secondary:hover {
55+
background: var(--vscode-button-secondaryHoverBackground);
56+
}
57+
58+
.mt-3 {
59+
margin-top: 12px;
60+
}
61+
62+
.me-2 {
63+
margin-right: 8px;
64+
}

src/views/components/ScanningCompleted/ScanningCompleted.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@ const ScanningCompleted: React.FC = () => {
1818
&nbsp;View Results in Corgea
1919
</button>
2020
)}
21-
<button className="btn btn-secondary" onClick={actions.scanProject}>
21+
<button className="btn btn-secondary me-2" onClick={actions.scanProject}>
2222
<i className="fas fa-redo"></i>
2323
&nbsp;Scan Again
2424
</button>
25+
<button className="btn btn-secondary" onClick={actions.clearScanState}>
26+
<i className="fas fa-times"></i>
27+
&nbsp;Clear
28+
</button>
2529
</div>
2630
</div>
2731
);

src/views/components/ScanningError/ScanningError.css

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,52 @@
1414
color: var(--vscode-foreground);
1515
margin-bottom: 16px;
1616
}
17+
18+
.error-actions {
19+
display: flex;
20+
justify-content: center;
21+
align-items: center;
22+
gap: 12px;
23+
flex-wrap: wrap;
24+
}
25+
26+
.btn {
27+
padding: 10px 20px;
28+
border: none;
29+
border-radius: 4px;
30+
cursor: pointer;
31+
font-size: 13px;
32+
font-weight: 500;
33+
transition: all 0.2s;
34+
display: flex;
35+
align-items: center;
36+
justify-content: center;
37+
gap: 6px;
38+
}
39+
40+
.btn-primary {
41+
background: var(--vscode-button-background);
42+
color: var(--vscode-button-foreground);
43+
}
44+
45+
.btn-primary:hover {
46+
background: var(--vscode-button-hoverBackground);
47+
}
48+
49+
.btn-secondary {
50+
background: var(--vscode-button-secondaryBackground);
51+
color: var(--vscode-button-secondaryForeground);
52+
border: 1px solid var(--vscode-button-border);
53+
}
54+
55+
.btn-secondary:hover {
56+
background: var(--vscode-button-secondaryHoverBackground);
57+
}
58+
59+
.mt-3 {
60+
margin-top: 12px;
61+
}
62+
63+
.ml-2 {
64+
margin-left: 8px;
65+
}

src/views/components/ScanningError/ScanningError.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@ const ScanningError: React.FC<ScanningErrorProps> = ({ isCancelled = false }) =>
1616
<i className="fas fa-times-circle" style={{ color: '#ff9500' }}></i>
1717
</div>
1818
<div className="error-message">Scan was cancelled</div>
19-
<button className="btn btn-primary mt-3" onClick={actions.scanProject}>
20-
<i className="fas fa-play"></i>
21-
&nbsp;Start New Scan
22-
</button>
19+
<div className="error-actions">
20+
<button className="btn btn-primary mt-3" onClick={actions.scanProject}>
21+
<i className="fas fa-play"></i>
22+
&nbsp;Start New Scan
23+
</button>
24+
<button className="btn btn-secondary mt-3 ml-2" onClick={actions.clearScanState}>
25+
<i className="fas fa-times"></i>
26+
&nbsp;Clear
27+
</button>
28+
</div>
2329
</div>
2430
);
2531
}

0 commit comments

Comments
 (0)