-
Notifications
You must be signed in to change notification settings - Fork 1
Supported Targeted scans & Project Name Param #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds targeted scanning capabilities and project name customization to the Corgea CLI scanner. The key changes enable users to scan specific files or directories instead of always scanning the entire repository, and to specify custom project names.
Key changes:
- Added
--targetparameter supporting files, directories, globs, git selectors (staged/modified/untracked/diff), and STDIN input - Added
--project-nameparameter with fallback logic (git repo name → directory name) - Refactored file packaging logic to support both full and targeted scans
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/terminal.rs | Added Yellow color variant to TerminalColor enum for warning messages |
| src/utils/generic.rs | Refactored zip creation to support targeted scans; added project name determination and URL parsing utilities |
| src/targets.rs | New module implementing target resolution logic for various input types (files, globs, git selectors, STDIN) |
| src/scanners/blast.rs | Updated scan runner to accept target and project_name parameters; integrated targeted scanning workflow |
| src/main.rs | Added CLI arguments for --target and --project-name parameters |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| let url = url.trim(); | ||
|
|
||
| let url = url.strip_suffix(".git").unwrap_or(url); | ||
|
|
||
| if let Some(name) = url.split('/').last() { | ||
| let name = name.trim(); | ||
| if !name.is_empty() { | ||
| return Some(name.to_string()); | ||
| } | ||
| } | ||
|
|
||
| if let Some(name) = url.split(':').last() { | ||
| let name = name.trim(); | ||
| if !name.is_empty() { | ||
| return Some(name.to_string()); | ||
| } | ||
| } | ||
|
|
Copilot
AI
Dec 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function attempts to extract repository name by splitting on '/' first, then falls back to splitting on ':'. For SSH URLs like 'git@github.com:user/repo', splitting on '/' would incorrectly return 'repo' before checking the ':' delimiter. This works by accident but is fragile. The logic should check for SSH format first (contains ':' but not '://'), then handle HTTPS format (contains '://'), to be more robust.
| let url = url.trim(); | |
| let url = url.strip_suffix(".git").unwrap_or(url); | |
| if let Some(name) = url.split('/').last() { | |
| let name = name.trim(); | |
| if !name.is_empty() { | |
| return Some(name.to_string()); | |
| } | |
| } | |
| if let Some(name) = url.split(':').last() { | |
| let name = name.trim(); | |
| if !name.is_empty() { | |
| return Some(name.to_string()); | |
| } | |
| } | |
| // | |
| // Prefer detecting SSH-style URLs (contain ':' but not '://') | |
| // before generic '/' splitting, to avoid relying on fragile | |
| // behaviour for different URL shapes. | |
| let trimmed = url.trim(); | |
| let url_no_git = trimmed.strip_suffix(".git").unwrap_or(trimmed); | |
| // HTTPS (or other scheme) URLs: scheme://host/path/to/repo | |
| if url_no_git.contains("://") { | |
| if let Some(after_scheme) = url_no_git.splitn(2, "://").nth(1) { | |
| if let Some(name) = after_scheme.rsplit('/').next() { | |
| let name = name.trim(); | |
| if !name.is_empty() { | |
| return Some(name.to_string()); | |
| } | |
| } | |
| } | |
| // SSH-style URLs: user@host:path/to/repo | |
| } else if url_no_git.contains(':') { | |
| if let Some(after_colon) = url_no_git.rsplitn(2, ':').next() { | |
| if let Some(name) = after_colon.rsplit('/').next() { | |
| let name = name.trim(); | |
| if !name.is_empty() { | |
| return Some(name.to_string()); | |
| } | |
| } | |
| } | |
| } else { | |
| // Fallback: treat as a simple path and split on '/' | |
| if let Some(name) = url_no_git.rsplit('/').next() { | |
| let name = name.trim(); | |
| if !name.is_empty() { | |
| return Some(name.to_string()); | |
| } | |
| } | |
| } |
| let parts: Vec<&str> = range.split("...").collect(); | ||
| let (old_ref, new_ref) = if parts.len() == 2 { | ||
| (parts[0].trim(), parts[1].trim()) | ||
| } else { | ||
| let parts: Vec<&str> = range.split("..").collect(); | ||
| if parts.len() == 2 { | ||
| (parts[0].trim(), parts[1].trim()) | ||
| } else { | ||
| return Err(format!("Invalid diff range format: {}. Expected format: 'old..new' or 'old...new'", range)); | ||
| } |
Copilot
AI
Dec 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The three-dot syntax check using split("...") will incorrectly match two-dot syntax. For example, "main..HEAD" will be split by "..." first, producing a single part "main..HEAD", then incorrectly fall through to the two-dot logic. Check for ".." first (which won't match "..."), then check for "..." to properly distinguish between the two git diff range syntaxes.
| let parts: Vec<&str> = range.split("...").collect(); | |
| let (old_ref, new_ref) = if parts.len() == 2 { | |
| (parts[0].trim(), parts[1].trim()) | |
| } else { | |
| let parts: Vec<&str> = range.split("..").collect(); | |
| if parts.len() == 2 { | |
| (parts[0].trim(), parts[1].trim()) | |
| } else { | |
| return Err(format!("Invalid diff range format: {}. Expected format: 'old..new' or 'old...new'", range)); | |
| } | |
| let (old_ref, new_ref) = if range.contains("..") && !range.contains("...") { | |
| let parts: Vec<&str> = range.split("..").collect(); | |
| if parts.len() == 2 { | |
| (parts[0].trim(), parts[1].trim()) | |
| } else { | |
| return Err(format!("Invalid diff range format: {}. Expected format: 'old..new' or 'old...new'", range)); | |
| } | |
| } else if range.contains("...") { | |
| let parts: Vec<&str> = range.split("...").collect(); | |
| if parts.len() == 2 { | |
| (parts[0].trim(), parts[1].trim()) | |
| } else { | |
| return Err(format!("Invalid diff range format: {}. Expected format: 'old..new' or 'old...new'", range)); | |
| } | |
| } else { | |
| return Err(format!("Invalid diff range format: {}. Expected format: 'old..new' or 'old...new'", range)); |
| } | ||
| match file.strip_prefix(¤t_dir) { | ||
| Ok(relative) => Some((file.clone(), relative.to_path_buf())), | ||
| Err(_) => { |
Copilot
AI
Dec 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When strip_prefix fails, the code uses the absolute path as both the full path and the "relative" path. This could lead to unexpected behavior downstream where relative paths are expected. Consider logging a warning or using a fallback that clearly indicates the path couldn't be made relative, rather than silently using the absolute path in both positions.
| Err(_) => { | |
| Err(_) => { | |
| // Log a warning instead of silently treating the absolute path as "relative". | |
| set_text_color(TerminalColor::Yellow); | |
| eprintln!( | |
| "Warning: failed to make path '{}' relative to '{}'; using absolute path as archive entry.", | |
| file.display(), | |
| current_dir.display() | |
| ); | |
| set_text_color(TerminalColor::Reset); |
| ) { | ||
| // Validate that only_uncommitted and target are not used together | ||
| if *only_uncommitted && target.is_some() { | ||
| eprintln!("--only_uncommitted and --target cannot be used together."); |
Copilot
AI
Dec 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message uses --only_uncommitted format, but based on typical CLI conventions, this should likely be --only-uncommitted (with hyphen). Verify the actual flag name and ensure consistency between the error message and the CLI argument definition.
| eprintln!("--only_uncommitted and --target cannot be used together."); | |
| eprintln!("--only-uncommitted and --target cannot be used together."); |
| let abs_path = if path.is_absolute() { | ||
| path.to_path_buf() | ||
| } else { | ||
| std::env::current_dir() | ||
| .map_err(|e| format!("Failed to get current directory: {}", e))? | ||
| .join(path) | ||
| .canonicalize() | ||
| .map_err(|e| format!("Failed to canonicalize path: {}", e))? | ||
| }; |
Copilot
AI
Dec 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the path is already absolute, it's not canonicalized, which could lead to inconsistent path representations (e.g., containing .. or . segments). Apply canonicalize to absolute paths as well to ensure all normalized paths have the same format.
Added
--project-nameto allow users to specify a project nameAdded
--targetparameter for selective scanning, supporting:git:untrackedgit:trackedgit:modifiedgit:diff=<range>-0