Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
40 changes: 28 additions & 12 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,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 @@ -719,14 +726,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 @@ -750,14 +762,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),
project_name,
None,
result.project_id,
crate::wait::WaitArgs {
scan_id: Some(result.scan_id),
selector: crate::utils::api::ProjectSelector {
name: project_name,
..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),
project_name,
None,
result.project_id,
crate::wait::WaitArgs {
scan_id: Some(result.scan_id),
selector: crate::utils::api::ProjectSelector {
name: project_name,
..Default::default()
},
project_id: result.project_id,
},
);
}
}
Expand Down
Loading
Loading