- updatePolicy
- .mutateAsync({ id, data: { releaseSequencing: value } })
- .then(invalidatePolicy)
+ onValueChange={(releaseSequencing: "wait" | "cancel") =>
+ onUpdate({ releaseSequencing })
}
>
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/environment-policy-drawer/RolloutAndTiming.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/policy-form-components/RolloutAndTiming.tsx
similarity index 92%
rename from apps/webservice/src/app/[workspaceSlug]/(app)/_components/environment-policy-drawer/RolloutAndTiming.tsx
rename to apps/webservice/src/app/[workspaceSlug]/(app)/_components/policy-form-components/RolloutAndTiming.tsx
index d18820ad..b878aec2 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/environment-policy-drawer/RolloutAndTiming.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/policy-form-components/RolloutAndTiming.tsx
@@ -29,10 +29,6 @@ import {
SelectTrigger,
SelectValue,
} from "@ctrlplane/ui/select";
-import { toast } from "@ctrlplane/ui/toast";
-
-import { api } from "~/trpc/react";
-import { useInvalidatePolicy } from "./useInvalidatePolicy";
const isValidDuration = (str: string) => {
try {
@@ -46,7 +42,6 @@ const isValidDuration = (str: string) => {
const schema = z.object({
releaseWindows: z.array(
z.object({
- policyId: z.string().uuid(),
recurrence: z.enum(["hourly", "daily", "weekly", "monthly"]),
startTime: z.date(),
endTime: z.date(),
@@ -61,15 +56,19 @@ const schema = z.object({
});
type RolloutAndTimingProps = {
- environmentPolicy: SCHEMA.EnvironmentPolicy & {
+ environmentPolicy: {
+ rolloutDuration: number;
+ minimumReleaseInterval: number;
releaseWindows: SCHEMA.EnvironmentPolicyReleaseWindow[];
};
isLoading: boolean;
+ onUpdate: (data: SCHEMA.UpdateEnvironmentPolicy) => Promise;
};
export const RolloutAndTiming: React.FC = ({
environmentPolicy,
isLoading,
+ onUpdate,
}) => {
const rolloutDuration = prettyMilliseconds(environmentPolicy.rolloutDuration);
const minimumReleaseInterval = prettyMilliseconds(
@@ -87,20 +86,12 @@ export const RolloutAndTiming: React.FC = ({
name: "releaseWindows",
});
- const updatePolicy = api.environment.policy.update.useMutation();
- const invalidatePolicy = useInvalidatePolicy(environmentPolicy);
-
- const { id: policyId } = environmentPolicy;
const onSubmit = form.handleSubmit((data) => {
const { releaseWindows, rolloutDuration: durationString } = data;
const rolloutDuration = ms(durationString);
const minimumReleaseInterval = ms(data.minimumReleaseInterval);
const updates = { rolloutDuration, releaseWindows, minimumReleaseInterval };
- updatePolicy
- .mutateAsync({ id: policyId, data: updates })
- .then(() => form.reset(data))
- .then(() => invalidatePolicy())
- .catch((e) => toast.error(e.message));
+ onUpdate(updates);
});
return (
@@ -211,7 +202,6 @@ export const RolloutAndTiming: React.FC = ({
className="w-fit"
onClick={() =>
append({
- policyId: environmentPolicy.id,
recurrence: "weekly",
startTime: new Date(),
endTime: new Date(),
@@ -287,10 +277,7 @@ export const RolloutAndTiming: React.FC = ({
)}
/>
-
+
Save
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/reactflow/edges.ts b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/reactflow/edges.ts
index 57eb78b3..b5d68338 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/reactflow/edges.ts
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/reactflow/edges.ts
@@ -1,10 +1,6 @@
-import type {
- EnvironmentPolicy,
- EnvironmentPolicyDeployment,
-} from "@ctrlplane/db/schema";
+import type * as SCHEMA from "@ctrlplane/db/schema";
import { MarkerType } from "reactflow";
import colors from "tailwindcss/colors";
-import { isPresent } from "ts-is-present";
const markerEnd = {
type: MarkerType.Arrow,
@@ -12,10 +8,14 @@ const markerEnd = {
};
export const createEdgesWhereEnvironmentHasNoPolicy = (
- envs: Array<{ id: string; policyId?: string | null }>,
+ envs: SCHEMA.Environment[],
+ standalonePolicies: SCHEMA.EnvironmentPolicy[],
) =>
envs.map((e) => {
- const source = isPresent(e.policyId) ? e.policyId : "trigger";
+ const isUsingStandalonePolicy = standalonePolicies.some(
+ (p) => p.id === e.policyId,
+ );
+ const source = isUsingStandalonePolicy ? e.policyId : "trigger";
return {
id: source + "-" + e.id,
source,
@@ -35,7 +35,7 @@ export const createEdgesFromPolicyToEnvironment = (
}));
export const createEdgesFromPolicyDeployment = (
- policyDeployments: Array,
+ policyDeployments: Array,
) =>
policyDeployments.map((p) => ({
id: p.id,
@@ -45,8 +45,8 @@ export const createEdgesFromPolicyDeployment = (
}));
export const createEdgesWherePolicyHasNoEnvironment = (
- policies: Array,
- policyDeployments: Array,
+ policies: Array,
+ policyDeployments: Array,
) =>
policies
.filter((t) => !policyDeployments.some((p) => p.policyId === t.id))
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/release-channel-drawer/Usage.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/release-channel-drawer/Usage.tsx
index fb38bad4..7767d53a 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/_components/release-channel-drawer/Usage.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/_components/release-channel-drawer/Usage.tsx
@@ -4,7 +4,7 @@ import { IconFilter, IconPlant } from "@tabler/icons-react";
import { Button } from "@ctrlplane/ui/button";
-import { EnvironmentDrawerTab } from "../environment-drawer/EnvironmentDrawer";
+import { EnvironmentDrawerTab } from "../environment-drawer/tabs";
import { EnvironmentPolicyDrawerTab } from "../environment-policy-drawer/EnvironmentPolicyDrawer";
type UsageInfo = {
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/ReleaseEnvironmentCell.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/ReleaseEnvironmentCell.tsx
index 98b13a0a..4abea218 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/ReleaseEnvironmentCell.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/ReleaseEnvironmentCell.tsx
@@ -51,10 +51,10 @@ const ReleaseEnvironmentCell: React.FC = ({
api.release.blocked.useQuery([release.id]);
const { data: approval, isLoading: isApprovalLoading } =
- api.environment.policy.approval.statusByReleasePolicyId.useQuery(
- { releaseId: release.id, policyId: environment.policyId ?? "" },
- { enabled: environment.policyId != null },
- );
+ api.environment.policy.approval.statusByReleasePolicyId.useQuery({
+ releaseId: release.id,
+ policyId: environment.policyId,
+ });
const blockedEnv = blockedEnvsResult?.find(
(b) => b.environmentId === environment.id,
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/EnvironmentNode.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/EnvironmentNode.tsx
index 33611c08..ef7ffb72 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/EnvironmentNode.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/EnvironmentNode.tsx
@@ -147,14 +147,14 @@ const ReleaseChannelCheck: React.FC = ({
(rc) => rc.deploymentId === deploymentId,
);
- const policyReleaseChannel = environment.data?.policy?.releaseChannels.find(
+ const policyReleaseChannel = environment.data?.policy.releaseChannels.find(
(prc) => prc.deploymentId === deploymentId,
);
const rcId = envReleaseChannel?.id ?? policyReleaseChannel?.id ?? null;
- const { filter } = envReleaseChannel ??
- policyReleaseChannel ?? { filter: null };
+ const { releaseFilter: filter } = envReleaseChannel ??
+ policyReleaseChannel ?? { releaseFilter: null };
const versionFilter: ReleaseCondition = {
type: ReleaseFilterType.Version,
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/useReleaseChannel.ts b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/useReleaseChannel.ts
index d1d97548..c4e50672 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/useReleaseChannel.ts
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/releases/[versionId]/useReleaseChannel.ts
@@ -20,12 +20,12 @@ export const useReleaseChannel = (
const envReleaseChannel = environment.data?.releaseChannels.find(
(rc) => rc.deploymentId === deploymentId,
);
- const policyReleaseChannel = environment.data?.policy?.releaseChannels.find(
+ const policyReleaseChannel = environment.data?.policy.releaseChannels.find(
(prc) => prc.deploymentId === deploymentId,
);
const rcId = envReleaseChannel?.id ?? policyReleaseChannel?.id ?? null;
- const { filter } = envReleaseChannel ??
- policyReleaseChannel ?? { filter: null };
+ const { releaseFilter: filter } = envReleaseChannel ??
+ policyReleaseChannel ?? { releaseFilter: null };
const versionFilter: ReleaseCondition = {
type: ReleaseFilterType.Version,
diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/environments/EnvFlowBuilder.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/environments/EnvFlowBuilder.tsx
index 8cfa9bfa..6a76f41d 100644
--- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/environments/EnvFlowBuilder.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/environments/EnvFlowBuilder.tsx
@@ -84,12 +84,6 @@ const useValidConnection = () => {
if (target.type === NodeType.Policy && source.type === NodeType.Policy)
return false;
- if (
- target.type === NodeType.Environment &&
- source.type === NodeType.Policy
- )
- return !isPresent(target.data.policyId);
-
return true;
},
[getNodes, getEdges, getNode],
@@ -175,6 +169,7 @@ export const EnvFlowBuilder: React.FC<{
policies: Array;
policyDeployments: Array;
}> = ({ systemId, envs, policies, policyDeployments }) => {
+ const standalonePolicies = policies.filter((p) => p.environmentId == null);
const [nodes, _, onNodesChange] = useNodesState([
triggerNode,
...envs.map((env) => ({
@@ -183,7 +178,7 @@ export const EnvFlowBuilder: React.FC<{
position: { x: 0, y: 0 },
data: { ...env, label: env.name },
})),
- ...policies.map((policy) => ({
+ ...standalonePolicies.map((policy) => ({
id: policy.id,
type: NodeType.Policy,
position: { x: 0, y: 0 },
@@ -204,8 +199,11 @@ export const EnvFlowBuilder: React.FC<{
});
const [edges, __, onEdgesChange] = useEdgesState([
- ...createEdgesWhereEnvironmentHasNoPolicy(envs),
- ...createEdgesWherePolicyHasNoEnvironment(policies, policyDeployments),
+ ...createEdgesWhereEnvironmentHasNoPolicy(envs, standalonePolicies),
+ ...createEdgesWherePolicyHasNoEnvironment(
+ standalonePolicies,
+ policyDeployments,
+ ),
...createEdgesFromPolicyDeployment(policyDeployments),
]);
diff --git a/apps/webservice/src/app/api/v1/environments/route.ts b/apps/webservice/src/app/api/v1/environments/route.ts
index fed76221..5c21c5f0 100644
--- a/apps/webservice/src/app/api/v1/environments/route.ts
+++ b/apps/webservice/src/app/api/v1/environments/route.ts
@@ -1,12 +1,10 @@
import type { PermissionChecker } from "@ctrlplane/auth/utils";
-import type { Tx } from "@ctrlplane/db";
import type { User } from "@ctrlplane/db/schema";
import { NextResponse } from "next/server";
import _ from "lodash";
-import { isPresent } from "ts-is-present";
import { z } from "zod";
-import { and, eq, inArray, takeFirst } from "@ctrlplane/db";
+import { and, createEnv, eq, inArray } from "@ctrlplane/db";
import * as schema from "@ctrlplane/db/schema";
import { createJobsForNewEnvironment } from "@ctrlplane/job-dispatch";
import { logger } from "@ctrlplane/logger";
@@ -24,19 +22,6 @@ const body = schema.createEnvironment.extend({
.optional(),
});
-const createReleaseChannels = (
- db: Tx,
- environmentId: string,
- releaseChannels: { channelId: string; deploymentId: string }[],
-) =>
- db.insert(schema.environmentReleaseChannel).values(
- releaseChannels.map(({ channelId, deploymentId }) => ({
- environmentId,
- channelId,
- deploymentId,
- })),
- );
-
export const POST = request()
.use(authn)
.use(parseBody(body))
@@ -63,42 +48,24 @@ export const POST = request()
try {
return ctx.db.transaction(async (tx) => {
- const environment = await tx
- .insert(schema.environment)
- .values({ ...ctx.body })
- .returning()
- .then(takeFirst);
+ const { releaseChannels, metadata, ...rest } = ctx.body;
- const { metadata } = ctx.body;
- if (metadata != null)
- await tx.insert(schema.environmentMetadata).values(
- Object.entries(metadata).map(([key, value]) => ({
- environmentId: environment.id,
- key,
- value,
- })),
- );
-
- if (
- isPresent(ctx.body.releaseChannels) &&
- ctx.body.releaseChannels.length > 0
- ) {
- const releaseChannels = await tx
- .select()
- .from(schema.releaseChannel)
- .where(
- inArray(schema.releaseChannel.id, ctx.body.releaseChannels),
- );
-
- await createReleaseChannels(
- tx,
- environment.id,
- _.uniqBy(releaseChannels, (r) => r.deploymentId).map((r) => ({
+ const channels = await tx
+ .select()
+ .from(schema.releaseChannel)
+ .where(inArray(schema.releaseChannel.id, releaseChannels))
+ .then((rows) =>
+ _.uniqBy(rows, (r) => r.deploymentId).map((r) => ({
channelId: r.id,
deploymentId: r.deploymentId,
})),
);
- }
+
+ const environment = await createEnv(tx, {
+ ...rest,
+ metadata,
+ releaseChannels: channels,
+ });
await createJobsForNewEnvironment(tx, environment);
return NextResponse.json({ ...environment, metadata });
diff --git a/packages/api/src/router/environment-policy.ts b/packages/api/src/router/environment-policy.ts
index 545d1483..6397b831 100644
--- a/packages/api/src/router/environment-policy.ts
+++ b/packages/api/src/router/environment-policy.ts
@@ -7,6 +7,7 @@ import {
buildConflictUpdateColumns,
eq,
inArray,
+ sql,
takeFirst,
} from "@ctrlplane/db";
import {
@@ -295,7 +296,7 @@ export const policyRouter = createTRPCRouter({
if (releaseWindows.length > 0)
await db
.insert(environmentPolicyReleaseWindow)
- .values(releaseWindows)
+ .values(releaseWindows.map((r) => ({ ...r, policyId: input.id })))
.returning();
});
}
@@ -316,10 +317,23 @@ export const policyRouter = createTRPCRouter({
})
.input(z.string().uuid())
.mutation(({ ctx, input }) =>
- ctx.db
- .delete(environmentPolicy)
- .where(eq(environmentPolicy.id, input))
- .returning()
- .then(takeFirst),
+ ctx.db.transaction((db) =>
+ db
+ .execute(
+ sql`UPDATE environment e
+ SET policy_id = ep.id
+ FROM environment_policy ep
+ WHERE e.id = ep.environment_id
+ AND e.policy_id = ${input}
+ `,
+ )
+ .then(() =>
+ db
+ .delete(environmentPolicy)
+ .where(eq(environmentPolicy.id, input))
+ .returning()
+ .then(takeFirst),
+ ),
+ ),
),
});
diff --git a/packages/api/src/router/environment.ts b/packages/api/src/router/environment.ts
index eefe8e04..010ce45a 100644
--- a/packages/api/src/router/environment.ts
+++ b/packages/api/src/router/environment.ts
@@ -1,4 +1,3 @@
-import type { Tx } from "@ctrlplane/db";
import type { ResourceCondition } from "@ctrlplane/validators/resources";
import _ from "lodash";
import { isPresent } from "ts-is-present";
@@ -7,6 +6,7 @@ import { z } from "zod";
import {
and,
buildConflictUpdateColumns,
+ createEnv,
eq,
inArray,
isNotNull,
@@ -21,6 +21,7 @@ import {
environmentMetadata,
environmentPolicy,
environmentPolicyReleaseChannel,
+ environmentPolicyReleaseWindow,
environmentReleaseChannel,
releaseChannel,
resource,
@@ -43,11 +44,6 @@ import {
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { policyRouter } from "./environment-policy";
-export const createEnv = async (
- db: Tx,
- input: z.infer,
-) => db.insert(environment).values(input).returning().then(takeFirst);
-
export const environmentRouter = createTRPCRouter({
policy: policyRouter,
@@ -64,6 +60,7 @@ export const environmentRouter = createTRPCRouter({
.select({
releaseChannelEnvId: environmentReleaseChannel.environmentId,
releaseChannelDeploymentId: releaseChannel.deploymentId,
+ releaseChannelDescription: releaseChannel.description,
releaseChannelFilter: releaseChannel.releaseFilter,
releaseChannelId: releaseChannel.id,
releaseChannelName: releaseChannel.name,
@@ -79,6 +76,7 @@ export const environmentRouter = createTRPCRouter({
.select({
releaseChannelPolicyId: environmentPolicyReleaseChannel.policyId,
releaseChannelDeploymentId: releaseChannel.deploymentId,
+ releaseChannelDescription: releaseChannel.description,
releaseChannelFilter: releaseChannel.releaseFilter,
releaseChannelId: releaseChannel.id,
releaseChannelName: releaseChannel.name,
@@ -93,10 +91,14 @@ export const environmentRouter = createTRPCRouter({
return ctx.db
.select()
.from(environment)
- .leftJoin(
+ .innerJoin(
environmentPolicy,
eq(environment.policyId, environmentPolicy.id),
)
+ .leftJoin(
+ environmentPolicyReleaseWindow,
+ eq(environmentPolicyReleaseWindow.policyId, environmentPolicy.id),
+ )
.innerJoin(system, eq(environment.systemId, system.id))
.leftJoin(
envRCSubquery,
@@ -114,23 +116,29 @@ export const environmentRouter = createTRPCRouter({
.then((rows) => {
const env = rows.at(0);
if (env == null) return null;
- const policy =
- env.environment_policy == null
- ? null
- : {
- ...env.environment_policy,
- releaseChannels: _.chain(rows)
- .map((r) => r.policyRCSubquery)
- .filter(isPresent)
- .uniqBy((r) => r.releaseChannelId)
- .map((r) => ({
- deploymentId: r.releaseChannelDeploymentId,
- filter: r.releaseChannelFilter,
- id: r.releaseChannelId,
- name: r.releaseChannelName,
- }))
- .value(),
- };
+
+ const policy = {
+ ...env.environment_policy,
+ releaseChannels: _.chain(rows)
+ .map((r) => r.policyRCSubquery)
+ .filter(isPresent)
+ .uniqBy((r) => r.releaseChannelId)
+ .map((r) => ({
+ deploymentId: r.releaseChannelDeploymentId,
+ description: r.releaseChannelDescription,
+ releaseFilter: r.releaseChannelFilter,
+ id: r.releaseChannelId,
+ name: r.releaseChannelName,
+ }))
+ .value(),
+ releaseWindows: _.chain(rows)
+ .map((r) => r.environment_policy_release_window)
+ .filter(isPresent)
+ .uniqBy((r) => r.id)
+ .value(),
+ isOverride:
+ env.environment_policy.environmentId === env.environment.id,
+ };
const releaseChannels = _.chain(rows)
.map((r) => r.envRCSubquery)
@@ -138,7 +146,8 @@ export const environmentRouter = createTRPCRouter({
.uniqBy((r) => r.releaseChannelId)
.map((r) => ({
deploymentId: r.releaseChannelDeploymentId,
- filter: r.releaseChannelFilter,
+ releaseFilter: r.releaseChannelFilter,
+ description: r.releaseChannelDescription,
id: r.releaseChannelId,
name: r.releaseChannelName,
}))
@@ -246,9 +255,23 @@ export const environmentRouter = createTRPCRouter({
.where(eq(environment.id, input.id))
.then(takeFirst);
+ const overridePolicy = await ctx.db
+ .select()
+ .from(environmentPolicy)
+ .where(eq(environmentPolicy.environmentId, input.id))
+ .then(takeFirst);
+
+ const getPolicyId = () => {
+ if (input.data.policyId != null) return input.data.policyId;
+ if (input.data.policyId === null) return overridePolicy.id;
+ return oldEnv.environment.policyId;
+ };
+
+ const policyId = getPolicyId();
+
const updatedEnv = await ctx.db
.update(environment)
- .set(input.data)
+ .set({ ...input.data, policyId })
.where(eq(environment.id, input.id))
.returning()
.then(takeFirst);
diff --git a/packages/api/src/router/system.ts b/packages/api/src/router/system.ts
index e11901c6..8a08f9a8 100644
--- a/packages/api/src/router/system.ts
+++ b/packages/api/src/router/system.ts
@@ -2,7 +2,7 @@ import _ from "lodash";
import { isPresent } from "ts-is-present";
import { z } from "zod";
-import { and, asc, count, eq, like, takeFirst } from "@ctrlplane/db";
+import { and, asc, count, createEnv, eq, like, takeFirst } from "@ctrlplane/db";
import {
createSystem,
environment,
@@ -13,7 +13,6 @@ import {
import { Permission } from "@ctrlplane/validators/auth";
import { createTRPCRouter, protectedProcedure } from "../trpc";
-import { createEnv } from "./environment";
export const systemRouter = createTRPCRouter({
list: protectedProcedure
diff --git a/packages/db/drizzle/0065_familiar_jazinda.sql b/packages/db/drizzle/0065_familiar_jazinda.sql
new file mode 100644
index 00000000..6182a37f
--- /dev/null
+++ b/packages/db/drizzle/0065_familiar_jazinda.sql
@@ -0,0 +1,27 @@
+BEGIN;
+ALTER TABLE "environment_policy" ADD COLUMN "environment_id" uuid;--> statement-breakpoint
+DO $$ BEGIN
+ALTER TABLE "environment_policy" ADD CONSTRAINT "environment_policy_environment_id_environment_id_fk" FOREIGN KEY ("environment_id") REFERENCES "public"."environment"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+WHEN duplicate_object THEN null;
+END $$;
+
+-- Backfill default environment policies for each environment
+INSERT INTO "environment_policy" ("name", "environment_id", "system_id")
+SELECT
+ e."name" AS "name",
+ e."id" AS "environment_id",
+ e."system_id" AS "system_id"
+FROM "environment" e
+LEFT JOIN environment_policy ep ON e.id = ep.environment_id
+WHERE ep.environment_id IS NULL;
+
+UPDATE "environment"
+SET "policy_id" = ep."id"
+FROM "environment_policy" ep
+WHERE "environment"."id" = ep."environment_id"
+ AND "environment"."policy_id" IS NULL;
+
+ALTER TABLE "environment" ALTER COLUMN "policy_id" SET NOT NULL;--> statement-breakpoint
+
+COMMIT;
\ No newline at end of file
diff --git a/packages/db/drizzle/meta/0065_snapshot.json b/packages/db/drizzle/meta/0065_snapshot.json
new file mode 100644
index 00000000..3d309fb5
--- /dev/null
+++ b/packages/db/drizzle/meta/0065_snapshot.json
@@ -0,0 +1,4614 @@
+{
+ "id": "742cf221-2571-49af-891c-e22d807395ae",
+ "prevId": "8c075e46-20aa-4a9f-bd95-a061e71abfca",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.account": {
+ "name": "account",
+ "schema": "",
+ "columns": {
+ "userId": {
+ "name": "userId",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider": {
+ "name": "provider",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "providerAccountId": {
+ "name": "providerAccountId",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "token_type": {
+ "name": "token_type",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "session_state": {
+ "name": "session_state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "account_userId_user_id_fk": {
+ "name": "account_userId_user_id_fk",
+ "tableFrom": "account",
+ "tableTo": "user",
+ "columnsFrom": ["userId"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "account_provider_providerAccountId_pk": {
+ "name": "account_provider_providerAccountId_pk",
+ "columns": ["provider", "providerAccountId"]
+ }
+ },
+ "uniqueConstraints": {}
+ },
+ "public.session": {
+ "name": "session",
+ "schema": "",
+ "columns": {
+ "sessionToken": {
+ "name": "sessionToken",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires": {
+ "name": "expires",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "session_userId_user_id_fk": {
+ "name": "session_userId_user_id_fk",
+ "tableFrom": "session",
+ "tableTo": "user",
+ "columnsFrom": ["userId"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.user": {
+ "name": "user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "emailVerified": {
+ "name": "emailVerified",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "image": {
+ "name": "image",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "active_workspace_id": {
+ "name": "active_workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "null"
+ },
+ "password_hash": {
+ "name": "password_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "null"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "user_active_workspace_id_workspace_id_fk": {
+ "name": "user_active_workspace_id_workspace_id_fk",
+ "tableFrom": "user",
+ "tableTo": "workspace",
+ "columnsFrom": ["active_workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.user_api_key": {
+ "name": "user_api_key",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(255)",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key_preview": {
+ "name": "key_preview",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key_hash": {
+ "name": "key_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key_prefix": {
+ "name": "key_prefix",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "user_api_key_key_prefix_key_hash_index": {
+ "name": "user_api_key_key_prefix_key_hash_index",
+ "columns": [
+ {
+ "expression": "key_prefix",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "user_api_key_user_id_user_id_fk": {
+ "name": "user_api_key_user_id_user_id_fk",
+ "tableFrom": "user_api_key",
+ "tableTo": "user",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.dashboard": {
+ "name": "dashboard",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "dashboard_workspace_id_workspace_id_fk": {
+ "name": "dashboard_workspace_id_workspace_id_fk",
+ "tableFrom": "dashboard",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.dashboard_widget": {
+ "name": "dashboard_widget",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "dashboard_id": {
+ "name": "dashboard_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "widget": {
+ "name": "widget",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "config": {
+ "name": "config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "x": {
+ "name": "x",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "y": {
+ "name": "y",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "w": {
+ "name": "w",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "h": {
+ "name": "h",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "dashboard_widget_dashboard_id_dashboard_id_fk": {
+ "name": "dashboard_widget_dashboard_id_dashboard_id_fk",
+ "tableFrom": "dashboard_widget",
+ "tableTo": "dashboard",
+ "columnsFrom": ["dashboard_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.deployment_variable": {
+ "name": "deployment_variable",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "''"
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "default_value_id": {
+ "name": "default_value_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ },
+ "schema": {
+ "name": "schema",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "deployment_variable_deployment_id_key_index": {
+ "name": "deployment_variable_deployment_id_key_index",
+ "columns": [
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "deployment_variable_deployment_id_deployment_id_fk": {
+ "name": "deployment_variable_deployment_id_deployment_id_fk",
+ "tableFrom": "deployment_variable",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "deployment_variable_default_value_id_deployment_variable_value_id_fk": {
+ "name": "deployment_variable_default_value_id_deployment_variable_value_id_fk",
+ "tableFrom": "deployment_variable",
+ "tableTo": "deployment_variable_value",
+ "columnsFrom": ["default_value_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.deployment_variable_set": {
+ "name": "deployment_variable_set",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "variable_set_id": {
+ "name": "variable_set_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "deployment_variable_set_deployment_id_variable_set_id_index": {
+ "name": "deployment_variable_set_deployment_id_variable_set_id_index",
+ "columns": [
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "variable_set_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "deployment_variable_set_deployment_id_deployment_id_fk": {
+ "name": "deployment_variable_set_deployment_id_deployment_id_fk",
+ "tableFrom": "deployment_variable_set",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "deployment_variable_set_variable_set_id_variable_set_id_fk": {
+ "name": "deployment_variable_set_variable_set_id_variable_set_id_fk",
+ "tableFrom": "deployment_variable_set",
+ "tableTo": "variable_set",
+ "columnsFrom": ["variable_set_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.deployment_variable_value": {
+ "name": "deployment_variable_value",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "variable_id": {
+ "name": "variable_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "resource_filter": {
+ "name": "resource_filter",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ }
+ },
+ "indexes": {
+ "deployment_variable_value_variable_id_value_index": {
+ "name": "deployment_variable_value_variable_id_value_index",
+ "columns": [
+ {
+ "expression": "variable_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "value",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "deployment_variable_value_variable_id_deployment_variable_id_fk": {
+ "name": "deployment_variable_value_variable_id_deployment_variable_id_fk",
+ "tableFrom": "deployment_variable_value",
+ "tableTo": "deployment_variable",
+ "columnsFrom": ["variable_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "restrict"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.deployment": {
+ "name": "deployment",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "system_id": {
+ "name": "system_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "job_agent_id": {
+ "name": "job_agent_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "job_agent_config": {
+ "name": "job_agent_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ },
+ "retry_count": {
+ "name": "retry_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "timeout": {
+ "name": "timeout",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ },
+ "resource_filter": {
+ "name": "resource_filter",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ }
+ },
+ "indexes": {
+ "deployment_system_id_slug_index": {
+ "name": "deployment_system_id_slug_index",
+ "columns": [
+ {
+ "expression": "system_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "deployment_system_id_system_id_fk": {
+ "name": "deployment_system_id_system_id_fk",
+ "tableFrom": "deployment",
+ "tableTo": "system",
+ "columnsFrom": ["system_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "deployment_job_agent_id_job_agent_id_fk": {
+ "name": "deployment_job_agent_id_job_agent_id_fk",
+ "tableFrom": "deployment",
+ "tableTo": "job_agent",
+ "columnsFrom": ["job_agent_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.deployment_meta_dependency": {
+ "name": "deployment_meta_dependency",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "depends_on_id": {
+ "name": "depends_on_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "deployment_meta_dependency_depends_on_id_deployment_id_index": {
+ "name": "deployment_meta_dependency_depends_on_id_deployment_id_index",
+ "columns": [
+ {
+ "expression": "depends_on_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "deployment_meta_dependency_deployment_id_deployment_id_fk": {
+ "name": "deployment_meta_dependency_deployment_id_deployment_id_fk",
+ "tableFrom": "deployment_meta_dependency",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "deployment_meta_dependency_depends_on_id_deployment_id_fk": {
+ "name": "deployment_meta_dependency_depends_on_id_deployment_id_fk",
+ "tableFrom": "deployment_meta_dependency",
+ "tableTo": "deployment",
+ "columnsFrom": ["depends_on_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_policy_deployment": {
+ "name": "environment_policy_deployment",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "policy_id": {
+ "name": "policy_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "environment_policy_deployment_policy_id_environment_id_index": {
+ "name": "environment_policy_deployment_policy_id_environment_id_index",
+ "columns": [
+ {
+ "expression": "policy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_policy_deployment_policy_id_environment_policy_id_fk": {
+ "name": "environment_policy_deployment_policy_id_environment_policy_id_fk",
+ "tableFrom": "environment_policy_deployment",
+ "tableTo": "environment_policy",
+ "columnsFrom": ["policy_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_deployment_environment_id_environment_id_fk": {
+ "name": "environment_policy_deployment_environment_id_environment_id_fk",
+ "tableFrom": "environment_policy_deployment",
+ "tableTo": "environment",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment": {
+ "name": "environment",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "system_id": {
+ "name": "system_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "''"
+ },
+ "policy_id": {
+ "name": "policy_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "resource_filter": {
+ "name": "resource_filter",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "environment_system_id_name_index": {
+ "name": "environment_system_id_name_index",
+ "columns": [
+ {
+ "expression": "system_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_system_id_system_id_fk": {
+ "name": "environment_system_id_system_id_fk",
+ "tableFrom": "environment",
+ "tableTo": "system",
+ "columnsFrom": ["system_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_id_environment_policy_id_fk": {
+ "name": "environment_policy_id_environment_policy_id_fk",
+ "tableFrom": "environment",
+ "tableTo": "environment_policy",
+ "columnsFrom": ["policy_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_metadata": {
+ "name": "environment_metadata",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "environment_metadata_key_environment_id_index": {
+ "name": "environment_metadata_key_environment_id_index",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_metadata_environment_id_environment_id_fk": {
+ "name": "environment_metadata_environment_id_environment_id_fk",
+ "tableFrom": "environment_metadata",
+ "tableTo": "environment",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_policy": {
+ "name": "environment_policy",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "system_id": {
+ "name": "system_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "approval_required": {
+ "name": "approval_required",
+ "type": "environment_policy_approval_requirement",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'manual'"
+ },
+ "success_status": {
+ "name": "success_status",
+ "type": "environment_policy_deployment_success_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'all'"
+ },
+ "minimum_success": {
+ "name": "minimum_success",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "concurrency_limit": {
+ "name": "concurrency_limit",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ },
+ "rollout_duration": {
+ "name": "rollout_duration",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "minimum_release_interval": {
+ "name": "minimum_release_interval",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "release_sequencing": {
+ "name": "release_sequencing",
+ "type": "release_sequencing_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'cancel'"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "environment_policy_system_id_system_id_fk": {
+ "name": "environment_policy_system_id_system_id_fk",
+ "tableFrom": "environment_policy",
+ "tableTo": "system",
+ "columnsFrom": ["system_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_environment_id_environment_id_fk": {
+ "name": "environment_policy_environment_id_environment_id_fk",
+ "tableFrom": "environment_policy",
+ "tableTo": "environment",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_policy_approval": {
+ "name": "environment_policy_approval",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "policy_id": {
+ "name": "policy_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "release_id": {
+ "name": "release_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "approval_status_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'pending'"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "approved_at": {
+ "name": "approved_at",
+ "type": "timestamp (0) with time zone",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ }
+ },
+ "indexes": {
+ "environment_policy_approval_policy_id_release_id_index": {
+ "name": "environment_policy_approval_policy_id_release_id_index",
+ "columns": [
+ {
+ "expression": "policy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "release_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_policy_approval_policy_id_environment_policy_id_fk": {
+ "name": "environment_policy_approval_policy_id_environment_policy_id_fk",
+ "tableFrom": "environment_policy_approval",
+ "tableTo": "environment_policy",
+ "columnsFrom": ["policy_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_approval_release_id_release_id_fk": {
+ "name": "environment_policy_approval_release_id_release_id_fk",
+ "tableFrom": "environment_policy_approval",
+ "tableTo": "release",
+ "columnsFrom": ["release_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_approval_user_id_user_id_fk": {
+ "name": "environment_policy_approval_user_id_user_id_fk",
+ "tableFrom": "environment_policy_approval",
+ "tableTo": "user",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_policy_release_window": {
+ "name": "environment_policy_release_window",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "policy_id": {
+ "name": "policy_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "start_time": {
+ "name": "start_time",
+ "type": "timestamp (0) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "end_time": {
+ "name": "end_time",
+ "type": "timestamp (0) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "recurrence": {
+ "name": "recurrence",
+ "type": "recurrence_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "environment_policy_release_window_policy_id_environment_policy_id_fk": {
+ "name": "environment_policy_release_window_policy_id_environment_policy_id_fk",
+ "tableFrom": "environment_policy_release_window",
+ "tableTo": "environment_policy",
+ "columnsFrom": ["policy_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.event": {
+ "name": "event",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.hook": {
+ "name": "hook",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope_type": {
+ "name": "scope_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope_id": {
+ "name": "scope_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.runhook": {
+ "name": "runhook",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "hook_id": {
+ "name": "hook_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "runbook_id": {
+ "name": "runbook_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "runhook_hook_id_runbook_id_index": {
+ "name": "runhook_hook_id_runbook_id_index",
+ "columns": [
+ {
+ "expression": "hook_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "runbook_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "runhook_hook_id_hook_id_fk": {
+ "name": "runhook_hook_id_hook_id_fk",
+ "tableFrom": "runhook",
+ "tableTo": "hook",
+ "columnsFrom": ["hook_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "runhook_runbook_id_runbook_id_fk": {
+ "name": "runhook_runbook_id_runbook_id_fk",
+ "tableFrom": "runhook",
+ "tableTo": "runbook",
+ "columnsFrom": ["runbook_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.github_entity": {
+ "name": "github_entity",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "github_entity_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'organization'"
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "added_by_user_id": {
+ "name": "added_by_user_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "avatar_url": {
+ "name": "avatar_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "unique_installation_workspace": {
+ "name": "unique_installation_workspace",
+ "columns": [
+ {
+ "expression": "installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "github_entity_added_by_user_id_user_id_fk": {
+ "name": "github_entity_added_by_user_id_user_id_fk",
+ "tableFrom": "github_entity",
+ "tableTo": "user",
+ "columnsFrom": ["added_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "github_entity_workspace_id_workspace_id_fk": {
+ "name": "github_entity_workspace_id_workspace_id_fk",
+ "tableFrom": "github_entity",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.github_user": {
+ "name": "github_user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "github_user_id": {
+ "name": "github_user_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "github_username": {
+ "name": "github_username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "github_user_user_id_user_id_fk": {
+ "name": "github_user_user_id_user_id_fk",
+ "tableFrom": "github_user",
+ "tableTo": "user",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.job_resource_relationship": {
+ "name": "job_resource_relationship",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "job_id": {
+ "name": "job_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "resource_identifier": {
+ "name": "resource_identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "job_resource_relationship_job_id_resource_identifier_index": {
+ "name": "job_resource_relationship_job_id_resource_identifier_index",
+ "columns": [
+ {
+ "expression": "job_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "resource_identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "job_resource_relationship_job_id_job_id_fk": {
+ "name": "job_resource_relationship_job_id_job_id_fk",
+ "tableFrom": "job_resource_relationship",
+ "tableTo": "job",
+ "columnsFrom": ["job_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource": {
+ "name": "resource",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "version": {
+ "name": "version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "config": {
+ "name": "config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "locked_at": {
+ "name": "locked_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "resource_identifier_workspace_id_index": {
+ "name": "resource_identifier_workspace_id_index",
+ "columns": [
+ {
+ "expression": "identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "resource_provider_id_resource_provider_id_fk": {
+ "name": "resource_provider_id_resource_provider_id_fk",
+ "tableFrom": "resource",
+ "tableTo": "resource_provider",
+ "columnsFrom": ["provider_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "resource_workspace_id_workspace_id_fk": {
+ "name": "resource_workspace_id_workspace_id_fk",
+ "tableFrom": "resource",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_metadata": {
+ "name": "resource_metadata",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "resource_id": {
+ "name": "resource_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "resource_metadata_key_resource_id_index": {
+ "name": "resource_metadata_key_resource_id_index",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "resource_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "resource_metadata_resource_id_resource_id_fk": {
+ "name": "resource_metadata_resource_id_resource_id_fk",
+ "tableFrom": "resource_metadata",
+ "tableTo": "resource",
+ "columnsFrom": ["resource_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_relationship": {
+ "name": "resource_relationship",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "from_identifier": {
+ "name": "from_identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "to_identifier": {
+ "name": "to_identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "resource_relationship_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "resource_relationship_to_identifier_from_identifier_index": {
+ "name": "resource_relationship_to_identifier_from_identifier_index",
+ "columns": [
+ {
+ "expression": "to_identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "from_identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "resource_relationship_workspace_id_workspace_id_fk": {
+ "name": "resource_relationship_workspace_id_workspace_id_fk",
+ "tableFrom": "resource_relationship",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_schema": {
+ "name": "resource_schema",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version": {
+ "name": "version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "json_schema": {
+ "name": "json_schema",
+ "type": "json",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "resource_schema_version_kind_workspace_id_index": {
+ "name": "resource_schema_version_kind_workspace_id_index",
+ "columns": [
+ {
+ "expression": "version",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "resource_schema_workspace_id_workspace_id_fk": {
+ "name": "resource_schema_workspace_id_workspace_id_fk",
+ "tableFrom": "resource_schema",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_variable": {
+ "name": "resource_variable",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "resource_id": {
+ "name": "resource_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "sensitive": {
+ "name": "sensitive",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {
+ "resource_variable_resource_id_key_index": {
+ "name": "resource_variable_resource_id_key_index",
+ "columns": [
+ {
+ "expression": "resource_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "resource_variable_resource_id_resource_id_fk": {
+ "name": "resource_variable_resource_id_resource_id_fk",
+ "tableFrom": "resource_variable",
+ "tableTo": "resource",
+ "columnsFrom": ["resource_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_view": {
+ "name": "resource_view",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "''"
+ },
+ "filter": {
+ "name": "filter",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "resource_view_workspace_id_workspace_id_fk": {
+ "name": "resource_view_workspace_id_workspace_id_fk",
+ "tableFrom": "resource_view",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.azure_tenant": {
+ "name": "azure_tenant",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "azure_tenant_tenant_id_index": {
+ "name": "azure_tenant_tenant_id_index",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "azure_tenant_workspace_id_workspace_id_fk": {
+ "name": "azure_tenant_workspace_id_workspace_id_fk",
+ "tableFrom": "azure_tenant",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_provider": {
+ "name": "resource_provider",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "resource_provider_workspace_id_name_index": {
+ "name": "resource_provider_workspace_id_name_index",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "resource_provider_workspace_id_workspace_id_fk": {
+ "name": "resource_provider_workspace_id_workspace_id_fk",
+ "tableFrom": "resource_provider",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_provider_aws": {
+ "name": "resource_provider_aws",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "resource_provider_id": {
+ "name": "resource_provider_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "aws_role_arns": {
+ "name": "aws_role_arns",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "import_eks": {
+ "name": "import_eks",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "import_vpc": {
+ "name": "import_vpc",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "resource_provider_aws_resource_provider_id_resource_provider_id_fk": {
+ "name": "resource_provider_aws_resource_provider_id_resource_provider_id_fk",
+ "tableFrom": "resource_provider_aws",
+ "tableTo": "resource_provider",
+ "columnsFrom": ["resource_provider_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_provider_azure": {
+ "name": "resource_provider_azure",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "resource_provider_id": {
+ "name": "resource_provider_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "subscription_id": {
+ "name": "subscription_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "resource_provider_azure_resource_provider_id_resource_provider_id_fk": {
+ "name": "resource_provider_azure_resource_provider_id_resource_provider_id_fk",
+ "tableFrom": "resource_provider_azure",
+ "tableTo": "resource_provider",
+ "columnsFrom": ["resource_provider_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "resource_provider_azure_tenant_id_azure_tenant_id_fk": {
+ "name": "resource_provider_azure_tenant_id_azure_tenant_id_fk",
+ "tableFrom": "resource_provider_azure",
+ "tableTo": "azure_tenant",
+ "columnsFrom": ["tenant_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.resource_provider_google": {
+ "name": "resource_provider_google",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "resource_provider_id": {
+ "name": "resource_provider_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "project_ids": {
+ "name": "project_ids",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "import_gke": {
+ "name": "import_gke",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "import_namespaces": {
+ "name": "import_namespaces",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "import_vcluster": {
+ "name": "import_vcluster",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "import_vms": {
+ "name": "import_vms",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "import_vpc": {
+ "name": "import_vpc",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "resource_provider_google_resource_provider_id_resource_provider_id_fk": {
+ "name": "resource_provider_google_resource_provider_id_resource_provider_id_fk",
+ "tableFrom": "resource_provider_google",
+ "tableTo": "resource_provider",
+ "columnsFrom": ["resource_provider_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.release": {
+ "name": "release",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version": {
+ "name": "version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "config": {
+ "name": "config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ },
+ "job_agent_config": {
+ "name": "job_agent_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "release_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'ready'"
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "release_deployment_id_version_index": {
+ "name": "release_deployment_id_version_index",
+ "columns": [
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "version",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "release_deployment_id_deployment_id_fk": {
+ "name": "release_deployment_id_deployment_id_fk",
+ "tableFrom": "release",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.release_channel": {
+ "name": "release_channel",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "''"
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "release_filter": {
+ "name": "release_filter",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ }
+ },
+ "indexes": {
+ "release_channel_deployment_id_name_index": {
+ "name": "release_channel_deployment_id_name_index",
+ "columns": [
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "release_channel_deployment_id_deployment_id_fk": {
+ "name": "release_channel_deployment_id_deployment_id_fk",
+ "tableFrom": "release_channel",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.release_dependency": {
+ "name": "release_dependency",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "release_id": {
+ "name": "release_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "release_filter": {
+ "name": "release_filter",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "NULL"
+ }
+ },
+ "indexes": {
+ "release_dependency_release_id_deployment_id_index": {
+ "name": "release_dependency_release_id_deployment_id_index",
+ "columns": [
+ {
+ "expression": "release_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "release_dependency_release_id_release_id_fk": {
+ "name": "release_dependency_release_id_release_id_fk",
+ "tableFrom": "release_dependency",
+ "tableTo": "release",
+ "columnsFrom": ["release_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "release_dependency_deployment_id_deployment_id_fk": {
+ "name": "release_dependency_deployment_id_deployment_id_fk",
+ "tableFrom": "release_dependency",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.release_job_trigger": {
+ "name": "release_job_trigger",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "job_id": {
+ "name": "job_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "release_job_trigger_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "caused_by_id": {
+ "name": "caused_by_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "release_id": {
+ "name": "release_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "resource_id": {
+ "name": "resource_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "release_job_trigger_job_id_job_id_fk": {
+ "name": "release_job_trigger_job_id_job_id_fk",
+ "tableFrom": "release_job_trigger",
+ "tableTo": "job",
+ "columnsFrom": ["job_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "release_job_trigger_caused_by_id_user_id_fk": {
+ "name": "release_job_trigger_caused_by_id_user_id_fk",
+ "tableFrom": "release_job_trigger",
+ "tableTo": "user",
+ "columnsFrom": ["caused_by_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "release_job_trigger_release_id_release_id_fk": {
+ "name": "release_job_trigger_release_id_release_id_fk",
+ "tableFrom": "release_job_trigger",
+ "tableTo": "release",
+ "columnsFrom": ["release_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "release_job_trigger_resource_id_resource_id_fk": {
+ "name": "release_job_trigger_resource_id_resource_id_fk",
+ "tableFrom": "release_job_trigger",
+ "tableTo": "resource",
+ "columnsFrom": ["resource_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "release_job_trigger_environment_id_environment_id_fk": {
+ "name": "release_job_trigger_environment_id_environment_id_fk",
+ "tableFrom": "release_job_trigger",
+ "tableTo": "environment",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "release_job_trigger_job_id_unique": {
+ "name": "release_job_trigger_job_id_unique",
+ "nullsNotDistinct": false,
+ "columns": ["job_id"]
+ }
+ }
+ },
+ "public.release_metadata": {
+ "name": "release_metadata",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "release_id": {
+ "name": "release_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "release_metadata_key_release_id_index": {
+ "name": "release_metadata_key_release_id_index",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "release_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "release_metadata_release_id_release_id_fk": {
+ "name": "release_metadata_release_id_release_id_fk",
+ "tableFrom": "release_metadata",
+ "tableTo": "release",
+ "columnsFrom": ["release_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.system": {
+ "name": "system",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "''"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "system_workspace_id_slug_index": {
+ "name": "system_workspace_id_slug_index",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "system_workspace_id_workspace_id_fk": {
+ "name": "system_workspace_id_workspace_id_fk",
+ "tableFrom": "system",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.runbook": {
+ "name": "runbook",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "system_id": {
+ "name": "system_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "job_agent_id": {
+ "name": "job_agent_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "job_agent_config": {
+ "name": "job_agent_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "runbook_system_id_system_id_fk": {
+ "name": "runbook_system_id_system_id_fk",
+ "tableFrom": "runbook",
+ "tableTo": "system",
+ "columnsFrom": ["system_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "runbook_job_agent_id_job_agent_id_fk": {
+ "name": "runbook_job_agent_id_job_agent_id_fk",
+ "tableFrom": "runbook",
+ "tableTo": "job_agent",
+ "columnsFrom": ["job_agent_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.runbook_job_trigger": {
+ "name": "runbook_job_trigger",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "job_id": {
+ "name": "job_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "runbook_id": {
+ "name": "runbook_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "runbook_job_trigger_job_id_job_id_fk": {
+ "name": "runbook_job_trigger_job_id_job_id_fk",
+ "tableFrom": "runbook_job_trigger",
+ "tableTo": "job",
+ "columnsFrom": ["job_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "runbook_job_trigger_runbook_id_runbook_id_fk": {
+ "name": "runbook_job_trigger_runbook_id_runbook_id_fk",
+ "tableFrom": "runbook_job_trigger",
+ "tableTo": "runbook",
+ "columnsFrom": ["runbook_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "runbook_job_trigger_job_id_unique": {
+ "name": "runbook_job_trigger_job_id_unique",
+ "nullsNotDistinct": false,
+ "columns": ["job_id"]
+ }
+ }
+ },
+ "public.team": {
+ "name": "team",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "text": {
+ "name": "text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "team_workspace_id_workspace_id_fk": {
+ "name": "team_workspace_id_workspace_id_fk",
+ "tableFrom": "team",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.team_member": {
+ "name": "team_member",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "team_id": {
+ "name": "team_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "team_member_team_id_user_id_index": {
+ "name": "team_member_team_id_user_id_index",
+ "columns": [
+ {
+ "expression": "team_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "team_member_team_id_team_id_fk": {
+ "name": "team_member_team_id_team_id_fk",
+ "tableFrom": "team_member",
+ "tableTo": "team",
+ "columnsFrom": ["team_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "team_member_user_id_user_id_fk": {
+ "name": "team_member_user_id_user_id_fk",
+ "tableFrom": "team_member",
+ "tableTo": "user",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.job": {
+ "name": "job",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "job_agent_id": {
+ "name": "job_agent_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "job_agent_config": {
+ "name": "job_agent_config",
+ "type": "json",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ },
+ "external_id": {
+ "name": "external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "job_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'pending'"
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reason": {
+ "name": "reason",
+ "type": "job_reason",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'policy_passing'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "job_created_at_idx": {
+ "name": "job_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "job_status_idx": {
+ "name": "job_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "job_job_agent_id_job_agent_id_fk": {
+ "name": "job_job_agent_id_job_agent_id_fk",
+ "tableFrom": "job",
+ "tableTo": "job_agent",
+ "columnsFrom": ["job_agent_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.job_metadata": {
+ "name": "job_metadata",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "job_id": {
+ "name": "job_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "job_metadata_key_job_id_index": {
+ "name": "job_metadata_key_job_id_index",
+ "columns": [
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "job_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "job_metadata_job_id_job_id_fk": {
+ "name": "job_metadata_job_id_job_id_fk",
+ "tableFrom": "job_metadata",
+ "tableTo": "job",
+ "columnsFrom": ["job_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.job_variable": {
+ "name": "job_variable",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "job_id": {
+ "name": "job_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "json",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "sensitive": {
+ "name": "sensitive",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {
+ "job_variable_job_id_key_index": {
+ "name": "job_variable_job_id_key_index",
+ "columns": [
+ {
+ "expression": "job_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "job_variable_job_id_job_id_fk": {
+ "name": "job_variable_job_id_job_id_fk",
+ "tableFrom": "job_variable",
+ "tableTo": "job",
+ "columnsFrom": ["job_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.workspace": {
+ "name": "workspace",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "google_service_account_email": {
+ "name": "google_service_account_email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "aws_role_arn": {
+ "name": "aws_role_arn",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "workspace_slug_unique": {
+ "name": "workspace_slug_unique",
+ "nullsNotDistinct": false,
+ "columns": ["slug"]
+ }
+ }
+ },
+ "public.workspace_email_domain_matching": {
+ "name": "workspace_email_domain_matching",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "domain": {
+ "name": "domain",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "role_id": {
+ "name": "role_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "verified": {
+ "name": "verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "verification_code": {
+ "name": "verification_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "verification_email": {
+ "name": "verification_email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "workspace_email_domain_matching_workspace_id_domain_index": {
+ "name": "workspace_email_domain_matching_workspace_id_domain_index",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "domain",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "workspace_email_domain_matching_workspace_id_workspace_id_fk": {
+ "name": "workspace_email_domain_matching_workspace_id_workspace_id_fk",
+ "tableFrom": "workspace_email_domain_matching",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "workspace_email_domain_matching_role_id_role_id_fk": {
+ "name": "workspace_email_domain_matching_role_id_role_id_fk",
+ "tableFrom": "workspace_email_domain_matching",
+ "tableTo": "role",
+ "columnsFrom": ["role_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.variable_set": {
+ "name": "variable_set",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "system_id": {
+ "name": "system_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "variable_set_system_id_system_id_fk": {
+ "name": "variable_set_system_id_system_id_fk",
+ "tableFrom": "variable_set",
+ "tableTo": "system",
+ "columnsFrom": ["system_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.variable_set_environment": {
+ "name": "variable_set_environment",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "variable_set_id": {
+ "name": "variable_set_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "variable_set_environment_variable_set_id_variable_set_id_fk": {
+ "name": "variable_set_environment_variable_set_id_variable_set_id_fk",
+ "tableFrom": "variable_set_environment",
+ "tableTo": "variable_set",
+ "columnsFrom": ["variable_set_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "variable_set_environment_environment_id_environment_id_fk": {
+ "name": "variable_set_environment_environment_id_environment_id_fk",
+ "tableFrom": "variable_set_environment",
+ "tableTo": "environment",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.variable_set_value": {
+ "name": "variable_set_value",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "variable_set_id": {
+ "name": "variable_set_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "variable_set_value_variable_set_id_key_index": {
+ "name": "variable_set_value_variable_set_id_key_index",
+ "columns": [
+ {
+ "expression": "variable_set_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "variable_set_value_variable_set_id_variable_set_id_fk": {
+ "name": "variable_set_value_variable_set_id_variable_set_id_fk",
+ "tableFrom": "variable_set_value",
+ "tableTo": "variable_set",
+ "columnsFrom": ["variable_set_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.workspace_invite_token": {
+ "name": "workspace_invite_token",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "role_id": {
+ "name": "role_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_by": {
+ "name": "created_by",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "workspace_invite_token_role_id_role_id_fk": {
+ "name": "workspace_invite_token_role_id_role_id_fk",
+ "tableFrom": "workspace_invite_token",
+ "tableTo": "role",
+ "columnsFrom": ["role_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "workspace_invite_token_workspace_id_workspace_id_fk": {
+ "name": "workspace_invite_token_workspace_id_workspace_id_fk",
+ "tableFrom": "workspace_invite_token",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "workspace_invite_token_created_by_user_id_fk": {
+ "name": "workspace_invite_token_created_by_user_id_fk",
+ "tableFrom": "workspace_invite_token",
+ "tableTo": "user",
+ "columnsFrom": ["created_by"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "workspace_invite_token_token_unique": {
+ "name": "workspace_invite_token_token_unique",
+ "nullsNotDistinct": false,
+ "columns": ["token"]
+ }
+ }
+ },
+ "public.resource_metadata_group": {
+ "name": "resource_metadata_group",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "keys": {
+ "name": "keys",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "include_null_combinations": {
+ "name": "include_null_combinations",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "resource_metadata_group_workspace_id_workspace_id_fk": {
+ "name": "resource_metadata_group_workspace_id_workspace_id_fk",
+ "tableFrom": "resource_metadata_group",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.runbook_variable": {
+ "name": "runbook_variable",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "''"
+ },
+ "runbook_id": {
+ "name": "runbook_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "schema": {
+ "name": "schema",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "required": {
+ "name": "required",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {
+ "runbook_variable_runbook_id_key_index": {
+ "name": "runbook_variable_runbook_id_key_index",
+ "columns": [
+ {
+ "expression": "runbook_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "runbook_variable_runbook_id_runbook_id_fk": {
+ "name": "runbook_variable_runbook_id_runbook_id_fk",
+ "tableFrom": "runbook_variable",
+ "tableTo": "runbook",
+ "columnsFrom": ["runbook_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.entity_role": {
+ "name": "entity_role",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "role_id": {
+ "name": "role_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "entity_type": {
+ "name": "entity_type",
+ "type": "entity_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "entity_id": {
+ "name": "entity_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope_id": {
+ "name": "scope_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope_type": {
+ "name": "scope_type",
+ "type": "scope_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "entity_role_role_id_entity_type_entity_id_scope_id_scope_type_index": {
+ "name": "entity_role_role_id_entity_type_entity_id_scope_id_scope_type_index",
+ "columns": [
+ {
+ "expression": "role_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "entity_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "entity_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "scope_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "scope_type",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "entity_role_role_id_role_id_fk": {
+ "name": "entity_role_role_id_role_id_fk",
+ "tableFrom": "entity_role",
+ "tableTo": "role",
+ "columnsFrom": ["role_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.role": {
+ "name": "role",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "role_workspace_id_workspace_id_fk": {
+ "name": "role_workspace_id_workspace_id_fk",
+ "tableFrom": "role",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.role_permission": {
+ "name": "role_permission",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "role_id": {
+ "name": "role_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "permission": {
+ "name": "permission",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "role_permission_role_id_permission_index": {
+ "name": "role_permission_role_id_permission_index",
+ "columns": [
+ {
+ "expression": "role_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "permission",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "role_permission_role_id_role_id_fk": {
+ "name": "role_permission_role_id_role_id_fk",
+ "tableFrom": "role_permission",
+ "tableTo": "role",
+ "columnsFrom": ["role_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.job_agent": {
+ "name": "job_agent",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "config": {
+ "name": "config",
+ "type": "json",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'"
+ }
+ },
+ "indexes": {
+ "job_agent_workspace_id_name_index": {
+ "name": "job_agent_workspace_id_name_index",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "job_agent_workspace_id_workspace_id_fk": {
+ "name": "job_agent_workspace_id_workspace_id_fk",
+ "tableFrom": "job_agent",
+ "tableTo": "workspace",
+ "columnsFrom": ["workspace_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_policy_release_channel": {
+ "name": "environment_policy_release_channel",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "policy_id": {
+ "name": "policy_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel_id": {
+ "name": "channel_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "environment_policy_release_channel_policy_id_channel_id_index": {
+ "name": "environment_policy_release_channel_policy_id_channel_id_index",
+ "columns": [
+ {
+ "expression": "policy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environment_policy_release_channel_policy_id_deployment_id_index": {
+ "name": "environment_policy_release_channel_policy_id_deployment_id_index",
+ "columns": [
+ {
+ "expression": "policy_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_policy_release_channel_policy_id_environment_policy_id_fk": {
+ "name": "environment_policy_release_channel_policy_id_environment_policy_id_fk",
+ "tableFrom": "environment_policy_release_channel",
+ "tableTo": "environment_policy",
+ "columnsFrom": ["policy_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_release_channel_channel_id_release_channel_id_fk": {
+ "name": "environment_policy_release_channel_channel_id_release_channel_id_fk",
+ "tableFrom": "environment_policy_release_channel",
+ "tableTo": "release_channel",
+ "columnsFrom": ["channel_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_policy_release_channel_deployment_id_deployment_id_fk": {
+ "name": "environment_policy_release_channel_deployment_id_deployment_id_fk",
+ "tableFrom": "environment_policy_release_channel",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "public.environment_release_channel": {
+ "name": "environment_release_channel",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel_id": {
+ "name": "channel_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deployment_id": {
+ "name": "deployment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "environment_release_channel_environment_id_channel_id_index": {
+ "name": "environment_release_channel_environment_id_channel_id_index",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environment_release_channel_environment_id_deployment_id_index": {
+ "name": "environment_release_channel_environment_id_deployment_id_index",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "deployment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_release_channel_environment_id_environment_id_fk": {
+ "name": "environment_release_channel_environment_id_environment_id_fk",
+ "tableFrom": "environment_release_channel",
+ "tableTo": "environment",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_release_channel_channel_id_release_channel_id_fk": {
+ "name": "environment_release_channel_channel_id_release_channel_id_fk",
+ "tableFrom": "environment_release_channel",
+ "tableTo": "release_channel",
+ "columnsFrom": ["channel_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_release_channel_deployment_id_deployment_id_fk": {
+ "name": "environment_release_channel_deployment_id_deployment_id_fk",
+ "tableFrom": "environment_release_channel",
+ "tableTo": "deployment",
+ "columnsFrom": ["deployment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ }
+ },
+ "enums": {
+ "public.environment_policy_approval_requirement": {
+ "name": "environment_policy_approval_requirement",
+ "schema": "public",
+ "values": ["manual", "automatic"]
+ },
+ "public.approval_status_type": {
+ "name": "approval_status_type",
+ "schema": "public",
+ "values": ["pending", "approved", "rejected"]
+ },
+ "public.environment_policy_deployment_success_type": {
+ "name": "environment_policy_deployment_success_type",
+ "schema": "public",
+ "values": ["all", "some", "optional"]
+ },
+ "public.recurrence_type": {
+ "name": "recurrence_type",
+ "schema": "public",
+ "values": ["hourly", "daily", "weekly", "monthly"]
+ },
+ "public.release_sequencing_type": {
+ "name": "release_sequencing_type",
+ "schema": "public",
+ "values": ["wait", "cancel"]
+ },
+ "public.github_entity_type": {
+ "name": "github_entity_type",
+ "schema": "public",
+ "values": ["organization", "user"]
+ },
+ "public.resource_relationship_type": {
+ "name": "resource_relationship_type",
+ "schema": "public",
+ "values": ["associated_with", "depends_on"]
+ },
+ "public.release_job_trigger_type": {
+ "name": "release_job_trigger_type",
+ "schema": "public",
+ "values": [
+ "new_release",
+ "release_updated",
+ "new_resource",
+ "resource_changed",
+ "api",
+ "redeploy",
+ "force_deploy",
+ "new_environment",
+ "variable_changed",
+ "retry"
+ ]
+ },
+ "public.release_status": {
+ "name": "release_status",
+ "schema": "public",
+ "values": ["building", "ready", "failed"]
+ },
+ "public.job_reason": {
+ "name": "job_reason",
+ "schema": "public",
+ "values": [
+ "policy_passing",
+ "policy_override",
+ "env_policy_override",
+ "config_policy_override"
+ ]
+ },
+ "public.job_status": {
+ "name": "job_status",
+ "schema": "public",
+ "values": [
+ "cancelled",
+ "skipped",
+ "in_progress",
+ "action_required",
+ "pending",
+ "failure",
+ "invalid_job_agent",
+ "invalid_integration",
+ "external_run_not_found",
+ "successful"
+ ]
+ },
+ "public.entity_type": {
+ "name": "entity_type",
+ "schema": "public",
+ "values": ["user", "team"]
+ },
+ "public.scope_type": {
+ "name": "scope_type",
+ "schema": "public",
+ "values": [
+ "release",
+ "releaseChannel",
+ "resource",
+ "resourceProvider",
+ "resourceMetadataGroup",
+ "workspace",
+ "environment",
+ "environmentPolicy",
+ "deploymentVariable",
+ "variableSet",
+ "system",
+ "deployment",
+ "job",
+ "jobAgent",
+ "runbook",
+ "resourceView"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json
index c28fd231..427a0ced 100644
--- a/packages/db/drizzle/meta/_journal.json
+++ b/packages/db/drizzle/meta/_journal.json
@@ -456,6 +456,13 @@
"when": 1737862789255,
"tag": "0064_misty_stryfe",
"breakpoints": true
+ },
+ {
+ "idx": 65,
+ "version": "7",
+ "when": 1738098519525,
+ "tag": "0065_familiar_jazinda",
+ "breakpoints": true
}
]
}
diff --git a/packages/db/src/create-env.ts b/packages/db/src/create-env.ts
new file mode 100644
index 00000000..dac226c6
--- /dev/null
+++ b/packages/db/src/create-env.ts
@@ -0,0 +1,60 @@
+import type { z } from "zod";
+import { eq } from "drizzle-orm";
+
+import type { Tx } from "./common.js";
+import { takeFirst } from "./common.js";
+import * as SCHEMA from "./schema/index.js";
+import { environment, environmentPolicy } from "./schema/index.js";
+
+const createReleaseChannels = (
+ db: Tx,
+ environmentId: string,
+ releaseChannels: { channelId: string; deploymentId: string }[],
+) =>
+ db.insert(SCHEMA.environmentReleaseChannel).values(
+ releaseChannels.map(({ channelId, deploymentId }) => ({
+ environmentId,
+ channelId,
+ deploymentId,
+ })),
+ );
+
+export const createEnv = async (
+ db: Tx,
+ input: z.infer,
+ metadata?: Record,
+ releaseChannels?: { channelId: string; deploymentId: string }[],
+) => {
+ const overridePolicyId = await db
+ .insert(environmentPolicy)
+ .values({ name: input.name, systemId: input.systemId })
+ .returning()
+ .then(takeFirst)
+ .then((policy) => policy.id);
+ const policyId = input.policyId ?? overridePolicyId;
+
+ const env = await db
+ .insert(environment)
+ .values({ ...input, policyId })
+ .returning()
+ .then(takeFirst);
+
+ if (metadata != null)
+ await db.insert(SCHEMA.environmentMetadata).values(
+ Object.entries(metadata).map(([key, value]) => ({
+ environmentId: env.id,
+ key,
+ value,
+ })),
+ );
+
+ if (releaseChannels != null && releaseChannels.length > 0)
+ await createReleaseChannels(db, env.id, releaseChannels);
+
+ await db
+ .update(environmentPolicy)
+ .set({ environmentId: env.id })
+ .where(eq(environmentPolicy.id, policyId));
+
+ return env;
+};
diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts
index dc132e56..c2e11263 100644
--- a/packages/db/src/index.ts
+++ b/packages/db/src/index.ts
@@ -6,3 +6,4 @@ export {
workspaceSchema,
systemSchema,
} from "./schema/index.js";
+export * from "./create-env.js";
diff --git a/packages/db/src/schema/environment-policy-deployment.ts b/packages/db/src/schema/environment-policy-deployment.ts
index b01acc25..9a8d8eef 100644
--- a/packages/db/src/schema/environment-policy-deployment.ts
+++ b/packages/db/src/schema/environment-policy-deployment.ts
@@ -2,8 +2,7 @@ import type { InferSelectModel } from "drizzle-orm";
import { pgTable, uniqueIndex, uuid } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
-import { environmentPolicy } from "./environment-policy.js";
-import { environment } from "./environment.js";
+import { environment, environmentPolicy } from "./environment.js";
export const environmentPolicyDeployment = pgTable(
"environment_policy_deployment",
diff --git a/packages/db/src/schema/environment-policy-relations.ts b/packages/db/src/schema/environment-policy-relations.ts
index 432640b3..12cf415c 100644
--- a/packages/db/src/schema/environment-policy-relations.ts
+++ b/packages/db/src/schema/environment-policy-relations.ts
@@ -1,7 +1,6 @@
import { relations } from "drizzle-orm";
-import { environmentPolicy } from "./environment-policy.js";
-import { environment } from "./environment.js";
+import { environment, environmentPolicy } from "./environment.js";
import { environmentPolicyReleaseChannel } from "./release-channel.js";
export const environmentPolicyRelations = relations(
diff --git a/packages/db/src/schema/environment-policy.ts b/packages/db/src/schema/environment-policy.ts
deleted file mode 100644
index 1edbb4d2..00000000
--- a/packages/db/src/schema/environment-policy.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import type { InferSelectModel } from "drizzle-orm";
-import { sql } from "drizzle-orm";
-import {
- bigint,
- integer,
- pgEnum,
- pgTable,
- text,
- timestamp,
- uniqueIndex,
- uuid,
-} from "drizzle-orm/pg-core";
-import { createInsertSchema } from "drizzle-zod";
-import { z } from "zod";
-
-import { user } from "./auth.js";
-import { release } from "./release.js";
-import { system } from "./system.js";
-
-export const approvalRequirement = pgEnum(
- "environment_policy_approval_requirement",
- ["manual", "automatic"],
-);
-
-export const environmentPolicyDeploymentSuccessType = pgEnum(
- "environment_policy_deployment_success_type",
- ["all", "some", "optional"],
-);
-
-export const releaseSequencingType = pgEnum("release_sequencing_type", [
- "wait",
- "cancel",
-]);
-
-export const environmentPolicy = pgTable("environment_policy", {
- id: uuid("id").primaryKey().defaultRandom(),
- name: text("name").notNull(),
- description: text("description"),
-
- systemId: uuid("system_id")
- .notNull()
- .references(() => system.id, { onDelete: "cascade" }),
- approvalRequirement: approvalRequirement("approval_required")
- .notNull()
- .default("manual"),
-
- successType: environmentPolicyDeploymentSuccessType("success_status")
- .notNull()
- .default("all"),
- successMinimum: integer("minimum_success").notNull().default(0),
- concurrencyLimit: integer("concurrency_limit").default(sql`NULL`),
-
- // Duration in milliseconds over which to gradually roll out releases to this
- // environment
- rolloutDuration: bigint("rollout_duration", { mode: "number" })
- .notNull()
- .default(0),
-
- // Minimum interval between releases in milliseconds
- minimumReleaseInterval: bigint("minimum_release_interval", {
- mode: "number",
- })
- .notNull()
- .default(0),
-
- releaseSequencing: releaseSequencingType("release_sequencing")
- .notNull()
- .default("cancel"),
-});
-
-export type EnvironmentPolicy = InferSelectModel;
-
-export const createEnvironmentPolicy = createInsertSchema(
- environmentPolicy,
-).omit({ id: true });
-
-export const updateEnvironmentPolicy = createEnvironmentPolicy
- .partial()
- .extend({
- releaseChannels: z.record(z.string().uuid().nullable()).optional(),
- releaseWindows: z
- .array(
- z.object({
- policyId: z.string().uuid(),
- recurrence: z.enum(["hourly", "daily", "weekly", "monthly"]),
- startTime: z.date(),
- endTime: z.date(),
- }),
- )
- .optional(),
- });
-
-export const recurrenceType = pgEnum("recurrence_type", [
- "hourly",
- "daily",
- "weekly",
- "monthly",
-]);
-
-export const environmentPolicyReleaseWindow = pgTable(
- "environment_policy_release_window",
- {
- id: uuid("id").primaryKey().defaultRandom(),
- policyId: uuid("policy_id")
- .notNull()
- .references(() => environmentPolicy.id, { onDelete: "cascade" }),
- startTime: timestamp("start_time", {
- withTimezone: true,
- precision: 0,
- }).notNull(),
- endTime: timestamp("end_time", {
- withTimezone: true,
- precision: 0,
- }).notNull(),
- recurrence: recurrenceType("recurrence").notNull(),
- },
-);
-
-export type EnvironmentPolicyReleaseWindow = InferSelectModel<
- typeof environmentPolicyReleaseWindow
->;
-
-export const approvalStatusType = pgEnum("approval_status_type", [
- "pending",
- "approved",
- "rejected",
-]);
-
-export const environmentPolicyApproval = pgTable(
- "environment_policy_approval",
- {
- id: uuid("id").primaryKey().defaultRandom(),
- policyId: uuid("policy_id")
- .notNull()
- .references(() => environmentPolicy.id, { onDelete: "cascade" }),
- releaseId: uuid("release_id")
- .notNull()
- .references(() => release.id, { onDelete: "cascade" }),
- status: approvalStatusType("status").notNull().default("pending"),
- userId: uuid("user_id").references(() => user.id, { onDelete: "set null" }),
- approvedAt: timestamp("approved_at", {
- withTimezone: true,
- precision: 0,
- }).default(sql`NULL`),
- },
- (t) => ({ uniq: uniqueIndex().on(t.policyId, t.releaseId) }),
-);
-
-export type EnvironmentPolicyApproval = InferSelectModel<
- typeof environmentPolicyApproval
->;
diff --git a/packages/db/src/schema/environment-relations.ts b/packages/db/src/schema/environment-relations.ts
index 97ef840a..ac54131e 100644
--- a/packages/db/src/schema/environment-relations.ts
+++ b/packages/db/src/schema/environment-relations.ts
@@ -1,7 +1,10 @@
import { relations } from "drizzle-orm";
-import { environmentPolicy } from "./environment-policy.js";
-import { environment, environmentMetadata } from "./environment.js";
+import {
+ environment,
+ environmentMetadata,
+ environmentPolicy,
+} from "./environment.js";
import { environmentReleaseChannel } from "./release-channel.js";
import { system } from "./system.js";
import { variableSetEnvironment } from "./variable-sets.js";
diff --git a/packages/db/src/schema/environment.ts b/packages/db/src/schema/environment.ts
index ee2aec75..de3fad59 100644
--- a/packages/db/src/schema/environment.ts
+++ b/packages/db/src/schema/environment.ts
@@ -1,8 +1,13 @@
import type { ResourceCondition } from "@ctrlplane/validators/resources";
import type { InferSelectModel } from "drizzle-orm";
+import type { AnyPgColumn, ColumnsWithTable } from "drizzle-orm/pg-core";
import { sql } from "drizzle-orm";
import {
+ bigint,
+ foreignKey,
+ integer,
jsonb,
+ pgEnum,
pgTable,
text,
timestamp,
@@ -17,7 +22,8 @@ import {
resourceCondition,
} from "@ctrlplane/validators/resources";
-import { environmentPolicy } from "./environment-policy.js";
+import { user } from "./auth.js";
+import { release } from "./release.js";
import { system } from "./system.js";
export const environment = pgTable(
@@ -29,9 +35,7 @@ export const environment = pgTable(
.references(() => system.id, { onDelete: "cascade" }),
name: text("name").notNull(),
description: text("description").default(""),
- policyId: uuid("policy_id").references(() => environmentPolicy.id, {
- onDelete: "set null",
- }),
+ policyId: uuid("policy_id").notNull(),
resourceFilter: jsonb("resource_filter")
.$type()
.default(sql`NULL`),
@@ -39,7 +43,13 @@ export const environment = pgTable(
.notNull()
.defaultNow(),
},
- (t) => ({ uniq: uniqueIndex().on(t.systemId, t.name) }),
+ (t) => ({
+ uniq: uniqueIndex().on(t.systemId, t.name),
+ policyIdFk: foreignKey({
+ columns: [t.policyId],
+ foreignColumns: [environmentPolicy.id],
+ }).onDelete("set null"),
+ }),
);
export type Environment = InferSelectModel;
@@ -49,7 +59,7 @@ export const createEnvironment = createInsertSchema(environment, {
.optional()
.refine((filter) => filter == null || isValidResourceCondition(filter)),
})
- .omit({ id: true })
+ .omit({ id: true, policyId: true })
.extend({
releaseChannels: z
.array(
@@ -65,9 +75,13 @@ export const createEnvironment = createInsertSchema(environment, {
return deploymentIds.size === channels.length;
}),
metadata: z.record(z.string()).optional(),
+ policyId: z.string().uuid().optional(),
});
-export const updateEnvironment = createEnvironment.partial();
+export const updateEnvironment = createEnvironment
+ .partial()
+ .omit({ policyId: true })
+ .extend({ policyId: z.string().uuid().nullable().optional() });
export type InsertEnvironment = z.infer;
export const environmentMetadata = pgTable(
@@ -82,3 +96,158 @@ export const environmentMetadata = pgTable(
},
(t) => ({ uniq: uniqueIndex().on(t.key, t.environmentId) }),
);
+
+export const approvalRequirement = pgEnum(
+ "environment_policy_approval_requirement",
+ ["manual", "automatic"],
+);
+
+export const environmentPolicyDeploymentSuccessType = pgEnum(
+ "environment_policy_deployment_success_type",
+ ["all", "some", "optional"],
+);
+
+export const releaseSequencingType = pgEnum("release_sequencing_type", [
+ "wait",
+ "cancel",
+]);
+
+export const environmentPolicy = pgTable(
+ "environment_policy",
+ {
+ id: uuid("id").primaryKey().defaultRandom(),
+ name: text("name").notNull(),
+ description: text("description"),
+
+ systemId: uuid("system_id")
+ .notNull()
+ .references(() => system.id, { onDelete: "cascade" }),
+ environmentId: uuid("environment_id").references(
+ (): any => environment.id,
+ { onDelete: "cascade" },
+ ),
+ approvalRequirement: approvalRequirement("approval_required")
+ .notNull()
+ .default("manual"),
+
+ successType: environmentPolicyDeploymentSuccessType("success_status")
+ .notNull()
+ .default("all"),
+ successMinimum: integer("minimum_success").notNull().default(0),
+ concurrencyLimit: integer("concurrency_limit").default(sql`NULL`),
+
+ // Duration in milliseconds over which to gradually roll out releases to this
+ // environment
+ rolloutDuration: bigint("rollout_duration", { mode: "number" })
+ .notNull()
+ .default(0),
+
+ // Minimum interval between releases in milliseconds
+ minimumReleaseInterval: bigint("minimum_release_interval", {
+ mode: "number",
+ })
+ .notNull()
+ .default(0),
+
+ releaseSequencing: releaseSequencingType("release_sequencing")
+ .notNull()
+ .default("cancel"),
+ },
+ () => ({
+ overridePolicyFK: foreignKey(overridePolicyFKConstraint).onDelete(
+ "cascade",
+ ),
+ }),
+);
+
+export type EnvironmentPolicy = InferSelectModel;
+
+const overridePolicyFKConstraint: {
+ columns: [AnyPgColumn<{ tableName: "environment_policy" }>];
+ foreignColumns: ColumnsWithTable<
+ "environment_policy",
+ "environment",
+ [AnyPgColumn<{ tableName: "environment_policy" }>]
+ >;
+} = {
+ columns: [environmentPolicy.environmentId],
+ foreignColumns: [environment.id],
+};
+
+export const createEnvironmentPolicy = createInsertSchema(environmentPolicy)
+ .omit({ id: true })
+ .extend({
+ releaseChannels: z.record(z.string().uuid().nullable()).optional(),
+ releaseWindows: z
+ .array(
+ z.object({
+ recurrence: z.enum(["hourly", "daily", "weekly", "monthly"]),
+ startTime: z.date(),
+ endTime: z.date(),
+ }),
+ )
+ .optional(),
+ });
+export type CreateEnvironmentPolicy = z.infer;
+export const updateEnvironmentPolicy = createEnvironmentPolicy.partial();
+export type UpdateEnvironmentPolicy = z.infer;
+
+export const recurrenceType = pgEnum("recurrence_type", [
+ "hourly",
+ "daily",
+ "weekly",
+ "monthly",
+]);
+
+export const environmentPolicyReleaseWindow = pgTable(
+ "environment_policy_release_window",
+ {
+ id: uuid("id").primaryKey().defaultRandom(),
+ policyId: uuid("policy_id")
+ .notNull()
+ .references(() => environmentPolicy.id, { onDelete: "cascade" }),
+ startTime: timestamp("start_time", {
+ withTimezone: true,
+ precision: 0,
+ }).notNull(),
+ endTime: timestamp("end_time", {
+ withTimezone: true,
+ precision: 0,
+ }).notNull(),
+ recurrence: recurrenceType("recurrence").notNull(),
+ },
+);
+
+export type EnvironmentPolicyReleaseWindow = InferSelectModel<
+ typeof environmentPolicyReleaseWindow
+>;
+
+export const approvalStatusType = pgEnum("approval_status_type", [
+ "pending",
+ "approved",
+ "rejected",
+]);
+
+export const environmentPolicyApproval = pgTable(
+ "environment_policy_approval",
+ {
+ id: uuid("id").primaryKey().defaultRandom(),
+ policyId: uuid("policy_id")
+ .notNull()
+ .references(() => environmentPolicy.id, { onDelete: "cascade" }),
+ releaseId: uuid("release_id")
+ .notNull()
+ .references(() => release.id, { onDelete: "cascade" }),
+ status: approvalStatusType("status").notNull().default("pending"),
+ userId: uuid("user_id").references(() => user.id, { onDelete: "set null" }),
+ approvedAt: timestamp("approved_at", {
+ withTimezone: true,
+ precision: 0,
+ }).default(sql`NULL`),
+ },
+ (t) => ({ uniq: uniqueIndex().on(t.policyId, t.releaseId) }),
+);
+
+export type EnvironmentPolicyApproval = InferSelectModel<
+ typeof environmentPolicyApproval
+>;
diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts
index 707e761f..1f2425cb 100644
--- a/packages/db/src/schema/index.ts
+++ b/packages/db/src/schema/index.ts
@@ -3,7 +3,6 @@ export * from "./resource.js";
export * from "./resource-provider.js";
export * from "./deployment.js";
export * from "./environment.js";
-export * from "./environment-policy.js";
export * from "./environment-policy-deployment.js";
export * from "./release.js";
export * from "./system.js";
diff --git a/packages/db/src/schema/release-channel-relations.ts b/packages/db/src/schema/release-channel-relations.ts
index ed6ac3ca..b001fea7 100644
--- a/packages/db/src/schema/release-channel-relations.ts
+++ b/packages/db/src/schema/release-channel-relations.ts
@@ -1,7 +1,6 @@
import { relations } from "drizzle-orm";
-import { environmentPolicy } from "./environment-policy.js";
-import { environment } from "./environment.js";
+import { environment, environmentPolicy } from "./environment.js";
import {
environmentPolicyReleaseChannel,
environmentReleaseChannel,
diff --git a/packages/db/src/schema/release-channel.ts b/packages/db/src/schema/release-channel.ts
index b9572dcd..51ac234b 100644
--- a/packages/db/src/schema/release-channel.ts
+++ b/packages/db/src/schema/release-channel.ts
@@ -2,8 +2,7 @@ import type { InferSelectModel } from "drizzle-orm";
import { pgTable, uniqueIndex, uuid } from "drizzle-orm/pg-core";
import { deployment } from "./deployment.js";
-import { environmentPolicy } from "./environment-policy.js";
-import { environment } from "./environment.js";
+import { environment, environmentPolicy } from "./environment.js";
import { releaseChannel } from "./release.js";
export const environmentPolicyReleaseChannel = pgTable(
diff --git a/packages/job-dispatch/src/__test__/job-variables-deployment.test.ts b/packages/job-dispatch/src/__test__/job-variables-deployment.test.ts
index b2a4012d..d0f57a9e 100644
--- a/packages/job-dispatch/src/__test__/job-variables-deployment.test.ts
+++ b/packages/job-dispatch/src/__test__/job-variables-deployment.test.ts
@@ -248,7 +248,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
@@ -317,7 +317,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
@@ -383,7 +383,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
@@ -449,7 +449,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
@@ -515,7 +515,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
@@ -611,7 +611,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
@@ -707,7 +707,7 @@ describe("job-variables-deployment", () => {
name: "test",
description: null,
systemId: "0",
- policyId: null,
+ policyId: "0",
resourceFilter: null,
createdAt: new Date(),
environments: [
diff --git a/packages/job-dispatch/src/environment-creation.ts b/packages/job-dispatch/src/environment-creation.ts
index b8df69f8..270a52f2 100644
--- a/packages/job-dispatch/src/environment-creation.ts
+++ b/packages/job-dispatch/src/environment-creation.ts
@@ -33,8 +33,7 @@ export const createJobsForNewEnvironment = async (
const { releaseChannels: envReleaseChannels, system } = releaseChannels;
const { workspaceId, deployments } = system;
- const policyReleaseChannels =
- releaseChannels.policy?.environmentPolicyReleaseChannels ?? [];
+ const { environmentPolicyReleaseChannels } = releaseChannels.policy;
const resources = await db
.select()
@@ -52,7 +51,7 @@ export const createJobsForNewEnvironment = async (
const envReleaseChannel = envReleaseChannels.find(
(erc) => erc.deploymentId === deployment.id,
);
- const policyReleaseChannel = policyReleaseChannels.find(
+ const policyReleaseChannel = environmentPolicyReleaseChannels.find(
(prc) => prc.deploymentId === deployment.id,
);
const { releaseFilter } =
diff --git a/packages/job-dispatch/src/resource/dispatch-resource.ts b/packages/job-dispatch/src/resource/dispatch-resource.ts
index 21b26b95..ee9e9aa8 100644
--- a/packages/job-dispatch/src/resource/dispatch-resource.ts
+++ b/packages/job-dispatch/src/resource/dispatch-resource.ts
@@ -66,12 +66,12 @@ export async function dispatchJobsForAddedResources(
const { releaseChannels, policy, system } = environment;
const { deployments } = system;
- const policyReleaseChannels = policy?.environmentPolicyReleaseChannels ?? [];
+ const { environmentPolicyReleaseChannels } = policy;
const deploymentsWithReleaseFilter = deployments.map((deployment) => {
const envReleaseChannel = releaseChannels.find(
(erc) => erc.deploymentId === deployment.id,
);
- const policyReleaseChannel = policyReleaseChannels.find(
+ const policyReleaseChannel = environmentPolicyReleaseChannels.find(
(prc) => prc.deploymentId === deployment.id,
);