Skip to content

feat(security-agent): add audit report UI#4082

Open
jeanduplessis wants to merge 3 commits into
jdp/security-agent-audit-backendfrom
jdp/security-agent-audit-ui
Open

feat(security-agent): add audit report UI#4082
jeanduplessis wants to merge 3 commits into
jdp/security-agent-audit-backendfrom
jdp/security-agent-audit-ui

Conversation

@jeanduplessis

@jeanduplessis jeanduplessis commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Security Agent now has the web UI for owner-scoped Audit Reports and a refreshed management experience, stacked on the backend/API foundation in #4081.

Why this change is needed

Security owners need an interactive way to review recorded Security Finding evidence by period, repository, severity, and state. Splitting the UI keeps the deployable backend migration and API review separate from the larger visual and interaction changes.

How this is addressed

  • Adds personal and organization Audit Report routes with an interactive report page, UTC date-range selection, provenance messaging, evidence filters, and deterministic finding timelines.
  • Refreshes Security Agent dashboard, finding list, finding detail, settings, navigation, help, and action surfaces around clearer user actions and outcomes.
  • Adds supporting Security Agent UI helpers for dismissal, remediation-unavailable copy, finding-list presentation, and command invalidation.
  • Adds shared UI primitive updates plus react-day-picker for report date-range selection.

Verification

  • Reviewed the stacked diff against feat(security-agent): add audit report backend #4081 and confirmed it is limited to web routes, React components, shared UI primitives, and the UI-only package/lockfile changes.
  • No browser or manual visual verification was performed in this environment; screenshots were not captured.

Visual Changes

localhost_3000_security-agent (6) localhost_3000_security-agent (7) localhost_3000_security-agent (8) localhost_3000_security-agent (9) localhost_3000_security-agent (10) localhost_3000_security-agent (11) localhost_3000_security-agent (12) localhost_3000_security-agent (13) localhost_3000_security-agent (14) localhost_3000_security-agent (15) localhost_3000_security-agent (16) localhost_3000_security-agent (17)

Reviewer Notes

Human Reviewer Flags

  • Review after feat(security-agent): add audit report backend #4081. This PR compiles against the audit report tRPC endpoints and report types introduced there.
  • This branch changes shared UI primitives and global app styling alongside Security Agent surfaces, so visual regression scope is broader than the report page alone.
  • Confirm the final navigation and historical-access behavior matches the Audit Report guarantees introduced in feat(security-agent): add audit report backend #4081.
  • Browser screenshots were not captured during PR preparation.

Code Reviewer Agent

Code Reviewer Notes
  • Audit Report UI keeps filtering client-side so matching finding groups retain their complete in-period timelines.
  • Date range and filter state are URL-backed, with repository options derived from recorded report evidence rather than current repository selection.
  • Focus review on route gating, responsive layout, keyboard/focus behavior for report filters, and finding detail action availability copy.
  • Backend/API behavior is intentionally excluded and lives in feat(security-agent): add audit report backend #4081.

@kilo-code-bot

kilo-code-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental diff (13 files) over the previously reviewed commit — clean refactoring of state management (useState → useReducer), component extraction (badge/button variants), React 19 pattern migration (forwardRef → ref prop), and semantic token adoption. No bugs, regressions, or memory leaks.

Files Reviewed (13 files in incremental diff)
  • apps/web/src/app/(app)/organizations/[id]/security-agent/page.tsx
  • apps/web/src/app/(app)/security-agent/page.tsx
  • apps/web/src/components/code-reviews/RepositoryMultiSelect.tsx
  • apps/web/src/components/security-agent/FindingDetailDialog.tsx
  • apps/web/src/components/security-agent/SecurityAuditReportPage.test.ts
  • apps/web/src/components/security-agent/SecurityAuditReportPage.tsx
  • apps/web/src/components/security-agent/SecurityConfigSections.tsx
  • apps/web/src/components/security-agent/SecurityDashboard.tsx
  • apps/web/src/components/ui/badge-variants.ts
  • apps/web/src/components/ui/badge.tsx
  • apps/web/src/components/ui/button-variants.ts
  • apps/web/src/components/ui/button.tsx
  • apps/web/src/components/ui/calendar.tsx
Previous Review Summary (commit 4b02241)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 4b02241)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Large UI feature adding audit report pages, refreshed dashboard, and finding detail flows — all well-structured with clean React patterns, proper URL validation, and no memory leaks.

Files Reviewed (42 files)
  • apps/web/package.json
  • apps/web/src/app/(app)/organizations/[id]/security-agent/audit-report/page.tsx
  • apps/web/src/app/(app)/organizations/[id]/security-agent/layout.tsx
  • apps/web/src/app/(app)/organizations/[id]/security-agent/page.tsx
  • apps/web/src/app/(app)/security-agent/audit-report/page.tsx
  • apps/web/src/app/(app)/security-agent/layout.tsx
  • apps/web/src/app/(app)/security-agent/page.tsx
  • apps/web/src/app/globals.css
  • apps/web/src/app/layout.tsx
  • apps/web/src/components/security-agent/DismissFindingDialog.test.ts
  • apps/web/src/components/security-agent/DismissFindingDialog.tsx
  • apps/web/src/components/security-agent/FindingDetailDialog.tsx
  • apps/web/src/components/security-agent/RepositoryFilter.tsx
  • apps/web/src/components/security-agent/SecurityAgentActionBar.tsx
  • apps/web/src/components/security-agent/SecurityAgentContext.test.ts
  • apps/web/src/components/security-agent/SecurityAgentContext.tsx
  • apps/web/src/components/security-agent/SecurityAgentGitHubInstallCta.tsx
  • apps/web/src/components/security-agent/SecurityAgentLayout.tsx
  • apps/web/src/components/security-agent/SecurityAuditReportPage.test.ts
  • apps/web/src/components/security-agent/SecurityAuditReportPage.tsx
  • apps/web/src/components/security-agent/SecurityConfigForm.tsx
  • apps/web/src/components/security-agent/SecurityConfigPage.tsx
  • apps/web/src/components/security-agent/SecurityConfigSections.tsx
  • apps/web/src/components/security-agent/SecurityDashboard.tsx
  • apps/web/src/components/security-agent/SecurityFindingRow.test.ts
  • apps/web/src/components/security-agent/SecurityFindingRow.tsx
  • apps/web/src/components/security-agent/SecurityFindingsCard.tsx
  • apps/web/src/components/security-agent/SecurityFindingsPage.tsx
  • apps/web/src/components/security-agent/dismiss-finding-form.ts
  • apps/web/src/components/security-agent/manual-analysis-admission-copy.test.ts
  • apps/web/src/components/security-agent/manual-analysis-admission-copy.ts
  • apps/web/src/components/security-agent/remediation-unavailable-copy.test.ts
  • apps/web/src/components/security-agent/remediation-unavailable-copy.ts
  • apps/web/src/components/security-agent/security-agent-command-invalidation.test.ts
  • apps/web/src/components/security-agent/security-agent-command-invalidation.ts
  • apps/web/src/components/security-agent/security-finding-list-presentation.ts
  • apps/web/src/components/ui/accordion.tsx
  • apps/web/src/components/ui/badge.tsx
  • apps/web/src/components/ui/button.tsx
  • apps/web/src/components/ui/calendar.tsx
  • apps/web/src/components/ui/progress.tsx
  • pnpm-lock.yaml

Reviewed by deepseek-v4-pro-20260423 · 461,582 tokens

Review guidance: REVIEW.md from base branch jdp/security-agent-audit-backend


export function SecurityAuditReportPage() {
const trpc = useTRPC();
const searchParams = useSearchParams();

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.

Low, Functional: Filter and date-range state is read from the URL on mount but never written back. useSearchParams() is read once inside the useReducer initializer (here and the parseAuditReportFilters call below), and submit-report/filter changes only update local reducer state. There is no router.replace/pushState anywhere in the file.

The PR notes describe this state as "URL-backed," but it is one-way: a pasted deep link is honored on first load, yet once the user changes the period or a filter the address bar goes stale. They cannot bookmark or share the view they are looking at, and back/forward will not move between filter states. For an audit report this sharing case is plausible.

Suggestion: on submit-report (and optionally filter changes), push the current range and filters to the URL with router.replace. If read-only deep-linking is the intended scope, consider softening the "URL-backed" wording so it does not imply round-tripping.

return finding.status === 'ignored' && finding.ignored_reason?.startsWith('superseded:');
}

export function getAnalysisPresentation(finding: SecurityFinding): FindingStatusPresentation {

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.

Low, Design: This getAnalysisPresentation and getAnalysisStatus in FindingDetailDialog.tsx both map analysis_status + sandboxAnalysis.isExploitable + triage.suggestedAction to a label and tone, and they have already drifted. This helper omits the sandbox.extractionStatus === 'failed' and isExploitable === 'unknown' branches the dialog handles, and labels the not-exploitable case "Not exploitable" where the dialog says "No reachable path."

The result is that the same finding can read differently depending on whether it is shown in the list or the detail dialog. Only this helper is unit-tested.

Suggestion: extract one shared, tested helper for the analysis-status-to-presentation mapping (surfaces can still pick their own icon/tooltip from a common state), or at minimum add a test around the dialog's getAnalysisStatus so the two stay aligned.

}

function formatReportDateTime(value: string): string {
return formatDateTime24Hour(value).replace(/, (\d{2}:\d{2} UTC)$/, ' at $1');

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.

Nit, Design: formatReportDateTime reshapes the formatted string with .replace(/, (\d{2}:\d{2} UTC)$/, ' at $1'), which depends on the exact Intl.DateTimeFormat output shape. If an ICU/runtime version formats the parts differently the replace silently no-ops and you get the unmodified string. Degradation is graceful, just brittle. Assembling the date and time from formatToParts (or composing two formatters) would avoid relying on the output layout.

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