Skip to content

FEAT: Scan results redesign and live scan attacks in Chat - #4032

Open
Richard Lundeen (richlundeen) wants to merge 3 commits into
microsoft:mainfrom
richlundeen:richlundeen-scanner-stack-3-redesign-and-live-chat
Open

Richard Lundeen (richlundeen) wants to merge 3 commits into
microsoft:mainfrom
richlundeen:richlundeen-scanner-stack-3-redesign-and-live-chat

Conversation

@richlundeen

Copy link
Copy Markdown
Contributor

Stacked on #4031 (which is stacked on #4030) — review only the commits after 8831052.

Description

Redesigns the scan results page around the scanner prototype and makes Chat the single conversation view for scan attacks, whether they are still running or finished.

  • Run page: the Operation shows as parent context above the title; the top summary grid is gone. Errors and notices stay explicit, but a single attack's own error is not repeated as a run error. The progress area has elapsed time, a stable ETA line ("Estimating time remaining"), and a View live attacks (N) popover. When the scan finishes it collapses in place (grid-rows/opacity, reduced-motion aware, hidden and inert), so results never jump.
  • Single atomic attack runs (e.g. technique.execute) show that attack as one framed card that stays mounted from preparing through running to completed. Multi-group runs keep the groups, datasets/objectives and configuration sections.
  • One attack details component (inline card and dialog, via ScenarioAttackDetails): Objective and Outcome (score popover, rationale, timing line, error), Technique / Objective scorer / Dataset identities, Findings only when useAttackFindings returns some, then Open conversation / Watch live conversation and Attach to findings (defaults to the run's Operation). The dialog has a single X close and the Operation link above its title.
  • Result tables are headerless with no result-type column. Rows open attack details, outcome badges open the score, and rows show the technique shorthand (also in the objective dialog).
  • Chat for live attacks: when the loaded attack is in_progress, useLiveAttackMetadata polls metadata at the scan interval while Chat re-reads the transcript and conversation list. An Attack in progress bar replaces the prompt bar. When the attack finishes, its saved result reloads in place on the same URL. A failed refresh keeps loaded messages and offers Retry. Switching branches never shows the previous branch.
  • MessageList uses one policy: open at the latest message, then follow new messages only within 48 px of the end.
  • Routing: every scan conversation link targets /attack/chat/:attack/conversations/:cid?scenarioResultId=. /scanner/history/:run/conversations/:cid redirects there (ScanConversationRedirect). ScenarioConversationPage, ScenarioRunOverview and ObjectiveScorerDetails are removed.
  • Pure layout rules live in scenarioRunLayout.ts: single-attack detection, live attack grouping, interrupted conversations, and conversation → attack lookup.

Layer 2 files touched where required: AtomicAttackGroupsSection (technique names, shared execution count, and restored metric column styling), ScenarioRunHeader (Operation link, "Rerun with changes"), ScenarioRunNotices, ScenarioRunProgress, AttackDetailsDialog, and ScenarioRunPage.styles.

Verified in a browser against a real local backend (in-memory DB, slow echo target, substring scorer), at 1360 px and 390 px: technique.execute live → saved in Chat on the same URL; a three-attack airt.rapid_response run whose results heading stayed fixed from 0 → 1 → 2 completed; findings and Operation links; no horizontal overflow; zero console errors on the production build.

- GET /api/attacks/{id}/findings lists findings linked to an attack across Operations,
  backed by a new FindingEvidenceEntries.attack_result_id index (Alembic b5d7f9a1c3e6).
- Attack read APIs (summary, metadata, conversations, messages) resolve scan attacks that
  are still running through a read-only LiveAttackLookup provided by ScenarioRunService.
  Saved results always win; summaries/metadata expose in_progress and scenario_result_id.
- ScenarioActiveConversation.conversation_ids lists every objective conversation so far.
- ScenarioProgressScore carries score_category for progress results and hierarchy nodes.
- Frontend types and attacksApi.getAttackFindings for later layers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Split ScenarioRunPage into section components and hooks, and add the shared
blocks the scan results redesign builds on: OperationParentLink, ScanStatusBadge,
OutcomeBadge progress labels and score popover, ScoreDetails over a narrow
ScoreSummary, DetailFacts, IdentityDisclosure, AttackActivity,
formatAttemptTiming, useAttackFindings, and AttachToFindingsButton.
Existing pages adopt them only where output is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Run page: Operation as parent context above the title, no summary grid,
  explicit notices with a single attack's own error not repeated as a run error,
  and a progress area (elapsed, ETA, "View live attacks") that collapses in place.
- A run of one atomic attack shows that attack as one framed card from preparing
  through completion; other runs keep groups, objectives and configuration.
- One attack details component (inline card and dialog): Objective and Outcome
  with score, technique/scorer/dataset identities, findings when present,
  conversation link and Attach to findings. Result rows open these details.
- Chat is the single conversation view for running and finished scan attacks:
  in-progress bar, polling of metadata, transcript and conversations, and an
  in-place reload when the attack finishes. Old scan conversation URLs redirect.
- MessageList follows new messages only while the reader is near the end.
- Remove ScenarioConversationPage, ScenarioRunOverview and ObjectiveScorerDetails.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 7, 2026 03:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved issues cause 404s when opening cancelled conversations, hide recent messages when long live transcripts switch to saved paging, and discard conversation-list responses when reads exceed the polling interval.

3 open issues
What changed in this PR

Redesigns PyRIT’s scan results experience and makes Chat the shared viewer for running and completed scan attacks, building on the backend and shared-component work in #4030 and #4031.

Changes:

  • Reorganizes scan results around attack details, Operation context, progress, and linked findings.
  • Adds live Chat polling, completion transitions, and redirects from older scan conversation URLs.
  • Adds supporting API contracts, finding lookups, shared presentation components, tests, and documentation.
File Description
tests/​unit/​memory/​test_score_participation_migration.py Allows a newer migration head.
tests/​unit/​memory/​test_findings.py Tests cross-Operation attack findings.
tests/​unit/​memory/​test_finding_evidence_attack_index_migration.py Tests index migration and portability.
tests/​unit/​memory/​memory_interface/​test_interface_scenario_progress.py Verifies score categories in progress.
tests/​unit/​backend/​test_scenario_resume.py Tests live-to-saved attack reads.
pyrit/​models/​scenario_progress.py Adds categories and live conversation IDs.
pyrit/​memory/​memory_models.py Declares the attack-evidence index.
pyrit/​memory/​memory_interface.py Adds finding lookup and shared reference paging.
pyrit/​memory/​alembic/​versions/​b5d7f9a1c3e6_index_finding_evidence_attack_result.py Creates the attack-evidence index.
pyrit/​backend/​services/​scenario_run_service.py Exposes live attack lookup.
pyrit/​backend/​services/​saved_conversation_read_service.py Accepts injectable conversation references.
pyrit/​backend/​services/​operation_service.py Returns findings linked to attacks.
pyrit/​backend/​services/​live_attack_reader.py Defines read-only live attack projections.
pyrit/​backend/​routes/​attacks.py Adds the attack findings endpoint.
pyrit/​backend/​README.md Documents live reads and findings.
pyrit/​backend/​models/​operations.py Defines attack findings responses.
pyrit/​backend/​models/​attacks.py Adds live status and scan provenance.
pyrit/​backend/​mappers/​attack_mappers.py Maps live status and provenance.
frontend/​src/​utils/​scoreSummary.ts Normalizes score presentation data.
frontend/​src/​utils/​scoreSummary.test.ts Tests score normalization.
frontend/​src/​utils/​routeParams.ts Removes the old conversation route helper.
frontend/​src/​types/​index.ts Extends live attack and findings contracts.
frontend/​src/​services/​api.ts Adds attack findings requests.
frontend/​src/​services/​api.test.ts Tests findings requests and failures.
frontend/​src/​hooks/​useScenarioRunControls.ts Extracts rerun, cancel, and resume controls.
frontend/​src/​hooks/​useScenarioRunAttackDetails.ts Manages routed details and focus return.
frontend/​src/​hooks/​useLiveAttackMetadata.ts Polls running attack metadata.
frontend/​src/​hooks/​useLiveAttackMetadata.test.tsx Tests polling lifecycle and recovery.
frontend/​src/​hooks/​useAttackFindings.ts Loads and refreshes linked findings.
frontend/​src/​hooks/​useAttackFindings.test.tsx Tests findings loading and isolation.
frontend/​src/​components/​ScenarioSuites/​ScenarioSuiteExecutionPage.tsx Uses shared scan status badges.
frontend/​src/​components/​Scenarios/​ScenarioTechniqueSection.tsx Reuses identity disclosure styles.
frontend/​src/​components/​Scenarios/​ScenarioRunTiming.tsx Keeps an estimating-time placeholder.
frontend/​src/​components/​Scenarios/​ScenarioRunSavedConversations.tsx Links interrupted conversations to Chat.
frontend/​src/​components/​Scenarios/​ScenarioRunProgress.tsx Combines progress, timing, and live attacks.
frontend/​src/​components/​Scenarios/​ScenarioRunPage.styles.ts Styles the redesigned run layout.
frontend/​src/​components/​Scenarios/​ScenarioRunObjectivesSection.tsx Presents datasets and objective totals.
frontend/​src/​components/​Scenarios/​ScenarioRunNotices.tsx Consolidates errors and run notices.
frontend/​src/​components/​Scenarios/​scenarioRunNavigation.ts Centralizes run back-link selection.
frontend/​src/​components/​Scenarios/​scenarioRunNavigation.test.ts Tests back-link destinations.
frontend/​src/​components/​Scenarios/​scenarioRunLayout.ts Defines attack layout and lookup rules.
frontend/​src/​components/​Scenarios/​scenarioRunLayout.test.ts Tests layout and conversation lookup.
frontend/​src/​components/​Scenarios/​ScenarioRunHeader.tsx Adds Operation context and run controls.
frontend/​src/​components/​Scenarios/​ScenarioRunDialogs.tsx Updates objective and cancellation dialogs.
frontend/​src/​components/​Scenarios/​ScenarioRunConfigurationSection.tsx Extracts saved configuration disclosure.
frontend/​src/​components/​Scenarios/​ScenarioResultHierarchy.tsx Removes outdated interaction guidance.
frontend/​src/​components/​Scenarios/​ScenarioResultHierarchy.test.tsx Updates row interaction expectations.
frontend/​src/​components/​Scenarios/​scenarioHierarchy.ts Centralizes execution totals.
frontend/​src/​components/​Scenarios/​ScenarioConversationPage.tsx Removes the separate conversation viewer.
frontend/​src/​components/​Scenarios/​ScenarioConversationPage.transitions.test.tsx Removes old viewer transition tests.
frontend/​src/​components/​Scenarios/​ScenarioConversationPage.test.tsx Removes old viewer tests.
frontend/​src/​components/​Scenarios/​ScenarioAttackDetails.tsx Resolves shared scan attack details.
frontend/​src/​components/​Scenarios/​ScanConversationRedirect.tsx Redirects legacy conversation URLs.
frontend/​src/​components/​Scenarios/​ScanConversationRedirect.test.tsx Tests redirects and lookup states.
frontend/​src/​components/​Scenarios/​LiveAttacksPopover.tsx Lists running attacks and Chat links.
frontend/​src/​components/​Scenarios/​AttackExecutionTable.styles.ts Compacts result table styling.
frontend/​src/​components/​Scenarios/​AttackDetailsDialog.tsx Wraps shared details with Operation context.
frontend/​src/​components/​Scenarios/​AttackActivity.tsx Adds a reusable activity indicator.
frontend/​src/​components/​Scenarios/​AttackActivity.test.tsx Tests activity labels.
frontend/​src/​components/​Scenarios/​AttackActivity.styles.ts Styles reduced-motion-aware activity.
frontend/​src/​components/​ScanStatusBadge.tsx Centralizes scan lifecycle badges.
frontend/​src/​components/​ScanStatusBadge.test.tsx Tests status labels and icons.
frontend/​src/​components/​Registry/​RegistryIdentityRow.tsx Reuses shared identity disclosure.
frontend/​src/​components/​Registry/​RegistryIdentityRow.styles.ts Removes extracted disclosure styles.
frontend/​src/​components/​Registry/​IdentityDisclosure.tsx Adds reusable identity JSON disclosure.
frontend/​src/​components/​Registry/​IdentityDisclosure.test.tsx Tests disclosure interaction and focus.
frontend/​src/​components/​Registry/​IdentityDisclosure.styles.ts Styles identity disclosures.
frontend/​src/​components/​OutcomeBadge.tsx Adds pending states and score popovers.
frontend/​src/​components/​OutcomeBadge.test.tsx Tests labels and score interactions.
frontend/​src/​components/​OutcomeBadge.styles.ts Styles pending states and score triggers.
frontend/​src/​components/​Operations/​OperationParentLink.tsx Adds reusable Operation context links.
frontend/​src/​components/​Operations/​OperationParentLink.test.tsx Tests links and missing identities.
frontend/​src/​components/​Operations/​OperationParentLink.styles.ts Styles Operation context links.
frontend/​src/​components/​Home/​Home.tsx Uses shared scan status badges.
frontend/​src/​components/​DetailFacts.tsx Adds aligned detail label/value pairs.
frontend/​src/​components/​DetailFacts.test.tsx Tests description-list semantics.
frontend/​src/​components/​DetailFacts.styles.ts Adds responsive detail layouts.
frontend/​src/​components/​Chat/​ScoreDetails.tsx Extracts shared score details.
frontend/​src/​components/​Chat/​ScoreDetails.test.tsx Tests score detail presentation.
frontend/​src/​components/​Chat/​ScoreDetails.styles.ts Extracts score popover styles.
frontend/​src/​components/​Chat/​MessageList.test.tsx Tests near-end scrolling behavior.
frontend/​src/​components/​Chat/​MessageList.styles.ts Removes extracted score styles.
frontend/​src/​components/​Chat/​FindingEvidenceDialog.tsx Reports completed attachments to callers.
frontend/​src/​components/​Chat/​ConversationPanel.tsx Adds live conversation-list polling.
frontend/​src/​components/​Chat/​ConversationPanel.test.tsx Tests polling recovery and row retention.
frontend/​src/​components/​Chat/​ChatWindow.tsx Integrates live polling and progress UI.
frontend/​src/​components/​Chat/​AttackInProgressBar.tsx Replaces input during live attacks.
frontend/​src/​components/​Chat/​AttackInProgressBar.styles.ts Styles the live attack bar.
frontend/​src/​components/​Chat/​AttachToFindingsButton.tsx Wraps the finding attachment workflow.
frontend/​src/​components/​Chat/​AttachToFindingsButton.test.tsx Tests attachment and focus return.
frontend/​src/​components/​Chat/​AttachToFindingsButton.styles.ts Adds attachment button touch sizing.
frontend/​src/​components/​AttackResults/​ObjectiveScorerDetails.tsx Removes the previous scorer details component.
frontend/​src/​components/​AttackResults/​ObjectiveScorerDetails.styles.ts Removes obsolete scorer styles.
frontend/​src/​components/​AttackResults/​attackAttemptFormatting.ts Adds retry and timing formatting.
frontend/​src/​components/​AttackResults/​attackAttemptFormatting.test.ts Tests retry and timing formatting.
frontend/​src/​components/​AttackResults/​AttackAttemptDetails.styles.ts Styles redesigned attack detail cards.
frontend/​src/​App.tsx Integrates live metadata and legacy redirects.
frontend/​src/​App.test.tsx Tests live-to-saved metadata transitions.
frontend/​src/​App.labels.test.tsx Verifies saved Operation attribution.
frontend/​README.md Documents redesigned results and live Chat.
doc/​gui/​0_gui.md Updates scan viewing and rerun guidance.

Review effort: Balanced

activeConversationId,
findingEvidenceId,
messagePageSize: executionReadOnly ? SAVED_MESSAGE_PAGE_SIZE : undefined,
messagePageSize: pagesSavedEvidence ? SAVED_MESSAGE_PAGE_SIZE : undefined,
const [pollCount, setPollCount] = useState(0)
useEffect(() => {
if (!pollIntervalMs || !attackResultId) return
const timer = setInterval(() => { setPollCount((count: number) => count + 1) }, pollIntervalMs)
Comment on lines +30 to +31
<Link to={attackConversationRoutePath(conversation.attack_result_id, conversation.conversation_id, scenarioResultId)}
state={conversationState}>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants