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,17 +1,30 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use dashmap::DashMap;
|
||||
use tokio::sync::{broadcast, watch, Semaphore};
|
||||
|
||||
use compliance_core::models::pentest::PentestEvent;
|
||||
use compliance_core::AgentConfig;
|
||||
|
||||
use crate::database::Database;
|
||||
use crate::llm::LlmClient;
|
||||
use crate::pipeline::orchestrator::PipelineOrchestrator;
|
||||
|
||||
/// Default maximum concurrent pentest sessions.
|
||||
const DEFAULT_MAX_CONCURRENT_SESSIONS: usize = 5;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ComplianceAgent {
|
||||
pub config: AgentConfig,
|
||||
pub db: Database,
|
||||
pub llm: Arc<LlmClient>,
|
||||
pub http: reqwest::Client,
|
||||
/// Per-session broadcast senders for SSE streaming.
|
||||
pub session_streams: Arc<DashMap<String, broadcast::Sender<PentestEvent>>>,
|
||||
/// Per-session pause controls (true = paused).
|
||||
pub session_pause: Arc<DashMap<String, watch::Sender<bool>>>,
|
||||
/// Semaphore limiting concurrent pentest sessions.
|
||||
pub session_semaphore: Arc<Semaphore>,
|
||||
}
|
||||
|
||||
impl ComplianceAgent {
|
||||
@@ -27,6 +40,9 @@ impl ComplianceAgent {
|
||||
db,
|
||||
llm,
|
||||
http: reqwest::Client::new(),
|
||||
session_streams: Arc::new(DashMap::new()),
|
||||
session_pause: Arc::new(DashMap::new()),
|
||||
session_semaphore: Arc::new(Semaphore::new(DEFAULT_MAX_CONCURRENT_SESSIONS)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,4 +90,54 @@ impl ComplianceAgent {
|
||||
.run_pr_review(&repo, repo_id, pr_number, base_sha, head_sha)
|
||||
.await
|
||||
}
|
||||
|
||||
// ── Session stream management ──────────────────────────────────
|
||||
|
||||
/// Register a broadcast sender for a session. Returns the sender.
|
||||
pub fn register_session_stream(&self, session_id: &str) -> broadcast::Sender<PentestEvent> {
|
||||
let (tx, _) = broadcast::channel(256);
|
||||
self.session_streams
|
||||
.insert(session_id.to_string(), tx.clone());
|
||||
tx
|
||||
}
|
||||
|
||||
/// Subscribe to a session's broadcast stream.
|
||||
pub fn subscribe_session(&self, session_id: &str) -> Option<broadcast::Receiver<PentestEvent>> {
|
||||
self.session_streams
|
||||
.get(session_id)
|
||||
.map(|tx| tx.subscribe())
|
||||
}
|
||||
|
||||
// ── Session pause/resume management ────────────────────────────
|
||||
|
||||
/// Register a pause control for a session. Returns the watch receiver.
|
||||
pub fn register_pause_control(&self, session_id: &str) -> watch::Receiver<bool> {
|
||||
let (tx, rx) = watch::channel(false);
|
||||
self.session_pause.insert(session_id.to_string(), tx);
|
||||
rx
|
||||
}
|
||||
|
||||
/// Pause a session.
|
||||
pub fn pause_session(&self, session_id: &str) -> bool {
|
||||
if let Some(tx) = self.session_pause.get(session_id) {
|
||||
tx.send(true).is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Resume a session.
|
||||
pub fn resume_session(&self, session_id: &str) -> bool {
|
||||
if let Some(tx) = self.session_pause.get(session_id) {
|
||||
tx.send(false).is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Clean up all per-session resources.
|
||||
pub fn cleanup_session(&self, session_id: &str) {
|
||||
self.session_streams.remove(session_id);
|
||||
self.session_pause.remove(session_id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user