feat: pentest onboarding — streaming, browser automation, reports, user cleanup (#16)
All checks were successful
CI / Check (push) Has been skipped
CI / Detect Changes (push) Successful in 7s
CI / Deploy Agent (push) Successful in 2s
CI / Deploy Dashboard (push) Successful in 2s
CI / Deploy Docs (push) Successful in 2s
CI / Deploy MCP (push) Successful in 2s

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:
2026-03-17 20:32:20 +00:00
parent 11e1c5f438
commit c461faa2fb
57 changed files with 8844 additions and 2423 deletions

View File

@@ -28,8 +28,9 @@ pub use graph::{
pub use issue::{IssueStatus, TrackerIssue, TrackerType};
pub use mcp::{McpServerConfig, McpServerStatus, McpTransport};
pub use pentest::{
AttackChainNode, AttackNodeStatus, CodeContextHint, PentestEvent, PentestMessage,
PentestSession, PentestStats, PentestStatus, PentestStrategy, SeverityDistribution,
AttackChainNode, AttackNodeStatus, AuthMode, CodeContextHint, Environment, IdentityProvider,
PentestAuthConfig, PentestConfig, PentestEvent, PentestMessage, PentestSession, PentestStats,
PentestStatus, PentestStrategy, SeverityDistribution, TestUserRecord, TesterInfo,
ToolCallRecord,
};
pub use repository::{ScanTrigger, TrackedRepository};

View File

@@ -1,3 +1,5 @@
use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
@@ -50,6 +52,132 @@ 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,
}
/// Identity provider type for cleanup routing
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum IdentityProvider {
Keycloak,
Auth0,
Okta,
Firebase,
Custom,
}
/// Details of a test user created during a pentest session.
/// Stored so the cleanup step knows exactly what to delete and where.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TestUserRecord {
/// Username used to register
pub username: Option<String>,
/// Email used to register
pub email: Option<String>,
/// User ID returned by the identity provider (if known)
pub provider_user_id: Option<String>,
/// Which identity provider holds this user
pub provider: Option<IdentityProvider>,
/// Whether cleanup has been completed
#[serde(default)]
pub cleaned_up: bool,
}
/// A pentest session initiated via the chat interface
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PentestSession {
@@ -60,7 +188,12 @@ 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>,
/// Test user created during auto-register (for cleanup)
#[serde(default)]
pub test_user: Option<TestUserRecord>,
/// Total number of tool invocations in this session
pub tool_invocations: u32,
/// Total successful tool invocations
@@ -83,7 +216,9 @@ impl PentestSession {
repo_id: None,
status: PentestStatus::Running,
strategy,
config: None,
created_by: None,
test_user: None,
tool_invocations: 0,
tool_successes: 0,
findings_count: 0,
@@ -261,6 +396,10 @@ pub enum PentestEvent {
Complete { summary: String },
/// Error occurred
Error { message: String },
/// Session paused
Paused,
/// Session resumed
Resumed,
}
/// Aggregated stats for the pentest dashboard