feat: pentest onboarding — streaming, browser automation, reports, user cleanup (#16)
All checks were successful
All checks were successful
Complete pentest feature overhaul: SSE streaming, session-persistent browser tool (CDP), AES-256 credential encryption, auto-screenshots in reports, code-level remediation correlation, SAST triage chunking, context window optimization, test user cleanup (Keycloak/Auth0/Okta), wizard dropdowns, attack chain improvements, architecture docs with Mermaid diagrams. Co-authored-by: Sharang Parnerkar <parnerkarsharang@gmail.com> Reviewed-on: #16
This commit was merged in pull request #16.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
pub mod api_fuzzer;
|
||||
pub mod auth_bypass;
|
||||
pub mod browser;
|
||||
pub mod console_log_detector;
|
||||
pub mod cookie_analyzer;
|
||||
pub mod cors_checker;
|
||||
@@ -114,6 +115,7 @@ impl ToolRegistry {
|
||||
Box::new(openapi_parser::OpenApiParserTool::new(http.clone())),
|
||||
);
|
||||
register(&mut tools, Box::new(recon::ReconTool::new(http)));
|
||||
register(&mut tools, Box::<browser::BrowserTool>::default());
|
||||
|
||||
Self { tools }
|
||||
}
|
||||
@@ -140,3 +142,105 @@ impl ToolRegistry {
|
||||
self.tools.keys().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn registry_has_all_expected_tools() {
|
||||
let registry = ToolRegistry::new();
|
||||
let names = registry.list_names();
|
||||
|
||||
let expected = [
|
||||
"recon",
|
||||
"openapi_parser",
|
||||
"dns_checker",
|
||||
"dmarc_checker",
|
||||
"tls_analyzer",
|
||||
"security_headers",
|
||||
"cookie_analyzer",
|
||||
"csp_analyzer",
|
||||
"cors_checker",
|
||||
"rate_limit_tester",
|
||||
"console_log_detector",
|
||||
"sql_injection_scanner",
|
||||
"xss_scanner",
|
||||
"ssrf_scanner",
|
||||
"auth_bypass_scanner",
|
||||
"api_fuzzer",
|
||||
"browser",
|
||||
];
|
||||
|
||||
for name in &expected {
|
||||
assert!(
|
||||
names.contains(&name.to_string()),
|
||||
"Missing tool: {name}. Registered: {names:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_get_returns_tool() {
|
||||
let registry = ToolRegistry::new();
|
||||
assert!(registry.get("recon").is_some());
|
||||
assert!(registry.get("browser").is_some());
|
||||
assert!(registry.get("nonexistent").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_definitions_have_valid_schemas() {
|
||||
let registry = ToolRegistry::new();
|
||||
let defs = registry.all_definitions();
|
||||
|
||||
assert!(!defs.is_empty());
|
||||
for def in &defs {
|
||||
assert!(!def.name.is_empty(), "Tool has empty name");
|
||||
assert!(
|
||||
!def.description.is_empty(),
|
||||
"Tool {} has empty description",
|
||||
def.name
|
||||
);
|
||||
assert!(
|
||||
def.input_schema.is_object(),
|
||||
"Tool {} schema is not an object",
|
||||
def.name
|
||||
);
|
||||
// Every schema should have "type": "object"
|
||||
assert_eq!(
|
||||
def.input_schema.get("type").and_then(|v| v.as_str()),
|
||||
Some("object"),
|
||||
"Tool {} schema type is not 'object'",
|
||||
def.name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn browser_tool_schema_has_action_enum() {
|
||||
let registry = ToolRegistry::new();
|
||||
let browser = registry.get("browser");
|
||||
assert!(browser.is_some());
|
||||
let schema = browser.map(|t| t.input_schema()).unwrap_or_default();
|
||||
let action_prop = schema.get("properties").and_then(|p| p.get("action"));
|
||||
assert!(
|
||||
action_prop.is_some(),
|
||||
"Browser tool missing 'action' property"
|
||||
);
|
||||
let action_enum = action_prop
|
||||
.and_then(|a| a.get("enum"))
|
||||
.and_then(|e| e.as_array());
|
||||
assert!(action_enum.is_some(), "Browser action missing enum");
|
||||
let actions: Vec<&str> = action_enum
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|v| v.as_str())
|
||||
.collect();
|
||||
assert!(actions.contains(&"navigate"));
|
||||
assert!(actions.contains(&"screenshot"));
|
||||
assert!(actions.contains(&"click"));
|
||||
assert!(actions.contains(&"fill"));
|
||||
assert!(actions.contains(&"get_content"));
|
||||
assert!(actions.contains(&"close"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user