Skip to content
102 changes: 55 additions & 47 deletions src/list.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,57 @@
use crate::config::Config;
use crate::log::debug;
use crate::utils;
use crate::utils::api::ProjectSelector;
use serde_json::json;
use std::path::Path;

#[allow(clippy::too_many_arguments)]
pub fn run(
config: &Config,
issues: &bool,
sca_issues: &bool,
json: &bool,
page: &Option<u16>,
page_size: &Option<u16>,
scan_id: &Option<String>,
project_name_override: Option<String>,
repo_override: Option<String>,
) {
#[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;
println!();
if *sca_issues {
// SCA has no project parameter; this name is only error copy.
let project_name = utils::generic::determine_project_name(None);
if sca_issues {
// Only an explicit --project-name/--repo scopes the SCA listing: the
// endpoint takes `project`, but unflagged `--sca-issues` has always
// returned the company-wide latest scan and narrowing that silently is
// not this change's to make. Without a selector the name below stays
// what it was — error copy only.
let resolved = (scan_id.is_none() && selector.is_set())
.then(|| utils::api::resolve_project_or_exit(&config.get_url(), &selector));
let project_name = resolved
.as_ref()
.map(|r| r.query_name.clone())
.unwrap_or_else(|| utils::generic::determine_project_name(None));
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(),
resolved.as_ref().map(|r| r.query_name.as_str()),
) {
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 @@ -48,7 +68,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 @@ -111,24 +131,20 @@ pub fn run(
Some(sca_issues_response.page),
Some(sca_issues_response.total_pages),
);
} else if *issues {
} else if issues {
// The --scan-id route hits /scan/{id}/issues and ignores the project.
let resolved = scan_id.is_none().then(|| {
utils::api::resolve_project_or_exit(
&config.get_url(),
project_name_override.as_deref(),
repo_override.as_deref(),
)
});
let resolved = scan_id
.is_none()
.then(|| utils::api::resolve_project_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,
Expand Down Expand Up @@ -160,14 +176,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 @@ -190,7 +202,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 @@ -279,17 +291,13 @@ pub fn run(

utils::terminal::print_table(table, issues_response.page, issues_response.total_pages);
} else {
let resolved = utils::api::resolve_project_or_exit(
&config.get_url(),
project_name_override.as_deref(),
repo_override.as_deref(),
);
let resolved = utils::api::resolve_project_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,
page,
page_size,
) {
Ok(scans) => {
let page = scans.page;
Expand All @@ -316,7 +324,7 @@ pub fn run(
std::process::exit(1);
}
};
if *json {
if json {
let output = json!({
"page": page,
"total_pages": total_pages,
Expand All @@ -330,14 +338,14 @@ pub fn run(
// confirmed project with no scans is a valid empty result. So is an
// explicit --project-name: /scans answers 200-empty either way, so the
// caller's own exact name is the better authority.
if scans.is_empty() && !resolved.confirmed && project_name_override.is_none() {
if scans.is_empty() && !resolved.confirmed && selector.name.is_none() {
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 {
if json {
return;
}
if scans.is_empty() {
Expand Down
52 changes: 36 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ enum Commands {
help = "Resolve the project from this repo (org/repo slug or remote URL) instead of the git remote."
)]
repo: Option<String>,
#[arg(
long,
requires = "scan_id",
value_parser = clap::builder::NonEmptyStringValueParser::new(),
help = "Use this known Corgea project id for the result link, skipping project resolution. Requires a scan id, which is what the id then belongs to."
)]
project_id: Option<String>,
},
/// List something, by default it lists the scans
#[command(alias = "ls")]
Expand Down Expand Up @@ -588,10 +595,14 @@ fn main() {
if *wait {
wait::run(
&corgea_config,
Some(result.scan_id.clone()),
Some(result.project_name.clone()),
None,
result.project_id.clone(),
wait::WaitArgs {
scan_id: Some(result.scan_id.clone()),
selector: utils::api::ProjectSelector {
name: Some(result.project_name.clone()),
..Default::default()
},
project_id: result.project_id.clone(),
},
);
} else {
scan::print_scan_tracking_url(&corgea_config, &result);
Expand Down Expand Up @@ -741,14 +752,19 @@ fn main() {
scan_id,
project_name,
repo,
project_id,
}) => {
verify_token_and_exit_when_fail(&corgea_config);
wait::run(
&corgea_config,
scan_id.clone(),
project_name.clone(),
repo.clone(),
None,
wait::WaitArgs {
scan_id: scan_id.clone(),
selector: utils::api::ProjectSelector {
name: project_name.clone(),
repo: repo.clone(),
},
project_id: project_id.clone(),
},
);
}
Some(Commands::List {
Expand All @@ -772,14 +788,18 @@ fn main() {
}
list::run(
&corgea_config,
issues,
sca_issues,
json,
page,
page_size,
scan_id,
project_name.clone(),
repo.clone(),
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
24 changes: 16 additions & 8 deletions src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,14 @@ pub fn run_semgrep(config: &Config, project_name: Option<String>) {
if let Some(result) = parse_scan(config, output, true, project_name.clone()) {
crate::wait::run(
config,
Some(result.scan_id),
Some(result.project_name.clone()),
None,
result.project_id,
crate::wait::WaitArgs {
scan_id: Some(result.scan_id),
selector: crate::utils::api::ProjectSelector {
name: Some(result.project_name.clone()),
..Default::default()
},
project_id: result.project_id,
},
);
}
}
Expand All @@ -131,10 +135,14 @@ pub fn run_snyk(config: &Config, project_name: Option<String>) {
if let Some(result) = parse_scan(config, output, true, project_name.clone()) {
crate::wait::run(
config,
Some(result.scan_id),
Some(result.project_name.clone()),
None,
result.project_id,
crate::wait::WaitArgs {
scan_id: Some(result.scan_id),
selector: crate::utils::api::ProjectSelector {
name: Some(result.project_name.clone()),
..Default::default()
},
project_id: result.project_id,
},
);
}
}
Expand Down
Loading
Loading