Skip to content
Open
138 changes: 95 additions & 43 deletions src/list.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,50 @@
use crate::config::Config;
use crate::log::debug;
use crate::utils;
use crate::utils::api::ProjectSelector;
use serde_json::json;
use std::path::Path;

pub fn run(
config: &Config,
issues: &bool,
sca_issues: &bool,
json: &bool,
page: &Option<u16>,
page_size: &Option<u16>,
scan_id: &Option<String>,
) {
let project_name = utils::generic::determine_project_name(None);
println!();
if *sca_issues {
#[derive(Default)]
pub struct ListArgs {
pub issues: bool,
pub sca_issues: bool,
pub json: bool,
pub page: Option<u16>,
pub page_size: Option<u16>,
pub scan_id: Option<String>,
pub selector: ProjectSelector,
}

pub fn run(config: &Config, args: ListArgs) {
let ListArgs {
issues,
sca_issues,
json,
page,
page_size,
scan_id,
selector,
} = args;
if !json {
println!();
}
if sca_issues {
// SCA has no project parameter; the CWD basename is only error copy.
let project_name =
utils::generic::get_current_working_directory().unwrap_or("unknown".to_string());
let sca_issues_response = match utils::api::get_sca_issues(
&config.get_url(),
Some((*page).unwrap_or(1)),
*page_size,
Some(page.unwrap_or(1)),
page_size,
scan_id.clone(),
) {
Ok(response) => response,
Err(e) => {
debug(&format!("Error Sending Request: {}", e));
if e.to_string().contains("404") {
if scan_id.is_some() {
log::error!("Scan with ID '{}' doesn't exist or has no SCA issues. Please run 'corgea scan' to create a new scan for this project.", scan_id.as_ref().unwrap());
if let Some(id) = &scan_id {
log::error!("Scan with ID '{}' doesn't exist or has no SCA issues. Please run 'corgea scan' to create a new scan for this project.", id);
} else {
log::error!("No SCA issues found for project '{}'. Please run 'corgea scan' to create a new scan for this project.", project_name);
}
Expand All @@ -44,7 +61,7 @@ pub fn run(
}
};

if *json {
if json {
let output = serde_json::json!({
"page": sca_issues_response.page,
"total_pages": sca_issues_response.total_pages,
Expand Down Expand Up @@ -107,22 +124,38 @@ pub fn run(
Some(sca_issues_response.page),
Some(sca_issues_response.total_pages),
);
} else if *issues {
return;
}

if issues {
// The --scan-id issue route hits /scan/{id}/issues and ignores the
// project, so it needs no resolution.
let resolved = scan_id
.is_none()
.then(|| utils::api::resolve_or_exit(&config.get_url(), &selector));
let project_name = resolved
.as_ref()
.map(|r| r.query_name.clone())
.unwrap_or_default();
let issues_response = match utils::api::get_scan_issues(
&config.get_url(),
&project_name,
Some((*page).unwrap_or(1)),
*page_size,
Some(page.unwrap_or(1)),
page_size,
scan_id.clone(),
) {
Ok(response) => response,
Err(e) => {
debug(&format!("Error Sending Request: {}", e));
if e.to_string().contains("404") {
if scan_id.is_some() {
log::error!("Scan with ID '{}' doesn't exist. Please run 'corgea scan' to create a new scan for this project.", scan_id.as_ref().unwrap());
} else {
log::error!("Project with name '{}' doesn't exist. Please run 'corgea scan' to create a new scan for this project.", project_name);
// `resolved` is None exactly on the --scan-id route.
match &resolved {
None => log::error!("Scan with ID '{}' doesn't exist. Please run 'corgea scan' to create a new scan for this project.", scan_id.as_ref().unwrap()),
Some(r) if r.confirmed => log::error!("Project '{}' has no issues yet. Run 'corgea scan' to create a scan for this project.", project_name),
Some(r) => log::error!(
"No Corgea project found for {}. Run 'corgea scan' to create one, or pass --project-name <NAME>.",
r.tried_label
),
}
} else {
log::error!(
Expand All @@ -140,14 +173,10 @@ pub fn run(
let mut blocking_rules: std::collections::HashMap<String, String> =
std::collections::HashMap::new();

if scan_id.is_some() {
if let Some(id) = &scan_id {
let mut page: u32 = 1;
loop {
match utils::api::check_blocking_rules(
&config.get_url(),
scan_id.as_ref().unwrap(),
Some(page),
) {
match utils::api::check_blocking_rules(&config.get_url(), id, Some(page)) {
Ok(rules) => {
if rules.block {
render_blocking_rules = true;
Expand All @@ -170,7 +199,7 @@ pub fn run(
}
}

if *json {
if json {
let mut json = serde_json::json!({
"page": issues_response.page,
"total_pages": issues_response.total_pages,
Expand Down Expand Up @@ -259,26 +288,28 @@ pub fn run(

utils::terminal::print_table(table, issues_response.page, issues_response.total_pages);
} else {
let resolved = utils::api::resolve_or_exit(&config.get_url(), &selector);
let project_name = &resolved.query_name;
let (scans, page, total_pages) = match utils::api::query_scan_list(
&config.get_url(),
Some(&project_name),
*page,
*page_size,
Some(project_name),
page,
page_size,
) {
Ok(scans) => {
let page = scans.page;
let total_pages = scans.total_pages;
let filtered_scans: Vec<utils::api::ScanResponse> = scans
.scans
.unwrap_or_default()
.into_iter()
.filter(|scan| scan.project == project_name)
.collect();
(filtered_scans, page, total_pages)
// The server already filtered by the resolved project; the old
// client-side `scan.project == cwd_basename` pass would discard
// every repo-resolved scan. (COR-1577)
(scans.scans.unwrap_or_default(), page, total_pages)
}
Err(e) => {
if e.to_string().contains("404") {
log::error!("Project with name '{}' doesn't exist. Please run 'corgea scan' to create a new scan for this project.", project_name);
log::error!(
"No Corgea project found for {}. Run 'corgea scan' to create one, or pass --project-name <NAME>.",
resolved.tried_label
);
} else {
log::error!(
"Unable to fetch scans. Please check your connection and ensure that:\n\
Expand All @@ -290,13 +321,33 @@ pub fn run(
std::process::exit(1);
}
};
if *json {
if json {
let output = json!({
"page": page,
"total_pages": total_pages,
"results": scans
});
// The envelope prints first so JSON consumers get valid stdout
// even when the miss below exits 1.
println!("{}", serde_json::to_string_pretty(&output).unwrap());
}
// An unresolved project is a miss (exit 1, as --issues and `wait`);
// a confirmed project with no scans is a valid empty result.
if scans.is_empty() && !resolved.confirmed {
log::error!(
"No Corgea project found for {}. Run 'corgea scan' to create one, or pass --project-name <NAME>.",
resolved.tried_label
);
std::process::exit(1);
}
if json {
return;
}
if scans.is_empty() {
println!(
"Project '{}' has no scans yet. Run 'corgea scan' to create one.",
project_name
);
return;
}
let mut table = vec![vec![
Expand All @@ -321,6 +372,7 @@ pub fn run(
} else {
formatted_repo
};

table.push(vec![
scan.id.clone(),
scan.project.clone(),
Expand Down
66 changes: 57 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,20 @@ enum Commands {
project_name: Option<String>,
},
/// Wait for the latest in progress scan
Wait { scan_id: Option<String> },
Wait {
scan_id: Option<String>,
#[arg(
long,
conflicts_with = "repo",
help = "Query this exact Corgea project name directly (skips repo auto-resolution)."
)]
project_name: Option<String>,
#[arg(
long,
help = "Resolve the project from this repo (org/repo slug or remote URL) instead of the git remote."
)]
repo: Option<String>,
},
/// List something, by default it lists the scans
#[command(alias = "ls")]
List {
Expand All @@ -166,6 +179,19 @@ enum Commands {

#[arg(long, value_parser = clap::value_parser!(u16), help = "Number of items per page")]
page_size: Option<u16>,

#[arg(
long,
conflicts_with = "repo",
help = "Query this exact Corgea project name directly (skips repo auto-resolution)."
)]
project_name: Option<String>,

#[arg(
long,
help = "Resolve the project from this repo (org/repo slug or remote URL) instead of the git remote."
)]
repo: Option<String>,
},
/// Inspect something, by default it will inspect a scan
Inspect {
Expand Down Expand Up @@ -663,9 +689,23 @@ fn main() {
),
}
}
Some(Commands::Wait { scan_id }) => {
Some(Commands::Wait {
scan_id,
project_name,
repo,
}) => {
verify_token_and_exit_when_fail(&corgea_config);
wait::run(&corgea_config, scan_id.clone(), None);
wait::run(
&corgea_config,
wait::WaitArgs {
scan_id: scan_id.clone(),
selector: utils::api::ProjectSelector {
name: project_name.clone(),
repo: repo.clone(),
},
upload_project_id: None,
},
);
}
Some(Commands::List {
issues,
Expand All @@ -674,6 +714,8 @@ fn main() {
page_size,
scan_id,
sca_issues,
project_name,
repo,
}) => {
verify_token_and_exit_when_fail(&corgea_config);
if *issues && *sca_issues {
Expand All @@ -686,12 +728,18 @@ fn main() {
}
list::run(
&corgea_config,
issues,
sca_issues,
json,
page,
page_size,
scan_id,
list::ListArgs {
issues: *issues,
sca_issues: *sca_issues,
json: *json,
page: *page,
page_size: *page_size,
scan_id: scan_id.clone(),
selector: utils::api::ProjectSelector {
name: project_name.clone(),
repo: repo.clone(),
},
},
);
}
Some(Commands::Inspect {
Expand Down
28 changes: 24 additions & 4 deletions src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,18 @@ pub fn run_semgrep(config: &Config, project_name: Option<String>) {

let output = run_command(&base_command.to_string(), command);

if let Some(result) = parse_scan(config, output, true, project_name) {
crate::wait::run(config, Some(result.scan_id), result.project_id);
if let Some(result) = parse_scan(config, output, true, project_name.clone()) {
crate::wait::run(
config,
crate::wait::WaitArgs {
scan_id: Some(result.scan_id),
selector: crate::utils::api::ProjectSelector {
name: project_name,
..Default::default()
},
upload_project_id: result.project_id,
},
);
}
}

Expand All @@ -80,8 +90,18 @@ pub fn run_snyk(config: &Config, project_name: Option<String>) {

let output = run_command(&base_command.to_string(), command);

if let Some(result) = parse_scan(config, output, true, project_name) {
crate::wait::run(config, Some(result.scan_id), result.project_id);
if let Some(result) = parse_scan(config, output, true, project_name.clone()) {
crate::wait::run(
config,
crate::wait::WaitArgs {
scan_id: Some(result.scan_id),
selector: crate::utils::api::ProjectSelector {
name: project_name,
..Default::default()
},
upload_project_id: result.project_id,
},
);
}
}

Expand Down
Loading
Loading