Skip to content

[dev] [carhartlewis] lewis/comp-people-fix#2596

Merged
carhartlewis merged 4 commits into
mainfrom
lewis/comp-people-fix
Apr 19, 2026
Merged

[dev] [carhartlewis] lewis/comp-people-fix#2596
carhartlewis merged 4 commits into
mainfrom
lewis/comp-people-fix

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

This is an automated pull request to merge lewis/comp-people-fix into dev.
It was created by the [Auto Pull Request] action.

@mintlify
Copy link
Copy Markdown
Contributor

mintlify Bot commented Apr 19, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
CompAI 🟢 Ready View Preview Apr 19, 2026, 11:47 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comp-framework-editor Ready Ready Preview, Comment Apr 19, 2026 0:28am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app Skipped Skipped Apr 19, 2026 0:28am
portal Skipped Skipped Apr 19, 2026 0:28am

Request Review

Comment thread apps/app/src/app/(app)/[orgId]/overview/components/FindingsTab.tsx
  Findings were scattered across ~7 entry points (Tasks, People directory,
  People Tasks, People Devices, People Chart, Documents/evidence form types,
  Questionnaire context, Admin). Consolidate everything into a dedicated
  `/overview/findings` route so auditors raise findings in one place and
  everyone else sees one list with deep-links back to the linked item.

  Highlights

  - Schema: drop `FindingScope`; add `FindingSeverity`, `FindingArea`; add
    nullable FKs for policy / vendor / risk / member / device alongside
    existing task / evidence-submission / evidence-form-type targets.
    Migration backfills legacy `scope` rows onto `area = 'people'`.
  - API: rewrite FindingsService, audit service, notifier, and controllers
    around the unified target validator (exactly one of 8 targets or an
    area). Single `GET /v1/findings` supports filtering by status, severity,
    area, and any target FK. Admin controller reuses the same DTO.
  - Permissions: `finding:create` and `finding:delete` are auditor-only;
    owners/admins keep `read` + `update` so they can transition status.
  - Frontend
    - New `/overview/findings` route with Link-based tabs so the dashboard
      no longer loads findings data. Open-count badge on the Findings tab.
    - DS-styled `FindingsTab` table with search + status / severity /
      framework filters, DS `Empty` state, 360px balanced columns, and
      truncated content with a hover tooltip.
    - `CreateFindingSheet`: target-type picker (task / policy / vendor /
      risk / person / device / document type / area) with live comboboxes
      backed by existing endpoints, capitalised labels, and
      auto-selection of the org's framework when only one is configured.
    - `FindingDetailSheet`: edit content (auditor-only), change status /
      severity, add revision note, view activity log, and delete. Content
      renders as read-only for non-auditors.
    - `use-findings-api` collapsed to `useOrganizationFindings`,
      `useFindingHistory`, `useFindingTemplates`, `useFindingActions`.
  - Deletions: `tasks/[taskId]/components/findings/` (whole folder),
    `PeopleFindingsUnifiedList`, `DocumentFindingsSection`,
    `FindingsOverview`, plus call-site cleanup in SingleTask,
    CompanyFormPageClient, people/page, and PeoplePageTabs.
  - Admin: old `FindingForm` removed; admin `FindingsTab` now reuses the
    unified `CreateFindingSheet` via a `createFn` override that targets
    `/v1/admin/organizations/:orgId/findings`.
  - People perf: wrap `TeamMembers` RSC in `<Suspense>` with a skeleton so
    the tabs paint immediately; `DevicesTabContent` renders agent devices
    right away and shows a small loading pill while the slower Fleet SWR
    resolves. Dev-only 3s delay in `useFleetHosts` for local testing.
  - Audit log: drop the "Admin"/"Auditor" prefix from finding descriptions
    in `extractFindingDescription` — the actor name already says it.
  - DX: `packages/db/scripts/seed-load-test.ts` seeds ~100 members, 25
    devices, and a 10×10 org-chart grid for local load testing.
  - Misc: auditor view "Export All Evidence" swapped from broken
    Popover-over-render-Button to a proper DS `Sheet`; local DS patch
    adding `nativeButton={false}` to pagination `ButtonPrimitive`s while
    the upstream fix lands.
  - Tests: placeholder specs replaced with real coverage for the target
    validator, notifier recipient resolution, admin findings tab, and the
    unified FindingsTab (empty state + auditor-gated create).
…b functionality

- Modified the deep link format in `finding-notifier.service.ts` to direct users to the Findings page with the finding sheet pre-opened.
- Enhanced `FindingsTab.tsx` to support deep linking by auto-opening the specified finding's sheet when the page loads, and removing the query parameter to prevent reopening on refresh.
- Integrated `useRouter` and `useSearchParams` from Next.js for improved navigation and state management.
… sharing functionality

- Implemented an AlertDialog for confirming the deletion of findings, enhancing user experience by preventing accidental deletions.
- Added a "Copy link" button to share the finding's link, allowing users to easily share findings with their team.
- Updated the delete button to open the confirmation dialog instead of directly deleting the finding.
`getTaskRecipients` was using `user.role != 'admin'` (better-auth platform
admin) in the where clause, which effectively matched every active
non-platform-admin member of the org. That meant a task-scoped finding
would email every employee/contractor/auditor/custom-role member with a
200-char preview of the finding content plus a deep link — rather than
just the people who can actually act on it.

This mirrors what the policy/vendor/risk/device branches already do:
fetch the target's assignee and union with org owners/admins via
`includeAdmins`. Finding content is now only disclosed to stakeholders
of that specific task.

Pre-existing behaviour (not introduced by the unified-findings PR) but
worth fixing here since it's a concrete over-share of audit content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@carhartlewis
Copy link
Copy Markdown
Contributor

carhartlewis commented Apr 19, 2026

Security Review — feat(findings): unify findings branch

Scope: changes introduced by this PR vs main.

Summary

No HIGH or MEDIUM confidence vulnerabilities (≥ 8/10) introduced by this PR.

Candidates investigated

# File Claim Verdict
1 apps/api/src/findings/finding-notifier.service.tsgetTaskRecipients Task-finding notifications fan out to every active non-platform-admin
member of the org (employees, contractors, etc.), each receiving a 200-char content preview + deep link. Pre-existing (identical `OR: [{ user: { role:
{ not: 'admin' } } }, { role: { contains: 'owner' } }]query existed onmainingetTaskAssigneeAndAdmins). **Fixed in this branch** (commit 2db2f7b`)
— now mirrors the policy/vendor/risk/device branches by notifying owners/admins + task assignee only.

Positive confirmations (verified secure in this PR)

  • Org-scoping on mutations. FindingsService.findById, update, delete, getActivity, and the target resolver use findFirst({ where: { id, organizationId } }) before any mutation. No findUnique(id) that would allow cross-tenant access.
  • Target FK validation. resolveTarget validates each supplied target FK (task/policy/vendor/risk/member/device/evidenceSubmission) is in the caller's
    org before attaching. Cross-tenant target attachment is prevented.
  • DTO validation. ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }) + class-validator decorators on CreateFindingDto /
    UpdateFindingDto. Enum filters via Object.values().includes(...) on status, area, severity. ValidateFindingIdPipe enforces fnd_[a-z0-9]+.
  • Permission gating. Every customer-facing endpoint on FindingsController has @UseGuards(HybridAuthGuard, PermissionGuard) +
    @RequirePermission('finding', ...). Admin controller retains PlatformAdminGuard.
  • Permission tightening. finding:create and finding:delete removed from owner/admin; only auditor + platform admin can create/delete findings.
  • Deep-link safety. buildFindingDeepLink returns /{orgId}/overview/findings?open={findingId}. Both params are non-secret, server-generated; no token,
    no redirect-back. FindingsTab only opens the detail sheet if the finding is present in the org-scoped list.
  • Share-link button. Uses window.location.origin + the same scoped route; no secrets or tokens embedded in the URL.
  • No SQL injection vectors. All queries use Prisma; the migration SQL is static with no dynamic input.
  • Cascade deletes. onDelete: Cascade on Finding FKs to task/evidenceSubmission/policy/vendor/risk/member/device is intentional (dependent findings
    are removed when target is gone). Cannot cross tenant boundaries because the target FKs themselves are org-scoped.
  • Route guards preserved. apps/app/src/app/(app)/[orgId]/overview/layout.tsx still calls await requireRoutePermission('overview', orgId).
  • Audit log content. AuditLog.data.previousContent / newContent are written server-side and scoped by organizationId on reads; no cross-tenant
    exposure.
  • Notifier unsubscribe honoured. isUserUnsubscribed(..., 'findingNotifications', organizationId) checked before send.

Recommendation

Approve from a security standpoint.

@carhartlewis carhartlewis merged commit cf4f782 into main Apr 19, 2026
14 checks passed
@carhartlewis carhartlewis deleted the lewis/comp-people-fix branch April 19, 2026 12:49
@claudfuen
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.24.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants