[comp] Production Deploy#2878
Conversation
feat(people): add employment events tracking and offboarding checklist
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
There was a problem hiding this comment.
20 issues found across 55 files
Confidence score: 2/5
- Several high-confidence backend issues are concrete and user-impacting (8/10), including unsanitized ZIP entry filenames in
apps/api/src/offboarding-checklist/offboarding-export.service.tsand unscoped tenant/member deletes inapps/api/src/offboarding-checklist/access-revocation.service.tsandapps/api/src/people/people.controller.ts. - There is meaningful data integrity risk in
apps/api/src/offboarding-checklist/offboarding-checklist.service.ts:completeItemcan remain completed when evidence upload fails, leaving partial state that should be rolled back. - Additional medium issues (6–7/10) in checklist/export flows suggest regression potential rather than just style concerns, such as CSV formula injection handling and pending-offboarding count mismatches in
apps/api/src/offboarding-checklist/offboarding-export.service.tsandapps/api/src/offboarding-checklist/offboarding-checklist.service.ts. - Pay close attention to
apps/api/src/offboarding-checklist/offboarding-export.service.ts,apps/api/src/offboarding-checklist/access-revocation.service.ts,apps/api/src/people/people.controller.ts,apps/api/src/offboarding-checklist/offboarding-checklist.service.ts- security scoping, path/input sanitization, and transactional consistency need tightening before merge.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/AccessRevocationList.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/AccessRevocationList.tsx:52">
P2: Using a single `processingVendorId` causes incorrect loading/disabled behavior when multiple row actions overlap. Track processing per vendor (or globally lock actions) to avoid prematurely re-enabling controls during in-flight requests.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/people/settings/components/OffboardingChecklistSettings.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/settings/components/OffboardingChecklistSettings.tsx:57">
P2: Rolling back with a full-list snapshot can clobber other in-flight item updates. Revert only the failed item field (or revalidate from server) instead of restoring `data: previous`.</violation>
</file>
<file name="apps/api/src/offboarding-checklist/offboarding-checklist.controller.ts">
<violation number="1" location="apps/api/src/offboarding-checklist/offboarding-checklist.controller.ts:251">
P2: Use a DTO with class-validator rules for `revokeVendorAccess` body instead of an inline type, and enforce all-or-none evidence fields with a 400 response on partial payloads.</violation>
</file>
<file name="apps/api/src/offboarding-checklist/offboarding-checklist.service.ts">
<violation number="1" location="apps/api/src/offboarding-checklist/offboarding-checklist.service.ts:49">
P2: `createTemplateItem` has a race condition for `sortOrder`; concurrent creates can assign the same order value.</violation>
</file>
<file name="apps/app/src/hooks/use-access-revocations.ts">
<violation number="1" location="apps/app/src/hooks/use-access-revocations.ts:49">
P2: Add a file-size check before base64 conversion to avoid loading oversized evidence files into browser memory.</violation>
</file>
<file name="apps/api/src/offboarding-checklist/access-revocation.service.ts">
<violation number="1" location="apps/api/src/offboarding-checklist/access-revocation.service.ts:204">
P2: Avoid calling the full `getAccessRevocations` path in completion sync; it does expensive attachment fetches that are unnecessary for count checks.</violation>
</file>
<file name="apps/app/src/hooks/use-employment-evidence.ts">
<violation number="1" location="apps/app/src/hooks/use-employment-evidence.ts:32">
P2: Add a client-side file size check before `readAsDataURL` to avoid loading oversized files into memory before the server rejects them.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| return; | ||
| } | ||
|
|
||
| const { totalVendors, revokedCount } = await this.getAccessRevocations( |
There was a problem hiding this comment.
P2: Avoid calling the full getAccessRevocations path in completion sync; it does expensive attachment fetches that are unnecessary for count checks.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/access-revocation.service.ts, line 204:
<comment>Avoid calling the full `getAccessRevocations` path in completion sync; it does expensive attachment fetches that are unnecessary for count checks.</comment>
<file context>
@@ -0,0 +1,233 @@
+ return;
+ }
+
+ const { totalVendors, revokedCount } = await this.getAccessRevocations(
+ organizationId,
+ memberId,
</file context>
|
|
||
| const uploadEvidence = useCallback( | ||
| (file: File): Promise<AttachmentMetadata> => { | ||
| return new Promise((resolve, reject) => { |
There was a problem hiding this comment.
P2: Add a client-side file size check before readAsDataURL to avoid loading oversized files into memory before the server rejects them.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/hooks/use-employment-evidence.ts, line 32:
<comment>Add a client-side file size check before `readAsDataURL` to avoid loading oversized files into memory before the server rejects them.</comment>
<file context>
@@ -0,0 +1,95 @@
+
+ const uploadEvidence = useCallback(
+ (file: File): Promise<AttachmentMetadata> => {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onload = async () => {
</file context>
* feat(frameworks): show controls as default tab with requirement column Users expect to see controls first when clicking into a framework. Adds a Controls tab (default) showing all controls with their mapped requirement identifiers, keeping Requirements as a secondary tab. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(people): use valid badge variant for critical offboarding items Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Mariano Fuentes <marfuen98@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(people): ds component compatibility fixes for offboarding UI - remove redundant wrapper divs from PopoverContent (DS already renders card chrome) - remove className from PopoverContent (not accepted by DS) - use render prop on DropdownMenuTrigger to avoid nested buttons - use accent variant for Critical badge instead of destructive Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(people): override popover width for date range filter DS PopoverContent has hardcoded w-72 which clips the 380px filter content. Use inline style to override width to auto. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Mariano Fuentes <marfuen98@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(evidence-export): load automations one at a time to prevent OOM The export endpoint loaded all automation runs with full results and logs into memory simultaneously, causing V8 heap OOM at ~6 GB on large orgs. Now loads lightweight headers first, then each automation's data individually so peak memory ≈ one automation instead of all combined. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(evidence-export): paginate runs, extract mappers, eliminate duplication - Paginate loadFullAutomation in batches of 50 runs to bound JSON.parse pressure for enormous automations - Extract Prisma→normalizer mappers (toAppAutomationRun, toCustomAutomationRun) as single source of truth — eliminates duplicated mapping in service - Rewrite getTaskEvidenceSummary to reuse data loader instead of duplicating 100 lines of query + mapping code - Extract buildAutomationJson to evidence-json-builder.ts - Service: 600 → 411 lines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(evidence-export): add deterministic tiebreaker to paginated queries Offset pagination ordered only by createdAt could skip or duplicate rows when multiple runs share the same timestamp. Adding id as a secondary sort key makes the ordering deterministic across batches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(evidence-export): use cursor pagination instead of offset Offset pagination (skip) can duplicate or miss rows when new automation runs are inserted during a long export. Cursor-based pagination uses keyset lookups (WHERE id < cursor) which are stable under concurrent writes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Mariano Fuentes <marfuen98@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…callers
A customer (Josh) hit a 401 calling
POST /v1/cloud-security/findings/:id/exception with an X-API-Key:
"Marking an exception requires session authentication." The same
inline check existed on revokeException and updateAwsScanMode. With
MCP integration coming soon we want the full cloud-tests mutation
surface to be API-callable.
The reason the wall existed: AuditLog.userId + FindingException.markedById
are both String/FK to User, and API keys are org-scoped (no per-user
identity). This change introduces a shared ActingUserResolver that
attributes API key / service-token mutations to the org's oldest
owner-role member — same pattern 19+ other services in the codebase
already use for owner lookups. The audit log description prepends
`[via API key "<name>"]` so reviewers see at a glance that it was
automation, not a UI action.
What's preserved:
- Authentication unchanged (HybridAuthGuard runs as before).
- RBAC unchanged (PermissionGuard runs as before — caller still
needs integration:update scope).
- Cross-tenant isolation preserved (owner lookup scoped to the
calling org).
- Session callers: zero behavior change — resolver short-circuits
to req.userId with NO DB query. Audit description unchanged
(no [via ...] prefix).
- Existing API key writes (vendor:create, risk:create, etc.):
untouched.
- Service tokens passing x-user-id: unchanged (HybridAuthGuard
already sets req.userId, resolver short-circuits).
What changes:
- Service tokens without x-user-id: now succeed with owner-fallback
attribution (previously hit the inline 401 too).
- API key callers: now succeed with owner-fallback attribution.
- Org with no owner-role member: 400 with actionable message
("ensure your organization has at least one user with the owner
role"). Soft failure, never a 500.
Tests:
- 10 acting-user.service tests (session short-circuit, owner
fallback, cross-tenant scoping, deterministic oldest-owner pick,
no-owner soft failure, caller-label formatting)
- 12 exception.service tests (+2 for callerLabel propagation —
audit description prefix + metadata field)
- 5 NEW aws-scan-mode.service tests (idempotent no-op, AWS-only
enforcement, owner-fallback callerLabel)
- 9 NEW controller-level tests covering all 3 endpoints × 3
scenarios (session, API-key+owner, no-owner → 400)
- 253 cloud-security + auth tests pass (3 pre-existing TLS-env
failures unrelated — same suites fail on main)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ations feat(api): unblock cloud-tests mutations for API key + service token callers
…2884) - prevent CSV formula injection in export by prefixing dangerous chars - sanitize filenames in ZIP paths to prevent path traversal - add member ID to export folder names to prevent collisions - scope revocation lookup by organizationId to prevent cross-tenant access - rollback completion record if evidence upload fails - filter completion counts to enabled template items only - use @ISINT() for sortOrder DTO validation - validate date query params before building DB filters - scope attachment deletion to member and event type - show "Until {date}" when only end date is set in filter - clear file input in finally block for retry support - validate tab param against dynamically available tabs - show error state in TodosOverview on fetch failure Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@cubic-dev-ai review it |
@tofikwest I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
16 issues found across 74 files
Confidence score: 2/5
- I’m rating this as high merge risk because several high-confidence issues are user-impacting: unhandled
archiveerrors inapps/api/src/offboarding-checklist/offboarding-export.service.tscan crash exports, and unboundedfindManyin the same flow can cause memory spikes on large organizations. - There are concrete data-integrity concerns:
onDelete: Cascadeinpackages/db/prisma/schema/offboarding-checklist.prismacan remove historical completion records, and failed evidence upload inapps/api/src/offboarding-checklist/access-revocation.service.tscan leave partial revocation data behind. - Auth and state-consistency gaps could cause incorrect behavior after merge, including missing Authorization forwarding in
apps/app/src/app/api/offboarding-export/route.tsand reactivation not clearingoffboardDateinapps/api/src/integration-platform/services/generic-employee-sync.service.ts. - Pay close attention to
apps/api/src/offboarding-checklist/offboarding-export.service.ts,packages/db/prisma/schema/offboarding-checklist.prisma,apps/api/src/offboarding-checklist/access-revocation.service.ts, andapps/app/src/app/api/offboarding-export/route.ts- they contain crash, data-loss, transactional consistency, and auth-forwarding risks.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/app/src/app/(app)/[orgId]/overview/components/ToDoOverview.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/overview/components/ToDoOverview.tsx:69">
P2: The offboarding tab collapses loading/error into an empty state, so failed fetches appear as “No pending offboardings.” Handle SWR loading/error states before showing the empty-success message.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/OffboardingChecklist.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/OffboardingChecklist.tsx:73">
P2: Opening download URLs with `window.open(..., '_blank')` without `noopener,noreferrer` leaves `window.opener` exposed. Add `noopener,noreferrer` to the window features.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/frameworks/[frameworkInstanceId]/components/FrameworkControls.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/frameworks/[frameworkInstanceId]/components/FrameworkControls.tsx:177">
P2: This per-row computation repeatedly scans tasks and re-sorts evidence submissions, causing avoidable O(n×m) render-time work for larger control lists.</violation>
</file>
<file name="apps/api/src/integration-platform/services/generic-employee-sync.service.ts">
<violation number="1" location="apps/api/src/integration-platform/services/generic-employee-sync.service.ts:198">
P2: Reactivating a member does not clear `offboardDate`, so active members can remain marked as offboarded.</violation>
<violation number="2" location="apps/api/src/integration-platform/services/generic-employee-sync.service.ts:241">
P2: `startDate` is written without validating date parseability, so malformed provider values can fail sync writes.</violation>
</file>
<file name="apps/app/src/app/api/offboarding-export/route.ts">
<violation number="1" location="apps/app/src/app/api/offboarding-export/route.ts:27">
P2: Forward the incoming Authorization header to the backend export API; otherwise token-authenticated callers will be rejected.</violation>
</file>
<file name="apps/api/src/offboarding-checklist/offboarding-export.service.ts">
<violation number="1" location="apps/api/src/offboarding-checklist/offboarding-export.service.ts:33">
P1: Add explicit `archive` error handling; unhandled archiver errors can crash the export path.</violation>
<violation number="2" location="apps/api/src/offboarding-checklist/offboarding-export.service.ts:116">
P2: Vendor evidence paths are collision-prone; include a unique prefix (e.g., attachment id) in the archive filename.</violation>
<violation number="3" location="apps/api/src/offboarding-checklist/offboarding-export.service.ts:157">
P1: `exportAllOffboardings` uses unbounded `findMany`; paginate with cursor batching to avoid memory spikes on large org exports.</violation>
</file>
<file name="apps/api/src/offboarding-checklist/offboarding-checklist.service.ts">
<violation number="1" location="apps/api/src/offboarding-checklist/offboarding-checklist.service.ts:187">
P2: `evidenceRequired` is not enforced when completing an item, so required-evidence tasks can be completed without any evidence.</violation>
<violation number="2" location="apps/api/src/offboarding-checklist/offboarding-checklist.service.ts:363">
P2: Default template seeding is race-prone and can insert duplicate default items for a new organization under concurrent requests.</violation>
</file>
<file name="packages/db/prisma/schema/offboarding-checklist.prisma">
<violation number="1" location="packages/db/prisma/schema/offboarding-checklist.prisma:32">
P1: Using `onDelete: Cascade` on `templateItem` can erase historical offboarding completion records when a template item is deleted.</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/people/all/components/TeamMembersClient.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/people/all/components/TeamMembersClient.tsx:300">
P2: Status filter label can display "Active" while data is actually filtered as "All People" when offboard date filtering is applied.</violation>
</file>
<file name="apps/api/src/offboarding-checklist/access-revocation.service.ts">
<violation number="1" location="apps/api/src/offboarding-checklist/access-revocation.service.ts:108">
P1: If evidence upload fails, the revocation record is left behind because this flow does not roll back the earlier create.</violation>
<violation number="2" location="apps/api/src/offboarding-checklist/access-revocation.service.ts:143">
P2: Undoing a revocation does not delete its evidence attachments, leaving orphaned attachment data.</violation>
<violation number="3" location="apps/api/src/offboarding-checklist/access-revocation.service.ts:204">
P2: Completion sync is doing expensive full access-revocation hydration just to calculate counts, which adds avoidable overhead to each mutation.</violation>
</file>
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
| const archive = archiver('zip', { zlib: { level: 9 } }); | ||
| archive.pipe(output); | ||
|
|
||
| const members = await db.member.findMany({ |
There was a problem hiding this comment.
P1: exportAllOffboardings uses unbounded findMany; paginate with cursor batching to avoid memory spikes on large org exports.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/offboarding-export.service.ts, line 157:
<comment>`exportAllOffboardings` uses unbounded `findMany`; paginate with cursor batching to avoid memory spikes on large org exports.</comment>
<file context>
@@ -0,0 +1,214 @@
+ const archive = archiver('zip', { zlib: { level: 9 } });
+ archive.pipe(output);
+
+ const members = await db.member.findMany({
+ where: { organizationId, offboardDate: { not: null }, deactivated: true },
+ include: { user: { select: { name: true, email: true } } },
</file context>
| memberId: string; | ||
| output: NodeJS.WritableStream; | ||
| }) { | ||
| const archive = archiver('zip', { zlib: { level: 9 } }); |
There was a problem hiding this comment.
P1: Add explicit archive error handling; unhandled archiver errors can crash the export path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/offboarding-export.service.ts, line 33:
<comment>Add explicit `archive` error handling; unhandled archiver errors can crash the export path.</comment>
<file context>
@@ -0,0 +1,214 @@
+ memberId: string;
+ output: NodeJS.WritableStream;
+ }) {
+ const archive = archiver('zip', { zlib: { level: 9 } });
+ archive.pipe(output);
+
</file context>
|
|
||
| organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) | ||
| member Member @relation(fields: [memberId], references: [id], onDelete: Cascade) | ||
| templateItem OffboardingChecklistTemplate @relation(fields: [templateItemId], references: [id], onDelete: Cascade) |
There was a problem hiding this comment.
P1: Using onDelete: Cascade on templateItem can erase historical offboarding completion records when a template item is deleted.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/db/prisma/schema/offboarding-checklist.prisma, line 32:
<comment>Using `onDelete: Cascade` on `templateItem` can erase historical offboarding completion records when a template item is deleted.</comment>
<file context>
@@ -0,0 +1,57 @@
+
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
+ member Member @relation(fields: [memberId], references: [id], onDelete: Cascade)
+ templateItem OffboardingChecklistTemplate @relation(fields: [templateItemId], references: [id], onDelete: Cascade)
+ completedBy User @relation("OffboardingChecklistCompletedBy", fields: [completedById], references: [id], onDelete: Cascade)
+
</file context>
| }); | ||
|
|
||
| if (evidence) { | ||
| await this.attachmentsService.uploadAttachment( |
There was a problem hiding this comment.
P1: If evidence upload fails, the revocation record is left behind because this flow does not roll back the earlier create.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/access-revocation.service.ts, line 108:
<comment>If evidence upload fails, the revocation record is left behind because this flow does not roll back the earlier create.</comment>
<file context>
@@ -0,0 +1,233 @@
+ });
+
+ if (evidence) {
+ await this.attachmentsService.uploadAttachment(
+ organizationId,
+ revocation.id,
</file context>
| const { data: pendingData } = useApiSWR<PendingOffboardingResponse>( | ||
| '/v1/offboarding-checklist/pending', | ||
| ); | ||
| const pendingOffboardings = pendingData?.data?.members ?? []; |
There was a problem hiding this comment.
P2: The offboarding tab collapses loading/error into an empty state, so failed fetches appear as “No pending offboardings.” Handle SWR loading/error states before showing the empty-success message.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/overview/components/ToDoOverview.tsx, line 69:
<comment>The offboarding tab collapses loading/error into an empty state, so failed fetches appear as “No pending offboardings.” Handle SWR loading/error states before showing the empty-success message.</comment>
<file context>
@@ -48,6 +63,11 @@ export function ToDoOverview({
+ const { data: pendingData } = useApiSWR<PendingOffboardingResponse>(
+ '/v1/offboarding-checklist/pending',
+ );
+ const pendingOffboardings = pendingData?.data?.members ?? [];
+
const isOnboardingInProgress = !!onboardingTriggerJobId;
</file context>
| } | ||
|
|
||
| private async seedDefaultsIfNeeded(organizationId: string) { | ||
| const count = await db.offboardingChecklistTemplate.count({ |
There was a problem hiding this comment.
P2: Default template seeding is race-prone and can insert duplicate default items for a new organization under concurrent requests.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/offboarding-checklist.service.ts, line 363:
<comment>Default template seeding is race-prone and can insert duplicate default items for a new organization under concurrent requests.</comment>
<file context>
@@ -0,0 +1,384 @@
+ }
+
+ private async seedDefaultsIfNeeded(organizationId: string) {
+ const count = await db.offboardingChecklistTemplate.count({
+ where: { organizationId },
+ });
</file context>
| throw new NotFoundException('Template item not found'); | ||
| } | ||
|
|
||
| const completion = await db.offboardingChecklistCompletion.create({ |
There was a problem hiding this comment.
P2: evidenceRequired is not enforced when completing an item, so required-evidence tasks can be completed without any evidence.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/offboarding-checklist.service.ts, line 187:
<comment>`evidenceRequired` is not enforced when completing an item, so required-evidence tasks can be completed without any evidence.</comment>
<file context>
@@ -0,0 +1,384 @@
+ throw new NotFoundException('Template item not found');
+ }
+
+ const completion = await db.offboardingChecklistCompletion.create({
+ data: {
+ organizationId,
</file context>
| <SelectTrigger> | ||
| <SelectValue placeholder="Active" /> | ||
| <SelectValue placeholder="Active"> | ||
| {{ all: 'All People', active: 'Active', pending: 'Pending', deactivated: 'Deactivated' }[statusFilter] ?? 'Active'} |
There was a problem hiding this comment.
P2: Status filter label can display "Active" while data is actually filtered as "All People" when offboard date filtering is applied.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/people/all/components/TeamMembersClient.tsx, line 300:
<comment>Status filter label can display "Active" while data is actually filtered as "All People" when offboard date filtering is applied.</comment>
<file context>
@@ -254,7 +296,9 @@ export function TeamMembersClient({
<SelectTrigger>
- <SelectValue placeholder="Active" />
+ <SelectValue placeholder="Active">
+ {{ all: 'All People', active: 'Active', pending: 'Pending', deactivated: 'Deactivated' }[statusFilter] ?? 'Active'}
+ </SelectValue>
</SelectTrigger>
</file context>
| {{ all: 'All People', active: 'Active', pending: 'Pending', deactivated: 'Deactivated' }[statusFilter] ?? 'Active'} | |
| {{ all: 'All People', active: 'Active', pending: 'Pending', deactivated: 'Deactivated' }[effectiveStatusFilter] ?? 'Active'} |
| return; | ||
| } | ||
|
|
||
| const { totalVendors, revokedCount } = await this.getAccessRevocations( |
There was a problem hiding this comment.
P2: Completion sync is doing expensive full access-revocation hydration just to calculate counts, which adds avoidable overhead to each mutation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/access-revocation.service.ts, line 204:
<comment>Completion sync is doing expensive full access-revocation hydration just to calculate counts, which adds avoidable overhead to each mutation.</comment>
<file context>
@@ -0,0 +1,233 @@
+ return;
+ }
+
+ const { totalVendors, revokedCount } = await this.getAccessRevocations(
+ organizationId,
+ memberId,
</file context>
| throw new NotFoundException('Revocation record not found'); | ||
| } | ||
|
|
||
| await db.offboardingAccessRevocation.delete({ |
There was a problem hiding this comment.
P2: Undoing a revocation does not delete its evidence attachments, leaving orphaned attachment data.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/offboarding-checklist/access-revocation.service.ts, line 143:
<comment>Undoing a revocation does not delete its evidence attachments, leaving orphaned attachment data.</comment>
<file context>
@@ -0,0 +1,233 @@
+ throw new NotFoundException('Revocation record not found');
+ }
+
+ await db.offboardingAccessRevocation.delete({
+ where: { id: revocation.id },
+ });
</file context>
|
@Marfuen take a look to bug report please, a lot of finding |
Adds a pure post-processing step that runs after the AI generates a fix plan to backfill cross-step values the model does not reliably emit. Today the normalizer handles a single concrete bug: when a plan needs a service-linked role (Config, GuardDuty, Inspector, Macie, Access Analyzer, Security Hub, Detective, Backup), the AI sometimes generates CreateServiceLinkedRoleCommand without populating AWSServiceName. AWS rejects the call with a cryptic "Member must not be null" error, leaving the customer stuck on the Auto-Remediate dialog with no actionable diagnosis. The normalizer infers the right principal from a nearest-neighbor scan across the plan's other steps (deterministic, idempotent, no mutation of input). Wiring it into the AI remediation service happens in a separate commit so each phase is reviewable in isolation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends validatePlanSteps with a REQUIRED_PARAMS check that runs before the executor makes the AWS SDK call. Today AWS surfaces a cryptic "Member must not be null" when a required top-level param is missing (e.g., AWSServiceName on CreateServiceLinkedRoleCommand, ConfigurationRecorder on PutConfigurationRecorderCommand), which leaves the Auto-Remediate dialog with an unhelpful error and the operation already billed. The check is intentionally narrow — only commands where we've seen the AI omit a required param in practice and where the SDK's error is unhelpful. The error message includes the step index and command name so customers know exactly which step is broken. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nly plans
Two coordinated fixes to the AI remediation pipeline:
1. Broadens enrichEmptyState to handle plans whose actionable steps are
not Create*. Previously a plan composed of Put*/Start*/Update*/
Enable*/Attach*/Set*/Modify* steps with both currentState and
proposedState empty rendered as "{} → {}" in the Auto-Remediate
dialog. The backstop now emits configured:false → configured:true
with a willChange list for these plans. Pure Create* plans keep the
existing exists:false → exists:true / willCreate language.
2. Wires the plan normalizer into all three sites that produce a
FixPlan: generateFixPlan (happy path), refineFixPlan (happy path),
and refineFixPlan (catch fallback). The normalizer's
CreateServiceLinkedRoleCommand AWSServiceName backfill now runs on
every plan that reaches the UI or the executor, so the bug-reported
"Member must not be null" failure on the AWS Config recorder finding
is resolved.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…prompt Adds a mandatory mapping table after the existing service-linked role guidance so the AI emits AWSServiceName values in the first pass for the eight AWS services we currently auto-fix. This is a belt-and- suspenders fix on top of the deterministic plan normalizer — the normalizer guarantees correctness; this reduces the rate at which the bug occurs in the first place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… sibling form controls The MultipleSelector's `CommandList` is rendered with `absolute top-1 z-10` and floats below the input. With several selected items and a tall option list it visually overlaps form fields below — including the `@base-ui/react` Select used elsewhere in the same form (e.g. the "Fail on open alerts at severity" dropdown in the GitHub integration setup). Two interacting behaviors made that overlap turn into "click does nothing": 1. The input's `onBlur` was gated on `onScrollbar` — when the mouse was over the open list (which it is, by definition, when the list overlaps the field you're trying to click), `setOpen(false)` was skipped and the list stayed mounted. 2. The `CommandList` re-focused the input on every `mouseup`, immediately reopening the dropdown after any click that happened over it. Together this trapped `mousedown`/`mouseup` on the floating popup. base-ui's `Select.Trigger` (the field below) registers a one-shot document `mouseup` listener when it receives `mousedown` and cancels the open if the `mouseup` lands outside the trigger's bounds — which is exactly what happened: the captured `mouseup` on `CommandList` told base-ui to cancel its open, so the severity dropdown never appeared. This change: - Removes the `if (!onScrollbar)` guard so the input's `onBlur` always closes the popup. Clicking anywhere outside the input now dismisses the dropdown immediately, restoring the natural focus contract. - Drops the `CommandList` `onMouseUp` re-focus that re-trapped the input. `CommandItem.onMouseDown` already calls `e.preventDefault()`, so item selection still keeps the input focused. The previous handler only mattered for stray clicks/scrollbar drags on the popup itself — and was the exact mechanism that made clicks on overlapped sibling controls (like the base-ui Select) unresponsive. Reproducible by: 1. Setting up the GitHub integration. 2. Picking one or more repositories so `CommandList` opens with options. 3. Clicking "Fail on open alerts at severity" — before this change the dropdown does not open; after this change it opens on the first click. Verified: `packages/ui` typecheck + build pass. No `MultipleSelector` consumer relies on `onMouseUp` re-focus (it was an internal CommandList prop, not part of the public API). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-command REQUIRED_PARAMS map and the SLR plan normalizer cover
the bugs we know about — but the AI can omit a required param on ANY
AWS command in ANY future plan, and we shouldn't ship a fix that needs
a code change every time a new finding hits this class of bug.
This adds a universal escape hatch:
1. New `looksLikeValidationError(message)` detector that pattern-matches
AWS's standard validation wording ("Member must not be null",
"failed to satisfy constraint", "ValidationException", etc.) — no
per-command enumeration.
2. New `StepRepairFn` callback contract on `executePlanSteps`. When a
step fails AND the rules-based fixer in `tryAutoFixValidationError`
can't recover AND the error looks like a validation error, the
executor calls the repair callback exactly once with the failing
step, the AWS error, and the step index. If the callback returns a
refined step with different params (same service + command), the
executor retries with it.
3. New `AiRemediationService.refineStepFromError` that fulfills the
contract — sends the failing step, AWS error verbatim, neighbor
steps, and finding context to the model and asks for a corrected
single step. Defensive guard: discards the refinement if the model
swaps to a different service or command.
4. `RemediationService.executeRemediation` wires the repair callback
at the fix-step execution site only (not reads or rollback) so the
AI cost is paid only on user-initiated fix attempts that actually
need it.
This is the universal fix the customer asked for: it uses AWS's own
validation as ground truth, scales to any future AWS command without
code changes, and pays the Opus cost only on the failure path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-params fix(cloud-tests): auto-remediate null AWSServiceName + empty state diff
…severity-dropdown [dev] [tofikwest] tofik/fix-github-multiselect-severity-dropdown
This is an automated pull request to release the candidate branch into production, which will trigger a deployment.
It was created by the [Production PR] action.
Summary by cubic
Ships the offboarding checklist with access revocation tracking, evidence uploads/export, and onboard/offboard date tracking across People and integrations. Also adds universal step‑repair for Cloud Security auto‑remediation, enables API key/service token mutations with clear audit attribution, sets Frameworks to default to a Controls view, fixes OOMs in task evidence export, hardens offboarding exports/validations, and fixes a multi‑select dropdown focus trap.
New Features
@trycompai/design-system→1.1.19.Bug Fixes
Written for commit b837dfb. Summary will update on new commits. Review in cubic