Skip to content

Conversation

@github-actions
Copy link
Contributor

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.

…ks (#2044)

Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
@vercel
Copy link

vercel bot commented Jan 23, 2026

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

Project Deployment Review Updated (UTC)
app (staging) Ready Ready Preview, Comment Jan 27, 2026 9:47pm
1 Skipped Deployment
Project Deployment Review Updated (UTC)
portal (staging) Skipped Skipped Jan 27, 2026 9:47pm

Request Review

@cursor
Copy link

cursor bot commented Jan 23, 2026

PR Summary

Introduces core compliance workflows and notifications across the API.

  • Adds Findings and Finding Templates modules with CRUD, validation pipes, audit logging, and notifier service (Novu in‑app + email)
  • Implements Evidence Export (task/organization): endpoints to fetch summaries and export PDFs/ZIPs with redaction and filename sanitization; exposes Content-Disposition via CORS
  • Enhances email system: Resend client with attachments; new templates for finding notifications, task status/assignee (single/bulk), and training completion
  • Adds bulk task status/assignee endpoints and a task notifier service; refactors modules (forwardRef) and injects Novu
  • Misc: order task attachments by newest first; app/module wiring for new modules (EvidenceExport, Findings, FindingTemplate, Training); add safe-stable-stringify dep; add Resend env vars in .env.example

Written by Cursor Bugbot for commit 5dbf5ba. This will update automatically on new commits. Configure here.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

* feat(training): implement training completion email with certificate attachment

* feat(training): enhance training certificate generation with member validation

* feat(training): add internal API token validation for certificate generation

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
cursor[bot]

This comment was marked as outdated.

…tion (#2047)

* fix(onboarding): clarify risk category requirements in onboarding helper

* fix(onboarding): refine category value instructions in onboarding helper

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
* feat(evidence-export): implement evidence export functionality with PDF and ZIP downloads

* feat(tasks): add success and error toast notifications for evidence download

* refactor(evidence-export): improve redaction logic for Map and Set types

* fix(evidence-export): enhance filename sanitization to handle non-ASCII characters

* fix(evidence-export): include ID suffix in folder names to prevent collisions

* fix(evidence-export): enhance redaction logic to handle sensitive keys

* fix(evidence-export): use safe stringify for JSON serialization to handle BigInt and circular references

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
};
Copy link

Choose a reason for hiding this comment

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

Certificate download silently fails without user feedback

Medium Severity

The handleDownloadCertificate function lacks error handling. If downloadTrainingCertificate fails or returns an error (e.g., serverError), the function silently completes without any user feedback. Unlike similar download handlers in SingleTask.tsx and TaskAutomations.tsx that use try/catch with toast.error, this handler only checks if (result?.data) and does nothing when data is absent. Users clicking the download button will see no response when errors occur.

Fix in Cursor Fix in Web

…status (#2049)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
* fix(app): show preview menu on Employee Device UI

* fix(app): remove unused imports in EmployeeTasks

* fix(portal): pass organizationId to confirm-fleet-policy and fleet-policy endpoints

* fix(app): pass FleetPolicyResults data to mark it passed on Employee Details UI

* fix(app): pass organizationId to get-image-url endpoint

* fix(portal): remove duplicated organizationId null check

* fix(portal): add verification that user is a member of the org for endpoints

* fix(app): add verification that user is a member of the org for get-image-url endpoint

* fix(portal): update color of Pass text

---------

Co-authored-by: chasprowebdev <chasgarciaprowebdev@gmail.com>
Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
}

@Post()
@UseGuards(RequireRoles('auditor', 'admin', 'owner'))
Copy link

Choose a reason for hiding this comment

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

Guard allows roles that internal check rejects

Medium Severity

The @UseGuards(RequireRoles('auditor', 'admin', 'owner')) decorator allows users with admin or owner roles to pass the initial guard check. However, the internal permission check at lines 206-209 only allows users with the auditor role or platform admins. This means an admin or owner who is not also an auditor will pass the guard but then receive a ForbiddenException. The same issue exists for the DELETE endpoint at line 313. The guards are inconsistent with both the API documentation ("Auditor or Platform Admin only") and the internal logic.

Additional Locations (1)

Fix in Cursor Fix in Web

taskId: createDto.taskId,
taskTitle: task.title,
content: createDto.content,
type: createDto.type ?? FindingType.soc2,
Copy link

Choose a reason for hiding this comment

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

Audit log uses assumed type instead of actual stored value

Medium Severity

When creating a finding, the type field is optional in the DTO. At line 205, createDto.type (which may be undefined) is passed directly to Prisma. However, at lines 250 and 264, the code uses createDto.type ?? FindingType.soc2 for audit logging and notifications. This means if the database schema has a different default or stores null, the audit log and notifications would incorrectly report soc2 instead of the actual stored value. The code should use finding.type (the value returned from the database after creation) instead of assuming a fallback.

Additional Locations (1)

Fix in Cursor Fix in Web

…ith email notifications (#2054)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
* feat(permissions): enhance role-based permissions for adding members and sending invitations

* feat(tasks): update attachment sorting order and enhance member role checks

* feat(people): add server action to invite new members and update modal integration

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
…ts and validation (#2056)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
* feat(auth): add redirect handling for sign-in flows with safe path validation

* fix(auth): improve redirect path validation to prevent open redirect vulnerabilities

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
* feat(organization): update invitation handling and logging for member invites

* feat(organization): move email masking logic to separate utility file

* refactor(mask-email): update email masking function for clarity and logging

* refactor(organization): replace maskEmail with maskEmailForLogs for improved logging

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
…signees (#2063)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
[FindingType.iso27001]: 'ISO 27001',
};
return labels[type] || type;
}
Copy link

Choose a reason for hiding this comment

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

Duplicated status and type label mappings in findings

Low Severity

The same FindingStatus and FindingType label mappings are duplicated in two files. finding-audit.service.ts defines private formatStatus() and formatType() methods, while finding-notifier.service.ts defines STATUS_LABELS and TYPE_LABELS constants with identical values (Open, Ready for Review, Needs Revision, Closed for statuses; SOC 2, ISO 27001 for types). These could be extracted to a shared constants file or utility module.

Additional Locations (1)

Fix in Cursor Fix in Web

export interface EvidenceExportOptions {
includeRawJson: boolean;
format: 'pdf' | 'zip';
}
Copy link

Choose a reason for hiding this comment

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

Unused EvidenceExportOptions interface never referenced

Low Severity

The EvidenceExportOptions interface is exported but never imported or used anywhere in the codebase. It defines includeRawJson and format fields, but the service methods use inline options objects with only includeRawJson: boolean instead. This dead code adds clutter without providing value.

Fix in Cursor Fix in Web

type: 'app_automation' | 'custom_automation';
// For app automations
integrationName?: string;
integrationLogoUrl?: string;
Copy link

Choose a reason for hiding this comment

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

Unused integrationLogoUrl field never populated

Low Severity

The integrationLogoUrl field is defined in the NormalizedAutomation interface but is never populated in groupAppAutomationRuns(). The function sets integrationName from run.connection.provider?.name but omits integrationLogoUrl. This unused field suggests incomplete implementation or over-specification of the interface.

Fix in Cursor Fix in Web

process.env.BETTER_AUTH_URL ??
'https://app.trycomp.ai'
);
}
Copy link

Choose a reason for hiding this comment

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

Duplicated getAppUrl pattern across notifier services

Low Severity

The getAppUrl() helper function duplicates an existing pattern found in comment-mention-notifier.service.ts (as getAppBaseUrl()) and inline in other notifier services. All implementations perform the same env var fallback chain: NEXT_PUBLIC_APP_URL ?? BETTER_AUTH_URL ?? 'https://app.trycomp.ai'. This common utility belongs in a shared module.

Fix in Cursor Fix in Web

…tion dialog (#2065)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

[FindingType.soc2]: 'SOC 2',
[FindingType.iso27001]: 'ISO 27001',
};

Copy link

Choose a reason for hiding this comment

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

Duplicate status and type label mappings

Low Severity

STATUS_LABELS and TYPE_LABELS constants in finding-notifier.service.ts duplicate the logic in formatStatus() and formatType() methods in finding-audit.service.ts. Both define identical human-readable labels for FindingStatus and FindingType enums. This mapping logic could be extracted to a shared constants file within the findings module.

Additional Locations (1)

Fix in Cursor Fix in Web

cleaned = cleaned.replace(new RegExp(unicode, 'g'), replacement);
}

return cleaned;
Copy link

Choose a reason for hiding this comment

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

Duplicate cleanTextForPDF function for PDF generation

Low Severity

The cleanTextForPDF() function in evidence-pdf-generator.ts is nearly identical to the private cleanTextForPDF() method in training-certificate-pdf.service.ts. Both strip invisible Unicode characters and replace curly quotes, dashes, and other special characters. This utility could be extracted to a shared PDF utilities file.

Additional Locations (1)

Fix in Cursor Fix in Web

export * from './finding-template.service';
export * from './finding-template.controller';
export * from './dto/create-finding-template.dto';
export * from './dto/update-finding-template.dto';
Copy link

Choose a reason for hiding this comment

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

Unused barrel export files never imported

Low Severity

The barrel export files (finding-template/index.ts, findings/index.ts, evidence-export/index.ts) are never imported anywhere in the codebase. All imports reference the specific files directly (e.g., ./finding-template.service). These unused index files add clutter without providing value.

Additional Locations (2)

Fix in Cursor Fix in Web

bigint: true,
circularValue: '[Circular]',
deterministic: false,
});
Copy link

Choose a reason for hiding this comment

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

Duplicate safeStringify configuration in same module

Low Severity

Both evidence-export.service.ts and evidence-pdf-generator.ts configure their own safeStringify instance from safe-stable-stringify. They have slightly different settings (deterministic: false vs default), which could lead to inconsistent JSON output format within the same feature. This configuration could be centralized.

Additional Locations (1)

Fix in Cursor Fix in Web

@tofikwest tofikwest merged commit 8db2f1f into release Jan 27, 2026
13 of 14 checks passed
@claudfuen
Copy link
Contributor

🎉 This PR is included in version 1.79.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.

3 participants