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:
@@ -270,8 +270,17 @@ pub fn AttackChainView(
|
||||
let duration = compute_duration(step);
|
||||
let started = step.get("started_at").map(format_bson_time).unwrap_or_default();
|
||||
|
||||
let tool_input_json = step.get("tool_input")
|
||||
.map(|v| serde_json::to_string_pretty(v).unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
let tool_output_json = step.get("tool_output")
|
||||
.map(|v| serde_json::to_string_pretty(v).unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
let is_pending = status == "pending";
|
||||
let is_node_running = status == "running";
|
||||
let pending_cls = if is_pending { " is-pending" } else { "" };
|
||||
let running_cls = if is_node_running { " ac-node-running" } else { "" };
|
||||
|
||||
let duration_cls = if status == "running" { "ac-tool-duration running-text" } else { "ac-tool-duration" };
|
||||
let duration_text = if status == "running" {
|
||||
@@ -299,7 +308,7 @@ pub fn AttackChainView(
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
class: "ac-tool-row{pending_cls}",
|
||||
class: "ac-tool-row{pending_cls}{running_cls}",
|
||||
id: "{row_id}",
|
||||
onclick: move |_| {
|
||||
if is_pending { return; }
|
||||
@@ -321,30 +330,40 @@ pub fn AttackChainView(
|
||||
div {
|
||||
class: "ac-tool-detail",
|
||||
id: "{detail_id_clone}",
|
||||
if !reasoning.is_empty() || !started.is_empty() {
|
||||
div { class: "ac-tool-detail-inner",
|
||||
if !reasoning.is_empty() {
|
||||
div { class: "ac-reasoning-block", "{reasoning}" }
|
||||
}
|
||||
if !started.is_empty() {
|
||||
div { class: "ac-detail-grid",
|
||||
span { class: "ac-detail-label", "Started" }
|
||||
span { class: "ac-detail-value", "{started}" }
|
||||
if !duration_text.is_empty() && status != "running" && duration_text != "\u{2014}" {
|
||||
span { class: "ac-detail-label", "Duration" }
|
||||
span { class: "ac-detail-value", "{duration_text}" }
|
||||
}
|
||||
span { class: "ac-detail-label", "Status" }
|
||||
if status == "completed" {
|
||||
span { class: "ac-detail-value", style: "color: var(--success, #16a34a);", "Completed" }
|
||||
} else if status == "failed" {
|
||||
span { class: "ac-detail-value", style: "color: var(--danger, #dc2626);", "Failed" }
|
||||
} else if status == "running" {
|
||||
span { class: "ac-detail-value", style: "color: var(--warning, #d97706);", "Running" }
|
||||
} else {
|
||||
span { class: "ac-detail-value", "{status}" }
|
||||
}
|
||||
div { class: "ac-tool-detail-inner",
|
||||
if !reasoning.is_empty() {
|
||||
div { class: "ac-reasoning-block", "{reasoning}" }
|
||||
}
|
||||
if !started.is_empty() {
|
||||
div { class: "ac-detail-grid",
|
||||
span { class: "ac-detail-label", "Started" }
|
||||
span { class: "ac-detail-value", "{started}" }
|
||||
if !duration_text.is_empty() && status != "running" && duration_text != "\u{2014}" {
|
||||
span { class: "ac-detail-label", "Duration" }
|
||||
span { class: "ac-detail-value", "{duration_text}" }
|
||||
}
|
||||
span { class: "ac-detail-label", "Status" }
|
||||
if status == "completed" {
|
||||
span { class: "ac-detail-value", style: "color: var(--success, #16a34a);", "Completed" }
|
||||
} else if status == "failed" {
|
||||
span { class: "ac-detail-value", style: "color: var(--danger, #dc2626);", "Failed" }
|
||||
} else if status == "running" {
|
||||
span { class: "ac-detail-value", style: "color: var(--warning, #d97706);", "Running" }
|
||||
} else {
|
||||
span { class: "ac-detail-value", "{status}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
if !tool_input_json.is_empty() && tool_input_json != "null" {
|
||||
div { class: "ac-data-section",
|
||||
div { class: "ac-data-label", "Input" }
|
||||
pre { class: "ac-data-block", "{tool_input_json}" }
|
||||
}
|
||||
}
|
||||
if !tool_output_json.is_empty() && tool_output_json != "null" {
|
||||
div { class: "ac-data-section",
|
||||
div { class: "ac-data-label", "Output" }
|
||||
pre { class: "ac-data-block", "{tool_output_json}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user