use parlov_core::Error;
use parlov_elicit::ScanContext;
use crate::parse::{parse_alt_credential, parse_known_duplicate, parse_risk, parse_state_field};
use crate::util::parse_headers;
use crate::vector_filter::{max_risk_from_filters, VectorFilter};
pub(crate) fn build_scan_context(
args: &crate::cli::ScanArgs,
vector_filters: &[VectorFilter],
) -> Result<ScanContext, Error> {
let probe_id = args
.probe_id
.clone()
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
let max_risk = if vector_filters.is_empty() {
parse_risk(&args.risk)?
} else {
max_risk_from_filters(vector_filters)
};
let headers = parse_headers(&args.headers)?;
let known_duplicate = args
.known_duplicate
.as_deref()
.map(parse_known_duplicate)
.transpose()?;
let state_field = args
.state_field
.as_deref()
.map(parse_state_field)
.transpose()?;
let alt_credential = args
.alt_credential
.as_deref()
.map(parse_alt_credential)
.transpose()?;
Ok(ScanContext {
target: args.target.clone(),
baseline_id: args.baseline_id.clone(),
probe_id,
headers,
max_risk,
known_duplicate,
state_field,
alt_credential,
body_template: args.body.clone(),
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::ScanArgs;
use parlov_elicit::RiskLevel;
fn minimal_args(target: &str, baseline_id: &str) -> ScanArgs {
ScanArgs {
target: target.to_owned(),
baseline_id: baseline_id.to_owned(),
probe_id: Some("9999".to_owned()),
risk: "safe".to_owned(),
headers: vec![],
alt_credential: None,
known_duplicate: None,
state_field: None,
vectors: vec![],
strategies: vec![],
body: None,
exhaustive: false,
repro: false,
verbose: false,
}
}
#[test]
fn build_scan_context_target_matches_and_risk_defaults_to_safe() {
let args = minimal_args("https://api.example.com/users/{id}", "1001");
let ctx = build_scan_context(&args, &[]).unwrap();
assert_eq!(ctx.target, "https://api.example.com/users/{id}");
assert_eq!(ctx.max_risk, RiskLevel::Safe);
}
}