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:
@@ -1,3 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -50,6 +52,104 @@ impl std::fmt::Display for PentestStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
/// Authentication mode for the pentest target
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AuthMode {
|
||||
#[default]
|
||||
None,
|
||||
Manual,
|
||||
AutoRegister,
|
||||
}
|
||||
|
||||
/// Target environment classification
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Environment {
|
||||
#[default]
|
||||
Development,
|
||||
Staging,
|
||||
Production,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Environment {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Development => write!(f, "Development"),
|
||||
Self::Staging => write!(f, "Staging"),
|
||||
Self::Production => write!(f, "Production"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tester identity for the engagement record
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct TesterInfo {
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
}
|
||||
|
||||
/// Authentication configuration for the pentest session
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct PentestAuthConfig {
|
||||
pub mode: AuthMode,
|
||||
pub username: Option<String>,
|
||||
pub password: Option<String>,
|
||||
/// Optional — if omitted the orchestrator uses Playwright to discover it.
|
||||
pub registration_url: Option<String>,
|
||||
/// Base email for plus-addressing (e.g. `pentest@scanner.example.com`).
|
||||
/// The orchestrator generates `base+{session_id}@domain` per session.
|
||||
pub verification_email: Option<String>,
|
||||
/// IMAP server to poll for verification emails (e.g. `imap.example.com`).
|
||||
pub imap_host: Option<String>,
|
||||
/// IMAP port (default 993 for TLS).
|
||||
pub imap_port: Option<u16>,
|
||||
/// IMAP username (defaults to `verification_email` if omitted).
|
||||
pub imap_username: Option<String>,
|
||||
/// IMAP password / app-specific password.
|
||||
pub imap_password: Option<String>,
|
||||
#[serde(default)]
|
||||
pub cleanup_test_user: bool,
|
||||
}
|
||||
|
||||
/// Full wizard configuration for a pentest session
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PentestConfig {
|
||||
// Step 1: Target & Scope
|
||||
pub app_url: String,
|
||||
pub git_repo_url: Option<String>,
|
||||
pub branch: Option<String>,
|
||||
pub commit_hash: Option<String>,
|
||||
pub app_type: Option<String>,
|
||||
pub rate_limit: Option<u32>,
|
||||
|
||||
// Step 2: Authentication
|
||||
#[serde(default)]
|
||||
pub auth: PentestAuthConfig,
|
||||
#[serde(default)]
|
||||
pub custom_headers: HashMap<String, String>,
|
||||
|
||||
// Step 3: Strategy & Instructions
|
||||
pub strategy: Option<String>,
|
||||
#[serde(default)]
|
||||
pub allow_destructive: bool,
|
||||
pub initial_instructions: Option<String>,
|
||||
#[serde(default)]
|
||||
pub scope_exclusions: Vec<String>,
|
||||
|
||||
// Step 4: Disclaimer & Confirm
|
||||
#[serde(default)]
|
||||
pub disclaimer_accepted: bool,
|
||||
pub disclaimer_accepted_at: Option<DateTime<Utc>>,
|
||||
#[serde(default)]
|
||||
pub environment: Environment,
|
||||
#[serde(default)]
|
||||
pub tester: TesterInfo,
|
||||
pub max_duration_minutes: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub skip_mode: bool,
|
||||
}
|
||||
|
||||
/// A pentest session initiated via the chat interface
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PentestSession {
|
||||
@@ -60,6 +160,8 @@ pub struct PentestSession {
|
||||
pub repo_id: Option<String>,
|
||||
pub status: PentestStatus,
|
||||
pub strategy: PentestStrategy,
|
||||
/// Wizard configuration (None for legacy sessions)
|
||||
pub config: Option<PentestConfig>,
|
||||
pub created_by: Option<String>,
|
||||
/// Total number of tool invocations in this session
|
||||
pub tool_invocations: u32,
|
||||
@@ -83,6 +185,7 @@ impl PentestSession {
|
||||
repo_id: None,
|
||||
status: PentestStatus::Running,
|
||||
strategy,
|
||||
config: None,
|
||||
created_by: None,
|
||||
tool_invocations: 0,
|
||||
tool_successes: 0,
|
||||
@@ -261,6 +364,10 @@ pub enum PentestEvent {
|
||||
Complete { summary: String },
|
||||
/// Error occurred
|
||||
Error { message: String },
|
||||
/// Session paused
|
||||
Paused,
|
||||
/// Session resumed
|
||||
Resumed,
|
||||
}
|
||||
|
||||
/// Aggregated stats for the pentest dashboard
|
||||
|
||||
Reference in New Issue
Block a user