feat: browser session persistence, auto-screenshots, context optimization, user cleanup
Some checks failed
CI / Check (pull_request) Failing after 5m55s
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped

Browser tool:
- Session-persistent Chrome tab (same tab reused across all calls in a pentest)
- Auto-screenshot on every navigate and click (stored in attack chain for report)
- Fill uses CDP Input.insertText (fixes WebSocket corruption on special chars)
- Switched from browserless/chromium to chromedp/headless-shell (stable WS)

Context window optimization:
- Strip screenshot_base64 from LLM conversation (kept in DB for report)
- Truncate HTML to 2KB, page text to 1.5KB in LLM messages
- Cap element/link arrays at 15 items
- SAST triage: batch 30 findings per LLM call instead of all at once

Report improvements:
- Auto-embed screenshots in attack chain timeline (navigate + click nodes)
- Cover page shows best app screenshot
- Attack chain phases capped at 8 (no more 20x "Final")

User cleanup:
- TestUserRecord model tracks created test users per session
- cleanup.rs: Keycloak (Admin REST API), Auth0 (Management API), Okta (Users API)
- Auto-cleanup on session completion when cleanup_test_user is enabled
- Env vars: KEYCLOAK_ADMIN_USERNAME, KEYCLOAK_ADMIN_PASSWORD

System prompt:
- Explicit browser usage instructions (navigate → get_content → click → fill)
- SPA auth bypass guidance (check page content, not HTTP status)
- Screenshot instructions for evidence collection

Other:
- Pin mongo:7 in docker-compose (mongo:latest/8 segfaults on kernel 6.19)
- Add deploy/docker-compose.mailserver.yml for Postfix + Dovecot

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-03-17 19:53:55 +01:00
parent a737c36bc9
commit 37690ce734
18 changed files with 1122 additions and 215 deletions

View File

@@ -27,6 +27,14 @@ pub struct AgentConfig {
pub ssh_key_path: String,
pub keycloak_url: Option<String>,
pub keycloak_realm: Option<String>,
pub keycloak_admin_username: Option<String>,
pub keycloak_admin_password: Option<SecretString>,
// Pentest defaults
pub pentest_verification_email: Option<String>,
pub pentest_imap_host: Option<String>,
pub pentest_imap_port: Option<u16>,
pub pentest_imap_username: Option<String>,
pub pentest_imap_password: Option<SecretString>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]

View File

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

View File

@@ -150,6 +150,34 @@ pub struct PentestConfig {
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 {
@@ -163,6 +191,9 @@ pub struct PentestSession {
/// 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
@@ -187,6 +218,7 @@ impl PentestSession {
strategy,
config: None,
created_by: None,
test_user: None,
tool_invocations: 0,
tool_successes: 0,
findings_count: 0,