|
1 | 1 | import { Injectable, Logger } from '@nestjs/common'; |
2 | 2 | import { db } from '@db'; |
3 | 3 | import { getManifest } from '@comp/integration-platform'; |
| 4 | +import { runs, tasks } from '@trigger.dev/sdk'; |
4 | 5 | import { CredentialVaultService } from '../integration-platform/services/credential-vault.service'; |
5 | 6 | import { OAuthCredentialsService } from '../integration-platform/services/oauth-credentials.service'; |
6 | 7 | import { GCPSecurityService } from './providers/gcp-security.service'; |
@@ -28,6 +29,12 @@ export interface ScanResult { |
28 | 29 | error?: string; |
29 | 30 | } |
30 | 31 |
|
| 32 | +export class ConnectionNotFoundError extends Error { |
| 33 | + constructor() { |
| 34 | + super('Connection not found'); |
| 35 | + } |
| 36 | +} |
| 37 | + |
31 | 38 | @Injectable() |
32 | 39 | export class CloudSecurityService { |
33 | 40 | private readonly logger = new Logger(CloudSecurityService.name); |
@@ -220,6 +227,65 @@ export class CloudSecurityService { |
220 | 227 | } |
221 | 228 | } |
222 | 229 |
|
| 230 | + async triggerScan( |
| 231 | + connectionId: string, |
| 232 | + organizationId: string, |
| 233 | + ): Promise<{ runId: string }> { |
| 234 | + // Validate connection exists and is active |
| 235 | + const connection = await db.integrationConnection.findFirst({ |
| 236 | + where: { |
| 237 | + id: connectionId, |
| 238 | + organizationId, |
| 239 | + status: 'active', |
| 240 | + }, |
| 241 | + }); |
| 242 | + |
| 243 | + if (!connection) { |
| 244 | + throw new Error('Connection not found or inactive'); |
| 245 | + } |
| 246 | + |
| 247 | + const handle = await tasks.trigger('run-cloud-security-scan', { |
| 248 | + connectionId, |
| 249 | + organizationId, |
| 250 | + providerSlug: 'platform', |
| 251 | + connectionName: connectionId, |
| 252 | + }); |
| 253 | + |
| 254 | + this.logger.log(`Triggered cloud security scan task`, { |
| 255 | + connectionId, |
| 256 | + runId: handle.id, |
| 257 | + }); |
| 258 | + |
| 259 | + return { runId: handle.id }; |
| 260 | + } |
| 261 | + |
| 262 | + async getRunStatus( |
| 263 | + runId: string, |
| 264 | + connectionId: string, |
| 265 | + organizationId: string, |
| 266 | + ): Promise<{ completed: boolean; success: boolean; output: unknown }> { |
| 267 | + // Verify the connection belongs to the caller's organization |
| 268 | + const connection = await db.integrationConnection.findFirst({ |
| 269 | + where: { |
| 270 | + id: connectionId, |
| 271 | + organizationId, |
| 272 | + }, |
| 273 | + select: { id: true }, |
| 274 | + }); |
| 275 | + |
| 276 | + if (!connection) { |
| 277 | + throw new ConnectionNotFoundError(); |
| 278 | + } |
| 279 | + |
| 280 | + const run = await runs.retrieve(runId); |
| 281 | + |
| 282 | + return { |
| 283 | + completed: run.isCompleted, |
| 284 | + success: run.isCompleted ? run.isSuccess : false, |
| 285 | + output: run.isCompleted ? run.output : null, |
| 286 | + }; |
| 287 | + } |
| 288 | + |
223 | 289 | private async storeFindings( |
224 | 290 | connectionId: string, |
225 | 291 | provider: string, |
|
0 commit comments