From ae1787cd71fec772403f625e3955664b339e47f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:39:36 -0500 Subject: [PATCH 1/3] [HOTFIX] Add orgId to /api/cloud-tests/providers endpoint (#1926) * fix(app): add orgId query parameter to /api/cloud-tests/providers endpoint * fix(app): add auth check to api/cloud-tests/providers endpoint * fix(app): verify if the user belongs to the org in cloud-tests/provider endpoint * fix(app): update cloud-tests/findings endpoint to have orgId as query param --------- Co-authored-by: chasprowebdev Co-authored-by: Mariano Fuentes --- .../cloud-tests/components/TestsLayout.tsx | 4 +-- .../src/app/api/cloud-tests/findings/route.ts | 26 ++++++++++++++++--- .../app/api/cloud-tests/providers/route.ts | 26 ++++++++++++++++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/apps/app/src/app/(app)/[orgId]/cloud-tests/components/TestsLayout.tsx b/apps/app/src/app/(app)/[orgId]/cloud-tests/components/TestsLayout.tsx index 8e3f7d579..3e8ecbc7b 100644 --- a/apps/app/src/app/(app)/[orgId]/cloud-tests/components/TestsLayout.tsx +++ b/apps/app/src/app/(app)/[orgId]/cloud-tests/components/TestsLayout.tsx @@ -75,7 +75,7 @@ export function TestsLayout({ initialFindings, initialProviders, orgId }: TestsL const { disconnectConnection } = useIntegrationMutations(); const { data: findings = initialFindings, mutate: mutateFindings } = useSWR( - '/api/cloud-tests/findings', + `/api/cloud-tests/findings?orgId=${orgId}`, async (url) => { const res = await fetch(url); if (!res.ok) throw new Error('Failed to fetch'); @@ -89,7 +89,7 @@ export function TestsLayout({ initialFindings, initialProviders, orgId }: TestsL ); const { data: providers = initialProviders, mutate: mutateProviders } = useSWR( - '/api/cloud-tests/providers', + `/api/cloud-tests/providers?orgId=${orgId}`, async (url) => { const res = await fetch(url); if (!res.ok) throw new Error('Failed to fetch'); diff --git a/apps/app/src/app/api/cloud-tests/findings/route.ts b/apps/app/src/app/api/cloud-tests/findings/route.ts index 8bdbfe918..b0f3ebe2b 100644 --- a/apps/app/src/app/api/cloud-tests/findings/route.ts +++ b/apps/app/src/app/api/cloud-tests/findings/route.ts @@ -1,20 +1,38 @@ import { auth } from '@/utils/auth'; import { db } from '@db'; import { headers } from 'next/headers'; -import { NextResponse } from 'next/server'; +import { NextRequest, NextResponse } from 'next/server'; const CLOUD_PROVIDER_SLUGS = ['aws', 'gcp', 'azure']; -export async function GET() { +export async function GET(request: NextRequest) { try { const session = await auth.api.getSession({ headers: await headers(), }); - const orgId = session?.session.activeOrganizationId; + if (!session?.user?.id) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const { searchParams } = new URL(request.url); + const orgId = searchParams.get('orgId'); if (!orgId) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + return NextResponse.json({ error: 'Organization ID is required' }, { status: 400 }); + } + + // Verify the user belongs to the requested organization + const member = await db.member.findFirst({ + where: { + userId: session.user.id, + organizationId: orgId, + deactivated: false, + }, + }); + + if (!member) { + return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); } // ==================================================================== diff --git a/apps/app/src/app/api/cloud-tests/providers/route.ts b/apps/app/src/app/api/cloud-tests/providers/route.ts index d486f3438..b958c3ad3 100644 --- a/apps/app/src/app/api/cloud-tests/providers/route.ts +++ b/apps/app/src/app/api/cloud-tests/providers/route.ts @@ -2,7 +2,7 @@ import { auth } from '@/utils/auth'; import { getManifest } from '@comp/integration-platform'; import { db } from '@db'; import { headers } from 'next/headers'; -import { NextResponse } from 'next/server'; +import { NextRequest, NextResponse } from 'next/server'; const CLOUD_PROVIDER_SLUGS = ['aws', 'gcp', 'azure']; @@ -24,16 +24,34 @@ const getRequiredVariables = (providerSlug: string): string[] => { return Array.from(requiredVars); }; -export async function GET() { +export async function GET(request: NextRequest) { try { const session = await auth.api.getSession({ headers: await headers(), }); - const orgId = session?.session.activeOrganizationId; + if (!session?.user?.id) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const { searchParams } = new URL(request.url); + const orgId = searchParams.get('orgId'); if (!orgId) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + return NextResponse.json({ error: 'Organization ID is required' }, { status: 400 }); + } + + // Verify the user belongs to the requested organization + const member = await db.member.findFirst({ + where: { + userId: session.user.id, + organizationId: orgId, + deactivated: false, + }, + }); + + if (!member) { + return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); } // Fetch from NEW integration platform (IntegrationConnection) From 7b92ce876d2b028433fcb2d959e7594fe22290de Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 16 Dec 2025 15:50:27 -0500 Subject: [PATCH 2/3] Mariano/fix existing automations missing (#1932) * fix(app): update custom automations section to show based on conditions * chore(api): add integration platform extension and update workflows --- .../workflows/trigger-tasks-deploy-main.yml | 6 ++ .../trigger-tasks-deploy-release.yml | 7 ++ apps/api/integrationPlatformExtension.ts | 95 +++++++++++++++++++ apps/api/trigger.config.ts | 2 + .../tasks/[taskId]/components/SingleTask.tsx | 6 +- 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 apps/api/integrationPlatformExtension.ts diff --git a/.github/workflows/trigger-tasks-deploy-main.yml b/.github/workflows/trigger-tasks-deploy-main.yml index 387b35c20..0dbd8b9db 100644 --- a/.github/workflows/trigger-tasks-deploy-main.yml +++ b/.github/workflows/trigger-tasks-deploy-main.yml @@ -24,9 +24,15 @@ jobs: - name: Install Email package dependencies working-directory: ./packages/email run: bun install --frozen-lockfile --ignore-scripts + - name: Install Integration Platform package dependencies + working-directory: ./packages/integration-platform + run: bun install --frozen-lockfile --ignore-scripts - name: Build DB package working-directory: ./packages/db run: bun run build + - name: Build Integration Platform package + working-directory: ./packages/integration-platform + run: bun run build - name: Copy schema to app and generate client working-directory: ./apps/app run: | diff --git a/.github/workflows/trigger-tasks-deploy-release.yml b/.github/workflows/trigger-tasks-deploy-release.yml index f941b1d60..c7c6d6c72 100644 --- a/.github/workflows/trigger-tasks-deploy-release.yml +++ b/.github/workflows/trigger-tasks-deploy-release.yml @@ -27,11 +27,18 @@ jobs: - name: Install Email package dependencies working-directory: ./packages/email run: bun install --frozen-lockfile --ignore-scripts + - name: Install Integration Platform package dependencies + working-directory: ./packages/integration-platform + run: bun install --frozen-lockfile --ignore-scripts - name: Build DB package working-directory: ./packages/db run: bun run build + - name: Build Integration Platform package + working-directory: ./packages/integration-platform + run: bun run build + - name: Copy schema to app and generate client working-directory: ./apps/app run: | diff --git a/apps/api/integrationPlatformExtension.ts b/apps/api/integrationPlatformExtension.ts new file mode 100644 index 000000000..e684812ab --- /dev/null +++ b/apps/api/integrationPlatformExtension.ts @@ -0,0 +1,95 @@ +import type { + BuildContext, + BuildExtension, + BuildManifest, +} from '@trigger.dev/build'; +import { existsSync } from 'node:fs'; +import { cp, mkdir } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; + +/** + * Custom Trigger.dev build extension for @comp/integration-platform workspace package. + * + * Since @comp/integration-platform is a workspace package (not published to npm), + * we need to manually copy its built dist files into the trigger.dev deployment. + */ +export function integrationPlatformExtension(): IntegrationPlatformExtension { + return new IntegrationPlatformExtension(); +} + +class IntegrationPlatformExtension implements BuildExtension { + public readonly name = 'IntegrationPlatformExtension'; + + externalsForTarget(target: string) { + if (target === 'dev') { + return []; + } + // Mark as external so esbuild doesn't try to bundle it + return ['@comp/integration-platform']; + } + + async onBuildComplete(context: BuildContext, manifest: BuildManifest) { + if (context.target === 'dev') { + return; + } + + // Find the integration-platform package dist + const packageDistPath = this.findPackageDist(context.workingDir); + + if (!packageDistPath) { + throw new Error( + [ + 'IntegrationPlatformExtension could not find @comp/integration-platform dist.', + 'Make sure the package is built (run `bun run build` in packages/integration-platform).', + 'Searched in: ' + + resolve( + context.workingDir, + '../../packages/integration-platform/dist', + ), + ].join('\n'), + ); + } + + context.logger.debug( + `Found integration-platform dist at ${packageDistPath}`, + ); + + // Copy the entire dist to the build output + const destPath = resolve( + manifest.outputPath, + 'node_modules/@comp/integration-platform', + ); + const destDistPath = resolve(destPath, 'dist'); + + await mkdir(destDistPath, { recursive: true }); + + // Copy dist files + await cp(packageDistPath, destDistPath, { recursive: true }); + + // Copy package.json for proper module resolution + const packageJsonPath = resolve(dirname(packageDistPath), 'package.json'); + if (existsSync(packageJsonPath)) { + await cp(packageJsonPath, resolve(destPath, 'package.json')); + } + + context.logger.log( + 'Copied @comp/integration-platform to deployment bundle', + ); + } + + private findPackageDist(workingDir: string): string | undefined { + // Look for the package relative to the api app + const candidates = [ + resolve(workingDir, '../../packages/integration-platform/dist'), + resolve(workingDir, '../packages/integration-platform/dist'), + ]; + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } + } + + return undefined; + } +} diff --git a/apps/api/trigger.config.ts b/apps/api/trigger.config.ts index 39dd5e306..7434b3d28 100644 --- a/apps/api/trigger.config.ts +++ b/apps/api/trigger.config.ts @@ -2,6 +2,7 @@ import { PrismaInstrumentation } from '@prisma/instrumentation'; import { syncVercelEnvVars } from '@trigger.dev/build/extensions/core'; import { defineConfig } from '@trigger.dev/sdk'; import { prismaExtension } from './customPrismaExtension'; +import { integrationPlatformExtension } from './integrationPlatformExtension'; export default defineConfig({ project: 'proj_zhioyrusqertqgafqgpj', // API project @@ -14,6 +15,7 @@ export default defineConfig({ version: '6.13.0', dbPackageVersion: '^1.3.15', // Version of @trycompai/db package with compiled JS }), + integrationPlatformExtension(), syncVercelEnvVars(), ], }, diff --git a/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/components/SingleTask.tsx b/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/components/SingleTask.tsx index 106ee0b1f..5a696d5a9 100644 --- a/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/components/SingleTask.tsx +++ b/apps/app/src/app/(app)/[orgId]/tasks/[taskId]/components/SingleTask.tsx @@ -205,8 +205,10 @@ export function SingleTask({ {/* Browser Automations Section */} {isWebAutomationsEnabled && } - {/* Custom Automations Section - only show if no mapped integration checks available */} - {!hasMappedChecks && } + {/* Custom Automations Section - always show if automations exist, or show empty state if no integration checks */} + {((automations && automations.length > 0) || !hasMappedChecks) && ( + + )} {/* Comments Section */}
From 912f4187787a82d8ead2a809a3f339d662f5e420 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Tue, 16 Dec 2025 15:59:02 -0500 Subject: [PATCH 3/3] Mariano/fix existing automations missing (#1933) * chore(workflows): add integration platform package installation and build steps --- .../trigger-api-tasks-deploy-main.yml | 6 ++ .../trigger-api-tasks-deploy-release.yml | 7 ++ apps/api/integrationPlatformExtension.ts | 88 +++++++++++++------ 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/.github/workflows/trigger-api-tasks-deploy-main.yml b/.github/workflows/trigger-api-tasks-deploy-main.yml index 57dd23ec2..6d780ed31 100644 --- a/.github/workflows/trigger-api-tasks-deploy-main.yml +++ b/.github/workflows/trigger-api-tasks-deploy-main.yml @@ -25,6 +25,12 @@ jobs: - name: Install DB package dependencies working-directory: ./packages/db run: bun install --frozen-lockfile --ignore-scripts + - name: Install Integration Platform package dependencies + working-directory: ./packages/integration-platform + run: bun install --frozen-lockfile --ignore-scripts + - name: Build Integration Platform package + working-directory: ./packages/integration-platform + run: bun run build - name: Build DB package working-directory: ./packages/db run: bun run build diff --git a/.github/workflows/trigger-api-tasks-deploy-release.yml b/.github/workflows/trigger-api-tasks-deploy-release.yml index 8ba396896..07861fc9e 100644 --- a/.github/workflows/trigger-api-tasks-deploy-release.yml +++ b/.github/workflows/trigger-api-tasks-deploy-release.yml @@ -28,6 +28,13 @@ jobs: working-directory: ./packages/db run: bun install --frozen-lockfile --ignore-scripts + - name: Install Integration Platform package dependencies + working-directory: ./packages/integration-platform + run: bun install --frozen-lockfile --ignore-scripts + - name: Build Integration Platform package + working-directory: ./packages/integration-platform + run: bun run build + - name: Build DB package working-directory: ./packages/db run: bun run build diff --git a/apps/api/integrationPlatformExtension.ts b/apps/api/integrationPlatformExtension.ts index e684812ab..3b8e96002 100644 --- a/apps/api/integrationPlatformExtension.ts +++ b/apps/api/integrationPlatformExtension.ts @@ -3,15 +3,20 @@ import type { BuildExtension, BuildManifest, } from '@trigger.dev/build'; +import type { Plugin } from 'esbuild'; import { existsSync } from 'node:fs'; import { cp, mkdir } from 'node:fs/promises'; import { dirname, resolve } from 'node:path'; +const PACKAGE_NAME = '@comp/integration-platform'; + /** * Custom Trigger.dev build extension for @comp/integration-platform workspace package. * * Since @comp/integration-platform is a workspace package (not published to npm), - * we need to manually copy its built dist files into the trigger.dev deployment. + * we need to: + * 1. Add an esbuild plugin to resolve the import path during build + * 2. Copy the built dist files into the trigger.dev deployment */ export function integrationPlatformExtension(): IntegrationPlatformExtension { return new IntegrationPlatformExtension(); @@ -19,40 +24,66 @@ export function integrationPlatformExtension(): IntegrationPlatformExtension { class IntegrationPlatformExtension implements BuildExtension { public readonly name = 'IntegrationPlatformExtension'; + private _packagePath: string | undefined; - externalsForTarget(target: string) { - if (target === 'dev') { - return []; - } - // Mark as external so esbuild doesn't try to bundle it - return ['@comp/integration-platform']; - } - - async onBuildComplete(context: BuildContext, manifest: BuildManifest) { + async onBuildStart(context: BuildContext) { if (context.target === 'dev') { return; } - // Find the integration-platform package dist - const packageDistPath = this.findPackageDist(context.workingDir); + // Find the package path + this._packagePath = this.findPackageRoot(context.workingDir); - if (!packageDistPath) { + if (!this._packagePath) { throw new Error( [ - 'IntegrationPlatformExtension could not find @comp/integration-platform dist.', + `IntegrationPlatformExtension could not find ${PACKAGE_NAME}.`, 'Make sure the package is built (run `bun run build` in packages/integration-platform).', - 'Searched in: ' + - resolve( - context.workingDir, - '../../packages/integration-platform/dist', - ), ].join('\n'), ); } - context.logger.debug( - `Found integration-platform dist at ${packageDistPath}`, - ); + context.logger.debug(`Found integration-platform at ${this._packagePath}`); + + // Register esbuild plugin to resolve the workspace package + const packagePath = this._packagePath; + const resolvePlugin: Plugin = { + name: 'resolve-integration-platform', + setup(build) { + // Resolve bare import + build.onResolve({ filter: /^@comp\/integration-platform$/ }, () => { + return { + path: resolve(packagePath, 'dist/index.js'), + }; + }); + + // Resolve subpath imports like @comp/integration-platform/types + build.onResolve( + { filter: /^@comp\/integration-platform\// }, + (args) => { + const subpath = args.path.replace(`${PACKAGE_NAME}/`, ''); + return { + path: resolve(packagePath, 'dist', `${subpath}/index.js`), + }; + }, + ); + }, + }; + + context.registerPlugin(resolvePlugin); + } + + async onBuildComplete(context: BuildContext, manifest: BuildManifest) { + if (context.target === 'dev') { + return; + } + + const packagePath = this._packagePath; + if (!packagePath) { + return; + } + + const packageDistPath = resolve(packagePath, 'dist'); // Copy the entire dist to the build output const destPath = resolve( @@ -67,7 +98,7 @@ class IntegrationPlatformExtension implements BuildExtension { await cp(packageDistPath, destDistPath, { recursive: true }); // Copy package.json for proper module resolution - const packageJsonPath = resolve(dirname(packageDistPath), 'package.json'); + const packageJsonPath = resolve(packagePath, 'package.json'); if (existsSync(packageJsonPath)) { await cp(packageJsonPath, resolve(destPath, 'package.json')); } @@ -77,15 +108,18 @@ class IntegrationPlatformExtension implements BuildExtension { ); } - private findPackageDist(workingDir: string): string | undefined { + private findPackageRoot(workingDir: string): string | undefined { // Look for the package relative to the api app const candidates = [ - resolve(workingDir, '../../packages/integration-platform/dist'), - resolve(workingDir, '../packages/integration-platform/dist'), + resolve(workingDir, '../../packages/integration-platform'), + resolve(workingDir, '../packages/integration-platform'), ]; for (const candidate of candidates) { - if (existsSync(candidate)) { + if ( + existsSync(candidate) && + existsSync(resolve(candidate, 'dist/index.js')) + ) { return candidate; } }