nyx/benches/dynamic_bench.rs

105 lines
3.4 KiB
Rust

/// Dynamic verification benchmarks (§8.4).
///
/// Tracks three cost anchors:
///
/// 1. `harness_build_cold` — fresh workdir, spec → BuiltHarness (source gen + disk write).
/// 2. `harness_build_warm` — same spec, workdir already staged (file write skipped).
/// 3. `sandbox_run_payload` — single payload run via process backend against
/// sqli_positive.py (subprocess + settrace overhead, no networking).
///
/// Baselines committed to `benches/dynamic_bench_baseline.json`.
/// Run: `cargo bench --features dynamic -- dynamic`
use criterion::{Criterion, criterion_group, criterion_main};
#[cfg(feature = "dynamic")]
use nyx_scanner::dynamic::spec::{EntryKind, HarnessSpec, PayloadSlot};
#[cfg(feature = "dynamic")]
use nyx_scanner::labels::Cap;
#[cfg(feature = "dynamic")]
use nyx_scanner::symbol::Lang;
#[cfg(feature = "dynamic")]
fn make_sqli_spec() -> HarnessSpec {
HarnessSpec {
finding_id: "bench0000000001".into(),
entry_file: "tests/dynamic_fixtures/python/sqli_positive.py".into(),
entry_name: "login".into(),
entry_kind: EntryKind::Function,
lang: Lang::Python,
toolchain_id: "python-3".into(),
payload_slot: PayloadSlot::Param(0),
expected_cap: Cap::SQL_QUERY,
constraint_hints: vec![],
sink_file: "tests/dynamic_fixtures/python/sqli_positive.py".into(),
sink_line: 7,
spec_hash: "benchsqli000001".into(),
}
}
#[cfg(feature = "dynamic")]
fn bench_harness_build_cold(c: &mut Criterion) {
use nyx_scanner::dynamic::harness;
let spec = make_sqli_spec();
c.bench_function("harness_build_cold", |b| {
b.iter(|| {
let workdir = std::env::temp_dir()
.join("nyx-harness")
.join(&spec.spec_hash);
let _ = std::fs::remove_dir_all(&workdir);
harness::build(&spec).expect("harness build")
});
});
}
#[cfg(feature = "dynamic")]
fn bench_harness_build_warm(c: &mut Criterion) {
use nyx_scanner::dynamic::harness;
let spec = make_sqli_spec();
harness::build(&spec).expect("harness pre-stage");
c.bench_function("harness_build_warm", |b| {
b.iter(|| harness::build(&spec).expect("harness build warm"));
});
}
#[cfg(feature = "dynamic")]
fn bench_sandbox_run_payload(c: &mut Criterion) {
use nyx_scanner::dynamic::corpus::payloads_for;
use nyx_scanner::dynamic::harness;
use nyx_scanner::dynamic::sandbox::{self, SandboxOptions};
let spec = make_sqli_spec();
let harness = harness::build(&spec).expect("harness build");
let payloads = payloads_for(Cap::SQL_QUERY);
let payload = payloads.iter().find(|p| !p.is_benign).expect("sqli payload");
let opts = SandboxOptions {
timeout: std::time::Duration::from_secs(10),
..SandboxOptions::default()
};
c.bench_function("sandbox_run_payload", |b| {
b.iter(|| sandbox::run(&harness, payload, &opts).expect("sandbox run"));
});
}
#[cfg(feature = "dynamic")]
fn bench_noop(_c: &mut Criterion) {}
// When dynamic feature is off, provide a stub so the binary still links.
#[cfg(not(feature = "dynamic"))]
fn bench_noop(c: &mut Criterion) {
c.bench_function("dynamic_disabled_noop", |b| b.iter(|| ()));
}
#[cfg(feature = "dynamic")]
criterion_group!(
dynamic,
bench_harness_build_cold,
bench_harness_build_warm,
bench_sandbox_run_payload,
);
#[cfg(not(feature = "dynamic"))]
criterion_group!(dynamic, bench_noop);
criterion_main!(dynamic);