feat: pentest feature improvements — streaming, pause/resume, encryption, browser tool, reports, docs
- True SSE streaming via broadcast channels (DashMap per session) - Session pause/resume with watch channels + dashboard buttons - AES-256-GCM credential encryption at rest (PENTEST_ENCRYPTION_KEY) - Concurrency limiter (Semaphore, max 5 sessions, 429 on overflow) - Browser tool: headless Chrome CDP automation (navigate, click, fill, screenshot, evaluate) - Report code-level correlation: SAST findings, code graph, SBOM linked per DAST finding - Split html.rs (1919 LOC) into html/ module directory (8 files) - Wizard: target/repo dropdowns from existing data, SSH key display, close button on all steps - Auth: auto-register with optional registration URL (Playwright discovery), plus-addressing email, IMAP overrides - Attack chain: tool input/output in detail panel, running node pulse animation - Architecture docs with Mermaid diagrams + 8 screenshots Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -436,6 +436,87 @@ fn pentest_event_serde_finding() {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── PentestEvent Paused/Resumed ───
|
||||
|
||||
#[test]
|
||||
fn pentest_event_serde_paused() {
|
||||
let event = pentest::PentestEvent::Paused;
|
||||
let json = serde_json::to_string(&event).unwrap();
|
||||
assert!(json.contains(r#""type":"paused""#));
|
||||
let back: pentest::PentestEvent = serde_json::from_str(&json).unwrap();
|
||||
assert!(matches!(back, pentest::PentestEvent::Paused));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pentest_event_serde_resumed() {
|
||||
let event = pentest::PentestEvent::Resumed;
|
||||
let json = serde_json::to_string(&event).unwrap();
|
||||
assert!(json.contains(r#""type":"resumed""#));
|
||||
let back: pentest::PentestEvent = serde_json::from_str(&json).unwrap();
|
||||
assert!(matches!(back, pentest::PentestEvent::Resumed));
|
||||
}
|
||||
|
||||
// ─── PentestConfig serde ───
|
||||
|
||||
#[test]
|
||||
fn pentest_config_serde_roundtrip() {
|
||||
let config = pentest::PentestConfig {
|
||||
app_url: "https://example.com".into(),
|
||||
git_repo_url: Some("https://github.com/org/repo".into()),
|
||||
branch: Some("main".into()),
|
||||
commit_hash: None,
|
||||
app_type: Some("web".into()),
|
||||
rate_limit: Some(10),
|
||||
auth: pentest::PentestAuthConfig {
|
||||
mode: pentest::AuthMode::Manual,
|
||||
username: Some("admin".into()),
|
||||
password: Some("pass123".into()),
|
||||
registration_url: None,
|
||||
verification_email: None,
|
||||
imap_host: None,
|
||||
imap_port: None,
|
||||
imap_username: None,
|
||||
imap_password: None,
|
||||
cleanup_test_user: true,
|
||||
},
|
||||
custom_headers: [("X-Token".to_string(), "abc".to_string())]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
strategy: Some("comprehensive".into()),
|
||||
allow_destructive: false,
|
||||
initial_instructions: Some("Test the login flow".into()),
|
||||
scope_exclusions: vec!["/admin".into()],
|
||||
disclaimer_accepted: true,
|
||||
disclaimer_accepted_at: Some(chrono::Utc::now()),
|
||||
environment: pentest::Environment::Staging,
|
||||
tester: pentest::TesterInfo {
|
||||
name: "Alice".into(),
|
||||
email: "alice@example.com".into(),
|
||||
},
|
||||
max_duration_minutes: Some(30),
|
||||
skip_mode: false,
|
||||
};
|
||||
let json = serde_json::to_string(&config).unwrap();
|
||||
let back: pentest::PentestConfig = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(back.app_url, "https://example.com");
|
||||
assert_eq!(back.auth.mode, pentest::AuthMode::Manual);
|
||||
assert_eq!(back.auth.username, Some("admin".into()));
|
||||
assert!(back.auth.cleanup_test_user);
|
||||
assert_eq!(back.scope_exclusions, vec!["/admin".to_string()]);
|
||||
assert_eq!(back.environment, pentest::Environment::Staging);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pentest_auth_config_default() {
|
||||
let auth = pentest::PentestAuthConfig::default();
|
||||
assert_eq!(auth.mode, pentest::AuthMode::None);
|
||||
assert!(auth.username.is_none());
|
||||
assert!(auth.password.is_none());
|
||||
assert!(auth.verification_email.is_none());
|
||||
assert!(auth.imap_host.is_none());
|
||||
assert!(!auth.cleanup_test_user);
|
||||
}
|
||||
|
||||
// ─── Serde helpers (BSON datetime) ───
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user