Skip to content

Commit 6bd2768

Browse files
committed
RBAC tests: extract projectCreated to break platform.v3.server cycle (TRI-8731)
After rebasing rbac-packages on origin/main, the e2e.full harness regressed with the same `TypeError: Cannot convert undefined or null to object at allMachines (build/index.js:71862)` that TRI-8731 worked around by switching the testcontainer to NODE_ENV=production. Recent main commits changed the bundled init order enough that the production-mode dodge no longer applies — the cycle now triggers in both NODE_ENV=test and NODE_ENV=production. Root cause is structural: app/services/platform.v3.server → imports createEnvironment from app/models/organization.server app/models/organization.server → imports getDefaultEnvironmentConcurrencyLimit from app/services/platform.v3.server Inside an esbuild __esm bundle, this manifests as: init_platform_v3_server() runs init_organization_server() in the middle of its body. organization.server's body re-enters init_platform_v3_server(), which short-circuits because the outer call already cleared its `fn` — so `({ defaultMachine, machines } = singleton("machinePresets", ...))` never completes its destructure and both vars stay undefined. Object.entries(undefined) crashes when `allMachines()` runs inside `createRunEngine()`. Fix: move the only function in platform.v3.server.ts that imports from organization.server (`projectCreated`, the sole caller of `createEnvironment`) into its own file. platform.v3.server.ts no longer imports from organization.server, so the cycle is gone. Two trivial supporting changes: - export `isCloud` from platform.v3.server (projectCreated needs it) - drop the now-unused `Organization` and `Project` type imports No dynamic imports, no application-code workarounds — just a structural file split. Verified: - 162/162 e2e.full pass (auth-api, auth-cross-cutting, auth-dashboard) - 31/31 api-auth.e2e pass - 31/31 @trigger.dev/rbac unit tests pass - 7/7 cloud enterprise e2e.full pass against the same webapp build
1 parent 0b7eaa6 commit 6bd2768

4 files changed

Lines changed: 120 additions & 48 deletions

File tree

apps/webapp/app/models/project.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { $replica, prisma } from "~/db.server";
44
import type { Prisma, Project } from "@trigger.dev/database";
55
import { type Organization, createEnvironment } from "./organization.server";
66
import { env } from "~/env.server";
7-
import { projectCreated } from "~/services/platform.v3.server";
7+
import { projectCreated } from "~/services/projectCreated.server";
88
export type { Project } from "@trigger.dev/database";
99

1010
const externalRefGenerator = customAlphabet("abcdefghijklmnopqrstuvwxyz", 20);

apps/webapp/app/services/platform.v3.server.ts

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { MachinePresetName, tryCatch } from "@trigger.dev/core/v3";
2-
import type { Organization, Project, RuntimeEnvironmentType } from "@trigger.dev/database";
2+
import type { RuntimeEnvironmentType } from "@trigger.dev/database";
33
import {
44
BillingClient,
55
defaultMachine as defaultMachineFromPlatform,
@@ -25,7 +25,6 @@ import { redirect } from "remix-typedjson";
2525
import { z } from "zod";
2626
import { env } from "~/env.server";
2727
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
28-
import { createEnvironment } from "~/models/organization.server";
2928
import { logger } from "~/services/logger.server";
3029
import { newProjectPath, organizationBillingPath } from "~/utils/pathBuilder";
3130
import { singleton } from "~/utils/singleton";
@@ -569,33 +568,6 @@ export async function getEntitlement(
569568
return result.val;
570569
}
571570

572-
export async function projectCreated(
573-
organization: Pick<Organization, "id" | "maximumConcurrencyLimit">,
574-
project: Project
575-
) {
576-
if (!isCloud()) {
577-
await createEnvironment({ organization, project, type: "STAGING" });
578-
await createEnvironment({
579-
organization,
580-
project,
581-
type: "PREVIEW",
582-
isBranchableEnvironment: true,
583-
});
584-
} else {
585-
//staging is only available on certain plans
586-
const plan = await getCurrentPlan(organization.id);
587-
if (plan?.v3Subscription.plan?.limits.hasStagingEnvironment) {
588-
await createEnvironment({ organization, project, type: "STAGING" });
589-
await createEnvironment({
590-
organization,
591-
project,
592-
type: "PREVIEW",
593-
isBranchableEnvironment: true,
594-
});
595-
}
596-
}
597-
}
598-
599571
export async function getBillingAlerts(
600572
organizationId: string
601573
): Promise<BillingAlertsResult | undefined> {
@@ -770,7 +742,7 @@ export async function triggerInitialDeployment(
770742
}
771743
}
772744

773-
function isCloud(): boolean {
745+
export function isCloud(): boolean {
774746
const acceptableHosts = [
775747
"https://cloud.trigger.dev",
776748
"https://test-cloud.trigger.dev",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { Organization, Project } from "@trigger.dev/database";
2+
import { createEnvironment } from "~/models/organization.server";
3+
import { getCurrentPlan, isCloud } from "~/services/platform.v3.server";
4+
5+
// Extracted from platform.v3.server.ts to break a circular import:
6+
// platform.v3.server ↔ models/organization.server (via createEnvironment).
7+
// The cycle caused the bundled __esm wrappers to re-enter and short-circuit
8+
// the platform.v3.server init, leaving `defaultMachine` and `machines`
9+
// undefined in `singleton("machinePresets", ...)` — the boot crash at
10+
// `allMachines()` traced to TRI-8731.
11+
export async function projectCreated(
12+
organization: Pick<Organization, "id" | "maximumConcurrencyLimit">,
13+
project: Project
14+
) {
15+
if (!isCloud()) {
16+
await createEnvironment({ organization, project, type: "STAGING" });
17+
await createEnvironment({
18+
organization,
19+
project,
20+
type: "PREVIEW",
21+
isBranchableEnvironment: true,
22+
});
23+
} else {
24+
const plan = await getCurrentPlan(organization.id);
25+
if (plan?.v3Subscription.plan?.limits.hasStagingEnvironment) {
26+
await createEnvironment({ organization, project, type: "STAGING" });
27+
await createEnvironment({
28+
organization,
29+
project,
30+
type: "PREVIEW",
31+
isBranchableEnvironment: true,
32+
});
33+
}
34+
}
35+
}

pnpm-lock.yaml

Lines changed: 82 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)