diff --git a/apps/event-worker/src/workers/evaluate-release-target.ts b/apps/event-worker/src/workers/evaluate-release-target.ts index ef1651d80..f2d94dc8d 100644 --- a/apps/event-worker/src/workers/evaluate-release-target.ts +++ b/apps/event-worker/src/workers/evaluate-release-target.ts @@ -7,40 +7,47 @@ import * as schema from "@ctrlplane/db/schema"; import { Channel, createWorker, getQueue } from "@ctrlplane/events"; import { logger } from "@ctrlplane/logger"; import { - DatabaseReleaseRepository, - evaluateRepository, + VariableReleaseManager, + VersionReleaseManager, } from "@ctrlplane/rule-engine"; import { env } from "../config.js"; import { ReleaseTargetMutex } from "../releases/mutex.js"; -const log = logger.child({ - worker: "policy-evaluate", -}); +const log = logger.child({ worker: "policy-evaluate" }); -const createJobForRelease = async (tx: Tx, chosenReleaseId: string) => { - const release = await tx.query.release.findFirst({ - where: eq(schema.release.id, chosenReleaseId), +const createRelease = async ( + tx: Tx, + release: { id: string; versionReleaseId: string; variableReleaseId: string }, +) => { + // Get version release and related data + const versionRelease = await tx.query.versionRelease.findFirst({ + where: eq(schema.versionRelease.id, release.versionReleaseId), with: { - variables: true, version: { with: { deployment: { with: { jobAgent: true } } } }, }, }); + if (!versionRelease) throw new Error("Failed to get release"); - if (release == null) throw new Error("Failed to get release"); + // Extract job agent info + const { jobAgent, jobAgentConfig: deploymentJobAgentConfig } = + versionRelease.version.deployment; + if (!jobAgent) throw new Error("Deployment has no Job Agent"); - const { version } = release; - const { deployment } = version; - const { jobAgent, jobAgentConfig: deploymentJobAgentConfig } = deployment; - if (jobAgent == null) throw new Error("Deployment has no Job Agent"); - - const jobAgentId = jobAgent.id; const jobAgentConfig = _.merge(jobAgent.config, deploymentJobAgentConfig); + // Get variable release data + const variableRelease = await tx.query.variableSetRelease.findFirst({ + where: eq(schema.variableSetRelease.id, release.variableReleaseId), + with: { values: { with: { variableValueSnapshot: true } } }, + }); + if (!variableRelease) throw new Error("Failed to get variable release"); + + // Create job const job = await tx .insert(schema.job) .values({ - jobAgentId, + jobAgentId: jobAgent.id, jobAgentConfig, status: "pending", reason: "policy_passing", @@ -48,58 +55,88 @@ const createJobForRelease = async (tx: Tx, chosenReleaseId: string) => { .returning() .then(takeFirst); - if (release.variables.length > 0) + // Add job variables if any exist + if (variableRelease.values.length > 0) { await tx.insert(schema.jobVariable).values( - release.variables.map((v) => ({ + variableRelease.values.map((v) => ({ jobId: job.id, - key: v.key, - sensitive: v.sensitive, - value: v.value, + key: v.variableValueSnapshot.key, + sensitive: v.variableValueSnapshot.sensitive, + value: v.variableValueSnapshot.value, })), ); + } + // Create release record await tx.insert(schema.releaseJob).values({ + releaseId: release.id, jobId: job.id, - releaseId: chosenReleaseId, }); return job; }; +const handleVersionRelease = async (releaseTarget: any) => { + const vrm = new VersionReleaseManager(db, { + ...releaseTarget, + workspaceId: releaseTarget.resource.workspaceId, + }); + + const { chosenCandidate } = await vrm.evaluate(); + if (!chosenCandidate) throw new Error("Failed to get chosen release"); + + const { release: versionRelease } = await vrm.upsertRelease( + chosenCandidate.id, + ); + + return versionRelease; +}; + +const handleVariableRelease = async (releaseTarget: any) => { + const varrm = new VariableReleaseManager(db, { + ...releaseTarget, + workspaceId: releaseTarget.resource.workspaceId, + }); + + const { chosenCandidate: variableValues } = await varrm.evaluate(); + const { release: variableRelease } = + await varrm.upsertRelease(variableValues); + + return variableRelease; +}; + export const evaluateReleaseTarget = createWorker( Channel.EvaluateReleaseTarget, async (job) => { const mutex = await ReleaseTargetMutex.lock(job.data); + try { + // Get release target const releaseTarget = await db.query.releaseTarget.findFirst({ where: and( eq(schema.releaseTarget.resourceId, job.data.resourceId), eq(schema.releaseTarget.environmentId, job.data.environmentId), eq(schema.releaseTarget.deploymentId, job.data.deploymentId), ), - with: { - resource: true, - environment: true, - deployment: true, - }, + with: { resource: true, environment: true, deployment: true }, }); - if (releaseTarget == null) - throw new Error("Failed to get release target"); + if (!releaseTarget) throw new Error("Failed to get release target"); - const releaseRepository = await DatabaseReleaseRepository.create({ - ...releaseTarget, - workspaceId: releaseTarget.resource.workspaceId, - }); + const versionRelease = await handleVersionRelease(releaseTarget); + const variableRelease = await handleVariableRelease(releaseTarget); - const { chosenRelease } = await evaluateRepository(releaseRepository); - if (chosenRelease == null) - throw new Error("Failed to get chosen release"); + const release = await db + .insert(schema.release) + .values({ + versionReleaseId: versionRelease.id, + variableReleaseId: variableRelease.id, + }) + .onConflictDoNothing() + .returning() + .then(takeFirst); if (env.NODE_ENV === "development") { - // In development dispatch the job immediately - const job = await db.transaction((tx) => - createJobForRelease(tx, chosenRelease.id), - ); + const job = await db.transaction((tx) => createRelease(tx, release)); getQueue(Channel.DispatchJob).add(job.id, { jobId: job.id }); } } catch (e) { diff --git a/apps/event-worker/src/workers/job-dispatch/github.ts b/apps/event-worker/src/workers/job-dispatch/github.ts index 0f58317d6..67b80d5e5 100644 --- a/apps/event-worker/src/workers/job-dispatch/github.ts +++ b/apps/event-worker/src/workers/job-dispatch/github.ts @@ -44,7 +44,8 @@ const getGithubEntity = async ( eq(SCHEMA.releaseJobTrigger.jobId, jobId), ), ) - .then(takeFirstOrNull); + .then(takeFirstOrNull) + .then((r) => r?.github_entity); const runbookGhEntityPromise = db .select() @@ -69,18 +70,23 @@ const getGithubEntity = async ( eq(SCHEMA.runbookJobTrigger.jobId, jobId), ), ) - .then(takeFirstOrNull); + .then(takeFirstOrNull) + .then((r) => r?.github_entity); const releaseJobEntityPromise = db .select() - .from(SCHEMA.releaseJob) + .from(SCHEMA.release) + .innerJoin( + SCHEMA.releaseJob, + eq(SCHEMA.release.id, SCHEMA.releaseJob.releaseId), + ) .innerJoin( - SCHEMA.release, - eq(SCHEMA.releaseJob.releaseId, SCHEMA.release.id), + SCHEMA.versionRelease, + eq(SCHEMA.release.versionReleaseId, SCHEMA.versionRelease.id), ) .innerJoin( SCHEMA.releaseTarget, - eq(SCHEMA.release.releaseTargetId, SCHEMA.releaseTarget.id), + eq(SCHEMA.versionRelease.releaseTargetId, SCHEMA.releaseTarget.id), ) .innerJoin( SCHEMA.resource, @@ -97,19 +103,13 @@ const getGithubEntity = async ( eq(SCHEMA.releaseJob.jobId, jobId), ), ) - .then(takeFirstOrNull); - - const [releaseGhEntityResult, runbookGhEntityResult, releaseJobEntityResult] = - await Promise.all([ - releaseGhEntityPromise, - runbookGhEntityPromise, - releaseJobEntityPromise, - ]); + .then(takeFirstOrNull) + .then((r) => r?.github_entity); return ( - releaseGhEntityResult?.github_entity ?? - runbookGhEntityResult?.github_entity ?? - releaseJobEntityResult?.github_entity + (await releaseGhEntityPromise) ?? + (await runbookGhEntityPromise) ?? + (await releaseJobEntityPromise) ); }; diff --git a/apps/event-worker/src/workers/new-deployment-version.ts b/apps/event-worker/src/workers/new-deployment-version.ts index 9439fb46e..767af5509 100644 --- a/apps/event-worker/src/workers/new-deployment-version.ts +++ b/apps/event-worker/src/workers/new-deployment-version.ts @@ -5,7 +5,6 @@ import { and, eq, isNull } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; import { Channel, createWorker, getQueue } from "@ctrlplane/events"; -import { DatabaseReleaseRepository } from "@ctrlplane/rule-engine"; const getDeploymentResources = async ( tx: Tx, @@ -79,18 +78,6 @@ export const newDeploymentVersionWorker = createWorker( where: eq(schema.releaseTarget.deploymentId, version.deploymentId), }); - const { system } = deployment; - const { workspaceId } = system; - - const updateReleaseVersionPromises = releaseTargets.map(async (rt) => { - const releaseRepository = await DatabaseReleaseRepository.create({ - ...rt, - workspaceId, - }); - await releaseRepository.updateReleaseVersion(version.id); - }); - await Promise.all(updateReleaseVersionPromises); - await getQueue(Channel.EvaluateReleaseTarget).addBulk( releaseTargets.map((rt) => ({ name: `${rt.resourceId}-${rt.environmentId}-${rt.deploymentId}`, diff --git a/apps/event-worker/src/workers/update-deployment-variable.ts b/apps/event-worker/src/workers/update-deployment-variable.ts index d78c72bac..13dde0953 100644 --- a/apps/event-worker/src/workers/update-deployment-variable.ts +++ b/apps/event-worker/src/workers/update-deployment-variable.ts @@ -2,7 +2,6 @@ import { eq } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; import { Channel, createWorker, getQueue } from "@ctrlplane/events"; -import { DatabaseReleaseRepository } from "@ctrlplane/rule-engine"; /** * Worker that handles deployment variable changes by triggering evaluations for @@ -26,20 +25,6 @@ export const updateDeploymentVariableWorker = createWorker( where: eq(schema.releaseTarget.deploymentId, variable.deploymentId), }); - const { deployment } = variable; - const { system } = deployment; - const { workspaceId } = system; - - const updateReleaseVariablePromises = releaseTargets.map(async (rt) => { - const releaseRepository = await DatabaseReleaseRepository.create({ - ...rt, - workspaceId, - }); - const variables = await releaseRepository.getLatestVariables(); - await releaseRepository.updateReleaseVariables(variables); - }); - await Promise.all(updateReleaseVariablePromises); - await getQueue(Channel.EvaluateReleaseTarget).addBulk( releaseTargets.map((rt) => ({ name: `${rt.resourceId}-${rt.environmentId}-${rt.deploymentId}`, diff --git a/apps/event-worker/src/workers/update-resource-variable.ts b/apps/event-worker/src/workers/update-resource-variable.ts index 00e350ab1..71b902990 100644 --- a/apps/event-worker/src/workers/update-resource-variable.ts +++ b/apps/event-worker/src/workers/update-resource-variable.ts @@ -2,7 +2,6 @@ import { and, eq, inArray } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; import { Channel, createWorker, getQueue } from "@ctrlplane/events"; -import { DatabaseReleaseRepository } from "@ctrlplane/rule-engine"; export const updateResourceVariableWorker = createWorker( Channel.UpdateResourceVariable, @@ -34,7 +33,6 @@ export const updateResourceVariableWorker = createWorker( const resource = rows[0]?.resource; if (!resource) throw new Error("Resource not found"); - const { workspaceId } = resource; const deploymentIds = rows.map((row) => row.deployment.id); const releaseTargets = await db.query.releaseTarget.findMany({ @@ -44,16 +42,6 @@ export const updateResourceVariableWorker = createWorker( ), }); - const updateReleaseVariablePromises = releaseTargets.map(async (rt) => { - const releaseRepository = await DatabaseReleaseRepository.create({ - ...rt, - workspaceId, - }); - const variables = await releaseRepository.getLatestVariables(); - await releaseRepository.updateReleaseVariables(variables); - }); - await Promise.all(updateReleaseVariablePromises); - await getQueue(Channel.EvaluateReleaseTarget).addBulk( releaseTargets.map((rt) => ({ name: `${rt.resourceId}-${rt.environmentId}-${rt.deploymentId}`, diff --git a/packages/db/drizzle/0085_sloppy_mister_fear.sql b/packages/db/drizzle/0085_sloppy_mister_fear.sql new file mode 100644 index 000000000..148f1145c --- /dev/null +++ b/packages/db/drizzle/0085_sloppy_mister_fear.sql @@ -0,0 +1,91 @@ +CREATE TABLE IF NOT EXISTS "variable_set_release" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "release_target_id" uuid NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "variable_set_release_value" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "variable_set_release_id" uuid NOT NULL, + "variable_value_snapshot_id" uuid NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "variable_value_snapshot" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "workspace_id" uuid NOT NULL, + "value" jsonb NOT NULL, + "key" text NOT NULL, + "sensitive" boolean DEFAULT false NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "version_release" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "release_target_id" uuid NOT NULL, + "version_id" uuid NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +DROP TABLE "release_variable";--> statement-breakpoint +ALTER TABLE "release" DROP CONSTRAINT "release_release_target_id_release_target_id_fk"; +--> statement-breakpoint +ALTER TABLE "release" DROP CONSTRAINT "release_version_id_deployment_version_id_fk"; +--> statement-breakpoint +ALTER TABLE "deployment_variable_value" ADD COLUMN "sensitive" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "variable_set_value" ADD COLUMN "sensitive" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "release" ADD COLUMN "version_release_id" uuid NOT NULL;--> statement-breakpoint +ALTER TABLE "release" ADD COLUMN "variable_release_id" uuid NOT NULL;--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "variable_set_release" ADD CONSTRAINT "variable_set_release_release_target_id_release_target_id_fk" FOREIGN KEY ("release_target_id") REFERENCES "public"."release_target"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "variable_set_release_value" ADD CONSTRAINT "variable_set_release_value_variable_set_release_id_variable_set_release_id_fk" FOREIGN KEY ("variable_set_release_id") REFERENCES "public"."variable_set_release"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "variable_set_release_value" ADD CONSTRAINT "variable_set_release_value_variable_value_snapshot_id_variable_value_snapshot_id_fk" FOREIGN KEY ("variable_value_snapshot_id") REFERENCES "public"."variable_value_snapshot"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "variable_value_snapshot" ADD CONSTRAINT "variable_value_snapshot_workspace_id_workspace_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspace"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "version_release" ADD CONSTRAINT "version_release_release_target_id_release_target_id_fk" FOREIGN KEY ("release_target_id") REFERENCES "public"."release_target"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "version_release" ADD CONSTRAINT "version_release_version_id_deployment_version_id_fk" FOREIGN KEY ("version_id") REFERENCES "public"."deployment_version"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "variable_set_release_value_variable_set_release_id_variable_value_snapshot_id_index" ON "variable_set_release_value" USING btree ("variable_set_release_id","variable_value_snapshot_id");--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "variable_value_snapshot_workspace_id_key_value_index" ON "variable_value_snapshot" USING btree ("workspace_id","key","value");--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "release" ADD CONSTRAINT "release_version_release_id_version_release_id_fk" FOREIGN KEY ("version_release_id") REFERENCES "public"."version_release"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "release" ADD CONSTRAINT "release_variable_release_id_variable_set_release_id_fk" FOREIGN KEY ("variable_release_id") REFERENCES "public"."variable_set_release"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +ALTER TABLE "release" DROP COLUMN IF EXISTS "release_target_id";--> statement-breakpoint +ALTER TABLE "release" DROP COLUMN IF EXISTS "version_id";--> statement-breakpoint +ALTER TABLE "release_job" DROP COLUMN IF EXISTS "created_at"; \ No newline at end of file diff --git a/packages/db/drizzle/0086_marvelous_katie_power.sql b/packages/db/drizzle/0086_marvelous_katie_power.sql new file mode 100644 index 000000000..884d4a40e --- /dev/null +++ b/packages/db/drizzle/0086_marvelous_katie_power.sql @@ -0,0 +1 @@ +ALTER TABLE "deployment_version" ALTER COLUMN "created_at" SET DATA TYPE timestamp (3) with time zone; \ No newline at end of file diff --git a/packages/db/drizzle/meta/0085_snapshot.json b/packages/db/drizzle/meta/0085_snapshot.json new file mode 100644 index 000000000..168e9e628 --- /dev/null +++ b/packages/db/drizzle/meta/0085_snapshot.json @@ -0,0 +1,5639 @@ +{ + "id": "01ef3e17-a606-4815-874b-a14f381cd46f", + "prevId": "43adecd5-8174-4ec6-898d-33900966efb4", + "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" + }, + "system_role": { + "name": "system_role", + "type": "system_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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": "cascade", + "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": "cascade", + "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 + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "resource_selector": { + "name": "resource_selector", + "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_version": { + "name": "deployment_version", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag": { + "name": "tag", + "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": "deployment_version_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": { + "deployment_version_deployment_id_tag_index": { + "name": "deployment_version_deployment_id_tag_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_version_created_at_idx": { + "name": "deployment_version_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_version_deployment_id_deployment_id_fk": { + "name": "deployment_version_deployment_id_deployment_id_fk", + "tableFrom": "deployment_version", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment_version_channel": { + "name": "deployment_version_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 + }, + "deployment_version_selector": { + "name": "deployment_version_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": { + "deployment_version_channel_deployment_id_name_index": { + "name": "deployment_version_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": { + "deployment_version_channel_deployment_id_deployment_id_fk": { + "name": "deployment_version_channel_deployment_id_deployment_id_fk", + "tableFrom": "deployment_version_channel", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment_version_metadata": { + "name": "deployment_version_metadata", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_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": { + "deployment_version_metadata_key_deployment_version_id_index": { + "name": "deployment_version_metadata_key_deployment_version_id_index", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_version_metadata_deployment_version_id_deployment_version_id_fk": { + "name": "deployment_version_metadata_deployment_version_id_deployment_version_id_fk", + "tableFrom": "deployment_version_metadata", + "tableTo": "deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment_version_dependency": { + "name": "deployment_version_dependency", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_version_selector": { + "name": "deployment_version_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": { + "deployment_version_dependency_deployment_version_id_deployment_id_index": { + "name": "deployment_version_dependency_deployment_version_id_deployment_id_index", + "columns": [ + { + "expression": "deployment_version_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_version_dependency_deployment_version_id_deployment_version_id_fk": { + "name": "deployment_version_dependency_deployment_version_id_deployment_version_id_fk", + "tableFrom": "deployment_version_dependency", + "tableTo": "deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_version_dependency_deployment_id_deployment_id_fk": { + "name": "deployment_version_dependency_deployment_id_deployment_id_fk", + "tableFrom": "deployment_version_dependency", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "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_selector": { + "name": "resource_selector", + "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.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 + }, + "directory": { + "name": "directory", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "policy_id": { + "name": "policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_selector": { + "name": "resource_selector", + "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": "'automatic'" + }, + "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_deployment_version_id_fk": { + "name": "environment_policy_approval_release_id_deployment_version_id_fk", + "tableFrom": "environment_policy_approval", + "tableTo": "deployment_version", + "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.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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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 + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "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_deployment_version_channel": { + "name": "environment_policy_deployment_version_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_deployment_version_channel_policy_id_channel_id_index": { + "name": "environment_policy_deployment_version_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_deployment_version_channel_policy_id_deployment_id_index": { + "name": "environment_policy_deployment_version_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_deployment_version_channel_policy_id_environment_policy_id_fk": { + "name": "environment_policy_deployment_version_channel_policy_id_environment_policy_id_fk", + "tableFrom": "environment_policy_deployment_version_channel", + "tableTo": "environment_policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_policy_deployment_version_channel_channel_id_deployment_version_channel_id_fk": { + "name": "environment_policy_deployment_version_channel_channel_id_deployment_version_channel_id_fk", + "tableFrom": "environment_policy_deployment_version_channel", + "tableTo": "deployment_version_channel", + "columnsFrom": ["channel_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_policy_deployment_version_channel_deployment_id_deployment_id_fk": { + "name": "environment_policy_deployment_version_channel_deployment_id_deployment_id_fk", + "tableFrom": "environment_policy_deployment_version_channel", + "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 + }, + "deployment_version_id": { + "name": "deployment_version_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_deployment_version_id_deployment_version_id_fk": { + "name": "release_job_trigger_deployment_version_id_deployment_version_id_fk", + "tableFrom": "release_job_trigger", + "tableTo": "deployment_version", + "columnsFrom": ["deployment_version_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.policy": { + "name": "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 + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_workspace_id_workspace_id_fk": { + "name": "policy_workspace_id_workspace_id_fk", + "tableFrom": "policy", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_deployment_version_selector": { + "name": "policy_deployment_version_selector", + "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 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_version_selector": { + "name": "deployment_version_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_deployment_version_selector_policy_id_policy_id_fk": { + "name": "policy_deployment_version_selector_policy_id_policy_id_fk", + "tableFrom": "policy_deployment_version_selector", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "policy_deployment_version_selector_policy_id_unique": { + "name": "policy_deployment_version_selector_policy_id_unique", + "nullsNotDistinct": false, + "columns": ["policy_id"] + } + } + }, + "public.policy_target": { + "name": "policy_target", + "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 + }, + "deployment_selector": { + "name": "deployment_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "environment_selector": { + "name": "environment_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_target_policy_id_policy_id_fk": { + "name": "policy_target_policy_id_policy_id_fk", + "tableFrom": "policy_target", + "tableTo": "policy", + "columnsFrom": ["policy_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()" + }, + "version_release_id": { + "name": "version_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "variable_release_id": { + "name": "variable_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "release_version_release_id_version_release_id_fk": { + "name": "release_version_release_id_version_release_id_fk", + "tableFrom": "release", + "tableTo": "version_release", + "columnsFrom": ["version_release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_variable_release_id_variable_set_release_id_fk": { + "name": "release_variable_release_id_variable_set_release_id_fk", + "tableFrom": "release", + "tableTo": "variable_set_release", + "columnsFrom": ["variable_release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.release_job": { + "name": "release_job", + "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 + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "release_job_release_id_release_id_fk": { + "name": "release_job_release_id_release_id_fk", + "tableFrom": "release_job", + "tableTo": "release", + "columnsFrom": ["release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_job_job_id_job_id_fk": { + "name": "release_job_job_id_job_id_fk", + "tableFrom": "release_job", + "tableTo": "job", + "columnsFrom": ["job_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.release_target": { + "name": "release_target", + "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 + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "desired_release_id": { + "name": "desired_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": { + "release_target_resource_id_environment_id_deployment_id_index": { + "name": "release_target_resource_id_environment_id_deployment_id_index", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "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": { + "release_target_resource_id_resource_id_fk": { + "name": "release_target_resource_id_resource_id_fk", + "tableFrom": "release_target", + "tableTo": "resource", + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_environment_id_environment_id_fk": { + "name": "release_target_environment_id_environment_id_fk", + "tableFrom": "release_target", + "tableTo": "environment", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_deployment_id_deployment_id_fk": { + "name": "release_target_deployment_id_deployment_id_fk", + "tableFrom": "release_target", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_id_release_id_fk": { + "name": "release_target_desired_release_id_release_id_fk", + "tableFrom": "release_target", + "tableTo": "release", + "columnsFrom": ["desired_release_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.variable_set_release": { + "name": "variable_set_release", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release_target_id": { + "name": "release_target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "variable_set_release_release_target_id_release_target_id_fk": { + "name": "variable_set_release_release_target_id_release_target_id_fk", + "tableFrom": "variable_set_release", + "tableTo": "release_target", + "columnsFrom": ["release_target_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.variable_set_release_value": { + "name": "variable_set_release_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "variable_set_release_id": { + "name": "variable_set_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "variable_value_snapshot_id": { + "name": "variable_value_snapshot_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "variable_set_release_value_variable_set_release_id_variable_value_snapshot_id_index": { + "name": "variable_set_release_value_variable_set_release_id_variable_value_snapshot_id_index", + "columns": [ + { + "expression": "variable_set_release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "variable_value_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_set_release_value_variable_set_release_id_variable_set_release_id_fk": { + "name": "variable_set_release_value_variable_set_release_id_variable_set_release_id_fk", + "tableFrom": "variable_set_release_value", + "tableTo": "variable_set_release", + "columnsFrom": ["variable_set_release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "variable_set_release_value_variable_value_snapshot_id_variable_value_snapshot_id_fk": { + "name": "variable_set_release_value_variable_value_snapshot_id_variable_value_snapshot_id_fk", + "tableFrom": "variable_set_release_value", + "tableTo": "variable_value_snapshot", + "columnsFrom": ["variable_value_snapshot_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.variable_value_snapshot": { + "name": "variable_value_snapshot", + "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 + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "variable_value_snapshot_workspace_id_key_value_index": { + "name": "variable_value_snapshot_workspace_id_key_value_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "value", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_value_snapshot_workspace_id_workspace_id_fk": { + "name": "variable_value_snapshot_workspace_id_workspace_id_fk", + "tableFrom": "variable_value_snapshot", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.version_release": { + "name": "version_release", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release_target_id": { + "name": "release_target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "version_release_release_target_id_release_target_id_fk": { + "name": "version_release_release_target_id_release_target_id_fk", + "tableFrom": "version_release", + "tableTo": "release_target", + "columnsFrom": ["release_target_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "version_release_version_id_deployment_version_id_fk": { + "name": "version_release_version_id_deployment_version_id_fk", + "tableFrom": "version_release", + "tableTo": "deployment_version", + "columnsFrom": ["version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_deny_window": { + "name": "policy_rule_deny_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "rrule": { + "name": "rrule", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "dtend": { + "name": "dtend", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "time_zone": { + "name": "time_zone", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_deny_window_policy_id_policy_id_fk": { + "name": "policy_rule_deny_window_policy_id_policy_id_fk", + "tableFrom": "policy_rule_deny_window", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_user_approval": { + "name": "policy_rule_user_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_user_approval_policy_id_policy_id_fk": { + "name": "policy_rule_user_approval_policy_id_policy_id_fk", + "tableFrom": "policy_rule_user_approval", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_user_approval_user_id_user_id_fk": { + "name": "policy_rule_user_approval_user_id_user_id_fk", + "tableFrom": "policy_rule_user_approval", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_user_approval_record": { + "name": "policy_rule_user_approval_record", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_user_approval_record_user_id_user_id_fk": { + "name": "policy_rule_user_approval_record_user_id_user_id_fk", + "tableFrom": "policy_rule_user_approval_record", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "policy_rule_user_approval_record_rule_id_policy_rule_user_approval_id_fk": { + "name": "policy_rule_user_approval_record_rule_id_policy_rule_user_approval_id_fk", + "tableFrom": "policy_rule_user_approval_record", + "tableTo": "policy_rule_user_approval", + "columnsFrom": ["rule_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_role_approval": { + "name": "policy_rule_role_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "role_id": { + "name": "role_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "required_approvals_count": { + "name": "required_approvals_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_role_approval_policy_id_policy_id_fk": { + "name": "policy_rule_role_approval_policy_id_policy_id_fk", + "tableFrom": "policy_rule_role_approval", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_role_approval_role_id_role_id_fk": { + "name": "policy_rule_role_approval_role_id_role_id_fk", + "tableFrom": "policy_rule_role_approval", + "tableTo": "role", + "columnsFrom": ["role_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_role_approval_record": { + "name": "policy_rule_role_approval_record", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_role_approval_record_user_id_user_id_fk": { + "name": "policy_rule_role_approval_record_user_id_user_id_fk", + "tableFrom": "policy_rule_role_approval_record", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "policy_rule_role_approval_record_rule_id_policy_rule_role_approval_id_fk": { + "name": "policy_rule_role_approval_record_rule_id_policy_rule_role_approval_id_fk", + "tableFrom": "policy_rule_role_approval_record", + "tableTo": "policy_rule_role_approval", + "columnsFrom": ["rule_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_any_approval": { + "name": "policy_rule_any_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "required_approvals_count": { + "name": "required_approvals_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_any_approval_policy_id_policy_id_fk": { + "name": "policy_rule_any_approval_policy_id_policy_id_fk", + "tableFrom": "policy_rule_any_approval", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_any_approval_record": { + "name": "policy_rule_any_approval_record", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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": { + "unique_rule_id_user_id": { + "name": "unique_rule_id_user_id", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "policy_rule_any_approval_record_user_id_user_id_fk": { + "name": "policy_rule_any_approval_record_user_id_user_id_fk", + "tableFrom": "policy_rule_any_approval_record", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "public.system_role": { + "name": "system_role", + "schema": "public", + "values": ["user", "admin"] + }, + "public.deployment_version_status": { + "name": "deployment_version_status", + "schema": "public", + "values": ["building", "ready", "failed"] + }, + "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.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": [ + "deploymentVersion", + "deploymentVersionChannel", + "resource", + "resourceProvider", + "resourceMetadataGroup", + "workspace", + "environment", + "environmentPolicy", + "deploymentVariable", + "variableSet", + "system", + "deployment", + "job", + "jobAgent", + "runbook", + "policy", + "resourceView" + ] + }, + "public.release_job_trigger_type": { + "name": "release_job_trigger_type", + "schema": "public", + "values": [ + "new_version", + "version_updated", + "new_resource", + "resource_changed", + "api", + "redeploy", + "force_deploy", + "new_environment", + "variable_changed", + "retry" + ] + }, + "public.approval_status": { + "name": "approval_status", + "schema": "public", + "values": ["approved", "rejected"] + } + }, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/drizzle/meta/0086_snapshot.json b/packages/db/drizzle/meta/0086_snapshot.json new file mode 100644 index 000000000..bc3da3e06 --- /dev/null +++ b/packages/db/drizzle/meta/0086_snapshot.json @@ -0,0 +1,5639 @@ +{ + "id": "49b8da5c-30ff-4789-947f-25fbe9d25b4e", + "prevId": "01ef3e17-a606-4815-874b-a14f381cd46f", + "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" + }, + "system_role": { + "name": "system_role", + "type": "system_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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": "cascade", + "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": "cascade", + "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 + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "resource_selector": { + "name": "resource_selector", + "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_version": { + "name": "deployment_version", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag": { + "name": "tag", + "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": "deployment_version_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 (3) with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "deployment_version_deployment_id_tag_index": { + "name": "deployment_version_deployment_id_tag_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_version_created_at_idx": { + "name": "deployment_version_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_version_deployment_id_deployment_id_fk": { + "name": "deployment_version_deployment_id_deployment_id_fk", + "tableFrom": "deployment_version", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment_version_channel": { + "name": "deployment_version_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 + }, + "deployment_version_selector": { + "name": "deployment_version_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": { + "deployment_version_channel_deployment_id_name_index": { + "name": "deployment_version_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": { + "deployment_version_channel_deployment_id_deployment_id_fk": { + "name": "deployment_version_channel_deployment_id_deployment_id_fk", + "tableFrom": "deployment_version_channel", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment_version_metadata": { + "name": "deployment_version_metadata", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_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": { + "deployment_version_metadata_key_deployment_version_id_index": { + "name": "deployment_version_metadata_key_deployment_version_id_index", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_version_metadata_deployment_version_id_deployment_version_id_fk": { + "name": "deployment_version_metadata_deployment_version_id_deployment_version_id_fk", + "tableFrom": "deployment_version_metadata", + "tableTo": "deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.deployment_version_dependency": { + "name": "deployment_version_dependency", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_version_selector": { + "name": "deployment_version_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": { + "deployment_version_dependency_deployment_version_id_deployment_id_index": { + "name": "deployment_version_dependency_deployment_version_id_deployment_id_index", + "columns": [ + { + "expression": "deployment_version_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_version_dependency_deployment_version_id_deployment_version_id_fk": { + "name": "deployment_version_dependency_deployment_version_id_deployment_version_id_fk", + "tableFrom": "deployment_version_dependency", + "tableTo": "deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_version_dependency_deployment_id_deployment_id_fk": { + "name": "deployment_version_dependency_deployment_id_deployment_id_fk", + "tableFrom": "deployment_version_dependency", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "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_selector": { + "name": "resource_selector", + "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.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 + }, + "directory": { + "name": "directory", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "policy_id": { + "name": "policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_selector": { + "name": "resource_selector", + "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": "'automatic'" + }, + "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_deployment_version_id_fk": { + "name": "environment_policy_approval_release_id_deployment_version_id_fk", + "tableFrom": "environment_policy_approval", + "tableTo": "deployment_version", + "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.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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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 + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "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_deployment_version_channel": { + "name": "environment_policy_deployment_version_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_deployment_version_channel_policy_id_channel_id_index": { + "name": "environment_policy_deployment_version_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_deployment_version_channel_policy_id_deployment_id_index": { + "name": "environment_policy_deployment_version_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_deployment_version_channel_policy_id_environment_policy_id_fk": { + "name": "environment_policy_deployment_version_channel_policy_id_environment_policy_id_fk", + "tableFrom": "environment_policy_deployment_version_channel", + "tableTo": "environment_policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_policy_deployment_version_channel_channel_id_deployment_version_channel_id_fk": { + "name": "environment_policy_deployment_version_channel_channel_id_deployment_version_channel_id_fk", + "tableFrom": "environment_policy_deployment_version_channel", + "tableTo": "deployment_version_channel", + "columnsFrom": ["channel_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "environment_policy_deployment_version_channel_deployment_id_deployment_id_fk": { + "name": "environment_policy_deployment_version_channel_deployment_id_deployment_id_fk", + "tableFrom": "environment_policy_deployment_version_channel", + "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 + }, + "deployment_version_id": { + "name": "deployment_version_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_deployment_version_id_deployment_version_id_fk": { + "name": "release_job_trigger_deployment_version_id_deployment_version_id_fk", + "tableFrom": "release_job_trigger", + "tableTo": "deployment_version", + "columnsFrom": ["deployment_version_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.policy": { + "name": "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 + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_workspace_id_workspace_id_fk": { + "name": "policy_workspace_id_workspace_id_fk", + "tableFrom": "policy", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_deployment_version_selector": { + "name": "policy_deployment_version_selector", + "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 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_version_selector": { + "name": "deployment_version_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_deployment_version_selector_policy_id_policy_id_fk": { + "name": "policy_deployment_version_selector_policy_id_policy_id_fk", + "tableFrom": "policy_deployment_version_selector", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "policy_deployment_version_selector_policy_id_unique": { + "name": "policy_deployment_version_selector_policy_id_unique", + "nullsNotDistinct": false, + "columns": ["policy_id"] + } + } + }, + "public.policy_target": { + "name": "policy_target", + "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 + }, + "deployment_selector": { + "name": "deployment_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "environment_selector": { + "name": "environment_selector", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_target_policy_id_policy_id_fk": { + "name": "policy_target_policy_id_policy_id_fk", + "tableFrom": "policy_target", + "tableTo": "policy", + "columnsFrom": ["policy_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()" + }, + "version_release_id": { + "name": "version_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "variable_release_id": { + "name": "variable_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "release_version_release_id_version_release_id_fk": { + "name": "release_version_release_id_version_release_id_fk", + "tableFrom": "release", + "tableTo": "version_release", + "columnsFrom": ["version_release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_variable_release_id_variable_set_release_id_fk": { + "name": "release_variable_release_id_variable_set_release_id_fk", + "tableFrom": "release", + "tableTo": "variable_set_release", + "columnsFrom": ["variable_release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.release_job": { + "name": "release_job", + "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 + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "release_job_release_id_release_id_fk": { + "name": "release_job_release_id_release_id_fk", + "tableFrom": "release_job", + "tableTo": "release", + "columnsFrom": ["release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_job_job_id_job_id_fk": { + "name": "release_job_job_id_job_id_fk", + "tableFrom": "release_job", + "tableTo": "job", + "columnsFrom": ["job_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.release_target": { + "name": "release_target", + "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 + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "desired_release_id": { + "name": "desired_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": false, + "default": "NULL" + } + }, + "indexes": { + "release_target_resource_id_environment_id_deployment_id_index": { + "name": "release_target_resource_id_environment_id_deployment_id_index", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "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": { + "release_target_resource_id_resource_id_fk": { + "name": "release_target_resource_id_resource_id_fk", + "tableFrom": "release_target", + "tableTo": "resource", + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_environment_id_environment_id_fk": { + "name": "release_target_environment_id_environment_id_fk", + "tableFrom": "release_target", + "tableTo": "environment", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_deployment_id_deployment_id_fk": { + "name": "release_target_deployment_id_deployment_id_fk", + "tableFrom": "release_target", + "tableTo": "deployment", + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_id_release_id_fk": { + "name": "release_target_desired_release_id_release_id_fk", + "tableFrom": "release_target", + "tableTo": "release", + "columnsFrom": ["desired_release_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.variable_set_release": { + "name": "variable_set_release", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release_target_id": { + "name": "release_target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "variable_set_release_release_target_id_release_target_id_fk": { + "name": "variable_set_release_release_target_id_release_target_id_fk", + "tableFrom": "variable_set_release", + "tableTo": "release_target", + "columnsFrom": ["release_target_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.variable_set_release_value": { + "name": "variable_set_release_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "variable_set_release_id": { + "name": "variable_set_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "variable_value_snapshot_id": { + "name": "variable_value_snapshot_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "variable_set_release_value_variable_set_release_id_variable_value_snapshot_id_index": { + "name": "variable_set_release_value_variable_set_release_id_variable_value_snapshot_id_index", + "columns": [ + { + "expression": "variable_set_release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "variable_value_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_set_release_value_variable_set_release_id_variable_set_release_id_fk": { + "name": "variable_set_release_value_variable_set_release_id_variable_set_release_id_fk", + "tableFrom": "variable_set_release_value", + "tableTo": "variable_set_release", + "columnsFrom": ["variable_set_release_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "variable_set_release_value_variable_value_snapshot_id_variable_value_snapshot_id_fk": { + "name": "variable_set_release_value_variable_value_snapshot_id_variable_value_snapshot_id_fk", + "tableFrom": "variable_set_release_value", + "tableTo": "variable_value_snapshot", + "columnsFrom": ["variable_value_snapshot_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.variable_value_snapshot": { + "name": "variable_value_snapshot", + "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 + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "variable_value_snapshot_workspace_id_key_value_index": { + "name": "variable_value_snapshot_workspace_id_key_value_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "value", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_value_snapshot_workspace_id_workspace_id_fk": { + "name": "variable_value_snapshot_workspace_id_workspace_id_fk", + "tableFrom": "variable_value_snapshot", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.version_release": { + "name": "version_release", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release_target_id": { + "name": "release_target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "version_release_release_target_id_release_target_id_fk": { + "name": "version_release_release_target_id_release_target_id_fk", + "tableFrom": "version_release", + "tableTo": "release_target", + "columnsFrom": ["release_target_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "version_release_version_id_deployment_version_id_fk": { + "name": "version_release_version_id_deployment_version_id_fk", + "tableFrom": "version_release", + "tableTo": "deployment_version", + "columnsFrom": ["version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_deny_window": { + "name": "policy_rule_deny_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "rrule": { + "name": "rrule", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "dtend": { + "name": "dtend", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "time_zone": { + "name": "time_zone", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_deny_window_policy_id_policy_id_fk": { + "name": "policy_rule_deny_window_policy_id_policy_id_fk", + "tableFrom": "policy_rule_deny_window", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_user_approval": { + "name": "policy_rule_user_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_user_approval_policy_id_policy_id_fk": { + "name": "policy_rule_user_approval_policy_id_policy_id_fk", + "tableFrom": "policy_rule_user_approval", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_user_approval_user_id_user_id_fk": { + "name": "policy_rule_user_approval_user_id_user_id_fk", + "tableFrom": "policy_rule_user_approval", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_user_approval_record": { + "name": "policy_rule_user_approval_record", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_user_approval_record_user_id_user_id_fk": { + "name": "policy_rule_user_approval_record_user_id_user_id_fk", + "tableFrom": "policy_rule_user_approval_record", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "policy_rule_user_approval_record_rule_id_policy_rule_user_approval_id_fk": { + "name": "policy_rule_user_approval_record_rule_id_policy_rule_user_approval_id_fk", + "tableFrom": "policy_rule_user_approval_record", + "tableTo": "policy_rule_user_approval", + "columnsFrom": ["rule_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_role_approval": { + "name": "policy_rule_role_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "role_id": { + "name": "role_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "required_approvals_count": { + "name": "required_approvals_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_role_approval_policy_id_policy_id_fk": { + "name": "policy_rule_role_approval_policy_id_policy_id_fk", + "tableFrom": "policy_rule_role_approval", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_role_approval_role_id_role_id_fk": { + "name": "policy_rule_role_approval_role_id_role_id_fk", + "tableFrom": "policy_rule_role_approval", + "tableTo": "role", + "columnsFrom": ["role_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_role_approval_record": { + "name": "policy_rule_role_approval_record", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_role_approval_record_user_id_user_id_fk": { + "name": "policy_rule_role_approval_record_user_id_user_id_fk", + "tableFrom": "policy_rule_role_approval_record", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "policy_rule_role_approval_record_rule_id_policy_rule_role_approval_id_fk": { + "name": "policy_rule_role_approval_record_rule_id_policy_rule_role_approval_id_fk", + "tableFrom": "policy_rule_role_approval_record", + "tableTo": "policy_rule_role_approval", + "columnsFrom": ["rule_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_any_approval": { + "name": "policy_rule_any_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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "required_approvals_count": { + "name": "required_approvals_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_any_approval_policy_id_policy_id_fk": { + "name": "policy_rule_any_approval_policy_id_policy_id_fk", + "tableFrom": "policy_rule_any_approval", + "tableTo": "policy", + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.policy_rule_any_approval_record": { + "name": "policy_rule_any_approval_record", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "approval_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "NULL" + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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": { + "unique_rule_id_user_id": { + "name": "unique_rule_id_user_id", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "policy_rule_any_approval_record_user_id_user_id_fk": { + "name": "policy_rule_any_approval_record_user_id_user_id_fk", + "tableFrom": "policy_rule_any_approval_record", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "public.system_role": { + "name": "system_role", + "schema": "public", + "values": ["user", "admin"] + }, + "public.deployment_version_status": { + "name": "deployment_version_status", + "schema": "public", + "values": ["building", "ready", "failed"] + }, + "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.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": [ + "deploymentVersion", + "deploymentVersionChannel", + "resource", + "resourceProvider", + "resourceMetadataGroup", + "workspace", + "environment", + "environmentPolicy", + "deploymentVariable", + "variableSet", + "system", + "deployment", + "job", + "jobAgent", + "runbook", + "policy", + "resourceView" + ] + }, + "public.release_job_trigger_type": { + "name": "release_job_trigger_type", + "schema": "public", + "values": [ + "new_version", + "version_updated", + "new_resource", + "resource_changed", + "api", + "redeploy", + "force_deploy", + "new_environment", + "variable_changed", + "retry" + ] + }, + "public.approval_status": { + "name": "approval_status", + "schema": "public", + "values": ["approved", "rejected"] + } + }, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 3887dc713..b7b2d9c12 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -596,6 +596,20 @@ "when": 1743976930686, "tag": "0084_abnormal_lady_ursula", "breakpoints": true + }, + { + "idx": 85, + "version": "7", + "when": 1744146886268, + "tag": "0085_sloppy_mister_fear", + "breakpoints": true + }, + { + "idx": 86, + "version": "7", + "when": 1744151212079, + "tag": "0086_marvelous_katie_power", + "breakpoints": true } ] } diff --git a/packages/db/src/schema/deployment-variables.ts b/packages/db/src/schema/deployment-variables.ts index f32883ada..b8d5a4004 100644 --- a/packages/db/src/schema/deployment-variables.ts +++ b/packages/db/src/schema/deployment-variables.ts @@ -4,6 +4,7 @@ import type { InferInsertModel, InferSelectModel } from "drizzle-orm"; import type { AnyPgColumn, ColumnsWithTable } from "drizzle-orm/pg-core"; import { relations, sql } from "drizzle-orm"; import { + boolean, foreignKey, jsonb, pgTable, @@ -60,6 +61,7 @@ export const deploymentVariableValue = pgTable( id: uuid("id").notNull().primaryKey().defaultRandom(), variableId: uuid("variable_id").notNull(), value: jsonb("value").$type().notNull(), + sensitive: boolean("sensitive").notNull().default(false), resourceSelector: jsonb("resource_selector") .$type() .default(sql`NULL`), diff --git a/packages/db/src/schema/deployment-version.ts b/packages/db/src/schema/deployment-version.ts index d25299c57..b3934c8d6 100644 --- a/packages/db/src/schema/deployment-version.ts +++ b/packages/db/src/schema/deployment-version.ts @@ -125,7 +125,9 @@ export const deploymentVersion = pgTable( .references(() => deployment.id, { onDelete: "cascade" }), status: versionStatus("status").notNull().default("ready"), message: text("message"), - createdAt: timestamp("created_at").notNull().defaultNow(), + createdAt: timestamp("created_at", { withTimezone: true, precision: 3 }) + .notNull() + .defaultNow(), }, (t) => ({ unq: uniqueIndex().on(t.deploymentId, t.tag), diff --git a/packages/db/src/schema/release.ts b/packages/db/src/schema/release.ts index f10606b34..27a6f2eeb 100644 --- a/packages/db/src/schema/release.ts +++ b/packages/db/src/schema/release.ts @@ -1,7 +1,7 @@ import { relations, sql } from "drizzle-orm"; import { boolean, - json, + jsonb, pgTable, text, timestamp, @@ -14,6 +14,7 @@ import { deployment } from "./deployment.js"; import { environment } from "./environment.js"; import { job } from "./job.js"; import { resource } from "./resource.js"; +import { workspace } from "./workspace.js"; export const releaseTarget = pgTable( "release_target", @@ -39,7 +40,7 @@ export const releaseTarget = pgTable( }), ); -export const release = pgTable("release", { +export const versionRelease = pgTable("version_release", { id: uuid("id").primaryKey().defaultRandom(), releaseTargetId: uuid("release_target_id") @@ -49,25 +50,76 @@ export const release = pgTable("release", { versionId: uuid("version_id") .notNull() .references(() => deploymentVersion.id, { onDelete: "cascade" }), + + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), +}); + +export const variableSetRelease = pgTable("variable_set_release", { + id: uuid("id").primaryKey().defaultRandom(), + releaseTargetId: uuid("release_target_id") + .notNull() + .references(() => releaseTarget.id, { onDelete: "cascade" }), createdAt: timestamp("created_at", { withTimezone: true }) .notNull() .defaultNow(), }); -export const releaseVariable = pgTable( - "release_variable", +export const variableSetReleaseValue = pgTable( + "variable_set_release_value", + { + id: uuid("id").primaryKey().defaultRandom(), + variableSetReleaseId: uuid("variable_set_release_id") + .notNull() + .references(() => variableSetRelease.id, { onDelete: "cascade" }), + + variableValueSnapshotId: uuid("variable_value_snapshot_id") + .notNull() + .references(() => variableValueSnapshot.id, { onDelete: "cascade" }), + + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + }, + (t) => ({ + uniq: uniqueIndex().on(t.variableSetReleaseId, t.variableValueSnapshotId), + }), +); + +export const variableValueSnapshot = pgTable( + "variable_value_snapshot", { id: uuid("id").primaryKey().defaultRandom(), - releaseId: uuid("release_id") + + workspaceId: uuid("workspace_id") .notNull() - .references(() => release.id, { onDelete: "cascade" }), + .references(() => workspace.id, { onDelete: "cascade" }), + + value: jsonb("value").$type().notNull(), key: text("key").notNull(), - value: json("value").notNull(), sensitive: boolean("sensitive").notNull().default(false), + + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), }, - (t) => ({ uniq: uniqueIndex().on(t.releaseId, t.key) }), + (t) => ({ uniq: uniqueIndex().on(t.workspaceId, t.key, t.value) }), ); +export const release = pgTable("release", { + id: uuid("id").primaryKey().defaultRandom(), + versionReleaseId: uuid("version_release_id") + .notNull() + .references(() => versionRelease.id, { onDelete: "cascade" }), + variableReleaseId: uuid("variable_release_id") + .notNull() + .references(() => variableSetRelease.id, { onDelete: "cascade" }), + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), +}); + export const releaseJob = pgTable("release_job", { id: uuid("id").primaryKey().defaultRandom(), releaseId: uuid("release_id") @@ -76,52 +128,13 @@ export const releaseJob = pgTable("release_job", { jobId: uuid("job_id") .notNull() .references(() => job.id, { onDelete: "cascade" }), - createdAt: timestamp("created_at", { withTimezone: true }) - .notNull() - .defaultNow(), }); -export const releaseRelations = relations(release, ({ one, many }) => ({ - version: one(deploymentVersion, { - fields: [release.versionId], - references: [deploymentVersion.id], - }), - releaseTarget: one(releaseTarget, { - fields: [release.releaseTargetId], - references: [releaseTarget.id], - }), - variables: many(releaseVariable), - jobs: many(releaseJob), -})); - -export const releaseVariableRelations = relations( - releaseVariable, - ({ one }) => ({ - release: one(release, { - fields: [releaseVariable.releaseId], - references: [release.id], - }), - }), -); - -export const releaseJobRelations = relations(releaseJob, ({ one }) => ({ - release: one(release, { - fields: [releaseJob.releaseId], - references: [release.id], - }), - job: one(job, { - fields: [releaseJob.jobId], - references: [job.id], - }), -})); +/* Relations */ export const releaseTargetRelations = relations( releaseTarget, ({ one, many }) => ({ - desiredRelease: one(release, { - fields: [releaseTarget.desiredReleaseId], - references: [release.id], - }), deployment: one(deployment, { fields: [releaseTarget.deploymentId], references: [deployment.id], @@ -135,6 +148,71 @@ export const releaseTargetRelations = relations( references: [resource.id], }), - releases: many(release), + versionReleases: many(versionRelease), + variableReleases: many(variableSetRelease), }), ); + +export const versionReleaseRelations = relations( + versionRelease, + ({ one, many }) => ({ + version: one(deploymentVersion, { + fields: [versionRelease.versionId], + references: [deploymentVersion.id], + }), + releaseTarget: one(releaseTarget, { + fields: [versionRelease.releaseTargetId], + references: [releaseTarget.id], + }), + release: many(release), + }), +); + +export const variableReleaseRelations = relations( + variableSetRelease, + ({ one, many }) => ({ + releaseTarget: one(releaseTarget, { + fields: [variableSetRelease.releaseTargetId], + references: [releaseTarget.id], + }), + release: many(release), + values: many(variableSetReleaseValue), + }), +); + +export const variableReleaseValueRelations = relations( + variableSetReleaseValue, + ({ one }) => ({ + variableSetRelease: one(variableSetRelease, { + fields: [variableSetReleaseValue.variableSetReleaseId], + references: [variableSetRelease.id], + }), + variableValueSnapshot: one(variableValueSnapshot, { + fields: [variableSetReleaseValue.variableValueSnapshotId], + references: [variableValueSnapshot.id], + }), + }), +); + +export const releaseRelations = relations(release, ({ many, one }) => ({ + versionRelease: one(versionRelease, { + fields: [release.versionReleaseId], + references: [versionRelease.id], + }), + variableSetRelease: one(variableSetRelease, { + fields: [release.variableReleaseId], + references: [variableSetRelease.id], + }), + releaseJobs: many(releaseJob), +})); + +export const releaseJobRelations = relations(releaseJob, ({ one }) => ({ + release: one(release, { + fields: [releaseJob.releaseId], + references: [release.id], + }), + job: one(job, { + fields: [releaseJob.jobId], + references: [job.id], + }), +})); diff --git a/packages/db/src/schema/variable-sets.ts b/packages/db/src/schema/variable-sets.ts index 09c61b84e..657e3814c 100644 --- a/packages/db/src/schema/variable-sets.ts +++ b/packages/db/src/schema/variable-sets.ts @@ -1,6 +1,13 @@ import type { InferSelectModel } from "drizzle-orm"; import { relations } from "drizzle-orm"; -import { jsonb, pgTable, text, uniqueIndex, uuid } from "drizzle-orm/pg-core"; +import { + boolean, + jsonb, + pgTable, + text, + uniqueIndex, + uuid, +} from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { z } from "zod"; @@ -55,6 +62,7 @@ export const variableSetValue = pgTable( key: text("key").notNull(), value: jsonb("value").$type().notNull(), + sensitive: boolean("sensitive").notNull().default(false), }, (t) => ({ uniq: uniqueIndex().on(t.variableSetId, t.key) }), ); diff --git a/packages/emails/.gitignore b/packages/emails/.gitignore index 7625c80f0..52c301ce2 100644 --- a/packages/emails/.gitignore +++ b/packages/emails/.gitignore @@ -1,2 +1,3 @@ src/**/*.js src/**/*.jsx +tailwind.config.js \ No newline at end of file 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 8ca0081ce..7a457ec4e 100644 --- a/packages/job-dispatch/src/__test__/job-variables-deployment.test.ts +++ b/packages/job-dispatch/src/__test__/job-variables-deployment.test.ts @@ -87,18 +87,21 @@ const variableValues: SCHEMA.DeploymentVariableValue[] = [ variableId: "0", value: "test1", resourceSelector: null, + sensitive: false, }, { id: "1", variableId: "0", value: "test2", resourceSelector: null, + sensitive: false, }, { id: "2", variableId: "0", value: "test3", resourceSelector: null, + sensitive: false, }, ]; @@ -268,6 +271,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test2", variableSetId: "0", + sensitive: false, }, ], }, @@ -338,6 +342,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test", variableSetId: "0", + sensitive: false, }, ], }, @@ -405,6 +410,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test", variableSetId: "0", + sensitive: false, }, ], }, @@ -472,6 +478,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test", variableSetId: "0", + sensitive: false, }, ], }, @@ -539,6 +546,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test", variableSetId: "0", + sensitive: false, }, ], }, @@ -558,6 +566,7 @@ describe("job-variables-deployment", () => { value: "test5", key: "test", variableSetId: "1", + sensitive: false, }, ], }, @@ -636,6 +645,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test", variableSetId: "0", + sensitive: false, }, ], }, @@ -655,6 +665,7 @@ describe("job-variables-deployment", () => { value: "test5", key: "test", variableSetId: "1", + sensitive: false, }, ], }, @@ -733,6 +744,7 @@ describe("job-variables-deployment", () => { value: "test4", key: "test", variableSetId: "0", + sensitive: false, }, ], }, @@ -752,6 +764,7 @@ describe("job-variables-deployment", () => { value: "test5", key: "test", variableSetId: "1", + sensitive: false, }, ], }, diff --git a/packages/rule-engine/src/evaluate.ts b/packages/rule-engine/src/evaluate.ts deleted file mode 100644 index 43394ed16..000000000 --- a/packages/rule-engine/src/evaluate.ts +++ /dev/null @@ -1,140 +0,0 @@ -import _ from "lodash"; - -import type { ReleaseRepository } from "./repositories/types.js"; -import type { DeploymentResourceSelectionResult } from "./types"; -import type { Policy } from "./types.js"; -import { Releases } from "./releases.js"; -import { RuleEngine } from "./rule-engine.js"; -import { DeploymentDenyRule } from "./rules/deployment-deny-rule.js"; -import { - getAnyApprovalRecords, - getRoleApprovalRecords, - getUserApprovalRecords, - VersionApprovalRule, -} from "./rules/version-approval-rule.js"; - -const denyWindows = (policy: Policy | null) => - policy == null - ? [] - : policy.denyWindows.map( - (denyWindow) => - new DeploymentDenyRule({ - ...denyWindow.rrule, - tzid: denyWindow.timeZone, - dtend: denyWindow.dtend, - }), - ); - -const versionAnyApprovalRule = ( - approvalRules?: Policy["versionAnyApprovals"] | null, -) => { - if (approvalRules == null) return []; - return approvalRules.map( - (approval) => - new VersionApprovalRule({ - minApprovals: approval.requiredApprovalsCount, - getApprovalRecords: getAnyApprovalRecords, - }), - ); -}; - -const versionRoleApprovalRule = ( - approvalRules?: Policy["versionRoleApprovals"] | null, -) => { - if (approvalRules == null) return []; - return approvalRules.map( - (approval) => - new VersionApprovalRule({ - minApprovals: approval.requiredApprovalsCount, - getApprovalRecords: getRoleApprovalRecords, - }), - ); -}; - -const versionUserApprovalRule = ( - approvalRules?: Policy["versionUserApprovals"] | null, -) => { - if (approvalRules == null) return []; - return approvalRules.map( - () => - new VersionApprovalRule({ - minApprovals: 1, - getApprovalRecords: getUserApprovalRecords, - }), - ); -}; - -/** - * Evaluates a deployment context against policy rules to determine if the - * deployment is allowed. - * - * @param policy - The policy containing deployment rules and deny windows - * @param getReleases - A function that returns a list of releases for a given - * policy - * @param context - The deployment context containing information needed for - * rule evaluation - * @returns A promise resolving to the evaluation result, including allowed - * status and chosen release - */ -// export const evaluate = async ( -// policy: Policy | Policy[] | null, -// context: DeploymentResourceContext, -// getReleases: GetReleasesFunc, -// ): Promise => { -// const policies = -// policy == null ? [] : Array.isArray(policy) ? policy : [policy]; - -// const mergedPolicy = mergePolicies(policies); -// if (mergedPolicy == null) -// return { -// allowed: false, -// chosenRelease: undefined, -// rejectionReasons: new Map(), -// }; - -// const rules = [...denyWindows(mergedPolicy)]; -// const engine = new RuleEngine(rules); -// const releases = await getReleases(context, mergedPolicy); -// const releaseCollection = Releases.from(releases); -// return engine.evaluate(releaseCollection, context); -// }; - -export const evaluateRepository = async ( - repository: ReleaseRepository, -): Promise => { - const ctx = await repository.getCtx(); - if (ctx == null) - return { - allowed: false, - chosenRelease: undefined, - rejectionReasons: new Map(), - }; - - const releases = await repository.findMatchingReleases(); - const resolvedReleases = releases.map((r) => ({ - ...r, - version: { - ...r.version, - metadata: _(r.version.metadata) - .map((v) => [v.key, v.value]) - .fromPairs() - .value(), - }, - variables: _(r.variables) - .map((v) => [v.key, v.value]) - .fromPairs() - .value(), - })); - const releaseCollection = Releases.from(resolvedReleases); - - const policy = await repository.getPolicy(); - const rules = [ - ...denyWindows(policy), - ...versionUserApprovalRule(policy?.versionUserApprovals), - ...versionAnyApprovalRule(policy?.versionAnyApprovals), - ...versionRoleApprovalRule(policy?.versionRoleApprovals), - ]; - const engine = new RuleEngine(rules); - - return engine.evaluate(releaseCollection, ctx); -}; diff --git a/packages/rule-engine/src/index.ts b/packages/rule-engine/src/index.ts index ac39fb9d1..d314068f7 100644 --- a/packages/rule-engine/src/index.ts +++ b/packages/rule-engine/src/index.ts @@ -1,6 +1,6 @@ -export * from "./evaluate.js"; -export * from "./repositories/index.js"; -export * from "./rule-engine.js"; +export * from "./manager/version-rule-engine.js"; export * from "./rules/index.js"; export * from "./utils/merge-policies.js"; export * from "./types.js"; +export * from "./manager/version-manager.js"; +export * from "./manager/variable-manager.js"; diff --git a/packages/rule-engine/src/manager/__tests__/version-rule-engine.test.ts b/packages/rule-engine/src/manager/__tests__/version-rule-engine.test.ts new file mode 100644 index 000000000..372137e23 --- /dev/null +++ b/packages/rule-engine/src/manager/__tests__/version-rule-engine.test.ts @@ -0,0 +1,159 @@ +import { beforeEach, describe, expect, it } from "vitest"; + +import type { + RuleEngineContext, + RuleEngineFilter, + RuleEngineRuleResult, +} from "../../types.js"; +import type { Version } from "../version-rule-engine.js"; +import { VersionRuleEngine } from "../version-rule-engine.js"; + +// Mock rule implementation +class MockRule implements RuleEngineFilter { + public readonly name = "MockRule"; + constructor(private readonly allowedIds: string[]) {} + + filter( + _: RuleEngineContext, + candidates: Version[], + ): RuleEngineRuleResult { + const rejectionReasons = new Map(); + const allowedCandidates = candidates.filter((candidate) => { + if (this.allowedIds.includes(candidate.id)) { + return true; + } + rejectionReasons.set(candidate.id, `Rejected by ${this.name}`); + return false; + }); + + return { allowedCandidates, rejectionReasons }; + } +} + +describe("VersionRuleEngine", () => { + let context: RuleEngineContext; + let candidates: Version[]; + + beforeEach(() => { + // Create a sample context + context = { + desiredReleaseId: null, + deployment: { + id: "deploy-1", + name: "Test Deployment", + }, + environment: { + id: "env-1", + name: "Test Environment", + }, + resource: { + id: "res-1", + name: "Test Resource", + }, + }; + + // Create sample versions + candidates = [ + { + id: "ver-1", + tag: "v1.0.0", + config: {}, + metadata: {}, + createdAt: new Date("2023-01-01T12:00:00Z"), + }, + { + id: "ver-2", + tag: "v1.1.0", + config: {}, + metadata: {}, + createdAt: new Date("2023-01-02T12:00:00Z"), + }, + { + id: "ver-3", + tag: "v1.2.0", + config: {}, + metadata: { requiresSequentialUpgrade: "true" }, + createdAt: new Date("2023-01-03T12:00:00Z"), + }, + { + id: "ver-4", + tag: "v1.3.0", + config: {}, + metadata: { requiresSequentialUpgrade: "true" }, + createdAt: new Date("2023-01-04T12:00:00Z"), + }, + ]; + }); + + it("should apply rules in sequence", async () => { + // Set up rules to filter out specific versions + const rule1 = new MockRule(["ver-1", "ver-2", "ver-3"]); + const rule2 = new MockRule(["ver-2", "ver-3"]); + + const engine = new VersionRuleEngine([rule1, rule2]); + const result = await engine.evaluate(context, candidates); + + expect(result.chosenCandidate).not.toBeNull(); + expect(result.chosenCandidate?.id).toBe("ver-3"); + expect(result.rejectionReasons.get("ver-1")).toBe("Rejected by MockRule"); + expect(result.rejectionReasons.get("ver-4")).toBe("Rejected by MockRule"); + }); + + it("should return null when all candidates are filtered out", async () => { + // Set up rules to filter out all versions + const rule1 = new MockRule([]); + + const engine = new VersionRuleEngine([rule1]); + const result = await engine.evaluate(context, candidates); + + expect(result.chosenCandidate).toBeNull(); + expect(result.rejectionReasons.size).toBe(4); + }); + + it("should select the oldest sequential upgrade version when present", async () => { + // Set up rule that allows all versions + const rule1 = new MockRule(["ver-1", "ver-2", "ver-3", "ver-4"]); + + const engine = new VersionRuleEngine([rule1]); + const result = await engine.evaluate(context, candidates); + + expect(result.chosenCandidate).not.toBeNull(); + expect(result.chosenCandidate?.id).toBe("ver-3"); // Should pick ver-3 as it's the oldest sequential upgrade + }); + + it("should select the newest version when no sequential upgrades are present", async () => { + // Set up rule that allows only non-sequential versions + const rule1 = new MockRule(["ver-1", "ver-2"]); + + const engine = new VersionRuleEngine([rule1]); + const result = await engine.evaluate(context, candidates); + + expect(result.chosenCandidate).not.toBeNull(); + expect(result.chosenCandidate?.id).toBe("ver-2"); // Should pick ver-2 as it's the newest non-sequential + }); + + it("should handle empty candidates array", async () => { + const engine = new VersionRuleEngine([]); + const result = await engine.evaluate(context, []); + + expect(result.chosenCandidate).toBeNull(); + }); + + it("should accumulate rejection reasons across multiple rules", async () => { + // First rule rejects ver-4 + const rule1 = new MockRule(["ver-1", "ver-2", "ver-3"]); + // Second rule rejects ver-1 + const rule2 = new MockRule(["ver-2", "ver-3"]); + // Third rule rejects ver-2 + const rule3 = new MockRule(["ver-3"]); + + const engine = new VersionRuleEngine([rule1, rule2, rule3]); + const result = await engine.evaluate(context, candidates); + + expect(result.chosenCandidate?.id).toBe("ver-3"); + expect(result.rejectionReasons.size).toBe(3); + expect(result.rejectionReasons.get("ver-1")).toBe("Rejected by MockRule"); + expect(result.rejectionReasons.get("ver-2")).toBe("Rejected by MockRule"); + expect(result.rejectionReasons.get("ver-4")).toBe("Rejected by MockRule"); + }); +}); diff --git a/packages/rule-engine/src/manager/types.ts b/packages/rule-engine/src/manager/types.ts new file mode 100644 index 000000000..97db3a230 --- /dev/null +++ b/packages/rule-engine/src/manager/types.ts @@ -0,0 +1,11 @@ +export interface ReleaseTarget { + id: string; + deploymentId: string; + environmentId: string; + resourceId: string; + workspaceId: string; +} + +export type ReleaseManager = { + upsertRelease: (...args: any[]) => Promise<{ created: boolean; release: T }>; +}; diff --git a/packages/rule-engine/src/manager/variable-manager.ts b/packages/rule-engine/src/manager/variable-manager.ts new file mode 100644 index 000000000..d6033f3c5 --- /dev/null +++ b/packages/rule-engine/src/manager/variable-manager.ts @@ -0,0 +1,89 @@ +import type { Tx } from "@ctrlplane/db"; +import _ from "lodash"; + +import { desc, eq, takeFirst } from "@ctrlplane/db"; +import { db as dbClient } from "@ctrlplane/db/client"; +import * as schema from "@ctrlplane/db/schema"; + +import type { Policy } from "../types.js"; +import type { ReleaseManager, ReleaseTarget } from "./types.js"; +import type { MaybeVariable } from "./variables/types.js"; +import { VariableManager } from "./variables/variables.js"; + +export class VariableReleaseManager implements ReleaseManager { + private cachedPolicy: Policy | null = null; + + constructor( + private readonly db: Tx = dbClient, + private readonly releaseTarget: ReleaseTarget, + ) {} + + async upsertRelease(variables: MaybeVariable[]) { + const latestRelease = await this.findLatestRelease(); + + const oldVars = _(latestRelease?.values ?? []) + .map((v) => [v.variableValueSnapshot.key, v.variableValueSnapshot.value]) + .fromPairs() + .value(); + + const newVars = _(variables) + .compact() + .map((v) => [v.key, v.value]) + .fromPairs() + .value(); + + const isSame = _.isEqual(oldVars, newVars); + if (latestRelease != null && isSame) + return { created: false, release: latestRelease }; + + return this.db.transaction(async (tx) => { + const release = await tx + .insert(schema.variableSetRelease) + .values({ releaseTargetId: this.releaseTarget.id }) + .returning() + .then(takeFirst); + + const vars = _.compact(variables); + if (vars.length === 0) return { created: true, release }; + + const variableValueSnapshot = await tx + .insert(schema.variableValueSnapshot) + .values( + vars.map((v) => ({ + workspaceId: this.releaseTarget.workspaceId, + key: v.key, + value: v.value, + sensitive: v.sensitive, + })), + ) + .onConflictDoNothing() + .returning(); + + await tx.insert(schema.variableSetReleaseValue).values( + variableValueSnapshot.map((v) => ({ + variableSetReleaseId: release.id, + variableValueSnapshotId: v.id, + })), + ); + + return { created: true, release }; + }); + } + + async findLatestRelease() { + return this.db.query.variableSetRelease.findFirst({ + where: eq( + schema.variableSetRelease.releaseTargetId, + this.releaseTarget.id, + ), + orderBy: desc(schema.variableSetRelease.createdAt), + with: { values: { with: { variableValueSnapshot: true } } }, + }); + } + + async evaluate() { + const variableManager = await VariableManager.database(this.releaseTarget); + const variables = await variableManager.getVariables(); + return { chosenCandidate: variables }; + } +} diff --git a/packages/rule-engine/src/repositories/variables/db-variable-providers.ts b/packages/rule-engine/src/manager/variables/db-variable-providers.ts similarity index 100% rename from packages/rule-engine/src/repositories/variables/db-variable-providers.ts rename to packages/rule-engine/src/manager/variables/db-variable-providers.ts diff --git a/packages/rule-engine/src/repositories/variables/types.ts b/packages/rule-engine/src/manager/variables/types.ts similarity index 100% rename from packages/rule-engine/src/repositories/variables/types.ts rename to packages/rule-engine/src/manager/variables/types.ts diff --git a/packages/rule-engine/src/repositories/variables/variables.ts b/packages/rule-engine/src/manager/variables/variables.ts similarity index 100% rename from packages/rule-engine/src/repositories/variables/variables.ts rename to packages/rule-engine/src/manager/variables/variables.ts diff --git a/packages/rule-engine/src/manager/version-manager-rules.ts b/packages/rule-engine/src/manager/version-manager-rules.ts new file mode 100644 index 000000000..791a2c1b0 --- /dev/null +++ b/packages/rule-engine/src/manager/version-manager-rules.ts @@ -0,0 +1,72 @@ +import type { Policy, RuleEngineFilter } from "../types"; +import type { Version } from "./version-rule-engine"; +import { DeploymentDenyRule } from "../rules/deployment-deny-rule.js"; +import { + getAnyApprovalRecords, + getRoleApprovalRecords, + getUserApprovalRecords, + VersionApprovalRule, +} from "../rules/version-approval-rule.js"; + +const denyWindows = (policy: Policy | null) => + policy == null + ? [] + : policy.denyWindows.map( + (denyWindow) => + new DeploymentDenyRule({ + ...denyWindow.rrule, + tzid: denyWindow.timeZone, + dtend: denyWindow.dtend, + getCandidateId: (candidate) => candidate.id, + }), + ); + +const versionAnyApprovalRule = ( + approvalRules?: Policy["versionAnyApprovals"] | null, +) => { + if (approvalRules == null) return []; + return approvalRules.map( + (approval) => + new VersionApprovalRule({ + minApprovals: approval.requiredApprovalsCount, + getApprovalRecords: getAnyApprovalRecords, + }), + ); +}; + +const versionRoleApprovalRule = ( + approvalRules?: Policy["versionRoleApprovals"] | null, +) => { + if (approvalRules == null) return []; + return approvalRules.map( + (approval) => + new VersionApprovalRule({ + minApprovals: approval.requiredApprovalsCount, + getApprovalRecords: getRoleApprovalRecords, + }), + ); +}; + +const versionUserApprovalRule = ( + approvalRules?: Policy["versionUserApprovals"] | null, +) => { + if (approvalRules == null) return []; + return approvalRules.map( + () => + new VersionApprovalRule({ + minApprovals: 1, + getApprovalRecords: getUserApprovalRecords, + }), + ); +}; + +export const getRules = ( + policy: Policy | null, +): RuleEngineFilter[] => { + return [ + ...denyWindows(policy), + ...versionUserApprovalRule(policy?.versionUserApprovals), + ...versionAnyApprovalRule(policy?.versionAnyApprovals), + ...versionRoleApprovalRule(policy?.versionRoleApprovals), + ]; +}; diff --git a/packages/rule-engine/src/manager/version-manager.ts b/packages/rule-engine/src/manager/version-manager.ts new file mode 100644 index 000000000..0558d112e --- /dev/null +++ b/packages/rule-engine/src/manager/version-manager.ts @@ -0,0 +1,181 @@ +import type { Tx } from "@ctrlplane/db"; +import _ from "lodash"; + +import { + and, + desc, + eq, + gte, + lte, + takeFirst, + takeFirstOrNull, +} from "@ctrlplane/db"; +import { db as dbClient } from "@ctrlplane/db/client"; +import * as schema from "@ctrlplane/db/schema"; +import { JobStatus } from "@ctrlplane/validators/jobs"; + +import type { Policy, RuleEngineContext } from "../types.js"; +import type { ReleaseManager, ReleaseTarget } from "./types.js"; +import { getApplicablePolicies } from "../db/get-applicable-policies.js"; +import { VersionRuleEngine } from "../manager/version-rule-engine.js"; +import { mergePolicies } from "../utils/merge-policies.js"; +import { getRules } from "./version-manager-rules.js"; + +export class VersionReleaseManager implements ReleaseManager { + private cachedPolicy: Policy | null = null; + constructor( + private readonly db: Tx = dbClient, + private readonly releaseTarget: ReleaseTarget, + ) {} + + async upsertRelease(versionId: string) { + const latestRelease = await this.findLatestRelease(); + if (latestRelease?.versionId === versionId) + return { created: false, release: latestRelease }; + + const release = await this.db + .insert(schema.versionRelease) + .values({ releaseTargetId: this.releaseTarget.id, versionId }) + .returning() + .then(takeFirst); + + return { created: true, release }; + } + + async findLatestVersionMatchingPolicy() { + const policy = await this.getPolicy(); + const deploymentVersion = await this.db.query.deploymentVersion.findFirst({ + where: and( + eq( + schema.deploymentVersion.deploymentId, + this.releaseTarget.deploymentId, + ), + schema.deploymentVersionMatchesCondition( + this.db, + policy?.deploymentVersionSelector?.deploymentVersionSelector, + ), + ), + orderBy: desc(schema.deploymentVersion.createdAt), + }); + + return deploymentVersion; + } + + async findLastestDeployedVersion() { + return this.db + .select() + .from(schema.deploymentVersion) + .innerJoin( + schema.versionRelease, + eq(schema.versionRelease.versionId, schema.deploymentVersion.id), + ) + .innerJoin( + schema.release, + eq(schema.release.versionReleaseId, schema.versionRelease.id), + ) + .innerJoin( + schema.releaseJob, + eq(schema.releaseJob.releaseId, schema.release.id), + ) + .innerJoin(schema.job, eq(schema.releaseJob.jobId, schema.job.id)) + .where( + and( + eq(schema.job.status, JobStatus.Successful), + eq(schema.versionRelease.releaseTargetId, this.releaseTarget.id), + ), + ) + .orderBy(desc(schema.job.createdAt)) + .limit(1) + .then(takeFirstOrNull) + .then((result) => result?.deployment_version); + } + + async findVersionsForEvaluate() { + const [latestDeployedVersion, latestVersionMatchingPolicy] = + await Promise.all([ + this.findLastestDeployedVersion(), + this.findLatestVersionMatchingPolicy(), + ]); + + const policy = await this.getPolicy(); + + return this.db.query.deploymentVersion + .findMany({ + where: and( + eq( + schema.deploymentVersion.deploymentId, + this.releaseTarget.deploymentId, + ), + schema.deploymentVersionMatchesCondition( + this.db, + policy?.deploymentVersionSelector?.deploymentVersionSelector, + ), + latestDeployedVersion != null + ? gte( + schema.deploymentVersion.createdAt, + latestDeployedVersion.createdAt, + ) + : undefined, + latestVersionMatchingPolicy != null + ? lte( + schema.deploymentVersion.createdAt, + latestVersionMatchingPolicy.createdAt, + ) + : undefined, + ), + with: { metadata: true }, + orderBy: desc(schema.deploymentVersion.createdAt), + }) + .then((versions) => + versions.map((version) => ({ + ...version, + metadata: Object.fromEntries( + version.metadata.map((m) => [m.key, m.value]), + ), + })), + ); + } + + async findLatestRelease() { + return this.db.query.versionRelease.findFirst({ + where: eq(schema.versionRelease.releaseTargetId, this.releaseTarget.id), + orderBy: desc(schema.versionRelease.createdAt), + }); + } + + async getPolicy(forceRefresh = false): Promise { + if (!forceRefresh && this.cachedPolicy !== null) return this.cachedPolicy; + + const policies = await getApplicablePolicies( + this.db, + this.releaseTarget.workspaceId, + this.releaseTarget, + ); + + this.cachedPolicy = mergePolicies(policies); + return this.cachedPolicy; + } + + async evaluate() { + const ctx: RuleEngineContext | undefined = + await this.db.query.releaseTarget.findFirst({ + where: eq(schema.releaseTarget.id, this.releaseTarget.id), + with: { + resource: true, + environment: true, + deployment: true, + }, + }); + + if (ctx == null) + throw new Error(`Release target ${this.releaseTarget.id} not found`); + + const policy = await this.getPolicy(); + const rules = getRules(policy); + + const engine = new VersionRuleEngine(rules); + const versions = await this.findVersionsForEvaluate(); + const result = await engine.evaluate(ctx, versions); + return result; + } +} diff --git a/packages/rule-engine/src/manager/version-rule-engine.ts b/packages/rule-engine/src/manager/version-rule-engine.ts new file mode 100644 index 000000000..7bec5c639 --- /dev/null +++ b/packages/rule-engine/src/manager/version-rule-engine.ts @@ -0,0 +1,151 @@ +import _ from "lodash"; + +import type { + RuleEngine, + RuleEngineContext, + RuleEngineFilter, + RuleEngineSelectionResult, +} from "../types.js"; + +export type Version = { + id: string; + tag: string; + config: Record; + metadata: Record; + createdAt: Date; +}; + +/** + * The VersionRuleEngine applies a sequence of rules to filter candidate versions + * and selects the most appropriate version based on configured criteria. + * + * The engine works by passing versions through each rule in sequence, where each + * rule can filter out versions that don't meet specific criteria. After all rules + * have been applied, a final selection strategy is used to choose the best + * remaining version. + */ +export class VersionRuleEngine implements RuleEngine { + /** + * Creates a new VersionRuleEngine with the specified rules. + * + * @param rules - An array of rules that implement the RuleEngineFilter + * interface. These rules will be applied in sequence during + * evaluation. Rules can be provided directly or as functions that + * return a rule or promise of a rule. + */ + constructor(private rules: Array>) {} + + /** + * Evaluates a context against all configured rules to determine which version + * should be used. + * + * The evaluation process: + * 1. Starts with all available versions as candidates + * 2. Applies each rule in sequence, updating the candidate list after each rule + * 3. If any rule disqualifies all candidates, evaluation stops with a null result + * 4. After all rules pass, selects the final version using the configured + * selection strategy + * + * Important implementation details for rule authors: + * - Rules should return ALL valid candidate versions, not just one + * - This ensures subsequent rules have a complete set of options to filter + * - For example, if multiple sequential upgrades are required, all should be + * returned, not just the oldest one + * - Otherwise, a subsequent rule might filter out the only returned candidate, + * even when other valid candidates existed + * + * @param context - The context containing all information needed for rule evaluation + * @param candidates - The versions to evaluate + * @returns A promise resolving to the evaluation result, including chosen version + * and any rejection reasons + */ + async evaluate( + context: RuleEngineContext, + candidates: Version[], + ): Promise> { + // Track rejection reasons for each version across all rules + let rejectionReasons = new Map(); + + // Apply each rule in sequence to filter candidate versions + for (const rule of this.rules) { + const result = await rule.filter(context, candidates); + + // If the rule yields no candidates, we must stop. + if (result.allowedCandidates.length === 0) { + return { + chosenCandidate: null, + rejectionReasons: result.rejectionReasons ?? rejectionReasons, + }; + } + + // Merge any new rejection reasons with our tracking map + if (result.rejectionReasons) { + rejectionReasons = new Map([ + ...rejectionReasons, + ...result.rejectionReasons, + ]); + } + + candidates = result.allowedCandidates; + } + + // Once all rules pass, select the final version + const chosen = this.selectFinalRelease(context, candidates); + return chosen == null + ? { + chosenCandidate: null, + rejectionReasons, + } + : { + chosenCandidate: chosen, + rejectionReasons, + }; + } + + /** + * Selects the most appropriate version from the candidate list after all rules + * have been applied. + * + * The selection strategy follows these priorities: + * 1. If sequential upgrade versions are present, select the oldest one + * 2. Otherwise, select the newest version (by createdAt timestamp) + * + * This selection logic ensures sequential upgrades are applied in the correct + * order while defaulting to the latest available version when no sequential + * upgrades are required. + * + * @param context - The context for version selection + * @param candidates - The list of version candidates that passed all rules + * @returns The selected version, or undefined if no suitable version can be chosen + */ + private selectFinalRelease( + context: RuleEngineContext, + candidates: Version[], + ): Version | undefined { + if (candidates.length === 0) { + return undefined; + } + + // First, check for sequential upgrades - if present, we must select the oldest + const sequentialReleases = this.findSequentialUpgradeReleases(candidates); + return sequentialReleases.length > 0 + ? _.minBy(sequentialReleases, (v) => v.createdAt) + : _.maxBy(candidates, (v) => v.createdAt); + } + + /** + * Identifies versions that require sequential upgrade application. + * + * Looks for the standard metadata flag that indicates a version requires + * sequential upgrade application. + * + * @param versions - The versions to check + * @returns An array of versions that require sequential upgrades + */ + private findSequentialUpgradeReleases(versions: Version[]): Version[] { + // Look for the standard metadata key used by SequentialUpgradeRule + return versions.filter( + (v) => v.metadata.requiresSequentialUpgrade === "true", + ); + } +} diff --git a/packages/rule-engine/src/releases.ts b/packages/rule-engine/src/releases.ts deleted file mode 100644 index cce5367e9..000000000 --- a/packages/rule-engine/src/releases.ts +++ /dev/null @@ -1,306 +0,0 @@ -import type { DeploymentResourceContext, ResolvedRelease } from "./types.js"; - -/** - * A class that encapsulates candidate releases with utility methods for common - * operations. - * - * This class is used throughout the rule engine to provide consistent handling - * of release collections. Rules should operate on CandidateReleases instances - * and return all valid candidates, not just a single one. This ensures that - * downstream rules have the full set of options to apply their own filtering - * logic. - * - * For example, if a rule determines that sequential upgrades are required, it - * should return all releases that are valid sequential candidates, not just the - * oldest one. This allows subsequent rules to further filter the candidates - * based on their criteria. - */ -export class Releases { - /** - * The internal array of release candidates - */ - private releases: ResolvedRelease[]; - - /** - * Creates a new CandidateReleases instance. - * - * @param releases - The array of releases to manage - */ - constructor(releases: ResolvedRelease[]) { - this.releases = [...releases]; - } - - /** - * Static factory method to create an empty CandidateReleases instance. - * - * @returns A new CandidateReleases instance with no releases - */ - static empty(): Releases { - return new Releases([]); - } - - /** - * Static factory method to create a new CandidateReleases instance. - * - * @param releases - The array of releases to manage - * @returns A new CandidateReleases instance - */ - static from(releases: ResolvedRelease | ResolvedRelease[]): Releases { - const releasesToInclude = Array.isArray(releases) ? releases : [releases]; - return new Releases(releasesToInclude); - } - - /** - * Returns all releases in this collection. - * - * @returns The array of all releases - */ - getAll(): ResolvedRelease[] { - return [...this.releases]; - } - - /** - * Returns the oldest release based on creation date. - * - * @returns The oldest release, or undefined if the collection is empty - */ - getOldest(): ResolvedRelease | undefined { - if (this.releases.length === 0) return undefined; - - return this.releases.reduce( - (oldest, current) => - current.createdAt < (oldest?.createdAt ?? current.createdAt) - ? current - : oldest, - this.releases[0], - ); - } - - /** - * Returns the newest release based on creation date. - * - * @returns The newest release, or undefined if the collection is empty - */ - getNewest(): ResolvedRelease | undefined { - if (this.releases.length === 0) return undefined; - - return this.releases.reduce( - (newest, current) => - current.createdAt > (newest?.createdAt ?? current.createdAt) - ? current - : newest, - this.releases[0], - ); - } - - /** - * Returns the release that matches the desired release ID from the context. - * - * @param context - The deployment context containing the desired release ID - * @returns The desired release if found, or undefined if not found or no ID - * specified - */ - getDesired(context: DeploymentResourceContext): ResolvedRelease | undefined { - if (!context.desiredReleaseId) return undefined; - - return this.releases.find( - (release) => release.id === context.desiredReleaseId, - ); - } - - /** - * Returns the effective target release - either the desired release if - * specified, or the newest available release if no desired release is - * specified. - * - * @param context - The deployment context containing the desired release ID - * @returns The effective target release, or undefined if no candidates are - * available - */ - getEffectiveTarget( - context: DeploymentResourceContext, - ): ResolvedRelease | undefined { - if (this.releases.length === 0) return undefined; - return this.getDesired(context) ?? this.getNewest(); - } - - /** - * Filters releases based on a metadata key and value. - * - * @param metadataKey - The metadata key to check - * @param metadataValue - The expected value for the metadata key - * @returns A new CandidateReleases instance with filtered releases - */ - filterByMetadata(metadataKey: string, metadataValue: string): Releases { - return this.filter( - (release) => release.version.metadata[metadataKey] === metadataValue, - ); - } - - /** - * Returns a new CandidateReleases instance sorted by creation date in - * ascending order (oldest first). - * - * @returns A new CandidateReleases instance with sorted releases - */ - sortByCreationDateAsc(): Releases { - const sorted = [...this.releases].sort( - (a, b) => a.createdAt.getTime() - b.createdAt.getTime(), - ); - return new Releases(sorted); - } - - /** - * Returns a new CandidateReleases instance sorted by creation date in - * descending order (newest first). - * - * @returns A new CandidateReleases instance with sorted releases - */ - sortByCreationDateDesc(): Releases { - const sorted = [...this.releases].sort( - (a, b) => b.createdAt.getTime() - a.createdAt.getTime(), - ); - return new Releases(sorted); - } - - /** - * Returns a new CandidateReleases instance with releases created before the - * reference release. - * - * @param referenceRelease - The reference release to compare against - * @returns A new CandidateReleases instance with filtered releases - */ - getCreatedBefore(referenceRelease: ResolvedRelease): Releases { - const filtered = this.releases.filter( - (release) => release.createdAt < referenceRelease.createdAt, - ); - return new Releases(filtered); - } - - /** - * Returns a new CandidateReleases instance with releases created after the - * reference release. - * - * @param referenceRelease - The reference release to compare against - * @returns A new CandidateReleases instance with filtered releases - */ - getCreatedAfter(referenceRelease: ResolvedRelease): Releases { - const filtered = this.releases.filter( - (release) => release.createdAt > referenceRelease.createdAt, - ); - return new Releases(filtered); - } - - /** - * Finds a release by ID. - * - * @param id - The release ID to search for - * @returns The matching release or undefined if not found - */ - findById(id: string): ResolvedRelease | undefined { - return this.releases.find((release) => release.id === id); - } - - /** - * Returns the number of releases in this collection. - * - * @returns The number of releases - */ - get length(): number { - return this.releases.length; - } - - /** - * Checks if the collection is empty. - * - * @returns True if there are no releases, false otherwise - */ - isEmpty(): boolean { - return this.releases.length === 0; - } - - /** - * Creates a new CandidateReleases instance with the given releases added. - * - * @param releases - Releases to add to the collection - * @returns A new CandidateReleases instance - */ - add(releases: ResolvedRelease | ResolvedRelease[]): Releases { - const releasesToAdd = Array.isArray(releases) ? releases : [releases]; - return new Releases([...this.releases, ...releasesToAdd]); - } - - /** - * Maps the releases using a mapping function. - * - * @param mapper - Function to transform each release - * @returns A new array with the mapped values - */ - map(mapper: (release: ResolvedRelease) => T): T[] { - return this.releases.map(mapper); - } - - /** - * Iterates over all releases in the collection. - * - * @param callback - Function to call for each release - */ - forEach(callback: (release: ResolvedRelease) => void): void { - this.releases.forEach(callback); - } - - /** - * Filters the releases using a predicate function. - * - * @param predicate - Function that determines whether to include a release - * @returns A new CandidateReleases instance with filtered releases - */ - filter(predicate: (release: ResolvedRelease) => boolean): Releases { - const filtered = this.releases.filter(predicate); - return new Releases(filtered); - } - - /** - * Finds a release that satisfies the provided predicate. - * - * @param predicate - Function to test each release - * @returns The first release that satisfies the predicate, or undefined if - * none is found - */ - find( - predicate: (release: ResolvedRelease) => boolean, - ): ResolvedRelease | undefined { - return this.releases.find(predicate); - } - - /** - * Checks if any release in the collection satisfies the predicate. - * - * @param predicate - Function to test each release - * @returns True if at least one release satisfies the predicate, false - * otherwise - */ - some(predicate: (release: ResolvedRelease) => boolean): boolean { - return this.releases.some(predicate); - } - - /** - * Checks if all releases in the collection satisfy the predicate. - * - * @param predicate - Function to test each release - * @returns True if all releases satisfy the predicate, false otherwise - */ - every(predicate: (release: ResolvedRelease) => boolean): boolean { - return this.releases.every(predicate); - } - - /** - * Returns the release at the specified index. - * - * @param index - The index of the release to return - * @returns The release at the specified index, or undefined if the index is out of bounds - */ - at(index: number): ResolvedRelease | undefined { - return this.releases[index]; - } -} diff --git a/packages/rule-engine/src/repositories/db-release-repository.ts b/packages/rule-engine/src/repositories/db-release-repository.ts deleted file mode 100644 index f65dc0f82..000000000 --- a/packages/rule-engine/src/repositories/db-release-repository.ts +++ /dev/null @@ -1,247 +0,0 @@ -import type { Tx } from "@ctrlplane/db"; -import _ from "lodash"; - -import { eq, takeFirst } from "@ctrlplane/db"; -import { db as dbClient } from "@ctrlplane/db/client"; -import * as schema from "@ctrlplane/db/schema"; - -import type { DeploymentResourceContext, Policy } from "../types.js"; -import type { - CompleteRelease, - Release, - ReleaseRepository, - ReleaseWithId, -} from "./types.js"; -import type { MaybeVariable } from "./variables/types.js"; -import { getApplicablePolicies } from "../db/get-applicable-policies.js"; -import { mergePolicies } from "../utils/merge-policies.js"; -import { - findLatestPolicyMatchingRelease, - findPolicyMatchingReleasesBetweenDeployments, -} from "./get-releases.js"; -import { VariableManager } from "./variables/variables.js"; - -/** - * Release target with associated identifiers - */ -interface ReleaseTarget { - id: string; - deploymentId: string; - environmentId: string; - resourceId: string; - workspaceId: string; -} - -/** - * Repository implementation that combines database operations with business logic - * for managing releases. Handles creating, updating and querying releases while - * enforcing policy constraints. - */ -export class DatabaseReleaseRepository implements ReleaseRepository { - /** - * Creates a new DatabaseReleaseRepository instance - * @param releaseTarget - The release target to manage releases for - * @returns A configured DatabaseReleaseRepository instance - */ - static async create(releaseTarget: ReleaseTarget) { - const variableManager = await VariableManager.database(releaseTarget); - return new DatabaseReleaseRepository( - dbClient, - releaseTarget, - variableManager, - ); - } - - // Cache for the calculated policy - private cachedPolicy: Policy | null = null; - - private constructor( - private readonly db: Tx = dbClient, - private readonly releaseTarget: ReleaseTarget, - private readonly variableManager: VariableManager, - ) {} - - /** - * Gets the latest variables for this release target - * @returns The current variables - */ - async getLatestVariables() { - return this.variableManager.getVariables(); - } - - /** - * Gets the merged policy that applies to this release target - * Uses a cached value if available - * @param forceRefresh - Whether to force a refresh of the policy from DB - * @returns The applicable policy, or null if none exist - */ - async getPolicy(forceRefresh = false): Promise { - // Return cached policy if available and refresh not forced - if (!forceRefresh && this.cachedPolicy !== null) { - return this.cachedPolicy; - } - - const policies = await getApplicablePolicies( - this.db, - this.releaseTarget.workspaceId, - this.releaseTarget, - ); - - this.cachedPolicy = mergePolicies(policies); - return this.cachedPolicy; - } - - /** - * Retrieves all releases that match the given policy - * @param policy - Optional policy to use; if not provided, will use cached or fetched policy - * @returns Promise resolving to array of matching releases - */ - async findMatchingReleases(): Promise { - const policy = await this.getPolicy(); - return findPolicyMatchingReleasesBetweenDeployments( - this.db, - this.releaseTarget.id, - policy, - ); - } - - /** - * Gets the most recent release matching policy constraints - * @param policy - Optional policy to use; if not provided, will use cached or fetched policy - * @returns Promise resolving to the latest matching release or null - */ - async findLatestRelease(): Promise { - const policy = await this.getPolicy(); - - return ( - (await findLatestPolicyMatchingRelease( - this.db, - policy, - this.releaseTarget, - )) ?? null - ); - } - - /** - * Creates a new release within a transaction - * @param release - The release to create - * @param tx - The transaction to use - * @returns The created release with ID - */ - private async createReleaseInTransaction( - release: Omit, - tx: Tx, - ): Promise { - const dbRelease = await tx - .insert(schema.release) - .values({ ...release, releaseTargetId: this.releaseTarget.id }) - .returning() - .then(takeFirst); - - if (release.variables.length > 0) - await tx.insert(schema.releaseVariable).values( - release.variables.map((v) => ({ - releaseId: dbRelease.id, - key: v.key, - value: v.value, - sensitive: v.sensitive, - })), - ); - - return { ...release, ...dbRelease }; - } - - /** - * Creates a new release - * @param release - The release to create - * @returns The created release with ID - */ - async createRelease( - release: Omit, - ): Promise { - return this.db.transaction((tx) => - this.createReleaseInTransaction(release, tx), - ); - } - - /** - * Creates a new release only if one doesn't already exist with the same version and variables - - * @param versionId - The version ID for the release - * @param variables - The variables for the release - * @returns Object indicating if a new release was created and the final release - */ - async upsertRelease( - versionId: string, - variables: MaybeVariable[], - ): Promise<{ created: boolean; release: ReleaseWithId }> { - const latestRelease = await this.findLatestRelease(); - - const latestReleaseInfo = { - versionId: latestRelease?.versionId, - variables: _(latestRelease?.variables ?? []) - .map((v) => [v.key, v.value]) - .fromPairs() - .value(), - }; - - const newReleaseInfo = { - versionId, - variables: _(variables) - .compact() - .map((v) => [v.key, v.value]) - .fromPairs() - .value(), - }; - - const isSame = - latestRelease != null && _.isEqual(latestReleaseInfo, newReleaseInfo); - return isSame - ? { created: false, release: latestRelease } - : { - created: true, - release: await this.createRelease({ - versionId, - releaseTargetId: this.releaseTarget.id, - variables: _.compact(variables), - }), - }; - } - - async updateReleaseVariables( - variables: MaybeVariable[], - ): Promise<{ created: boolean; release: ReleaseWithId } | null> { - const latestRelease = await this.findLatestRelease(); - const versionId = latestRelease?.versionId ?? null; - return versionId == null ? null : this.upsertRelease(versionId, variables); - } - - async updateReleaseVersion( - versionId: string, - ): Promise<{ created: boolean; release: ReleaseWithId }> { - const latestRelease = await this.findLatestRelease(); - return this.upsertRelease(versionId, latestRelease?.variables ?? []); - } - - /** - * Sets the desired release for the target - * @param desiredReleaseId - ID of the release to set as desired - */ - async setDesiredRelease(desiredReleaseId: string | null): Promise { - await this.db - .update(schema.releaseTarget) - .set({ desiredReleaseId }) - .where(eq(schema.releaseTarget.id, this.releaseTarget.id)); - } - - async getCtx(): Promise { - return this.db.query.releaseTarget.findFirst({ - where: eq(schema.releaseTarget.id, this.releaseTarget.id), - with: { - resource: true, - environment: true, - deployment: true, - }, - }); - } -} diff --git a/packages/rule-engine/src/repositories/get-releases.ts b/packages/rule-engine/src/repositories/get-releases.ts deleted file mode 100644 index 6df10f32b..000000000 --- a/packages/rule-engine/src/repositories/get-releases.ts +++ /dev/null @@ -1,144 +0,0 @@ -import type { Tx } from "@ctrlplane/db"; -import { isAfter } from "date-fns"; - -import { and, desc, eq, exists, gte, lte, sql } from "@ctrlplane/db"; -import * as schema from "@ctrlplane/db/schema"; -import { logger } from "@ctrlplane/logger"; -import { JobStatus } from "@ctrlplane/validators/jobs"; - -import type { Policy } from "../types.js"; -import type { CompleteRelease } from "./types.js"; - -const log = logger.child({ - module: "rule-engine", - function: "getReleases", -}); - -/** - * Checks if the date bounds between the latest deployed release and desired release are valid - * @param latestDeployedReleaseDate - Creation date of the latest deployed release - * @param desiredReleaseCreatedAt - Creation date of the desired release - * @returns True if dates are valid (deployed not after desired) - */ -const isDateBoundsValid = ( - latestDeployedReleaseDate?: Date, - desiredReleaseCreatedAt?: Date, -): boolean => { - if (latestDeployedReleaseDate == null) return true; - if (desiredReleaseCreatedAt == null) return true; - return !isAfter(latestDeployedReleaseDate, desiredReleaseCreatedAt); -}; - -/** - * Finds all releases between two deployments that match the given policy - * - * @param db - Database transaction object for querying - * @param releaseTargetId - ID of the release target to find releases for - * @param policy - Optional policy to filter releases by version selector - * @returns Promise resolving to array of matching releases with their - * associated version and variable data - */ -export const findPolicyMatchingReleasesBetweenDeployments = async ( - db: Tx, - releaseTargetId: string, - policy?: Policy | null, -): Promise => { - const releaseTarget = await db.query.releaseTarget.findFirst({ - where: eq(schema.releaseTarget.id, releaseTargetId), - with: { - desiredRelease: true, - releases: { - limit: 1, - where: exists( - db - .select() - .from(schema.releaseJob) - .innerJoin(schema.job, eq(schema.releaseJob.jobId, schema.job.id)) - .where( - and( - sql`${schema.releaseJob.releaseId} = "releaseTarget_releases"."id"`, - eq(schema.job.status, JobStatus.Successful), - ), - ) - .limit(1), - ), - orderBy: desc(schema.release.createdAt), - }, - }, - }); - - if (releaseTarget == null) return []; - - const latestDeployedRelease = releaseTarget.releases.at(0); - - const dateCheckResult = isDateBoundsValid( - latestDeployedRelease?.createdAt, - releaseTarget.desiredRelease?.createdAt, - ); - - if (!dateCheckResult) { - log.warn( - `Date bounds are invalid, latestDeployedRelease is after desiredRelease: - latestDeployedRelease: ${latestDeployedRelease?.createdAt != null ? latestDeployedRelease.createdAt.toISOString() : "null"}, - releaseTarget: ${releaseTarget.desiredRelease?.createdAt != null ? releaseTarget.desiredRelease.createdAt.toISOString() : "null"}`, - ); - } - - return db.query.release.findMany({ - where: and( - eq(schema.release.releaseTargetId, releaseTarget.id), - schema.deploymentVersionMatchesCondition( - db, - policy?.deploymentVersionSelector?.deploymentVersionSelector, - ), - latestDeployedRelease != null - ? gte(schema.release.createdAt, latestDeployedRelease.createdAt) - : undefined, - releaseTarget.desiredRelease != null - ? lte(schema.release.createdAt, releaseTarget.desiredRelease.createdAt) - : undefined, - ), - with: { - version: { with: { metadata: true } }, - variables: true, - }, - orderBy: desc(schema.release.createdAt), - }); -}; - -/** - * Finds the latest release that matches the applicable policies for a given - * release target - * - * @param tx - Database transaction object for querying - * @param policy - The policy to filter releases by - * @param releaseTarget - The release target to find matching releases for - * @returns Promise resolving to the latest matching release, or undefined if none found - */ -export const findLatestPolicyMatchingRelease = async ( - tx: Tx, - policy: Policy | null, - releaseTarget: { id: string }, -): Promise => { - // If no deployment version selector in policy, return latest release for target - if (policy?.deploymentVersionSelector == null) { - return tx.query.release.findFirst({ - where: eq(schema.release.releaseTargetId, releaseTarget.id), - orderBy: desc(schema.release.createdAt), - with: { variables: true, version: { with: { metadata: true } } }, - }); - } - - // Otherwise filter by policy deployment version selector - return tx.query.release.findFirst({ - where: and( - eq(schema.release.releaseTargetId, releaseTarget.id), - schema.deploymentVersionMatchesCondition( - tx, - policy.deploymentVersionSelector.deploymentVersionSelector, - ), - ), - with: { variables: true, version: { with: { metadata: true } } }, - orderBy: desc(schema.release.createdAt), - }); -}; diff --git a/packages/rule-engine/src/repositories/index.ts b/packages/rule-engine/src/repositories/index.ts deleted file mode 100644 index 2157c14c3..000000000 --- a/packages/rule-engine/src/repositories/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./db-release-repository.js"; -export * from "./types.js"; -export * from "./variables/types.js"; -export * from "./variables/variables.js"; diff --git a/packages/rule-engine/src/repositories/types.ts b/packages/rule-engine/src/repositories/types.ts deleted file mode 100644 index 3261c7df7..000000000 --- a/packages/rule-engine/src/repositories/types.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type * as schema from "@ctrlplane/db/schema"; - -import type { DeploymentResourceContext, Policy } from "../types.js"; -import type { MaybeVariable, Variable } from "./variables/types.js"; - -/** - * Base release type with essential properties from schema - */ -export type Release = typeof schema.release.$inferSelect & { - variables: Variable[]; -}; - -/** - * Release with an ID property - */ -export type ReleaseWithId = Release & { id: string }; - -/** - * Release with version information - */ -export type ReleaseWithVersion = Release & { - version: typeof schema.deploymentVersion.$inferSelect & { - metadata: (typeof schema.deploymentVersionMetadata.$inferInsert)[]; - }; -}; - -/** - * Release with variables property - * Note: This is redundant since it's already in the base Release type - * Keeping for backward compatibility - */ -export type ReleaseWithVariables = Release; - -/** - * Complete release type with ID, version and variables - */ -export type CompleteRelease = ReleaseWithVersion & ReleaseWithId; - -/** - * Repository interface for managing releases - */ -export interface ReleaseRepository { - /** - * Retrieves all releases that match the given policy - * @returns Promise resolving to array of matching releases - */ - findMatchingReleases(): Promise; - - /** - * Gets the most recent release matching policy constraints - * @returns Promise resolving to the latest matching release or null - */ - findLatestRelease(): Promise; - - /** - * Creates or retrieves an existing release for given parameters - * @param options - The release target identifier - * @param versionId - Version ID for the release - * @param variables - Variables for the release - * @returns Object with created flag and the release - */ - upsertRelease( - versionId: string, - variables: MaybeVariable[], - ): Promise<{ created: boolean; release: ReleaseWithId }>; - - /** - * Sets the desired release for the target - * @param desiredReleaseId - ID of the release to set as desired - */ - setDesiredRelease(desiredReleaseId: string | null): Promise; - - getCtx(): Promise; - - getPolicy(): Promise; -} diff --git a/packages/rule-engine/src/rule-engine.ts b/packages/rule-engine/src/rule-engine.ts deleted file mode 100644 index 6311ca46e..000000000 --- a/packages/rule-engine/src/rule-engine.ts +++ /dev/null @@ -1,158 +0,0 @@ -import type { Releases } from "./releases.js"; -import type { - DeploymentResourceContext, - DeploymentResourceRule, - DeploymentResourceSelectionResult, - ResolvedRelease, -} from "./types.js"; - -/** - * The RuleEngine applies a sequence of deployment rules to filter candidate - * releases and selects the most appropriate release based on configured - * criteria. - * - * The engine works by passing releases through each rule in sequence, where - * each rule can filter out releases that don't meet specific criteria. After - * all rules have been applied, a final selection strategy is used to choose the - * best remaining release. - */ -export class RuleEngine { - /** - * Creates a new RuleEngine with the specified rules. - * - * @param rules - An array of rules that implement the DeploymentResourceRule - * interface. These rules will be applied in sequence during - * evaluation. - */ - constructor( - private rules: Array< - | (() => Promise | DeploymentResourceRule) - | DeploymentResourceRule - >, - ) {} - - /** - * Evaluates a deployment context against all configured rules to determine if - * the deployment is allowed and which release should be used. - * - * The evaluation process: - * 1. Starts with all available releases as candidates - * 2. Applies each rule in sequence, updating the candidate list after each - * rule - * 3. If any rule disqualifies all candidates, evaluation stops with a denial - * result - * 4. After all rules pass, selects the final release using the configured - * selection strategy - * - * Important implementation details for rule authors: - * - Rules should return ALL valid candidate releases, not just one - * - This ensures subsequent rules have a complete set of options to filter - * - For example, if multiple sequential upgrades are required, all should be - * returned, not just the oldest one - * - Otherwise, a subsequent rule might filter out the only returned - * candidate, even when other valid candidates existed - * - * @param releases - The releases to evaluate - * @param context - The deployment context containing all information needed - * for rule evaluation - * @returns A promise resolving to the evaluation result, including allowed - * status and chosen release - */ - async evaluate( - releases: Releases, - context: DeploymentResourceContext, - ): Promise { - // Track rejection reasons for each release across all rules - let rejectionReasons = new Map(); - - // Apply each rule in sequence to filter candidate releases - for (const rule of this.rules) { - const result = await ( - typeof rule === "function" ? await rule() : rule - ).filter(context, releases); - - // If the rule yields no candidates, we must stop. - if (result.allowedReleases.isEmpty()) { - return { - allowed: false, - rejectionReasons: result.rejectionReasons ?? rejectionReasons, - }; - } - - // Merge any new rejection reasons with our tracking map - if (result.rejectionReasons) { - rejectionReasons = new Map([ - ...rejectionReasons, - ...result.rejectionReasons, - ]); - } - - releases = result.allowedReleases; - } - - // Once all rules pass, select the final release - const chosen = this.selectFinalRelease(context, releases); - return chosen == null - ? { - allowed: false, - rejectionReasons, - } - : { - allowed: true, - chosenRelease: chosen, - rejectionReasons, - }; - } - - /** - * Selects the most appropriate release from the candidate list after all - * rules have been applied. - * - * The selection strategy follows these priorities: - * 1. If sequential upgrade releases are present, select the oldest one - * 2. If a desiredReleaseId is specified and it's in the candidate list, that - * release is selected - * 3. Otherwise, the newest release (by createdAt timestamp) is selected - * - * This selection logic provides a balance between respecting explicit release - * requests and defaulting to the latest available release when no specific - * preference is indicated, while ensuring sequential upgrades are applied in - * the correct order. - * - * @param context - The deployment context containing the desired release ID - * if specified - * @param candidates - The list of release candidates that passed all rules - * @returns The selected release, or undefined if no suitable release can be - * chosen - */ - private selectFinalRelease( - context: DeploymentResourceContext, - candidates: Releases, - ): ResolvedRelease | undefined { - if (candidates.isEmpty()) { - return undefined; - } - - // First, check for sequential upgrades - if present, we must select the - // oldest - const sequentialReleases = this.findSequentialUpgradeReleases(candidates); - if (!sequentialReleases.isEmpty()) return sequentialReleases.getOldest(); - - // No sequential releases, use standard selection logic - return candidates.getEffectiveTarget(context); - } - - /** - * Identifies releases that require sequential upgrade application. - * - * Looks for the standard metadata flag that indicates a release requires - * sequential upgrade application. - * - * @param releases - The releases to check - * @returns A Releases collection with only sequential upgrade releases - */ - private findSequentialUpgradeReleases(releases: Releases): Releases { - // Look for the standard metadata key used by SequentialUpgradeRule - return releases.filterByMetadata("requiresSequentialUpgrade", "true"); - } -} diff --git a/packages/rule-engine/src/rules/__tests__/deployment-deny-rule.test.ts b/packages/rule-engine/src/rules/__tests__/deployment-deny-rule.test.ts index 3882db26d..26a53b736 100644 --- a/packages/rule-engine/src/rules/__tests__/deployment-deny-rule.test.ts +++ b/packages/rule-engine/src/rules/__tests__/deployment-deny-rule.test.ts @@ -1,17 +1,24 @@ -import { TZDate } from "@date-fns/tz"; import { Frequency, RRule } from "rrule"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { - DeploymentResourceContext, - ResolvedRelease, -} from "../../types.js"; -import { Releases } from "../../releases.js"; +import type { RuleEngineContext } from "../../types.js"; import { DeploymentDenyRule } from "../deployment-deny-rule.js"; +export type ResolvedRelease = { + id: string; + createdAt: Date; + version: { + id: string; + tag: string; + config: Record; + metadata: Record; + }; + variables: Record; +}; + describe("DeploymentDenyRule", () => { - let releases: Releases; - let context: DeploymentResourceContext; + let releases: ResolvedRelease[]; + let context: RuleEngineContext; beforeEach(() => { // Create a sample set of releases @@ -40,7 +47,7 @@ describe("DeploymentDenyRule", () => { }, ]; - releases = new Releases(sampleReleases); + releases = sampleReleases; // Create a sample context context = { @@ -62,10 +69,11 @@ describe("DeploymentDenyRule", () => { it("should allow deployments when not in a denied period", () => { // Create a rule that denies deployments on Mondays - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.WEEKLY, byweekday: [RRule.MO], // Monday dtstart: new Date("2023-01-01T00:00:00Z"), + getCandidateId: (candidate) => candidate.id, }); // Mock getCurrentTime to return a Sunday @@ -76,28 +84,29 @@ describe("DeploymentDenyRule", () => { const result = rule.filter(context, releases); // Expect all releases to be allowed - expect(result.allowedReleases.length).toBe(2); + expect(result.allowedCandidates.length).toBe(2); expect(result.rejectionReasons).toBeUndefined(); }); it("should deny deployments when in a denied period", () => { // Create a rule that denies deployments on Mondays - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.WEEKLY, byweekday: [RRule.MO], // Monday dtstart: new Date("2023-01-02T00:00:00Z"), // Monday tzid: "UTC", + getCandidateId: (candidate) => candidate.id, }); // Mock getCurrentTime to return a Monday vi.spyOn(rule as any, "getCurrentTime").mockReturnValue( - new TZDate("2023-01-02T12:00:00Z"), // Monday, Jan 2, 2023 + new Date("2023-01-02T12:00:00Z"), // Monday, Jan 2, 2023 ); const result = rule.filter(context, releases); // Expect no releases to be allowed - expect(result.allowedReleases.length).toBe(0); + expect(result.allowedCandidates.length).toBe(0); expect(result.rejectionReasons).toBeDefined(); expect(result.rejectionReasons?.get("rel-1")).toBe( "Deployment denied due to time-based restrictions", @@ -109,11 +118,12 @@ describe("DeploymentDenyRule", () => { it("should respect the custom deny reason", () => { const customReason = "Maintenance window in progress"; - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.WEEKLY, byweekday: [RRule.MO], // Monday dtstart: new Date("2023-01-02T00:00:00Z"), // Monday denyReason: customReason, + getCandidateId: (candidate) => candidate.id, }); // Mock getCurrentTime to return a Monday @@ -131,12 +141,13 @@ describe("DeploymentDenyRule", () => { it("should check for specific time intervals when dtend is specified", () => { // Create a rule that denies deployments from 9:00 to 17:00 on weekdays - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.WEEKLY, byweekday: [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR], // Weekdays dtstart: new Date("2023-01-02T09:00:00Z"), // 9:00 AM dtend: new Date("2023-01-02T17:00:00Z"), // 5:00 PM tzid: "UTC", + getCandidateId: (candidate) => candidate.id, }); // Test time within the denied period (Wednesday at 10:00 AM) @@ -144,7 +155,7 @@ describe("DeploymentDenyRule", () => { new Date("2023-01-04T10:00:00Z"), ); let result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(0); + expect(result.allowedCandidates.length).toBe(0); expect(result.rejectionReasons).toBeDefined(); // Test time outside the denied period (Wednesday at 8:00 AM) @@ -152,7 +163,7 @@ describe("DeploymentDenyRule", () => { new Date("2023-01-04T08:00:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); + expect(result.allowedCandidates.length).toBe(2); expect(result.rejectionReasons).toBeUndefined(); // Test time outside the denied period (Wednesday at 6:00 PM) @@ -160,18 +171,19 @@ describe("DeploymentDenyRule", () => { new Date("2023-01-04T18:00:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); + expect(result.allowedCandidates.length).toBe(2); expect(result.rejectionReasons).toBeUndefined(); }); it("should handle timezone conversions correctly", () => { // Create a rule that denies deployments from 9:00 to 17:00 EST on weekdays - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.WEEKLY, byweekday: [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR], // Weekdays dtstart: new Date("2023-01-02T09:00:00Z"), // 9:00 AM EST (UTC-5) dtend: new Date("2023-01-02T17:00:00Z"), // 5:00 PM EST (UTC-5) tzid: "America/New_York", + getCandidateId: (candidate) => candidate.id, }); // Test time within the denied period in ET (10:00 AM EST) @@ -179,7 +191,7 @@ describe("DeploymentDenyRule", () => { new Date("2023-01-05T15:00:00Z"), // 10:00 AM EST ); let result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(0); + expect(result.allowedCandidates.length).toBe(0); expect(result.rejectionReasons).toBeDefined(); // Test time outside the denied period in ET (8:00 AM EST) @@ -187,16 +199,17 @@ describe("DeploymentDenyRule", () => { new Date("2023-01-04T13:00:00Z"), // 8:00 AM EST ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); + expect(result.allowedCandidates.length).toBe(2); expect(result.rejectionReasons).toBeUndefined(); }); it("should handle standard time to daylight time changes correctly (EST -> EDT in March)", () => { - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.DAILY, dtstart: new Date("2023-03-09T09:00:00Z"), // 9:00am EST dtend: new Date("2023-03-09T17:00:00Z"), // 5:00pm EST tzid: "America/New_York", + getCandidateId: (candidate) => candidate.id, }); /** @@ -210,14 +223,14 @@ describe("DeploymentDenyRule", () => { new Date("2023-03-11T21:30:00Z"), ); let result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(0); + expect(result.allowedCandidates.length).toBe(0); expect(result.rejectionReasons).toBeDefined(); vi.spyOn(rule as any, "getCurrentTime").mockReturnValue( new Date("2023-03-12T21:30:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); + expect(result.allowedCandidates.length).toBe(2); expect(result.rejectionReasons).toBeUndefined(); /** @@ -231,23 +244,24 @@ describe("DeploymentDenyRule", () => { new Date("2023-03-11T13:30:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); + expect(result.allowedCandidates.length).toBe(2); expect(result.rejectionReasons).toBeUndefined(); vi.spyOn(rule as any, "getCurrentTime").mockReturnValue( new Date("2023-03-12T13:30:00Z"), ); const result2 = rule.filter(context, releases); - expect(result2.allowedReleases.length).toBe(0); + expect(result2.allowedCandidates.length).toBe(0); expect(result2.rejectionReasons).toBeDefined(); }); it("should handle daylight time to standard time changes correctly (EDT -> EST in November)", () => { - const rule = new DeploymentDenyRule({ + const rule = new DeploymentDenyRule({ freq: Frequency.DAILY, dtstart: new Date("2023-11-04T09:00:00Z"), // 9:00am EDT dtend: new Date("2023-11-04T17:00:00Z"), // 5:00pm EDT tzid: "America/New_York", + getCandidateId: (candidate) => candidate.id, }); /** @@ -261,14 +275,14 @@ describe("DeploymentDenyRule", () => { new Date("2023-11-04T13:30:00Z"), ); let result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(0); // Should be DENIED + expect(result.allowedCandidates.length).toBe(0); // Should be DENIED expect(result.rejectionReasons).toBeDefined(); vi.spyOn(rule as any, "getCurrentTime").mockReturnValue( new Date("2023-11-05T13:30:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); // Should be ALLOWED + expect(result.allowedCandidates.length).toBe(2); // Should be ALLOWED expect(result.rejectionReasons).toBeUndefined(); /** @@ -282,14 +296,14 @@ describe("DeploymentDenyRule", () => { new Date("2023-11-04T21:30:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(2); // Should be ALLOWED + expect(result.allowedCandidates.length).toBe(2); // Should be ALLOWED expect(result.rejectionReasons).toBeUndefined(); vi.spyOn(rule as any, "getCurrentTime").mockReturnValue( new Date("2023-11-05T21:30:00Z"), ); result = rule.filter(context, releases); - expect(result.allowedReleases.length).toBe(0); // Should be DENIED + expect(result.allowedCandidates.length).toBe(0); // Should be DENIED expect(result.rejectionReasons).toBeDefined(); }); }); diff --git a/packages/rule-engine/src/rules/__tests__/version-approval-rule.test.ts b/packages/rule-engine/src/rules/__tests__/version-approval-rule.test.ts index 502287cef..2b518c52b 100644 --- a/packages/rule-engine/src/rules/__tests__/version-approval-rule.test.ts +++ b/packages/rule-engine/src/rules/__tests__/version-approval-rule.test.ts @@ -1,47 +1,12 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { - DeploymentResourceContext, - ResolvedRelease, -} from "../../types.js"; -import type { GetApprovalRecordsFunc } from "../version-approval-rule.js"; -import { Releases } from "../../releases.js"; +import type { RuleEngineContext } from "../../types.js"; import { VersionApprovalRule } from "../version-approval-rule.js"; describe("VersionApprovalRule", () => { - let releases: Releases; - let context: DeploymentResourceContext; - let mockGetApprovalRecords: ReturnType>; + let context: RuleEngineContext; beforeEach(() => { - // Create a sample set of releases - const sampleReleases: ResolvedRelease[] = [ - { - id: "rel-1", - createdAt: new Date("2023-01-01T12:00:00Z"), - version: { - id: "ver-1", - tag: "v1.0.0", - config: {}, - metadata: {}, - }, - variables: {}, - }, - { - id: "rel-2", - createdAt: new Date("2023-01-02T12:00:00Z"), - version: { - id: "ver-2", - tag: "v1.1.0", - config: {}, - metadata: {}, - }, - variables: {}, - }, - ]; - - releases = new Releases(sampleReleases); - // Create a sample context context = { desiredReleaseId: null, @@ -58,35 +23,49 @@ describe("VersionApprovalRule", () => { name: "Test Resource", }, }; - - // Create a mock getApprovalRecords function - mockGetApprovalRecords = vi.fn().mockResolvedValue([]); }); - - it("should reject all releases if minApprovals is not met", async () => { - mockGetApprovalRecords.mockResolvedValue([]); + it("should filter out versions with no approvals when minApprovals > 0", async () => { + const mockGetApprovalRecords = vi.fn().mockResolvedValue([]); const rule = new VersionApprovalRule({ minApprovals: 1, getApprovalRecords: mockGetApprovalRecords, }); - const result = await rule.filter(context, releases); + const candidates = [ + { + id: "ver-1", + tag: "v1.0.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + { + id: "ver-2", + tag: "v1.1.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + ]; + + const result = await rule.filter(context, candidates); - expect(result.allowedReleases.length).toBe(0); + expect(result.allowedCandidates.length).toBe(0); + expect(result.rejectionReasons).toBeDefined(); expect(mockGetApprovalRecords).toHaveBeenCalledWith(context, [ "ver-1", "ver-2", ]); }); - it("should allow releases with sufficient approvals", async () => { - mockGetApprovalRecords.mockResolvedValue([ + it("should filter out rejected versions regardless of approval count", async () => { + const mockGetApprovalRecords = vi.fn().mockResolvedValue([ { versionId: "ver-1", - status: "approved", + status: "rejected", userId: "user-1", - reason: null, + reason: "Found a bug", }, { versionId: "ver-1", @@ -94,21 +73,54 @@ describe("VersionApprovalRule", () => { userId: "user-2", reason: null, }, + { + versionId: "ver-1", + status: "approved", + userId: "user-3", + reason: null, + }, + { + versionId: "ver-2", + status: "approved", + userId: "user-1", + reason: null, + }, ]); const rule = new VersionApprovalRule({ - minApprovals: 2, + minApprovals: 1, getApprovalRecords: mockGetApprovalRecords, }); - const result = await rule.filter(context, releases); + const candidates = [ + { + id: "ver-1", + tag: "v1.0.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + { + id: "ver-2", + tag: "v1.1.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + ]; + + const result = await rule.filter(context, candidates); - expect(result.allowedReleases.length).toBe(1); - expect(result.allowedReleases.getAll()[0]!.id).toBe("rel-1"); + expect(result.allowedCandidates.length).toBe(1); + expect(result.allowedCandidates[0]?.id).toBe("ver-2"); + expect(result.rejectionReasons).toBeDefined(); + expect(result.rejectionReasons?.get("ver-1")).toBe( + "Has been rejected by 1 users.", + ); }); - it("should reject releases with any rejections regardless of approvals", async () => { - mockGetApprovalRecords.mockResolvedValue([ + it("should allow versions with sufficient approvals", async () => { + const mockGetApprovalRecords = vi.fn().mockResolvedValue([ { versionId: "ver-1", status: "approved", @@ -122,58 +134,94 @@ describe("VersionApprovalRule", () => { reason: null, }, { - versionId: "ver-1", - status: "rejected", - userId: "user-3", - reason: "Security issue", + versionId: "ver-2", + status: "approved", + userId: "user-1", + reason: null, }, ]); const rule = new VersionApprovalRule({ - minApprovals: 1, + minApprovals: 2, getApprovalRecords: mockGetApprovalRecords, }); - const result = await rule.filter(context, releases); + const candidates = [ + { + id: "ver-1", + tag: "v1.0.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + { + id: "ver-2", + tag: "v1.1.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + ]; + + const result = await rule.filter(context, candidates); - expect(result.allowedReleases.length).toBe(0); - expect(result.rejectionReasons?.get("rel-1")).toBe( - "Has been rejected by 1 users.", - ); + expect(result.allowedCandidates.length).toBe(1); + expect(result.allowedCandidates[0]?.id).toBe("ver-1"); + expect(result.rejectionReasons).toBeDefined(); }); - it("should allow all releases if minApprovals is 0", async () => { - mockGetApprovalRecords.mockResolvedValue([]); + it("should handle minApprovals=0 case correctly", async () => { + const mockGetApprovalRecords = vi.fn().mockResolvedValue([]); const rule = new VersionApprovalRule({ minApprovals: 0, getApprovalRecords: mockGetApprovalRecords, }); - const result = await rule.filter(context, releases); + const candidates = [ + { + id: "ver-1", + tag: "v1.0.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + { + id: "ver-2", + tag: "v1.1.0", + config: {}, + metadata: {}, + createdAt: new Date(), + }, + ]; - expect(result.allowedReleases.length).toBe(2); + const result = await rule.filter(context, candidates); + + expect(result.allowedCandidates.length).toBe(2); + expect(result.rejectionReasons).toBeDefined(); + // Map should be empty + expect(result.rejectionReasons?.size).toBe(0); }); - it("should handle mixed approval scenarios correctly", async () => { - mockGetApprovalRecords.mockResolvedValue([ + it("should handle multiple rejections correctly", async () => { + const mockGetApprovalRecords = vi.fn().mockResolvedValue([ { versionId: "ver-1", - status: "approved", + status: "rejected", userId: "user-1", - reason: null, + reason: "Found a bug", }, { - versionId: "ver-2", - status: "approved", - userId: "user-1", - reason: null, + versionId: "ver-1", + status: "rejected", + userId: "user-2", + reason: "Security issue", }, { versionId: "ver-2", status: "rejected", - userId: "user-2", - reason: "Not ready for production", + userId: "user-1", + reason: "Not ready", }, ]); @@ -182,53 +230,32 @@ describe("VersionApprovalRule", () => { getApprovalRecords: mockGetApprovalRecords, }); - const result = await rule.filter(context, releases); - - expect(result.allowedReleases.length).toBe(1); - expect(result.allowedReleases.getAll()[0]!.id).toBe("rel-1"); - expect(result.rejectionReasons?.get("rel-2")).toBe( - "Has been rejected by 1 users.", - ); - }); - - it("should test different approval record retrieval functions", async () => { - // Test with getAnyApprovalRecords mock - const anyRecordsMock = vi.fn().mockResolvedValue([ + const candidates = [ { - versionId: "ver-1", - status: "approved", - userId: "user-1", - reason: null, + id: "ver-1", + tag: "v1.0.0", + config: {}, + metadata: {}, + createdAt: new Date(), }, - ]); - - const anyRule = new VersionApprovalRule({ - minApprovals: 1, - getApprovalRecords: anyRecordsMock, - }); - - const anyResult = await anyRule.filter(context, releases); - expect(anyResult.allowedReleases.length).toBe(1); - expect(anyRecordsMock).toHaveBeenCalledWith(context, ["ver-1", "ver-2"]); - - // Test with getRoleApprovalRecords mock - const roleRecordsMock = vi.fn().mockResolvedValue([ { - versionId: "ver-2", - status: "approved", - userId: "user-1", - reason: null, + id: "ver-2", + tag: "v1.1.0", + config: {}, + metadata: {}, + createdAt: new Date(), }, - ]); + ]; - const roleRule = new VersionApprovalRule({ - minApprovals: 1, - getApprovalRecords: roleRecordsMock, - }); + const result = await rule.filter(context, candidates); - const roleResult = await roleRule.filter(context, releases); - expect(roleResult.allowedReleases.length).toBe(1); - expect(roleResult.allowedReleases.getAll()[0]!.id).toBe("rel-2"); - expect(roleRecordsMock).toHaveBeenCalledWith(context, ["ver-1", "ver-2"]); + expect(result.allowedCandidates.length).toBe(0); + expect(result.rejectionReasons).toBeDefined(); + expect(result.rejectionReasons?.get("ver-1")).toBe( + "Has been rejected by 2 users.", + ); + expect(result.rejectionReasons?.get("ver-2")).toBe( + "Has been rejected by 1 users.", + ); }); }); diff --git a/packages/rule-engine/src/rules/deployment-deny-rule.ts b/packages/rule-engine/src/rules/deployment-deny-rule.ts index ce2713c01..ecda16191 100644 --- a/packages/rule-engine/src/rules/deployment-deny-rule.ts +++ b/packages/rule-engine/src/rules/deployment-deny-rule.ts @@ -8,11 +8,10 @@ import { import rrule from "rrule"; import type { - DeploymentResourceContext, - DeploymentResourceRule, - DeploymentResourceRuleResult, + RuleEngineContext, + RuleEngineFilter, + RuleEngineRuleResult, } from "../types.js"; -import { Releases } from "../releases.js"; // https://github.com/jkbrzt/rrule/issues/478 // common js bs @@ -43,7 +42,7 @@ function getDatePartsInTimeZone(date: Date, timeZone: string) { }; } -export interface DeploymentDenyRuleOptions extends Partial { +export interface DeploymentDenyRuleOptions extends Partial { dtend?: Date | null; /** @@ -51,26 +50,32 @@ export interface DeploymentDenyRuleOptions extends Partial { * denied due to time-based restrictions" */ denyReason?: string; + + getCandidateId(this: void, candidate: T): string; } -export class DeploymentDenyRule implements DeploymentResourceRule { +export class DeploymentDenyRule implements RuleEngineFilter { public readonly name = "DeploymentDenyRule"; private rrule: rrule.RRule; private denyReason: string; private dtend: Date | null; private timezone: string; private dtstart: Date | null; + private getCandidateId: (candidate: T) => string; constructor({ denyReason = "Deployment denied due to time-based restrictions", dtend = null, dtstart = null, until = null, + getCandidateId, ...options - }: DeploymentDenyRuleOptions) { + }: DeploymentDenyRuleOptions) { this.timezone = options.tzid ?? "UTC"; this.denyReason = denyReason; + this.getCandidateId = getCandidateId; + const dtStartCasted = dtstart != null ? this.castTimezone(dtstart, this.timezone) : null; @@ -92,10 +97,7 @@ export class DeploymentDenyRule implements DeploymentResourceRule { return new Date(); } - filter( - _: DeploymentResourceContext, - releases: Releases, - ): DeploymentResourceRuleResult { + filter(_: RuleEngineContext, candidates: T[]): RuleEngineRuleResult { const now = this.getCurrentTime(); // Check if current time matches one of the rrules @@ -104,13 +106,16 @@ export class DeploymentDenyRule implements DeploymentResourceRule { if (isDenied) { // Build rejection reasons for each release const rejectionReasons = new Map( - releases.map((release) => [release.id, this.denyReason]), + candidates.map((candidate) => [ + this.getCandidateId(candidate), + this.denyReason, + ]), ); - return { allowedReleases: Releases.empty(), rejectionReasons }; + return { allowedCandidates: [], rejectionReasons }; } // Allow all releases if time is not denied - return { allowedReleases: releases }; + return { allowedCandidates: candidates }; } /** diff --git a/packages/rule-engine/src/rules/version-approval-rule.ts b/packages/rule-engine/src/rules/version-approval-rule.ts index 1dbca9125..c46388679 100644 --- a/packages/rule-engine/src/rules/version-approval-rule.ts +++ b/packages/rule-engine/src/rules/version-approval-rule.ts @@ -4,11 +4,11 @@ import { inArray } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; import * as schema from "@ctrlplane/db/schema"; -import type { Releases } from "../releases.js"; +import type { Version } from "../manager/version-rule-engine.js"; import type { - DeploymentResourceContext, - DeploymentResourceRule, - DeploymentResourceRuleResult, + RuleEngineContext, + RuleEngineFilter, + RuleEngineRuleResult, } from "../types.js"; type Record = { @@ -19,7 +19,7 @@ type Record = { }; export type GetApprovalRecordsFunc = ( - context: DeploymentResourceContext, + context: RuleEngineContext, versionIds: string[], ) => Promise; @@ -29,18 +29,18 @@ type VersionApprovalRuleOptions = { getApprovalRecords: GetApprovalRecordsFunc; }; -export class VersionApprovalRule implements DeploymentResourceRule { +export class VersionApprovalRule implements RuleEngineFilter { public readonly name = "VersionApprovalRule"; constructor(private readonly options: VersionApprovalRuleOptions) {} async filter( - context: DeploymentResourceContext, - releases: Releases, - ): Promise { + context: RuleEngineContext, + candidates: Version[], + ): Promise> { const rejectionReasons = new Map(); - const versionIds = _(releases.getAll()) - .map((r) => r.version.id) + const versionIds = _(candidates) + .map((r) => r.id) .uniq() .value(); const approvalRecords = await this.options.getApprovalRecords( @@ -48,10 +48,8 @@ export class VersionApprovalRule implements DeploymentResourceRule { versionIds, ); - const allowedReleases = releases.filter((release) => { - const records = approvalRecords.filter( - (r) => r.versionId === release.version.id, - ); + const allowedCandidates = candidates.filter((release) => { + const records = approvalRecords.filter((r) => r.versionId === release.id); const approvals = records.filter((r) => r.status === "approved"); const rejections = records.filter((r) => r.status === "rejected"); @@ -67,12 +65,12 @@ export class VersionApprovalRule implements DeploymentResourceRule { return approvals.length >= this.options.minApprovals; }); - return { allowedReleases, rejectionReasons }; + return { allowedCandidates, rejectionReasons }; } } export const getAnyApprovalRecords: GetApprovalRecordsFunc = async ( - _: DeploymentResourceContext, + _: RuleEngineContext, versionIds: string[], ) => { const records = await db.query.policyRuleAnyApprovalRecord.findMany({ @@ -88,7 +86,7 @@ export const getAnyApprovalRecords: GetApprovalRecordsFunc = async ( }; export const getRoleApprovalRecords: GetApprovalRecordsFunc = async ( - _: DeploymentResourceContext, + _: RuleEngineContext, versionIds: string[], ) => { const records = await db.query.policyRuleRoleApprovalRecord.findMany({ @@ -104,7 +102,7 @@ export const getRoleApprovalRecords: GetApprovalRecordsFunc = async ( }; export const getUserApprovalRecords: GetApprovalRecordsFunc = async ( - _: DeploymentResourceContext, + _: RuleEngineContext, versionIds: string[], ) => { const records = await db.query.policyRuleUserApprovalRecord.findMany({ diff --git a/packages/rule-engine/src/types.ts b/packages/rule-engine/src/types.ts index c839054d3..8b6e06e8b 100644 --- a/packages/rule-engine/src/types.ts +++ b/packages/rule-engine/src/types.ts @@ -2,20 +2,6 @@ import type * as schema from "@ctrlplane/db/schema"; import type { DeploymentVersionCondition } from "@ctrlplane/validators/releases"; import type { ResourceCondition } from "@ctrlplane/validators/resources"; -import type { Releases } from "./releases.js"; - -export type ResolvedRelease = { - id: string; - createdAt: Date; - version: { - id: string; - tag: string; - config: Record; - metadata: Record; - }; - variables: Record; -}; - export type Deployment = { id: string; name: string; @@ -34,33 +20,32 @@ export type Environment = { resourceSelector?: ResourceCondition | null; }; -export type DeploymentResourceContext = { +export type RuleEngineContext = { desiredReleaseId: string | null; deployment: Deployment; environment: Environment; resource: Resource; }; -export type DeploymentResourceRuleResult = { - allowedReleases: Releases; +export type RuleEngineRuleResult = { + allowedCandidates: T[]; rejectionReasons?: Map; }; -export type DeploymentResourceSelectionResult = { - allowed: boolean; - chosenRelease?: ResolvedRelease; +export type RuleEngineSelectionResult = { + chosenCandidate: T | null; rejectionReasons: Map; }; /** * A rule to filter/reorder the candidate versions. */ -export interface DeploymentResourceRule { +export interface RuleEngineFilter { name: string; filter( - context: DeploymentResourceContext, - releases: Releases, - ): DeploymentResourceRuleResult | Promise; + context: RuleEngineContext, + candidates: T[], + ): RuleEngineRuleResult | Promise>; } export type Policy = schema.Policy & { @@ -77,7 +62,9 @@ export type ReleaseTargetIdentifier = { resourceId: string; }; -export type GetReleasesFunc = ( - ctx: DeploymentResourceContext, - policy: Policy, -) => Promise | ResolvedRelease[]; +export type RuleEngine = { + evaluate: ( + context: RuleEngineContext, + candidates: T[], + ) => Promise>; +};