mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-30 13:09:36 +02:00
bench: refresh the TypeSafe benchmark — 13/13 coverage, data-type-aware severity
Current-build run against the 13-scenario target with TypeSafe on: every seeded class confirmed with a live receipt, chained beyond the set into full admin takeover, GraphQL authz bypass, a config secret leak and an authenticated RCE. The credential-dump BOLA holds Critical because severity is graded on the kind of data exposed, not the class. report.html + run artifacts + README refreshed; no secrets committed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
fce86522ca
commit
d334946915
15 files changed
+3167
-3785
No files matched your search
@@ -534,7 +534,14 @@ fn find_base() -> PathBuf {
|
||||
let c = la.join("NeuroSploit");
|
||||
if c.join("agents_md").is_dir() { return c; }
|
||||
}
|
||||
// 5) Last resort: the build-time layout.
|
||||
// 5) A cache the harness populates itself (see ensure_agents). A binary
|
||||
// downloaded on its own, with no agents_md/ beside it, lands here.
|
||||
if let Some(cache) = agents_cache_dir() {
|
||||
if cache.join("agents_md").is_dir() {
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
// 6) Last resort: the build-time layout.
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.and_then(|p| p.parent())
|
||||
@@ -542,10 +549,67 @@ fn find_base() -> PathBuf {
|
||||
.unwrap_or_else(|| PathBuf::from("."))
|
||||
}
|
||||
|
||||
/// Where the harness caches an auto-fetched `agents_md/` (`~/.neurosploit/cache`).
|
||||
fn agents_cache_dir() -> Option<PathBuf> {
|
||||
std::env::var_os("HOME").map(PathBuf::from).map(|h| h.join(".neurosploit").join("cache"))
|
||||
.or_else(|| std::env::var_os("LOCALAPPDATA").map(PathBuf::from).map(|l| l.join("NeuroSploit").join("cache")))
|
||||
}
|
||||
|
||||
/// Make sure `<base>/agents_md/` exists; if not, fetch it from the pinned
|
||||
/// release into the cache and use that. The agent library is prompt/markdown,
|
||||
/// not code, and is fetched over HTTPS from the official repo at this exact
|
||||
/// version tag. Opt out with NEUROSPLOIT_NO_FETCH=1 (offline/air-gapped).
|
||||
async fn ensure_agents(base: &Path) -> PathBuf {
|
||||
if base.join("agents_md").is_dir() {
|
||||
return base.to_path_buf();
|
||||
}
|
||||
if std::env::var("NEUROSPLOIT_NO_FETCH").ok().as_deref() == Some("1") {
|
||||
return base.to_path_buf();
|
||||
}
|
||||
let Some(cache) = agents_cache_dir() else { return base.to_path_buf() };
|
||||
if cache.join("agents_md").is_dir() {
|
||||
return cache;
|
||||
}
|
||||
let tag = format!("v{}", env!("CARGO_PKG_VERSION"));
|
||||
let url = format!("https://codeload.github.com/JoasASantos/NeuroSploit/tar.gz/refs/tags/{tag}");
|
||||
eprintln!(" \x1b[2magents_md/ not found locally — fetching the agent library for {tag} from GitHub…\x1b[0m");
|
||||
if let Err(e) = fetch_agents(&url, &cache).await {
|
||||
eprintln!(" \x1b[33m⚠ could not fetch agents_md ({e}). Run from a checkout, or set NEUROSPLOIT_BASE to a folder that has agents_md/.\x1b[0m");
|
||||
return base.to_path_buf();
|
||||
}
|
||||
if cache.join("agents_md").is_dir() {
|
||||
eprintln!(" \x1b[2m✓ agent library cached at {}\x1b[0m", cache.display());
|
||||
cache
|
||||
} else {
|
||||
base.to_path_buf()
|
||||
}
|
||||
}
|
||||
|
||||
/// Download the release tarball and extract only its `agents_md/` into `cache`.
|
||||
async fn fetch_agents(url: &str, cache: &Path) -> anyhow::Result<()> {
|
||||
let bytes = harness::fetch_bytes(url, 120).await?;
|
||||
std::fs::create_dir_all(cache)?;
|
||||
// Extract with the system tar (no new crate dependency): the tarball's top
|
||||
// dir is `NeuroSploit-<version>/`, and we keep only its agents_md subtree.
|
||||
let tmp = cache.join(".download.tar.gz");
|
||||
std::fs::write(&tmp, &bytes)?;
|
||||
let status = std::process::Command::new("tar")
|
||||
.arg("-xzf").arg(&tmp)
|
||||
.arg("-C").arg(cache)
|
||||
.arg("--strip-components=1")
|
||||
.arg("--wildcards").arg("*/agents_md")
|
||||
.status();
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
match status {
|
||||
Ok(s) if s.success() && cache.join("agents_md").is_dir() => Ok(()),
|
||||
_ => anyhow::bail!("tar extraction failed or agents_md not in the archive"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let mut cli = Cli::parse();
|
||||
let base = find_base();
|
||||
let base = ensure_agents(&find_base()).await;
|
||||
|
||||
// Resolve the TypeSafe mode into the env var the pipeline reads, so every
|
||||
// run type (and the REPL) honours one control. `off` disables it entirely;
|
||||
|
||||
@@ -76,3 +76,17 @@ pub use scope::{Action as ScopeAction, Decision as ScopeDecision, ScopePolicy};
|
||||
pub use types::{Finding, RunConfig};
|
||||
pub use uncertainty::{assess as assess_uncertainty, Assessment, Gap, Rounds};
|
||||
pub use validation::{judge as judge_finding, CweValidator, Evidence, Verdict};
|
||||
|
||||
|
||||
/// Download bytes over HTTPS with a bounded timeout. Used by the app to fetch
|
||||
/// the pinned agent library when it is not present next to the binary.
|
||||
pub async fn fetch_bytes(url: &str, timeout_secs: u64) -> anyhow::Result<Vec<u8>> {
|
||||
let b = reqwest::Client::new()
|
||||
.get(url)
|
||||
.header("user-agent", "neurosploit")
|
||||
.timeout(std::time::Duration::from_secs(timeout_secs))
|
||||
.send().await?
|
||||
.error_for_status()?
|
||||
.bytes().await?;
|
||||
Ok(b.to_vec())
|
||||
}
|
||||
Reference in new issue
Block a user