Skip to content

[comp] Production Deploy#2083

Merged
tofikwest merged 13 commits intoreleasefrom
main
Feb 3, 2026
Merged

[comp] Production Deploy#2083
tofikwest merged 13 commits intoreleasefrom
main

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.

github-actions bot and others added 2 commits January 30, 2026 17:03
…2079)

* feat(app): add 'Remove Device' menu on Employ Devices tab

* feat(api): create delete endpoint to remove single host from fleet

* feat(app): integrate delete endpoint to remove the host

* fix(api): missing host ownership validation allows cross-organization deletion

* fix(app): redundant null check after early return guard on handleRemoveDeviceClick

* fix(api): duplicated host deletion logic not consolidated on fleet.service

* fix(app): remove unnecessary accessorKey on actions column

* fix(app): remove duplicated database query for current user member

---------

Co-authored-by: chasprowebdev <chasgarciaprowebdev@gmail.com>
@vercel
Copy link

vercel bot commented Jan 30, 2026

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

Project Deployment Actions Updated (UTC)
app (staging) Ready Ready Preview, Comment Feb 3, 2026 7:40pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
portal (staging) Skipped Skipped Feb 3, 2026 7:40pm

Request Review

@CLAassistant
Copy link

CLAassistant commented Jan 30, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ tofikwest
❌ github-actions[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@cursor
Copy link

cursor bot commented Jan 30, 2026

PR Summary

High Risk
Large changes to policy persistence/publishing/approval flows (including new version records, S3 PDF copying/deletion, and migration tasks) can impact existing policy data and downstream consumers. Additional new admin/device-management and cloud-scan workflow changes increase integration risk across API + app surfaces.

Overview
Introduces policy versioning end-to-end: new PolicyVersion DTOs/endpoints (list/create/edit/delete/publish/activate/submit-for-approval), policy creation now seeds version 1, publishing/approval flows now manipulate currentVersionId/pendingVersionId, and multiple callers (AI chat, trust portal PDF bundles, vector-store sync) now prefer currentVersion.content/pdfUrl with fallbacks.

Adds migration + cleanup for legacy policies (Trigger.dev tasks for org/all-org batch migration and app-side migration helpers) and new S3 helpers to copy/delete version PDFs; policy deletion now attempts to remove policy + version PDFs from S3 before cascade deletes.

Expands adjacent workflows: adds owner-only People API/UI support to remove a single FleetDM host, adds revisionNote handling for findings when moving into/out of needs_revision, wraps cloud-security findings writes in a DB transaction, updates cloud scan UX to wait for Trigger runs and revalidate without SWR polling, and adds isSubProcessor to vendor create/response.

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

* feat(api): add revision note handling for findings update

* feat(app): update onStatusChange to support async handling in FindingItem

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
} finally {
setIsSubmitting(false);
}
};
Copy link

Choose a reason for hiding this comment

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

Revision dialog closes on API failure, losing user input

Medium Severity

The handleRevisionSubmit and handleRevisionSkip functions expect onStatusChange to throw on API failure so the dialog remains open for retry. However, handleStatusChange (the implementation of onStatusChange) catches errors internally and shows a toast but doesn't re-throw. This causes await onStatusChange(...) to always resolve successfully, so the dialog closes and the user's typed revision note is cleared even when the API call fails. The user sees an error toast but loses their input.

Additional Locations (1)

Fix in Cursor Fix in Web

@IsString()
@IsOptional()
@MaxLength(2000)
revisionNote?: string | null;
Copy link

Choose a reason for hiding this comment

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

Missing explicit type causes incorrect OpenAPI schema

Low Severity

The @ApiProperty decorator for revisionNote is missing an explicit type: String specification. Combined with nullable: true and TypeScript type string | null, this causes NestJS Swagger to generate "type": "object" in the OpenAPI spec instead of "type": "string". Add type: String to the decorator options.

Fix in Cursor Fix in Web

* feat(api): add policy versioning with create, update, delete, and fetch operations

* fix(api): update approver handling and current version assignment in policy changes

* feat(api): enhance deleteById to clean up PDFs from S3 before deletion

* feat(api): update policy version creation to handle S3 copy after transaction

* feat(api): clear pending approval state when publishing or activating versions

* feat(api): include organizationId check to prevent cross-org access in PDF URL retrieval

* feat(api): sync draft content to prevent unpublished changes UI bug

* feat(api): prevent activating a different version when another is pending approval

* feat(api): add validation for deactivated members as approvers

* feat(api): clear signatures when publishing or activating policy versions

* feat(api): sync draft content to prevent false unpublished changes indicator

* feat(api): use transaction for atomic policy updates and sync draft content

---------

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

return processed;
}
Copy link

Choose a reason for hiding this comment

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

Duplicated processContent function and ContentNode interface

Medium Severity

The ContentNode interface and processContent function are duplicated in both update-draft.ts and update-version-content.ts. These are nearly identical implementations that sanitize TipTap editor content. Extract to a shared utility like apps/app/src/actions/policies/lib/content-utils.ts.

Fix in Cursor Fix in Web

console.error('Error copying policy PDF:', error);
return null;
}
}
Copy link

Choose a reason for hiding this comment

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

Duplicated S3 PDF copy helper function

Low Severity

The copyPolicyVersionPdf function duplicates the logic in AttachmentsService.copyPolicyVersionPdf (apps/api/src/attachments/attachments.service.ts lines 341-358). Consider extracting to a shared S3 utility module or creating a reusable pattern.

Fix in Cursor Fix in Web

* fix(trust-portal): improve error handling for custom domain updates

* fix(trust-portal): enhance error handling for domain ownership checks

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
console.error('Error copying policy PDF:', error);
return null;
}
}
Copy link

Choose a reason for hiding this comment

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

Duplicate S3 helper functions across packages

Low Severity

copyPolicyVersionPdf in create-version.ts and deletePolicyVersionPdf in delete-version.ts duplicate functionality that already exists in AttachmentsService (attachments.service.ts lines 341-374). Consider creating a shared S3 utility in the app package or calling the API endpoints.

Fix in Cursor Fix in Web

const content = policy.currentVersion?.content ?? policy.content;
const pdfUrl = policy.currentVersion?.pdfUrl ?? policy.pdfUrl;
return { content, pdfUrl };
};
Copy link

Choose a reason for hiding this comment

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

Duplicated getEffectiveData helper in two services

Low Severity

The getEffectiveData helper function is identically defined in both policies.service.ts (lines 946-951) and trust-access.service.ts (lines 2005-2009). Both extract content and pdfUrl from a policy's currentVersion with fallback to policy-level values.

Fix in Cursor Fix in Web

github-actions bot and others added 2 commits February 3, 2026 10:14
* feat(policies): enhance policy versioning and status handling

* refactor(policies): simplify policy header layout and actions

* refactor(policies): update publish action to handle empty content and add pdfUrl

* refactor(policies): clear approval fields in publish action

* refactor(policies): sync draft content with published version in publish action

* refactor(policies): optimize initialVersionId change detection in PolicyDetails

* refactor(policies): add draft badge to policy details for better status indication

* refactor(policies): add lastPublishedAt to policy details and tabs for status display

* refactor(policies): implement transaction in publish action to prevent orphaned versions

* refactor(cloud-tests): update legacy integration filtering for cloud providers

---------

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
* feat(vendor): add isSubProcessor field to vendor DTOs and forms

* refactor(vendor): update isSubProcessor field layout and tooltip

* feat(vendor): add onUpdate callback to SecondaryFields component

---------

Co-authored-by: Lewis Carhart <lewis@trycomp.ai>
* feat(vendor): add isSubProcessor field to vendor DTOs and forms

* refactor(vendor): update isSubProcessor field layout and tooltip

* feat(vendor): add onUpdate callback to SecondaryFields component

* feat(trust): move Trust Portal to dedicated sidebar navigation and settings

---------

Co-authored-by: Lewis Carhart <lewis@trycomp.ai>
github-actions bot and others added 2 commits February 3, 2026 12:06
* feat(settings): moved AddSecretDialog to settings header for secrets page to conform with UI pattern

* feat(trust): ensure friendlyUrl defaults to organizationId and update status to published

---------

Co-authored-by: Lewis Carhart <lewis@trycomp.ai>
…page to conform with UI pattern (#2098)

Co-authored-by: Lewis Carhart <lewis@trycomp.ai>
@vercel vercel bot temporarily deployed to staging – portal February 3, 2026 17:09 Inactive
@vercel vercel bot temporarily deployed to staging – app February 3, 2026 17:09 Inactive
#2100)

* feat(cloud-tests): enhance legacy integration filtering and add support for multiple connections

* refactor(cloud-tests): improve filtering logic for recent scan results

* refactor(cloud-tests): enhance filtering logic for legacy results

* refactor(policies): simplify policy header layout and remove PageHeader component
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 2 potential issues.

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

status: PolicyStatus.needs_review,
approverId: dto.approverId,
},
});
Copy link

Choose a reason for hiding this comment

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

API missing check for existing pending version

Medium Severity

The API's submitForApproval method doesn't check if another version is already pending approval before overwriting pendingVersionId. The corresponding app action at submit-version-for-approval.ts lines 42-45 has this validation: if (policy.pendingVersionId && policy.pendingVersionId !== versionId). Without this check in the API, an approver could be reviewing one version while it silently changes to a different version, leading to incorrect approvals.

Fix in Cursor Fix in Web

…creation (#2101)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
Comment on lines +44 to +50
const response = await fetch(`${apiUrl}/v1/cloud-security/scan/${connectionId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-organization-id': orgId,
},
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 1 day ago

In general, to fix this kind of issue you should validate and constrain any user-controlled values before incorporating them into an outbound request URL. The hostname and protocol should never be derived from user input, and any user-provided path components should be validated against an allow-list of expected patterns and rejected if they do not match.

For this specific case, the best fix with minimal behavioral change is to enforce that connectionId conforms to the expected IntegrationConnection ID format before using it in the URL, and to reject the request if it does not. The JSDoc comment states that the parameter is an "icn_..." ID, so we can validate it against a strict regular expression (for example, ^icn_[A-Za-z0-9]+$). If the value fails validation, we return an error response instead of calling fetch. This keeps existing functionality for legitimate IDs while preventing arbitrary strings from flowing into the URL. The change is localized to runPlatformScan in apps/app/src/app/(app)/[orgId]/cloud-tests/actions/run-platform-scan.ts and does not require new imports; we just add a small validation block near the top of the function, after the existing session/org checks and before constructing or using apiUrl.

Concretely:

  • Inside runPlatformScan, after verifying orgId (just after line 32 and before the try block), add a validation step for connectionId using a regular expression for allowed IDs.
  • If connectionId fails validation, immediately return a structured error object (success: false, error: 'Invalid connection ID') without performing the outbound fetch.
  • No change is needed to the fetch call itself or any imports.

Suggested changeset 1
apps/app/src/app/(app)/[orgId]/cloud-tests/actions/run-platform-scan.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/apps/app/src/app/(app)/[orgId]/cloud-tests/actions/run-platform-scan.ts b/apps/app/src/app/(app)/[orgId]/cloud-tests/actions/run-platform-scan.ts
--- a/apps/app/src/app/(app)/[orgId]/cloud-tests/actions/run-platform-scan.ts
+++ b/apps/app/src/app/(app)/[orgId]/cloud-tests/actions/run-platform-scan.ts
@@ -31,6 +31,15 @@
     };
   }
 
+  // Validate the IntegrationConnection ID format before using it in the request URL
+  const isValidConnectionId = /^icn_[A-Za-z0-9]+$/.test(connectionId);
+  if (!isValidConnectionId) {
+    return {
+      success: false,
+      error: 'Invalid connection ID',
+    };
+  }
+
   try {
     // Call the cloud security scan API
     const apiUrl = process.env.NEXT_PUBLIC_API_URL || process.env.API_URL;
EOF
@@ -31,6 +31,15 @@
};
}

// Validate the IntegrationConnection ID format before using it in the request URL
const isValidConnectionId = /^icn_[A-Za-z0-9]+$/.test(connectionId);
if (!isValidConnectionId) {
return {
success: false,
error: 'Invalid connection ID',
};
}

try {
// Call the cloud security scan API
const apiUrl = process.env.NEXT_PUBLIC_API_URL || process.env.API_URL;
Copilot is powered by AI and may make mistakes. Always verify output.
@tofikwest tofikwest merged commit 7268e9d into release Feb 3, 2026
12 of 14 checks passed
@claudfuen
Copy link
Contributor

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