nyx/src/dynamic/verify.rs

87 lines
3 KiB
Rust
Raw Normal View History

//! Top-level entry point for the dynamic layer.
//!
//! The CLI subcommand and any library consumer call [`verify_finding`].
//! It is the only function the rest of the crate needs to know about.
use crate::commands::scan::Diag;
use crate::dynamic::report::{AttemptSummary, VerifyResult, VerifyStatus};
use crate::dynamic::runner::{run_spec, RunError};
use crate::dynamic::sandbox::SandboxOptions;
use crate::dynamic::spec::HarnessSpec;
#[derive(Debug, Clone, Default)]
pub struct VerifyOptions {
pub sandbox: SandboxOptions,
}
/// Try to dynamically confirm a static finding.
///
/// Never fails: every error path collapses into a [`VerifyStatus`] so the
/// caller can treat dynamic verification as best-effort enrichment.
pub fn verify_finding(diag: &Diag, opts: &VerifyOptions) -> VerifyResult {
let finding_id = diag.id.clone();
let Some(spec) = HarnessSpec::from_finding(diag) else {
return VerifyResult {
finding_id,
status: VerifyStatus::Unsupported,
triggered_payload: None,
reason: Some("no harness spec derivable from finding".into()),
attempts: vec![],
};
};
match run_spec(&spec, &opts.sandbox) {
Ok(run) => {
let attempts = run
.attempts
.iter()
.map(|a| AttemptSummary {
payload_label: a.payload_label.to_string(),
exit_code: a.outcome.exit_code,
timed_out: a.outcome.timed_out,
triggered: a.triggered,
})
.collect();
match run.triggered_by {
Some(i) => VerifyResult {
finding_id,
status: VerifyStatus::Confirmed,
triggered_payload: Some(run.attempts[i].payload_label.to_string()),
reason: None,
attempts,
},
None => VerifyResult {
finding_id,
status: VerifyStatus::NotConfirmed,
triggered_payload: None,
reason: None,
attempts,
},
}
}
Err(RunError::NoPayloadsForCap) => VerifyResult {
finding_id,
status: VerifyStatus::Unsupported,
triggered_payload: None,
reason: Some("no payload corpus for sink cap".into()),
attempts: vec![],
},
Err(RunError::Harness(e)) => VerifyResult {
finding_id,
status: VerifyStatus::Inconclusive,
triggered_payload: None,
reason: Some(format!("harness build failed: {e:?}")),
attempts: vec![],
},
Err(RunError::Sandbox(e)) => VerifyResult {
finding_id,
status: VerifyStatus::Inconclusive,
triggered_payload: None,
reason: Some(format!("sandbox failed: {e:?}")),
attempts: vec![],
},
}
}