From 618bf9c2fd053ca1d621e0a3fbcd044563765481 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 09:54:44 -0400 Subject: [PATCH 01/14] feat(variable-schema): add refactored db tables * add migration for new tables variable and variable_value --- packages/db/drizzle/0187_dry_quicksilver.sql | 93 + packages/db/drizzle/meta/0187_snapshot.json | 7265 ++++++++++++++++++ packages/db/drizzle/meta/_journal.json | 9 +- packages/db/src/schema/index.ts | 1 + packages/db/src/schema/variable.ts | 189 + 5 files changed, 7556 insertions(+), 1 deletion(-) create mode 100644 packages/db/drizzle/0187_dry_quicksilver.sql create mode 100644 packages/db/drizzle/meta/0187_snapshot.json create mode 100644 packages/db/src/schema/variable.ts diff --git a/packages/db/drizzle/0187_dry_quicksilver.sql b/packages/db/drizzle/0187_dry_quicksilver.sql new file mode 100644 index 000000000..1080db947 --- /dev/null +++ b/packages/db/drizzle/0187_dry_quicksilver.sql @@ -0,0 +1,93 @@ +CREATE TYPE "public"."variable_scope" AS ENUM('resource', 'deployment', 'job_agent');--> statement-breakpoint +CREATE TYPE "public"."variable_value_kind" AS ENUM('literal', 'ref', 'secret_ref');--> statement-breakpoint +CREATE TABLE "variable" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "scope" "variable_scope" NOT NULL, + "resource_id" uuid, + "deployment_id" uuid, + "job_agent_id" uuid, + "key" text NOT NULL, + "is_sensitive" boolean DEFAULT false NOT NULL, + "description" text, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "variable_scope_target_check" CHECK ( + ( + "variable"."scope" = 'resource' + and "variable"."resource_id" is not null + and "variable"."deployment_id" is null + and "variable"."job_agent_id" is null + ) + or + ( + "variable"."scope" = 'deployment' + and "variable"."deployment_id" is not null + and "variable"."resource_id" is null + and "variable"."job_agent_id" is null + ) + or + ( + "variable"."scope" = 'job_agent' + and "variable"."job_agent_id" is not null + and "variable"."resource_id" is null + and "variable"."deployment_id" is null + ) + ) +); +--> statement-breakpoint +CREATE TABLE "variable_value" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "variable_id" uuid NOT NULL, + "resource_selector" text, + "priority" bigint DEFAULT 0 NOT NULL, + "kind" "variable_value_kind" NOT NULL, + "literal_value" jsonb, + "ref_key" text, + "ref_path" text[], + "secret_provider" text, + "secret_key" text, + "secret_path" text[], + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "variable_value_kind_shape_check" CHECK ( + ( + "variable_value"."kind" = 'literal' + and "variable_value"."literal_value" is not null + and "variable_value"."ref_key" is null + and "variable_value"."ref_path" is null + and "variable_value"."secret_provider" is null + and "variable_value"."secret_key" is null + and "variable_value"."secret_path" is null + ) + or + ( + "variable_value"."kind" = 'ref' + and "variable_value"."literal_value" is null + and "variable_value"."ref_key" is not null + and "variable_value"."secret_provider" is null + and "variable_value"."secret_key" is null + and "variable_value"."secret_path" is null + ) + or + ( + "variable_value"."kind" = 'secret_ref' + and "variable_value"."literal_value" is null + and "variable_value"."ref_key" is null + and "variable_value"."ref_path" is null + and "variable_value"."secret_provider" is not null + and "variable_value"."secret_key" is not null + ) + ) +); +--> statement-breakpoint +ALTER TABLE "variable" ADD CONSTRAINT "variable_resource_id_resource_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resource"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "variable" ADD CONSTRAINT "variable_deployment_id_deployment_id_fk" FOREIGN KEY ("deployment_id") REFERENCES "public"."deployment"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "variable" ADD CONSTRAINT "variable_job_agent_id_job_agent_id_fk" FOREIGN KEY ("job_agent_id") REFERENCES "public"."job_agent"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "variable_value" ADD CONSTRAINT "variable_value_variable_id_variable_id_fk" FOREIGN KEY ("variable_id") REFERENCES "public"."variable"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE UNIQUE INDEX "variable_resource_key_uniq" ON "variable" USING btree ("resource_id","key") WHERE "variable"."resource_id" is not null;--> statement-breakpoint +CREATE UNIQUE INDEX "variable_deployment_key_uniq" ON "variable" USING btree ("deployment_id","key") WHERE "variable"."deployment_id" is not null;--> statement-breakpoint +CREATE UNIQUE INDEX "variable_job_agent_key_uniq" ON "variable" USING btree ("job_agent_id","key") WHERE "variable"."job_agent_id" is not null;--> statement-breakpoint +CREATE INDEX "variable_scope_idx" ON "variable" USING btree ("scope");--> statement-breakpoint +CREATE INDEX "variable_value_variable_priority_idx" ON "variable_value" USING btree ("variable_id","priority","id");--> statement-breakpoint +CREATE INDEX "variable_value_kind_idx" ON "variable_value" USING btree ("kind");--> statement-breakpoint +CREATE UNIQUE INDEX "variable_value_resolution_uniq" ON "variable_value" USING btree ("variable_id",coalesce("resource_selector", ''),"priority"); \ No newline at end of file diff --git a/packages/db/drizzle/meta/0187_snapshot.json b/packages/db/drizzle/meta/0187_snapshot.json new file mode 100644 index 000000000..88e6063f4 --- /dev/null +++ b/packages/db/drizzle/meta/0187_snapshot.json @@ -0,0 +1,7265 @@ +{ + "id": "071d2fd0-a17a-4ebc-826a-9d728d97b563", + "prevId": "e54e0502-cd4c-42e1-8de8-7d3410c7a098", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "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 + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp with time zone", + "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 + }, + "password": { + "name": "password", + "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": true, + "default": "now()" + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "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": true + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_session_token_unique": { + "name": "session_session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "session_token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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()" + }, + "updated_at": { + "name": "updated_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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.changelog_entry": { + "name": "changelog_entry", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_data": { + "name": "entity_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "changelog_entry_workspace_id_workspace_id_fk": { + "name": "changelog_entry_workspace_id_workspace_id_fk", + "tableFrom": "changelog_entry", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "changelog_entry_workspace_id_entity_type_entity_id_pk": { + "name": "changelog_entry_workspace_id_entity_type_entity_id_pk", + "columns": [ + "workspace_id", + "entity_type", + "entity_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan": { + "name": "deployment_plan", + "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 + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_tag": { + "name": "version_tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version_name": { + "name": "version_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version_config": { + "name": "version_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "version_job_agent_config": { + "name": "version_job_agent_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "version_metadata": { + "name": "version_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "deployment_plan_workspace_id_index": { + "name": "deployment_plan_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_plan_deployment_id_index": { + "name": "deployment_plan_deployment_id_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_plan_expires_at_index": { + "name": "deployment_plan_expires_at_index", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_workspace_id_workspace_id_fk": { + "name": "deployment_plan_workspace_id_workspace_id_fk", + "tableFrom": "deployment_plan", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_deployment_id_deployment_id_fk": { + "name": "deployment_plan_deployment_id_deployment_id_fk", + "tableFrom": "deployment_plan", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan_target": { + "name": "deployment_plan_target", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "plan_id": { + "name": "plan_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "current_release_id": { + "name": "current_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_plan_target_plan_id_index": { + "name": "deployment_plan_target_plan_id_index", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_plan_target_plan_id_environment_id_resource_id_index": { + "name": "deployment_plan_target_plan_id_environment_id_resource_id_index", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_target_plan_id_deployment_plan_id_fk": { + "name": "deployment_plan_target_plan_id_deployment_plan_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "deployment_plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_target_environment_id_environment_id_fk": { + "name": "deployment_plan_target_environment_id_environment_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_target_resource_id_resource_id_fk": { + "name": "deployment_plan_target_resource_id_resource_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_target_current_release_id_release_id_fk": { + "name": "deployment_plan_target_current_release_id_release_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "release", + "columnsFrom": [ + "current_release_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan_target_result": { + "name": "deployment_plan_target_result", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "target_id": { + "name": "target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "dispatch_context": { + "name": "dispatch_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "agent_state": { + "name": "agent_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deployment_plan_target_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'computing'" + }, + "has_changes": { + "name": "has_changes", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current": { + "name": "current", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "proposed": { + "name": "proposed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_plan_target_result_target_id_index": { + "name": "deployment_plan_target_result_target_id_index", + "columns": [ + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_target_result_target_id_deployment_plan_target_id_fk": { + "name": "deployment_plan_target_result_target_id_deployment_plan_target_id_fk", + "tableFrom": "deployment_plan_target_result", + "tableTo": "deployment_plan_target", + "columnsFrom": [ + "target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan_target_variable": { + "name": "deployment_plan_target_variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "target_id": { + "name": "target_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 + }, + "encrypted": { + "name": "encrypted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "deployment_plan_target_variable_target_id_key_index": { + "name": "deployment_plan_target_variable_target_id_key_index", + "columns": [ + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_target_variable_target_id_deployment_plan_target_id_fk": { + "name": "deployment_plan_target_variable_target_id_deployment_plan_target_id_fk", + "tableFrom": "deployment_plan_target_variable", + "tableTo": "deployment_plan_target", + "columnsFrom": [ + "target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_trace_span": { + "name": "deployment_trace_span", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "trace_id": { + "name": "trace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "span_id": { + "name": "span_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_span_id": { + "name": "parent_span_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "release_target_key": { + "name": "release_target_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "release_id": { + "name": "release_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parent_trace_id": { + "name": "parent_trace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "node_type": { + "name": "node_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "depth": { + "name": "depth", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "attributes": { + "name": "attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "events": { + "name": "events", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "deployment_trace_span_trace_span_idx": { + "name": "deployment_trace_span_trace_span_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "span_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_trace_id_idx": { + "name": "deployment_trace_span_trace_id_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_parent_span_id_idx": { + "name": "deployment_trace_span_parent_span_id_idx", + "columns": [ + { + "expression": "parent_span_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_workspace_id_idx": { + "name": "deployment_trace_span_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_release_target_key_idx": { + "name": "deployment_trace_span_release_target_key_idx", + "columns": [ + { + "expression": "release_target_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_release_id_idx": { + "name": "deployment_trace_span_release_id_idx", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_job_id_idx": { + "name": "deployment_trace_span_job_id_idx", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_parent_trace_id_idx": { + "name": "deployment_trace_span_parent_trace_id_idx", + "columns": [ + { + "expression": "parent_trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_created_at_idx": { + "name": "deployment_trace_span_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_phase_idx": { + "name": "deployment_trace_span_phase_idx", + "columns": [ + { + "expression": "phase", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_node_type_idx": { + "name": "deployment_trace_span_node_type_idx", + "columns": [ + { + "expression": "node_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_status_idx": { + "name": "deployment_trace_span_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_trace_span_workspace_id_workspace_id_fk": { + "name": "deployment_trace_span_workspace_id_workspace_id_fk", + "tableFrom": "deployment_trace_span", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_variable": { + "name": "deployment_variable", + "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 + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_value": { + "name": "default_value", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_variable_deployment_id_index": { + "name": "deployment_variable_deployment_id_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployment_variable_deployment_id_key_unique": { + "name": "deployment_variable_deployment_id_key_unique", + "nullsNotDistinct": false, + "columns": [ + "deployment_id", + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_variable_value": { + "name": "deployment_variable_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_variable_id": { + "name": "deployment_variable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "deployment_variable_value_deployment_variable_id_index": { + "name": "deployment_variable_value_deployment_variable_id_index", + "columns": [ + { + "expression": "deployment_variable_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_variable_value_deployment_variable_id_deployment_variable_id_fk": { + "name": "deployment_variable_value_deployment_variable_id_deployment_variable_id_fk", + "tableFrom": "deployment_variable_value", + "tableTo": "deployment_variable", + "columnsFrom": [ + "deployment_variable_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "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_workspace_id_workspace_id_fk": { + "name": "deployment_version_workspace_id_workspace_id_fk", + "tableFrom": "deployment_version", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_deployment_resource": { + "name": "computed_deployment_resource", + "schema": "", + "columns": { + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_evaluated_at": { + "name": "last_evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "computed_deployment_resource_deployment_id_deployment_id_fk": { + "name": "computed_deployment_resource_deployment_id_deployment_id_fk", + "tableFrom": "computed_deployment_resource", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_deployment_resource_resource_id_resource_id_fk": { + "name": "computed_deployment_resource_resource_id_resource_id_fk", + "tableFrom": "computed_deployment_resource", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "computed_deployment_resource_deployment_id_resource_id_pk": { + "name": "computed_deployment_resource_deployment_id_resource_id_pk", + "columns": [ + "deployment_id", + "resource_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "job_agent_selector": { + "name": "job_agent_selector", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'false'" + }, + "job_agent_config": { + "name": "job_agent_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_workspace_id_index": { + "name": "deployment_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_workspace_id_workspace_id_fk": { + "name": "deployment_workspace_id_workspace_id_fk", + "tableFrom": "deployment", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_environment_resource": { + "name": "computed_environment_resource", + "schema": "", + "columns": { + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_evaluated_at": { + "name": "last_evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "computed_environment_resource_environment_id_environment_id_fk": { + "name": "computed_environment_resource_environment_id_environment_id_fk", + "tableFrom": "computed_environment_resource", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_environment_resource_resource_id_resource_id_fk": { + "name": "computed_environment_resource_resource_id_resource_id_fk", + "tableFrom": "computed_environment_resource", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "computed_environment_resource_environment_id_resource_id_pk": { + "name": "computed_environment_resource_environment_id_resource_id_pk", + "columns": [ + "environment_id", + "resource_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "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": "''" + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "environment_workspace_id_index": { + "name": "environment_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environment_workspace_id_workspace_id_fk": { + "name": "environment_workspace_id_workspace_id_fk", + "tableFrom": "environment", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.event": { + "name": "event", + "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 + }, + "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": { + "event_workspace_id_workspace_id_fk": { + "name": "event_workspace_id_workspace_id_fk", + "tableFrom": "event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "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": {} + }, + "resource_workspace_id_active_idx": { + "name": "resource_workspace_id_active_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resource_workspace_id_deleted_at_index": { + "name": "resource_workspace_id_deleted_at_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resource_aggregate": { + "name": "resource_aggregate", + "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": 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 + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "filter": { + "name": "filter", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'true'" + }, + "group_by": { + "name": "group_by", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "resource_aggregate_workspace_id_index": { + "name": "resource_aggregate_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resource_aggregate_workspace_id_workspace_id_fk": { + "name": "resource_aggregate_workspace_id_workspace_id_fk", + "tableFrom": "resource_aggregate", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "resource_aggregate_created_by_user_id_fk": { + "name": "resource_aggregate_created_by_user_id_fk", + "tableFrom": "resource_aggregate", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "indexes": { + "system_workspace_id_index": { + "name": "system_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_deployment": { + "name": "system_deployment", + "schema": "", + "columns": { + "system_id": { + "name": "system_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_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": { + "system_deployment_system_id_system_id_fk": { + "name": "system_deployment_system_id_system_id_fk", + "tableFrom": "system_deployment", + "tableTo": "system", + "columnsFrom": [ + "system_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "system_deployment_deployment_id_deployment_id_fk": { + "name": "system_deployment_deployment_id_deployment_id_fk", + "tableFrom": "system_deployment", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "system_deployment_system_id_deployment_id_pk": { + "name": "system_deployment_system_id_deployment_id_pk", + "columns": [ + "system_id", + "deployment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_environment": { + "name": "system_environment", + "schema": "", + "columns": { + "system_id": { + "name": "system_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 with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "system_environment_system_id_system_id_fk": { + "name": "system_environment_system_id_system_id_fk", + "tableFrom": "system_environment", + "tableTo": "system", + "columnsFrom": [ + "system_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "system_environment_environment_id_environment_id_fk": { + "name": "system_environment_environment_id_environment_id_fk", + "tableFrom": "system_environment", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "system_environment_system_id_environment_id_pk": { + "name": "system_environment_system_id_environment_id_pk", + "columns": [ + "system_id", + "environment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "trace_token": { + "name": "trace_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dispatch_context": { + "name": "dispatch_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "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": {} + }, + "job_external_id_idx": { + "name": "job_external_id_idx", + "columns": [ + { + "expression": "external_id", + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {} + }, + "job_metadata_job_id_idx": { + "name": "job_metadata_job_id_idx", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": false + }, + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "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" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release": { + "name": "release", + "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 + }, + "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": { + "release_resource_id_environment_id_deployment_id_index": { + "name": "release_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": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_deployment_id_index": { + "name": "release_deployment_id_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_resource_id_resource_id_fk": { + "name": "release_resource_id_resource_id_fk", + "tableFrom": "release", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_environment_id_environment_id_fk": { + "name": "release_environment_id_environment_id_fk", + "tableFrom": "release", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_deployment_id_deployment_id_fk": { + "name": "release_deployment_id_deployment_id_fk", + "tableFrom": "release", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_version_id_deployment_version_id_fk": { + "name": "release_version_id_deployment_version_id_fk", + "tableFrom": "release", + "tableTo": "deployment_version", + "columnsFrom": [ + "version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_job": { + "name": "release_job", + "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 + }, + "release_id": { + "name": "release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "release_job_release_id_job_id_index": { + "name": "release_job_release_id_job_id_index", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_job_job_id_index": { + "name": "release_job_job_id_index", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_job_release_id_index": { + "name": "release_job_release_id_index", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "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" + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_target_desired_release": { + "name": "release_target_desired_release", + "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 + } + }, + "indexes": { + "release_target_desired_release_resource_id_environment_id_deployment_id_index": { + "name": "release_target_desired_release_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_desired_release_resource_id_resource_id_fk": { + "name": "release_target_desired_release_resource_id_resource_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_environment_id_environment_id_fk": { + "name": "release_target_desired_release_environment_id_environment_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_deployment_id_deployment_id_fk": { + "name": "release_target_desired_release_deployment_id_deployment_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_desired_release_id_release_id_fk": { + "name": "release_target_desired_release_desired_release_id_release_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "release", + "columnsFrom": [ + "desired_release_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_variable": { + "name": "release_variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release_id": { + "name": "release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "encrypted": { + "name": "encrypted", + "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": { + "release_variable_release_id_key_index": { + "name": "release_variable_release_id_key_index", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_variable_release_id_release_id_fk": { + "name": "release_variable_release_id_release_id_fk", + "tableFrom": "release_variable", + "tableTo": "release", + "columnsFrom": [ + "release_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reconcile_work_scope": { + "name": "reconcile_work_scope", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "byDefault", + "name": "reconcile_work_scope_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "9223372036854775807", + "cache": "1", + "cycle": false + } + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "scope_id": { + "name": "scope_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "event_ts": { + "name": "event_ts", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "priority": { + "name": "priority", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": 100 + }, + "not_before": { + "name": "not_before", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "attempt_count": { + "name": "attempt_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_by": { + "name": "claimed_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_until": { + "name": "claimed_until", + "type": "timestamp with time zone", + "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": true, + "default": "now()" + } + }, + "indexes": { + "reconcile_work_scope_workspace_id_kind_scope_type_scope_id_index": { + "name": "reconcile_work_scope_workspace_id_kind_scope_type_scope_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "reconcile_work_scope_unclaimed_idx": { + "name": "reconcile_work_scope_unclaimed_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_ts", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"reconcile_work_scope\".\"claimed_until\" is null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "reconcile_work_scope_expired_claims_idx": { + "name": "reconcile_work_scope_expired_claims_idx", + "columns": [ + { + "expression": "claimed_until", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"reconcile_work_scope\".\"claimed_until\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "selector": { + "name": "selector", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'true'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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()" + } + }, + "indexes": { + "policy_workspace_id_index": { + "name": "policy_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "min_approvals": { + "name": "min_approvals", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_deployment_dependency": { + "name": "policy_rule_deployment_dependency", + "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 + }, + "depends_on": { + "name": "depends_on", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_deployment_dependency_policy_id_policy_id_fk": { + "name": "policy_rule_deployment_dependency_policy_id_policy_id_fk", + "tableFrom": "policy_rule_deployment_dependency", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_deployment_window": { + "name": "policy_rule_deployment_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 + }, + "allow_window": { + "name": "allow_window", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "duration_minutes": { + "name": "duration_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rrule": { + "name": "rrule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_deployment_window_policy_id_policy_id_fk": { + "name": "policy_rule_deployment_window_policy_id_policy_id_fk", + "tableFrom": "policy_rule_deployment_window", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_environment_progression": { + "name": "policy_rule_environment_progression", + "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 + }, + "depends_on_environment_selector": { + "name": "depends_on_environment_selector", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "maximum_age_hours": { + "name": "maximum_age_hours", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "minimum_soak_time_minutes": { + "name": "minimum_soak_time_minutes", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "minimum_success_percentage": { + "name": "minimum_success_percentage", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "success_statuses": { + "name": "success_statuses", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "require_verification_passed": { + "name": "require_verification_passed", + "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": {}, + "foreignKeys": { + "policy_rule_environment_progression_policy_id_policy_id_fk": { + "name": "policy_rule_environment_progression_policy_id_policy_id_fk", + "tableFrom": "policy_rule_environment_progression", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_gradual_rollout": { + "name": "policy_rule_gradual_rollout", + "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 + }, + "rollout_type": { + "name": "rollout_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "time_scale_interval": { + "name": "time_scale_interval", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_gradual_rollout_policy_id_policy_id_fk": { + "name": "policy_rule_gradual_rollout_policy_id_policy_id_fk", + "tableFrom": "policy_rule_gradual_rollout", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_retry": { + "name": "policy_rule_retry", + "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 + }, + "max_retries": { + "name": "max_retries", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "backoff_seconds": { + "name": "backoff_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "backoff_strategy": { + "name": "backoff_strategy", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_backoff_seconds": { + "name": "max_backoff_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "retry_on_statuses": { + "name": "retry_on_statuses", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_retry_policy_id_policy_id_fk": { + "name": "policy_rule_retry_policy_id_policy_id_fk", + "tableFrom": "policy_rule_retry", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_rollback": { + "name": "policy_rule_rollback", + "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 + }, + "on_job_statuses": { + "name": "on_job_statuses", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "on_verification_failure": { + "name": "on_verification_failure", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_rollback_policy_id_policy_id_fk": { + "name": "policy_rule_rollback_policy_id_policy_id_fk", + "tableFrom": "policy_rule_rollback", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_verification": { + "name": "policy_rule_verification", + "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 + }, + "metrics": { + "name": "metrics", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "trigger_on": { + "name": "trigger_on", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_verification_policy_id_policy_id_fk": { + "name": "policy_rule_verification_policy_id_policy_id_fk", + "tableFrom": "policy_rule_verification", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_version_cooldown": { + "name": "policy_rule_version_cooldown", + "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 + }, + "interval_seconds": { + "name": "interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_version_cooldown_policy_id_policy_id_fk": { + "name": "policy_rule_version_cooldown_policy_id_policy_id_fk", + "tableFrom": "policy_rule_version_cooldown", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_version_selector": { + "name": "policy_rule_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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "selector": { + "name": "selector", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_version_selector_policy_id_policy_id_fk": { + "name": "policy_rule_version_selector_policy_id_policy_id_fk", + "tableFrom": "policy_rule_version_selector", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_approval_record": { + "name": "user_approval_record", + "schema": "", + "columns": { + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_approval_record_version_id_user_id_environment_id_pk": { + "name": "user_approval_record_version_id_user_id_environment_id_pk", + "columns": [ + "version_id", + "user_id", + "environment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resource_variable": { + "name": "resource_variable", + "schema": "", + "columns": { + "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 + } + }, + "indexes": {}, + "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": { + "resource_variable_resource_id_key_pk": { + "name": "resource_variable_resource_id_key_pk", + "columns": [ + "resource_id", + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inputs": { + "name": "inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "job_agents": { + "name": "job_agents", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_job": { + "name": "workflow_job", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_run_id": { + "name": "workflow_run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_job_workflow_run_id_workflow_run_id_fk": { + "name": "workflow_job_workflow_run_id_workflow_run_id_fk", + "tableFrom": "workflow_job", + "tableTo": "workflow_run", + "columnsFrom": [ + "workflow_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_job_job_id_job_id_fk": { + "name": "workflow_job_job_id_job_id_fk", + "tableFrom": "workflow_job", + "tableTo": "job", + "columnsFrom": [ + "job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_run": { + "name": "workflow_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "inputs": { + "name": "inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_workflow_id_workflow_id_fk": { + "name": "workflow_run_workflow_id_workflow_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_skip": { + "name": "policy_skip", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_policy_release_target": { + "name": "computed_policy_release_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 + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "computed_at": { + "name": "computed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "computed_policy_release_target_policy_id_environment_id_deployment_id_resource_id_index": { + "name": "computed_policy_release_target_policy_id_environment_id_deployment_id_resource_id_index", + "columns": [ + { + "expression": "policy_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" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "computed_policy_release_target_policy_id_index": { + "name": "computed_policy_release_target_policy_id_index", + "columns": [ + { + "expression": "policy_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "computed_policy_release_target_resource_id_environment_id_deployment_id_index": { + "name": "computed_policy_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": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "computed_policy_release_target_policy_id_policy_id_fk": { + "name": "computed_policy_release_target_policy_id_policy_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_policy_release_target_environment_id_environment_id_fk": { + "name": "computed_policy_release_target_environment_id_environment_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_policy_release_target_deployment_id_deployment_id_fk": { + "name": "computed_policy_release_target_deployment_id_deployment_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_policy_release_target_resource_id_resource_id_fk": { + "name": "computed_policy_release_target_resource_id_resource_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_evaluation": { + "name": "policy_rule_evaluation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "rule_type": { + "name": "rule_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "allowed": { + "name": "allowed", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "action_required": { + "name": "action_required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "action_type": { + "name": "action_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "satisfied_at": { + "name": "satisfied_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "next_evaluation_at": { + "name": "next_evaluation_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "evaluated_at": { + "name": "evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "policy_rule_evaluation_rule_id_environment_id_version_id_resource_id_index": { + "name": "policy_rule_evaluation_rule_id_environment_id_version_id_resource_id_index", + "columns": [ + { + "expression": "rule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "policy_rule_evaluation_environment_id_version_id_resource_id_rule_type_index": { + "name": "policy_rule_evaluation_environment_id_version_id_resource_id_rule_type_index", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "rule_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "policy_rule_evaluation_environment_id_environment_id_fk": { + "name": "policy_rule_evaluation_environment_id_environment_id_fk", + "tableFrom": "policy_rule_evaluation", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_evaluation_version_id_deployment_version_id_fk": { + "name": "policy_rule_evaluation_version_id_deployment_version_id_fk", + "tableFrom": "policy_rule_evaluation", + "tableTo": "deployment_version", + "columnsFrom": [ + "version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_evaluation_resource_id_resource_id_fk": { + "name": "policy_rule_evaluation_resource_id_resource_id_fk", + "tableFrom": "policy_rule_evaluation", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_verification_metric_measurement": { + "name": "job_verification_metric_measurement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "job_verification_metric_status_id": { + "name": "job_verification_metric_status_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "measured_at": { + "name": "measured_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "status": { + "name": "status", + "type": "job_verification_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "job_verification_metric_measurement_job_verification_metric_status_id_index": { + "name": "job_verification_metric_measurement_job_verification_metric_status_id_index", + "columns": [ + { + "expression": "job_verification_metric_status_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_verification_metric_measurement_job_verification_metric_status_id_job_verification_metric_id_fk": { + "name": "job_verification_metric_measurement_job_verification_metric_status_id_job_verification_metric_id_fk", + "tableFrom": "job_verification_metric_measurement", + "tableTo": "job_verification_metric", + "columnsFrom": [ + "job_verification_metric_status_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_verification_metric": { + "name": "job_verification_metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "policy_rule_verification_metric_id": { + "name": "policy_rule_verification_metric_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "interval_seconds": { + "name": "interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "success_threshold": { + "name": "success_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "failure_condition": { + "name": "failure_condition", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "failure_threshold": { + "name": "failure_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": { + "job_verification_metric_job_id_index": { + "name": "job_verification_metric_job_id_index", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_verification_metric_policy_rule_verification_metric_id_index": { + "name": "job_verification_metric_policy_rule_verification_metric_id_index", + "columns": [ + { + "expression": "policy_rule_verification_metric_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_verification_metric_policy_rule_verification_metric_id_policy_rule_job_verification_metric_id_fk": { + "name": "job_verification_metric_policy_rule_verification_metric_id_policy_rule_job_verification_metric_id_fk", + "tableFrom": "job_verification_metric", + "tableTo": "policy_rule_job_verification_metric", + "columnsFrom": [ + "policy_rule_verification_metric_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_job_verification_metric": { + "name": "policy_rule_job_verification_metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "trigger_on": { + "name": "trigger_on", + "type": "job_verification_trigger_on", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'jobSuccess'" + }, + "policy_id": { + "name": "policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "interval_seconds": { + "name": "interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "success_threshold": { + "name": "success_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "failure_condition": { + "name": "failure_condition", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "failure_threshold": { + "name": "failure_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_job_verification_metric_policy_id_policy_id_fk": { + "name": "policy_rule_job_verification_metric_policy_id_policy_id_fk", + "tableFrom": "policy_rule_job_verification_metric", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_entity_relationship": { + "name": "computed_entity_relationship", + "schema": "", + "columns": { + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "from_entity_type": { + "name": "from_entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_entity_id": { + "name": "from_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "to_entity_type": { + "name": "to_entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "to_entity_id": { + "name": "to_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "last_evaluated_at": { + "name": "last_evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "computed_entity_relationship_from_idx": { + "name": "computed_entity_relationship_from_idx", + "columns": [ + { + "expression": "from_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "from_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "computed_entity_relationship_to_idx": { + "name": "computed_entity_relationship_to_idx", + "columns": [ + { + "expression": "to_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "to_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "computed_entity_relationship_rule_id_relationship_rule_id_fk": { + "name": "computed_entity_relationship_rule_id_relationship_rule_id_fk", + "tableFrom": "computed_entity_relationship", + "tableTo": "relationship_rule", + "columnsFrom": [ + "rule_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "computed_entity_relationship_rule_id_from_entity_type_from_entity_id_to_entity_type_to_entity_id_pk": { + "name": "computed_entity_relationship_rule_id_from_entity_type_from_entity_id_to_entity_type_to_entity_id_pk", + "columns": [ + "rule_id", + "from_entity_type", + "from_entity_id", + "to_entity_type", + "to_entity_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.relationship_rule": { + "name": "relationship_rule", + "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": true + }, + "reference": { + "name": "reference", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cel": { + "name": "cel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + } + }, + "indexes": { + "relationship_rule_workspace_id_reference_index": { + "name": "relationship_rule_workspace_id_reference_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "reference", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "relationship_rule_workspace_id_index": { + "name": "relationship_rule_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "relationship_rule_workspace_id_workspace_id_fk": { + "name": "relationship_rule_workspace_id_workspace_id_fk", + "tableFrom": "relationship_rule", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": true, + "default": "''" + }, + "selector": { + "name": "selector", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "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": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "variable_set_workspace_id_workspace_id_fk": { + "name": "variable_set_workspace_id_workspace_id_fk", + "tableFrom": "variable_set", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.variable_set_variable": { + "name": "variable_set_variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "variable_set_id": { + "name": "variable_set_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "variable_set_variable_variable_set_id_variable_set_id_fk": { + "name": "variable_set_variable_variable_set_id_variable_set_id_fk", + "tableFrom": "variable_set_variable", + "tableTo": "variable_set", + "columnsFrom": [ + "variable_set_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "variable_set_variable_variable_set_id_key_unique": { + "name": "variable_set_variable_variable_set_id_key_unique", + "nullsNotDistinct": false, + "columns": [ + "variable_set_id", + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.variable": { + "name": "variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "scope": { + "name": "scope", + "type": "variable_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "job_agent_id": { + "name": "job_agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_sensitive": { + "name": "is_sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "description": { + "name": "description", + "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": true, + "default": "now()" + } + }, + "indexes": { + "variable_resource_key_uniq": { + "name": "variable_resource_key_uniq", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"variable\".\"resource_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_deployment_key_uniq": { + "name": "variable_deployment_key_uniq", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"variable\".\"deployment_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_job_agent_key_uniq": { + "name": "variable_job_agent_key_uniq", + "columns": [ + { + "expression": "job_agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"variable\".\"job_agent_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_scope_idx": { + "name": "variable_scope_idx", + "columns": [ + { + "expression": "scope", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_resource_id_resource_id_fk": { + "name": "variable_resource_id_resource_id_fk", + "tableFrom": "variable", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "variable_deployment_id_deployment_id_fk": { + "name": "variable_deployment_id_deployment_id_fk", + "tableFrom": "variable", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "variable_job_agent_id_job_agent_id_fk": { + "name": "variable_job_agent_id_job_agent_id_fk", + "tableFrom": "variable", + "tableTo": "job_agent", + "columnsFrom": [ + "job_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "variable_scope_target_check": { + "name": "variable_scope_target_check", + "value": "\n (\n \"variable\".\"scope\" = 'resource'\n and \"variable\".\"resource_id\" is not null\n and \"variable\".\"deployment_id\" is null\n and \"variable\".\"job_agent_id\" is null\n )\n or\n (\n \"variable\".\"scope\" = 'deployment'\n and \"variable\".\"deployment_id\" is not null\n and \"variable\".\"resource_id\" is null\n and \"variable\".\"job_agent_id\" is null\n )\n or\n (\n \"variable\".\"scope\" = 'job_agent'\n and \"variable\".\"job_agent_id\" is not null\n and \"variable\".\"resource_id\" is null\n and \"variable\".\"deployment_id\" is null\n )\n " + } + }, + "isRLSEnabled": false + }, + "public.variable_value": { + "name": "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 + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "kind": { + "name": "kind", + "type": "variable_value_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "literal_value": { + "name": "literal_value", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ref_key": { + "name": "ref_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ref_path": { + "name": "ref_path", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "secret_provider": { + "name": "secret_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_key": { + "name": "secret_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_path": { + "name": "secret_path", + "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": true, + "default": "now()" + } + }, + "indexes": { + "variable_value_variable_priority_idx": { + "name": "variable_value_variable_priority_idx", + "columns": [ + { + "expression": "variable_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_value_kind_idx": { + "name": "variable_value_kind_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_value_resolution_uniq": { + "name": "variable_value_resolution_uniq", + "columns": [ + { + "expression": "variable_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"resource_selector\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_value_variable_id_variable_id_fk": { + "name": "variable_value_variable_id_variable_id_fk", + "tableFrom": "variable_value", + "tableTo": "variable", + "columnsFrom": [ + "variable_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "variable_value_kind_shape_check": { + "name": "variable_value_kind_shape_check", + "value": "\n (\n \"variable_value\".\"kind\" = 'literal'\n and \"variable_value\".\"literal_value\" is not null\n and \"variable_value\".\"ref_key\" is null\n and \"variable_value\".\"ref_path\" is null\n and \"variable_value\".\"secret_provider\" is null\n and \"variable_value\".\"secret_key\" is null\n and \"variable_value\".\"secret_path\" is null\n )\n or\n (\n \"variable_value\".\"kind\" = 'ref'\n and \"variable_value\".\"literal_value\" is null\n and \"variable_value\".\"ref_key\" is not null\n and \"variable_value\".\"secret_provider\" is null\n and \"variable_value\".\"secret_key\" is null\n and \"variable_value\".\"secret_path\" is null\n )\n or\n (\n \"variable_value\".\"kind\" = 'secret_ref'\n and \"variable_value\".\"literal_value\" is null\n and \"variable_value\".\"ref_key\" is null\n and \"variable_value\".\"ref_path\" is null\n and \"variable_value\".\"secret_provider\" is not null\n and \"variable_value\".\"secret_key\" is not null\n )\n " + } + }, + "isRLSEnabled": false + } + }, + "enums": { + "public.system_role": { + "name": "system_role", + "schema": "public", + "values": [ + "user", + "admin" + ] + }, + "public.deployment_plan_target_status": { + "name": "deployment_plan_target_status", + "schema": "public", + "values": [ + "computing", + "completed", + "errored", + "unsupported" + ] + }, + "public.deployment_version_status": { + "name": "deployment_version_status", + "schema": "public", + "values": [ + "unspecified", + "building", + "ready", + "failed", + "rejected", + "paused" + ] + }, + "public.job_reason": { + "name": "job_reason", + "schema": "public", + "values": [ + "policy_passing", + "policy_override", + "env_policy_override", + "config_policy_override", + "redeploy" + ] + }, + "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", + "resource", + "resourceProvider", + "workspace", + "environment", + "system", + "deployment" + ] + }, + "public.job_verification_status": { + "name": "job_verification_status", + "schema": "public", + "values": [ + "failed", + "inconclusive", + "passed" + ] + }, + "public.job_verification_trigger_on": { + "name": "job_verification_trigger_on", + "schema": "public", + "values": [ + "jobCreated", + "jobStarted", + "jobSuccess", + "jobFailure" + ] + }, + "public.variable_scope": { + "name": "variable_scope", + "schema": "public", + "values": [ + "resource", + "deployment", + "job_agent" + ] + }, + "public.variable_value_kind": { + "name": "variable_value_kind", + "schema": "public", + "values": [ + "literal", + "ref", + "secret_ref" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index d9cf4289e..3fab01602 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -1310,6 +1310,13 @@ "when": 1776272131457, "tag": "0186_cooing_doomsday", "breakpoints": true + }, + { + "idx": 187, + "version": "7", + "when": 1776692328153, + "tag": "0187_dry_quicksilver", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts index 256853d5d..3bd0d2481 100644 --- a/packages/db/src/schema/index.ts +++ b/packages/db/src/schema/index.ts @@ -29,3 +29,4 @@ export * from "./job-verification-metric.js"; export * from "./relationships.js"; export * from "./job-agent.js"; export * from "./variable-set.js"; +export * from "./variable.js"; diff --git a/packages/db/src/schema/variable.ts b/packages/db/src/schema/variable.ts new file mode 100644 index 000000000..f1db98736 --- /dev/null +++ b/packages/db/src/schema/variable.ts @@ -0,0 +1,189 @@ +import { sql } from "drizzle-orm"; +import { + bigint, + boolean, + check, + index, + jsonb, + pgEnum, + pgTable, + text, + timestamp, + uniqueIndex, + uuid, +} from "drizzle-orm/pg-core"; + +import { deployment } from "./deployment.js"; +import { jobAgent } from "./job-agent.js"; +import { resource } from "./resource.js"; + +export const variableScopeEnum = pgEnum("variable_scope", [ + "resource", + "deployment", + "job_agent", +]); + +export const variableValueKindEnum = pgEnum("variable_value_kind", [ + "literal", + "ref", + "secret_ref", +]); + +export const variable = pgTable( + "variable", + { + id: uuid("id").defaultRandom().primaryKey(), + + scope: variableScopeEnum("scope").notNull(), + + resourceId: uuid("resource_id").references(() => resource.id, { + onDelete: "cascade", + }), + + deploymentId: uuid("deployment_id").references(() => deployment.id, { + onDelete: "cascade", + }), + + jobAgentId: uuid("job_agent_id").references(() => jobAgent.id, { + onDelete: "cascade", + }), + + key: text("key").notNull(), + + isSensitive: boolean("is_sensitive").notNull().default(false), + description: text("description"), + + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), + }, + (table) => [ + uniqueIndex("variable_resource_key_uniq") + .on(table.resourceId, table.key) + .where(sql`${table.resourceId} is not null`), + + uniqueIndex("variable_deployment_key_uniq") + .on(table.deploymentId, table.key) + .where(sql`${table.deploymentId} is not null`), + + uniqueIndex("variable_job_agent_key_uniq") + .on(table.jobAgentId, table.key) + .where(sql`${table.jobAgentId} is not null`), + + index("variable_scope_idx").on(table.scope), + + check( + "variable_scope_target_check", + sql` + ( + ${table.scope} = 'resource' + and ${table.resourceId} is not null + and ${table.deploymentId} is null + and ${table.jobAgentId} is null + ) + or + ( + ${table.scope} = 'deployment' + and ${table.deploymentId} is not null + and ${table.resourceId} is null + and ${table.jobAgentId} is null + ) + or + ( + ${table.scope} = 'job_agent' + and ${table.jobAgentId} is not null + and ${table.resourceId} is null + and ${table.deploymentId} is null + ) + `, + ), + ], +); + +export const variableValue = pgTable( + "variable_value", + { + id: uuid("id").defaultRandom().primaryKey(), + + variableId: uuid("variable_id") + .notNull() + .references(() => variable.id, { onDelete: "cascade" }), + + resourceSelector: text("resource_selector"), + + priority: bigint("priority", { mode: "number" }).notNull().default(0), + + kind: variableValueKindEnum("kind").notNull(), + + literalValue: jsonb("literal_value"), + + refKey: text("ref_key"), + refPath: text("ref_path").array(), + + secretProvider: text("secret_provider"), + secretKey: text("secret_key"), + secretPath: text("secret_path").array(), + + createdAt: timestamp("created_at", { withTimezone: true }) + .notNull() + .defaultNow(), + + updatedAt: timestamp("updated_at", { withTimezone: true }) + .notNull() + .defaultNow() + .$onUpdate(() => new Date()), + }, + (table) => [ + index("variable_value_variable_priority_idx").on( + table.variableId, + table.priority, + table.id, + ), + + index("variable_value_kind_idx").on(table.kind), + + uniqueIndex("variable_value_resolution_uniq").on( + table.variableId, + sql`coalesce(${table.resourceSelector}, '')`, + table.priority, + ), + + check( + "variable_value_kind_shape_check", + sql` + ( + ${table.kind} = 'literal' + and ${table.literalValue} is not null + and ${table.refKey} is null + and ${table.refPath} is null + and ${table.secretProvider} is null + and ${table.secretKey} is null + and ${table.secretPath} is null + ) + or + ( + ${table.kind} = 'ref' + and ${table.literalValue} is null + and ${table.refKey} is not null + and ${table.secretProvider} is null + and ${table.secretKey} is null + and ${table.secretPath} is null + ) + or + ( + ${table.kind} = 'secret_ref' + and ${table.literalValue} is null + and ${table.refKey} is null + and ${table.refPath} is null + and ${table.secretProvider} is not null + and ${table.secretKey} is not null + ) + `, + ), + ], +); From 16304154e7dbbc40fe825f9a3468c226b526a3b9 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 12:08:05 -0400 Subject: [PATCH 02/14] feat: migrate and refactor variables * this migrates the variable data and refactors all variable tables into a single place for different types ie deployments, resources, job_agents, this does not update job agent reconciler to use varirables yet but the architecture is there --- apps/api/openapi/openapi.json | 6 - .../schemas/deploymentvariables.jsonnet | 2 - .../v1/workspaces/deployment-variables.ts | 217 +- .../api/src/routes/v1/workspaces/resources.ts | 92 +- apps/api/src/types/openapi.ts | 2 - apps/web/app/api/openapi.ts | 4 +- .../variables/DeploymentVariableSection.tsx | 1 - .../settings/page.$deploymentId.general.tsx | 6 - apps/workspace-engine/oapi/openapi.json | 14 +- .../oapi/spec/schemas/deployments.jsonnet | 1 - .../spec/schemas/resourcevariables.jsonnet | 12 + apps/workspace-engine/pkg/db/convert.go | 121 +- apps/workspace-engine/pkg/db/convert_test.go | 116 +- .../pkg/db/deployment_variables.sql.go | 273 - apps/workspace-engine/pkg/db/models.go | 137 +- .../pkg/db/queries/deployment_variables.sql | 55 - .../pkg/db/queries/resource_variables.sql | 29 - .../pkg/db/queries/schema.sql | 56 +- .../pkg/db/queries/variables.sql | 102 + .../pkg/db/resource_variables.sql.go | 126 - apps/workspace-engine/pkg/db/sqlc.yaml | 23 +- apps/workspace-engine/pkg/db/variables.sql.go | 239 + apps/workspace-engine/pkg/oapi/oapi.gen.go | 15 +- .../desiredrelease/getters_postgres_test.go | 56 +- .../desiredrelease/reconcile_test.go | 4 +- .../variableresolver/getters.go | 2 +- .../variableresolver/getters_postgres.go | 90 +- .../variableresolver/resolve.go | 47 +- .../variableresolver/resolve_test.go | 171 +- .../test/controllers/harness/mocks.go | 4 +- .../test/controllers/harness/pipeline.go | 2 +- .../test/controllers/harness/pipeline_opts.go | 23 +- .../test/controllers/variable_test.go | 19 +- .../db/drizzle/0188_backfill_variables.sql | 53 + packages/db/drizzle/meta/0188_snapshot.json | 7265 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/trpc/src/routes/_variables.ts | 22 + packages/trpc/src/routes/deployments.ts | 43 +- packages/trpc/src/routes/resources.ts | 58 +- packages/workspace-engine-sdk/src/schema.ts | 3410 ++++---- 40 files changed, 10254 insertions(+), 2671 deletions(-) delete mode 100644 apps/workspace-engine/pkg/db/deployment_variables.sql.go delete mode 100644 apps/workspace-engine/pkg/db/queries/deployment_variables.sql delete mode 100644 apps/workspace-engine/pkg/db/queries/resource_variables.sql create mode 100644 apps/workspace-engine/pkg/db/queries/variables.sql delete mode 100644 apps/workspace-engine/pkg/db/resource_variables.sql.go create mode 100644 apps/workspace-engine/pkg/db/variables.sql.go create mode 100644 packages/db/drizzle/0188_backfill_variables.sql create mode 100644 packages/db/drizzle/meta/0188_snapshot.json create mode 100644 packages/trpc/src/routes/_variables.ts diff --git a/apps/api/openapi/openapi.json b/apps/api/openapi/openapi.json index 1860ff727..9d1e015a2 100644 --- a/apps/api/openapi/openapi.json +++ b/apps/api/openapi/openapi.json @@ -690,9 +690,6 @@ }, "DeploymentVariable": { "properties": { - "defaultValue": { - "$ref": "#/components/schemas/LiteralValue" - }, "deploymentId": { "type": "string" }, @@ -2619,9 +2616,6 @@ }, "UpsertDeploymentVariableRequest": { "properties": { - "defaultValue": { - "$ref": "#/components/schemas/LiteralValue" - }, "deploymentId": { "type": "string" }, diff --git a/apps/api/openapi/schemas/deploymentvariables.jsonnet b/apps/api/openapi/schemas/deploymentvariables.jsonnet index b18dad568..1bcdd7265 100644 --- a/apps/api/openapi/schemas/deploymentvariables.jsonnet +++ b/apps/api/openapi/schemas/deploymentvariables.jsonnet @@ -9,7 +9,6 @@ local openapi = import '../lib/openapi.libsonnet'; key: { type: 'string' }, description: { type: 'string' }, deploymentId: { type: 'string' }, - defaultValue: openapi.schemaRef('LiteralValue'), }, }, @@ -59,7 +58,6 @@ local openapi = import '../lib/openapi.libsonnet'; deploymentId: { type: 'string' }, key: { type: 'string' }, description: { type: 'string' }, - defaultValue: openapi.schemaRef('LiteralValue'), }, }, diff --git a/apps/api/src/routes/v1/workspaces/deployment-variables.ts b/apps/api/src/routes/v1/workspaces/deployment-variables.ts index 3d31768a0..68681643f 100644 --- a/apps/api/src/routes/v1/workspaces/deployment-variables.ts +++ b/apps/api/src/routes/v1/workspaces/deployment-variables.ts @@ -2,17 +2,34 @@ import type { AsyncTypedHandler } from "@/types/api.js"; import { ApiError, asyncHandler } from "@/types/api.js"; import { Router } from "express"; -import { and, eq, inArray, takeFirstOrNull } from "@ctrlplane/db"; +import { and, eq, inArray, sql, takeFirstOrNull } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; import { enqueueReleaseTargetsForDeployment } from "@ctrlplane/db/reconcilers"; -import { - deployment, - deploymentVariable, - deploymentVariableValue, -} from "@ctrlplane/db/schema"; +import { deployment, variable, variableValue } from "@ctrlplane/db/schema"; import { validResourceSelector } from "../valid-selector.js"; +type VariableValueRow = typeof variableValue.$inferSelect; + +const flattenVariableValue = (v: VariableValueRow): unknown => { + if (v.kind === "literal") return v.literalValue; + if (v.kind === "ref") + return { reference: v.refKey, path: v.refPath ?? [] }; + return { + provider: v.secretProvider, + key: v.secretKey, + path: v.secretPath ?? [], + }; +}; + +const toApiVariableValue = (v: VariableValueRow) => ({ + id: v.id, + deploymentVariableId: v.variableId, + value: flattenVariableValue(v), + resourceSelector: v.resourceSelector ?? undefined, + priority: v.priority, +}); + const listDeploymentVariablesByDeployment: AsyncTypedHandler< "/v1/workspaces/{workspaceId}/deployments/{deploymentId}/variables", "get" @@ -23,8 +40,13 @@ const listDeploymentVariablesByDeployment: AsyncTypedHandler< const allVariables = await db .select() - .from(deploymentVariable) - .where(eq(deploymentVariable.deploymentId, deploymentId)); + .from(variable) + .where( + and( + eq(variable.scope, "deployment"), + eq(variable.deploymentId, deploymentId), + ), + ); const total = allVariables.length; const paginatedVariables = allVariables.slice(offset, offset + limit); @@ -34,29 +56,20 @@ const listDeploymentVariablesByDeployment: AsyncTypedHandler< variableIds.length > 0 ? await db .select() - .from(deploymentVariableValue) - .where( - inArray(deploymentVariableValue.deploymentVariableId, variableIds), - ) + .from(variableValue) + .where(inArray(variableValue.variableId, variableIds)) : []; - const items = paginatedVariables.map((variable) => ({ + const items = paginatedVariables.map((v) => ({ variable: { - id: variable.id, - deploymentId: variable.deploymentId, - key: variable.key, - description: variable.description ?? "", - defaultValue: variable.defaultValue ?? undefined, + id: v.id, + deploymentId: v.deploymentId!, + key: v.key, + description: v.description ?? "", }, values: values - .filter((v) => v.deploymentVariableId === variable.id) - .map((v) => ({ - id: v.id, - deploymentVariableId: v.deploymentVariableId, - value: v.value, - resourceSelector: v.resourceSelector ?? undefined, - priority: v.priority, - })), + .filter((val) => val.variableId === v.id) + .map(toApiVariableValue), })); res.json({ items, total, limit, offset }); @@ -68,35 +81,30 @@ const getDeploymentVariable: AsyncTypedHandler< > = async (req, res) => { const { variableId } = req.params; - const variable = await db + const v = await db .select() - .from(deploymentVariable) - .where(eq(deploymentVariable.id, variableId)) + .from(variable) + .where( + and(eq(variable.id, variableId), eq(variable.scope, "deployment")), + ) .then(takeFirstOrNull); - if (variable == null) + if (v == null) throw new ApiError("Deployment variable not found", 404); const values = await db .select() - .from(deploymentVariableValue) - .where(eq(deploymentVariableValue.deploymentVariableId, variableId)); + .from(variableValue) + .where(eq(variableValue.variableId, variableId)); res.json({ variable: { - id: variable.id, - deploymentId: variable.deploymentId, - key: variable.key, - description: variable.description ?? "", - defaultValue: variable.defaultValue ?? undefined, - }, - values: values.map((v) => ({ id: v.id, - deploymentVariableId: v.deploymentVariableId, - value: v.value, - resourceSelector: v.resourceSelector ?? undefined, - priority: v.priority, - })), + deploymentId: v.deploymentId!, + key: v.key, + description: v.description ?? "", + }, + values: values.map(toApiVariableValue), }); }; @@ -105,8 +113,7 @@ const upsertDeploymentVariable: AsyncTypedHandler< "put" > = async (req, res) => { const { workspaceId, variableId } = req.params; - const { body } = req; - const { deploymentId } = req.body; + const { deploymentId, key, description } = req.body; const dep = await db .select() @@ -125,15 +132,18 @@ const upsertDeploymentVariable: AsyncTypedHandler< } await db - .insert(deploymentVariable) - .values({ id: variableId, ...body }) + .insert(variable) + .values({ + id: variableId, + scope: "deployment", + deploymentId, + key, + description: description ?? null, + }) .onConflictDoUpdate({ - target: [deploymentVariable.deploymentId, deploymentVariable.key], - set: { - id: variableId, - description: body.description ?? "", - defaultValue: body.defaultValue ?? undefined, - }, + target: [variable.deploymentId, variable.key], + targetWhere: sql`${variable.deploymentId} is not null`, + set: { description: description ?? null }, }); enqueueReleaseTargetsForDeployment(db, workspaceId, deploymentId); @@ -150,33 +160,27 @@ const deleteDeploymentVariable: AsyncTypedHandler< > = async (req, res) => { const { workspaceId, variableId } = req.params; - const variable = await db - .select() - .from(deploymentVariable) - .innerJoin(deployment, eq(deploymentVariable.deploymentId, deployment.id)) + const v = await db + .select({ deploymentId: variable.deploymentId }) + .from(variable) + .innerJoin(deployment, eq(variable.deploymentId, deployment.id)) .where( and( - eq(deploymentVariable.id, variableId), + eq(variable.id, variableId), + eq(variable.scope, "deployment"), eq(deployment.workspaceId, workspaceId), ), ) - .then(takeFirstOrNull) - .then((row) => row?.deployment_variable ?? null); + .then(takeFirstOrNull); - if (variable == null) { + if (v == null) { res.status(404).json({ error: "Deployment variable not found" }); return; } - await db - .delete(deploymentVariable) - .where(eq(deploymentVariable.id, variableId)); + await db.delete(variable).where(eq(variable.id, variableId)); - enqueueReleaseTargetsForDeployment( - db, - workspaceId, - variable.deploymentId, - ); + enqueueReleaseTargetsForDeployment(db, workspaceId, v.deploymentId!); res.status(202).json({ id: variableId, @@ -190,19 +194,16 @@ const getDeploymentVariableValue: AsyncTypedHandler< > = async (req, res) => { const { valueId } = req.params; - const value = await db + const val = await db .select() - .from(deploymentVariableValue) - .where(eq(deploymentVariableValue.id, valueId)) + .from(variableValue) + .where(eq(variableValue.id, valueId)) .then(takeFirstOrNull); - if (value == null) + if (val == null) throw new ApiError("Deployment variable value not found", 404); - res.json({ - ...value, - resourceSelector: value.resourceSelector ?? undefined, - }); + res.json(toApiVariableValue(val)); }; const upsertDeploymentVariableValue: AsyncTypedHandler< @@ -211,7 +212,6 @@ const upsertDeploymentVariableValue: AsyncTypedHandler< > = async (req, res) => { const { workspaceId, valueId } = req.params; const { body } = req; - const { deploymentVariableId } = body; const isValidCel = validResourceSelector(body.resourceSelector); @@ -221,47 +221,45 @@ const upsertDeploymentVariableValue: AsyncTypedHandler< return; } - const variable = await db - .select() - .from(deploymentVariable) - .innerJoin(deployment, eq(deploymentVariable.deploymentId, deployment.id)) + const owner = await db + .select({ deploymentId: variable.deploymentId }) + .from(variable) + .innerJoin(deployment, eq(variable.deploymentId, deployment.id)) .where( and( - eq(deploymentVariable.id, deploymentVariableId), + eq(variable.id, deploymentVariableId), + eq(variable.scope, "deployment"), eq(deployment.workspaceId, workspaceId), ), ) - .then(takeFirstOrNull) - .then((row) => row?.deployment_variable ?? null); + .then(takeFirstOrNull); - if (variable == null) { + if (owner == null) { res.status(404).json({ error: "Deployment variable not found" }); return; } await db - .insert(deploymentVariableValue) + .insert(variableValue) .values({ id: valueId, - deploymentVariableId, + variableId: deploymentVariableId, priority: body.priority, - resourceSelector: body.resourceSelector ?? undefined, - value: body.value, + resourceSelector: body.resourceSelector ?? null, + kind: "literal", + literalValue: body.value, }) .onConflictDoUpdate({ - target: [deploymentVariableValue.id], + target: [variableValue.id], set: { priority: body.priority, - resourceSelector: body.resourceSelector ?? undefined, - value: body.value, + resourceSelector: body.resourceSelector ?? null, + kind: "literal", + literalValue: body.value, }, }); - enqueueReleaseTargetsForDeployment( - db, - workspaceId, - variable.deploymentId, - ); + enqueueReleaseTargetsForDeployment(db, workspaceId, owner.deploymentId!); res.status(202).json({ id: valueId, @@ -276,16 +274,13 @@ const deleteDeploymentVariableValue: AsyncTypedHandler< const { workspaceId, valueId } = req.params; const entry = await db - .select() - .from(deploymentVariableValue) - .innerJoin( - deploymentVariable, - eq(deploymentVariableValue.deploymentVariableId, deploymentVariable.id), - ) - .innerJoin(deployment, eq(deploymentVariable.deploymentId, deployment.id)) + .select({ deploymentId: variable.deploymentId }) + .from(variableValue) + .innerJoin(variable, eq(variableValue.variableId, variable.id)) + .innerJoin(deployment, eq(variable.deploymentId, deployment.id)) .where( and( - eq(deploymentVariableValue.id, valueId), + eq(variableValue.id, valueId), eq(deployment.workspaceId, workspaceId), ), ) @@ -296,13 +291,9 @@ const deleteDeploymentVariableValue: AsyncTypedHandler< return; } - const { deployment: dep } = entry; - - await db - .delete(deploymentVariableValue) - .where(eq(deploymentVariableValue.id, valueId)); + await db.delete(variableValue).where(eq(variableValue.id, valueId)); - enqueueReleaseTargetsForDeployment(db, workspaceId, dep.id); + enqueueReleaseTargetsForDeployment(db, workspaceId, entry.deploymentId!); res.status(202).json({ id: valueId, diff --git a/apps/api/src/routes/v1/workspaces/resources.ts b/apps/api/src/routes/v1/workspaces/resources.ts index 9b94f21fe..ac5568d1e 100644 --- a/apps/api/src/routes/v1/workspaces/resources.ts +++ b/apps/api/src/routes/v1/workspaces/resources.ts @@ -139,18 +139,40 @@ const upsertResourceByIdentifier: AsyncTypedHandler< if (variables != null) await db.transaction(async (tx) => { await tx - .delete(schema.resourceVariable) - .where(eq(schema.resourceVariable.resourceId, upsertedResource.id)); + .delete(schema.variable) + .where( + and( + eq(schema.variable.scope, "resource"), + eq(schema.variable.resourceId, upsertedResource.id), + ), + ); const entries = Object.entries(variables); - if (entries.length > 0) - await tx.insert(schema.resourceVariable).values( + if (entries.length > 0) { + const inserted = await tx + .insert(schema.variable) + .values( + entries.map(([key]) => ({ + scope: "resource" as const, + resourceId: upsertedResource.id, + key, + })), + ) + .returning({ + id: schema.variable.id, + key: schema.variable.key, + }); + + const byKey = new Map(inserted.map((v) => [v.key, v.id])); + await tx.insert(schema.variableValue).values( entries.map(([key, value]) => ({ - resourceId: upsertedResource.id, - key, - value, + variableId: byKey.get(key)!, + priority: 0, + kind: "literal" as const, + literalValue: value, })), ); + } }); enqueueReleaseTargetsForResource(db, workspaceId, upsertedResource.id); @@ -216,12 +238,22 @@ const getVariablesForResource: AsyncTypedHandler< const rows = await db .select({ - resourceId: schema.resourceVariable.resourceId, - key: schema.resourceVariable.key, - value: schema.resourceVariable.value, + resourceId: schema.variable.resourceId, + key: schema.variable.key, + value: schema.variableValue.literalValue, }) - .from(schema.resourceVariable) - .where(eq(schema.resourceVariable.resourceId, resource.id)); + .from(schema.variable) + .innerJoin( + schema.variableValue, + eq(schema.variableValue.variableId, schema.variable.id), + ) + .where( + and( + eq(schema.variable.scope, "resource"), + eq(schema.variable.resourceId, resource.id), + eq(schema.variableValue.kind, "literal"), + ), + ); const total = rows.length; const items = rows.slice(offset, offset + limit); @@ -242,17 +274,39 @@ const updateVariablesForResource: AsyncTypedHandler< await db.transaction(async (tx) => { await tx - .delete(schema.resourceVariable) - .where(eq(schema.resourceVariable.resourceId, resource.id)); + .delete(schema.variable) + .where( + and( + eq(schema.variable.scope, "resource"), + eq(schema.variable.resourceId, resource.id), + ), + ); const entries = Object.entries(body); - if (entries.length > 0) - await tx.insert(schema.resourceVariable).values( + if (entries.length > 0) { + const inserted = await tx + .insert(schema.variable) + .values( + entries.map(([key]) => ({ + scope: "resource" as const, + resourceId, + key, + })), + ) + .returning({ + id: schema.variable.id, + key: schema.variable.key, + }); + + const byKey = new Map(inserted.map((v) => [v.key, v.id])); + await tx.insert(schema.variableValue).values( entries.map(([key, value]) => ({ - resourceId, - key, - value, + variableId: byKey.get(key)!, + priority: 0, + kind: "literal" as const, + literalValue: value, })), ); + } }); enqueueReleaseTargetsForResource(db, workspaceId, resourceId); diff --git a/apps/api/src/types/openapi.ts b/apps/api/src/types/openapi.ts index c2d090ab0..dabd7e9ac 100644 --- a/apps/api/src/types/openapi.ts +++ b/apps/api/src/types/openapi.ts @@ -1296,7 +1296,6 @@ export interface components { message: string; }; DeploymentVariable: { - defaultValue?: components["schemas"]["LiteralValue"]; deploymentId: string; description?: string; id: string; @@ -1974,7 +1973,6 @@ export interface components { slug: string; }; UpsertDeploymentVariableRequest: { - defaultValue?: components["schemas"]["LiteralValue"]; deploymentId: string; description?: string; key: string; diff --git a/apps/web/app/api/openapi.ts b/apps/web/app/api/openapi.ts index 0720f320a..dabd7e9ac 100644 --- a/apps/web/app/api/openapi.ts +++ b/apps/web/app/api/openapi.ts @@ -1296,7 +1296,6 @@ export interface components { message: string; }; DeploymentVariable: { - defaultValue?: components["schemas"]["LiteralValue"]; deploymentId: string; description?: string; id: string; @@ -1974,7 +1973,6 @@ export interface components { slug: string; }; UpsertDeploymentVariableRequest: { - defaultValue?: components["schemas"]["LiteralValue"]; deploymentId: string; description?: string; key: string; @@ -2964,6 +2962,8 @@ export interface operations { limit?: number; /** @description Number of items to skip */ offset?: number; + /** @description CEL expression to filter the results */ + cel?: string; }; header?: never; path: { diff --git a/apps/web/app/routes/ws/deployments/_components/variables/DeploymentVariableSection.tsx b/apps/web/app/routes/ws/deployments/_components/variables/DeploymentVariableSection.tsx index e4a58614a..cc7d8d613 100644 --- a/apps/web/app/routes/ws/deployments/_components/variables/DeploymentVariableSection.tsx +++ b/apps/web/app/routes/ws/deployments/_components/variables/DeploymentVariableSection.tsx @@ -38,7 +38,6 @@ type VariableWithValues = { deploymentId: string; key: string; description: string | null; - defaultValue: unknown; }; values: VariableValue[]; }; diff --git a/apps/web/app/routes/ws/deployments/settings/page.$deploymentId.general.tsx b/apps/web/app/routes/ws/deployments/settings/page.$deploymentId.general.tsx index 4e4798a11..e759560e5 100644 --- a/apps/web/app/routes/ws/deployments/settings/page.$deploymentId.general.tsx +++ b/apps/web/app/routes/ws/deployments/settings/page.$deploymentId.general.tsx @@ -147,12 +147,6 @@ export default function DeploymentsSettingsPage() { {variable.key} - {variable.defaultValue != null && ( - - Default:{" "} - {formatValue(variable.defaultValue)} - - )} {values.length > 0 && ( 0 { + ref.Path = append([]string(nil), r.RefPath...) + } + if err := v.FromReferenceValue(ref); err != nil { + return v, err + } + case "secret_ref": + return v, fmt.Errorf("secret_ref variable values are not yet supported") + default: + return v, fmt.Errorf("unknown variable_value kind: %q", r.Kind) + } + return v, nil +} + +func derefString(p *string) string { + if p == nil { + return "" + } + return *p +} + +func ToOapiDeploymentVariable( + row ListVariablesWithValuesByDeploymentIDRow, +) oapi.DeploymentVariable { v := oapi.DeploymentVariable{ Id: row.ID.String(), DeploymentId: row.DeploymentID.String(), @@ -296,28 +349,51 @@ func ToOapiDeploymentVariable(row DeploymentVariable) oapi.DeploymentVariable { if row.Description.Valid { v.Description = &row.Description.String } - if len(row.DefaultValue) > 0 { - var lv oapi.LiteralValue - if err := json.Unmarshal(row.DefaultValue, &lv); err == nil { - v.DefaultValue = &lv - } - } return v } -func ToOapiDeploymentVariableValue(row DeploymentVariableValue) oapi.DeploymentVariableValue { - v := oapi.DeploymentVariableValue{ - Id: row.ID.String(), - DeploymentVariableId: row.DeploymentVariableID.String(), - Priority: row.Priority, +func ToOapiDeploymentVariableValueFromAgg( + r VariableValueAggRow, +) (oapi.DeploymentVariableValue, error) { + val, err := flattenVariableValue(r) + if err != nil { + return oapi.DeploymentVariableValue{}, err } - if len(row.Value) > 0 { - _ = json.Unmarshal(row.Value, &v.Value) + out := oapi.DeploymentVariableValue{ + Id: r.ID.String(), + DeploymentVariableId: r.VariableID.String(), + Priority: r.Priority, + Value: val, } - if row.ResourceSelector.Valid && row.ResourceSelector.String != "" { - v.ResourceSelector = &row.ResourceSelector.String + if r.ResourceSelector != nil && *r.ResourceSelector != "" { + out.ResourceSelector = r.ResourceSelector } - return v + return out, nil +} + +func ToOapiResourceVariablesFromAgg( + resourceID uuid.UUID, + key string, + aggs []VariableValueAggRow, +) ([]oapi.ResourceVariable, error) { + out := make([]oapi.ResourceVariable, 0, len(aggs)) + for _, a := range aggs { + val, err := flattenVariableValue(a) + if err != nil { + return nil, err + } + rv := oapi.ResourceVariable{ + ResourceId: resourceID.String(), + Key: key, + Value: val, + Priority: a.Priority, + } + if a.ResourceSelector != nil && *a.ResourceSelector != "" { + rv.ResourceSelector = a.ResourceSelector + } + out = append(out, rv) + } + return out, nil } func ToOapiVariableSetWithVariables( @@ -363,17 +439,6 @@ func ToOapiVariableSetWithVariables( return vs } -func ToOapiResourceVariable(row ResourceVariable) oapi.ResourceVariable { - v := oapi.ResourceVariable{ - ResourceId: row.ResourceID.String(), - Key: row.Key, - } - if len(row.Value) > 0 { - _ = json.Unmarshal(row.Value, &v.Value) - } - return v -} - func ToOapiSystem(row System) *oapi.System { s := &oapi.System{ Id: row.ID.String(), diff --git a/apps/workspace-engine/pkg/db/convert_test.go b/apps/workspace-engine/pkg/db/convert_test.go index fb7b21773..5412c9b84 100644 --- a/apps/workspace-engine/pkg/db/convert_test.go +++ b/apps/workspace-engine/pkg/db/convert_test.go @@ -224,56 +224,100 @@ func TestToOapiPolicyWithRules_EnvironmentProgressionPlainCEL(t *testing.T) { } // --------------------------------------------------------------------------- -// ToOapiDeploymentVariableValue — resource selector +// flattenVariableValue + ToOapiDeploymentVariableValueFromAgg // --------------------------------------------------------------------------- -func TestToOapiDeploymentVariableValue_PlainCELSelector(t *testing.T) { - id := uuid.New() - dvID := uuid.New() - celExpr := `resource.kind == "Cluster"` +func TestFlattenVariableValue_Literal(t *testing.T) { + agg := VariableValueAggRow{ + ID: uuid.New(), + VariableID: uuid.New(), + Priority: 5, + Kind: "literal", + LiteralValue: json.RawMessage(`"hi"`), + } + v, err := flattenVariableValue(agg) + require.NoError(t, err) + lv, err := v.AsLiteralValue() + require.NoError(t, err) + s, err := lv.AsStringValue() + require.NoError(t, err) + assert.Equal(t, "hi", string(s)) +} - row := DeploymentVariableValue{ - ID: id, - DeploymentVariableID: dvID, - Value: []byte(`{"string":"hello"}`), - ResourceSelector: pgtype.Text{String: celExpr, Valid: true}, - Priority: 1, +func TestFlattenVariableValue_Ref(t *testing.T) { + refKey := "db.config" + agg := VariableValueAggRow{ + ID: uuid.New(), + VariableID: uuid.New(), + Priority: 0, + Kind: "ref", + RefKey: &refKey, + RefPath: []string{"host"}, } + v, err := flattenVariableValue(agg) + require.NoError(t, err) + rv, err := v.AsReferenceValue() + require.NoError(t, err) + assert.Equal(t, "db.config", rv.Reference) + assert.Equal(t, []string{"host"}, rv.Path) +} - v := ToOapiDeploymentVariableValue(row) +func TestFlattenVariableValue_SecretRefUnsupported(t *testing.T) { + provider := "vault" + key := "kv/data/prod/db" + agg := VariableValueAggRow{ + ID: uuid.New(), + VariableID: uuid.New(), + Priority: 0, + Kind: "secret_ref", + SecretProvider: &provider, + SecretKey: &key, + } + _, err := flattenVariableValue(agg) + require.Error(t, err) +} + +func TestToOapiDeploymentVariableValueFromAgg_CELSelector(t *testing.T) { + celExpr := `resource.kind == "Cluster"` + agg := VariableValueAggRow{ + ID: uuid.New(), + VariableID: uuid.New(), + ResourceSelector: &celExpr, + Priority: 1, + Kind: "literal", + LiteralValue: json.RawMessage(`"hello"`), + } + v, err := ToOapiDeploymentVariableValueFromAgg(agg) + require.NoError(t, err) require.NotNil(t, v.ResourceSelector) assert.Equal(t, celExpr, *v.ResourceSelector) } -func TestToOapiDeploymentVariableValue_EmptySelector(t *testing.T) { - id := uuid.New() - dvID := uuid.New() - - row := DeploymentVariableValue{ - ID: id, - DeploymentVariableID: dvID, - Value: []byte(`{"string":"hello"}`), - ResourceSelector: pgtype.Text{Valid: false}, - Priority: 1, +func TestToOapiDeploymentVariableValueFromAgg_EmptySelector(t *testing.T) { + agg := VariableValueAggRow{ + ID: uuid.New(), + VariableID: uuid.New(), + Priority: 1, + Kind: "literal", + LiteralValue: json.RawMessage(`"hello"`), } - - v := ToOapiDeploymentVariableValue(row) + v, err := ToOapiDeploymentVariableValueFromAgg(agg) + require.NoError(t, err) assert.Nil(t, v.ResourceSelector) } -func TestToOapiDeploymentVariableValue_EmptyStringSelector(t *testing.T) { - id := uuid.New() - dvID := uuid.New() - - row := DeploymentVariableValue{ - ID: id, - DeploymentVariableID: dvID, - Value: []byte(`{"string":"hello"}`), - ResourceSelector: pgtype.Text{String: "", Valid: true}, - Priority: 1, +func TestToOapiDeploymentVariableValueFromAgg_EmptyStringSelector(t *testing.T) { + empty := "" + agg := VariableValueAggRow{ + ID: uuid.New(), + VariableID: uuid.New(), + ResourceSelector: &empty, + Priority: 1, + Kind: "literal", + LiteralValue: json.RawMessage(`"hello"`), } - - v := ToOapiDeploymentVariableValue(row) + v, err := ToOapiDeploymentVariableValueFromAgg(agg) + require.NoError(t, err) assert.Nil(t, v.ResourceSelector) } diff --git a/apps/workspace-engine/pkg/db/deployment_variables.sql.go b/apps/workspace-engine/pkg/db/deployment_variables.sql.go deleted file mode 100644 index 4e47c0cda..000000000 --- a/apps/workspace-engine/pkg/db/deployment_variables.sql.go +++ /dev/null @@ -1,273 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.30.0 -// source: deployment_variables.sql - -package db - -import ( - "context" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -const deleteDeploymentVariable = `-- name: DeleteDeploymentVariable :exec -DELETE FROM deployment_variable WHERE id = $1 -` - -func (q *Queries) DeleteDeploymentVariable(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteDeploymentVariable, id) - return err -} - -const deleteDeploymentVariableValue = `-- name: DeleteDeploymentVariableValue :exec -DELETE FROM deployment_variable_value WHERE id = $1 -` - -func (q *Queries) DeleteDeploymentVariableValue(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteDeploymentVariableValue, id) - return err -} - -const getDeploymentVariableByID = `-- name: GetDeploymentVariableByID :one -SELECT id, deployment_id, key, description, default_value -FROM deployment_variable -WHERE id = $1 -` - -func (q *Queries) GetDeploymentVariableByID(ctx context.Context, id uuid.UUID) (DeploymentVariable, error) { - row := q.db.QueryRow(ctx, getDeploymentVariableByID, id) - var i DeploymentVariable - err := row.Scan( - &i.ID, - &i.DeploymentID, - &i.Key, - &i.Description, - &i.DefaultValue, - ) - return i, err -} - -const getDeploymentVariableValueByID = `-- name: GetDeploymentVariableValueByID :one -SELECT id, deployment_variable_id, value, resource_selector, priority -FROM deployment_variable_value -WHERE id = $1 -` - -func (q *Queries) GetDeploymentVariableValueByID(ctx context.Context, id uuid.UUID) (DeploymentVariableValue, error) { - row := q.db.QueryRow(ctx, getDeploymentVariableValueByID, id) - var i DeploymentVariableValue - err := row.Scan( - &i.ID, - &i.DeploymentVariableID, - &i.Value, - &i.ResourceSelector, - &i.Priority, - ) - return i, err -} - -const listDeploymentVariableValuesByVariableID = `-- name: ListDeploymentVariableValuesByVariableID :many -SELECT id, deployment_variable_id, value, resource_selector, priority -FROM deployment_variable_value -WHERE deployment_variable_id = $1 -ORDER BY priority DESC, id -` - -func (q *Queries) ListDeploymentVariableValuesByVariableID(ctx context.Context, deploymentVariableID uuid.UUID) ([]DeploymentVariableValue, error) { - rows, err := q.db.Query(ctx, listDeploymentVariableValuesByVariableID, deploymentVariableID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []DeploymentVariableValue - for rows.Next() { - var i DeploymentVariableValue - if err := rows.Scan( - &i.ID, - &i.DeploymentVariableID, - &i.Value, - &i.ResourceSelector, - &i.Priority, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const listDeploymentVariableValuesByWorkspaceID = `-- name: ListDeploymentVariableValuesByWorkspaceID :many -SELECT dvv.id, dvv.deployment_variable_id, dvv.value, dvv.resource_selector, dvv.priority -FROM deployment_variable_value dvv -INNER JOIN deployment_variable dv ON dv.id = dvv.deployment_variable_id -INNER JOIN deployment d ON d.id = dv.deployment_id -WHERE d.workspace_id = $1 -` - -func (q *Queries) ListDeploymentVariableValuesByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) ([]DeploymentVariableValue, error) { - rows, err := q.db.Query(ctx, listDeploymentVariableValuesByWorkspaceID, workspaceID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []DeploymentVariableValue - for rows.Next() { - var i DeploymentVariableValue - if err := rows.Scan( - &i.ID, - &i.DeploymentVariableID, - &i.Value, - &i.ResourceSelector, - &i.Priority, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const listDeploymentVariablesByDeploymentID = `-- name: ListDeploymentVariablesByDeploymentID :many -SELECT id, deployment_id, key, description, default_value -FROM deployment_variable -WHERE deployment_id = $1 -` - -func (q *Queries) ListDeploymentVariablesByDeploymentID(ctx context.Context, deploymentID uuid.UUID) ([]DeploymentVariable, error) { - rows, err := q.db.Query(ctx, listDeploymentVariablesByDeploymentID, deploymentID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []DeploymentVariable - for rows.Next() { - var i DeploymentVariable - if err := rows.Scan( - &i.ID, - &i.DeploymentID, - &i.Key, - &i.Description, - &i.DefaultValue, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const listDeploymentVariablesByWorkspaceID = `-- name: ListDeploymentVariablesByWorkspaceID :many -SELECT dv.id, dv.deployment_id, dv.key, dv.description, dv.default_value -FROM deployment_variable dv -INNER JOIN deployment d ON d.id = dv.deployment_id -WHERE d.workspace_id = $1 -` - -func (q *Queries) ListDeploymentVariablesByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) ([]DeploymentVariable, error) { - rows, err := q.db.Query(ctx, listDeploymentVariablesByWorkspaceID, workspaceID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []DeploymentVariable - for rows.Next() { - var i DeploymentVariable - if err := rows.Scan( - &i.ID, - &i.DeploymentID, - &i.Key, - &i.Description, - &i.DefaultValue, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const upsertDeploymentVariable = `-- name: UpsertDeploymentVariable :one -INSERT INTO deployment_variable (id, deployment_id, key, description, default_value) -VALUES ($1, $2, $3, $4, $5) -ON CONFLICT (id) DO UPDATE -SET deployment_id = EXCLUDED.deployment_id, key = EXCLUDED.key, - description = EXCLUDED.description, default_value = EXCLUDED.default_value -RETURNING id, deployment_id, key, description, default_value -` - -type UpsertDeploymentVariableParams struct { - ID uuid.UUID - DeploymentID uuid.UUID - Key string - Description pgtype.Text - DefaultValue []byte -} - -func (q *Queries) UpsertDeploymentVariable(ctx context.Context, arg UpsertDeploymentVariableParams) (DeploymentVariable, error) { - row := q.db.QueryRow(ctx, upsertDeploymentVariable, - arg.ID, - arg.DeploymentID, - arg.Key, - arg.Description, - arg.DefaultValue, - ) - var i DeploymentVariable - err := row.Scan( - &i.ID, - &i.DeploymentID, - &i.Key, - &i.Description, - &i.DefaultValue, - ) - return i, err -} - -const upsertDeploymentVariableValue = `-- name: UpsertDeploymentVariableValue :one -INSERT INTO deployment_variable_value (id, deployment_variable_id, value, resource_selector, priority) -VALUES ($1, $2, $3, $4, $5) -ON CONFLICT (id) DO UPDATE -SET deployment_variable_id = EXCLUDED.deployment_variable_id, value = EXCLUDED.value, - resource_selector = EXCLUDED.resource_selector, priority = EXCLUDED.priority -RETURNING id, deployment_variable_id, value, resource_selector, priority -` - -type UpsertDeploymentVariableValueParams struct { - ID uuid.UUID - DeploymentVariableID uuid.UUID - Value []byte - ResourceSelector pgtype.Text - Priority int64 -} - -func (q *Queries) UpsertDeploymentVariableValue(ctx context.Context, arg UpsertDeploymentVariableValueParams) (DeploymentVariableValue, error) { - row := q.db.QueryRow(ctx, upsertDeploymentVariableValue, - arg.ID, - arg.DeploymentVariableID, - arg.Value, - arg.ResourceSelector, - arg.Priority, - ) - var i DeploymentVariableValue - err := row.Scan( - &i.ID, - &i.DeploymentVariableID, - &i.Value, - &i.ResourceSelector, - &i.Priority, - ) - return i, err -} diff --git a/apps/workspace-engine/pkg/db/models.go b/apps/workspace-engine/pkg/db/models.go index c6f84753e..884eb2d17 100644 --- a/apps/workspace-engine/pkg/db/models.go +++ b/apps/workspace-engine/pkg/db/models.go @@ -283,6 +283,92 @@ func (ns NullJobVerificationTriggerOn) Value() (driver.Value, error) { return string(ns.JobVerificationTriggerOn), nil } +type VariableScope string + +const ( + VariableScopeResource VariableScope = "resource" + VariableScopeDeployment VariableScope = "deployment" + VariableScopeJobAgent VariableScope = "job_agent" +) + +func (e *VariableScope) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = VariableScope(s) + case string: + *e = VariableScope(s) + default: + return fmt.Errorf("unsupported scan type for VariableScope: %T", src) + } + return nil +} + +type NullVariableScope struct { + VariableScope VariableScope + Valid bool // Valid is true if VariableScope is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullVariableScope) Scan(value interface{}) error { + if value == nil { + ns.VariableScope, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.VariableScope.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullVariableScope) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.VariableScope), nil +} + +type VariableValueKind string + +const ( + VariableValueKindLiteral VariableValueKind = "literal" + VariableValueKindRef VariableValueKind = "ref" + VariableValueKindSecretRef VariableValueKind = "secret_ref" +) + +func (e *VariableValueKind) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = VariableValueKind(s) + case string: + *e = VariableValueKind(s) + default: + return fmt.Errorf("unsupported scan type for VariableValueKind: %T", src) + } + return nil +} + +type NullVariableValueKind struct { + VariableValueKind VariableValueKind + Valid bool // Valid is true if VariableValueKind is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullVariableValueKind) Scan(value interface{}) error { + if value == nil { + ns.VariableValueKind, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.VariableValueKind.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullVariableValueKind) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.VariableValueKind), nil +} + type ChangelogEntry struct { WorkspaceID uuid.UUID EntityType string @@ -372,22 +458,6 @@ type DeploymentPlanTargetResult struct { CompletedAt pgtype.Timestamptz } -type DeploymentVariable struct { - ID uuid.UUID - DeploymentID uuid.UUID - Key string - Description pgtype.Text - DefaultValue []byte -} - -type DeploymentVariableValue struct { - ID uuid.UUID - DeploymentVariableID uuid.UUID - Value []byte - ResourceSelector pgtype.Text - Priority int64 -} - type DeploymentVersion struct { ID uuid.UUID Name string @@ -673,12 +743,6 @@ type ResourceProvider struct { Metadata map[string]string } -type ResourceVariable struct { - ResourceID uuid.UUID - Key string - Value []byte -} - type System struct { ID uuid.UUID Name string @@ -708,6 +772,19 @@ type UserApprovalRecord struct { CreatedAt pgtype.Timestamptz } +type Variable struct { + ID uuid.UUID + Scope VariableScope + ResourceID uuid.UUID + DeploymentID uuid.UUID + JobAgentID uuid.UUID + Key string + IsSensitive bool + Description pgtype.Text + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} + type VariableSet struct { ID uuid.UUID Name string @@ -727,6 +804,22 @@ type VariableSetVariable struct { Value []byte } +type VariableValue struct { + ID uuid.UUID + VariableID uuid.UUID + ResourceSelector pgtype.Text + Priority int64 + Kind VariableValueKind + LiteralValue []byte + RefKey pgtype.Text + RefPath []string + SecretProvider pgtype.Text + SecretKey pgtype.Text + SecretPath []string + CreatedAt pgtype.Timestamptz + UpdatedAt pgtype.Timestamptz +} + type Workflow struct { ID uuid.UUID Name string diff --git a/apps/workspace-engine/pkg/db/queries/deployment_variables.sql b/apps/workspace-engine/pkg/db/queries/deployment_variables.sql deleted file mode 100644 index edcaca444..000000000 --- a/apps/workspace-engine/pkg/db/queries/deployment_variables.sql +++ /dev/null @@ -1,55 +0,0 @@ --- name: GetDeploymentVariableByID :one -SELECT id, deployment_id, key, description, default_value -FROM deployment_variable -WHERE id = $1; - --- name: ListDeploymentVariablesByDeploymentID :many -SELECT id, deployment_id, key, description, default_value -FROM deployment_variable -WHERE deployment_id = $1; - --- name: UpsertDeploymentVariable :one -INSERT INTO deployment_variable (id, deployment_id, key, description, default_value) -VALUES ($1, $2, $3, $4, $5) -ON CONFLICT (id) DO UPDATE -SET deployment_id = EXCLUDED.deployment_id, key = EXCLUDED.key, - description = EXCLUDED.description, default_value = EXCLUDED.default_value -RETURNING *; - --- name: DeleteDeploymentVariable :exec -DELETE FROM deployment_variable WHERE id = $1; - --- name: ListDeploymentVariablesByWorkspaceID :many -SELECT dv.id, dv.deployment_id, dv.key, dv.description, dv.default_value -FROM deployment_variable dv -INNER JOIN deployment d ON d.id = dv.deployment_id -WHERE d.workspace_id = $1; - --- name: GetDeploymentVariableValueByID :one -SELECT id, deployment_variable_id, value, resource_selector, priority -FROM deployment_variable_value -WHERE id = $1; - --- name: ListDeploymentVariableValuesByVariableID :many -SELECT id, deployment_variable_id, value, resource_selector, priority -FROM deployment_variable_value -WHERE deployment_variable_id = $1 -ORDER BY priority DESC, id; - --- name: UpsertDeploymentVariableValue :one -INSERT INTO deployment_variable_value (id, deployment_variable_id, value, resource_selector, priority) -VALUES ($1, $2, $3, $4, $5) -ON CONFLICT (id) DO UPDATE -SET deployment_variable_id = EXCLUDED.deployment_variable_id, value = EXCLUDED.value, - resource_selector = EXCLUDED.resource_selector, priority = EXCLUDED.priority -RETURNING *; - --- name: DeleteDeploymentVariableValue :exec -DELETE FROM deployment_variable_value WHERE id = $1; - --- name: ListDeploymentVariableValuesByWorkspaceID :many -SELECT dvv.id, dvv.deployment_variable_id, dvv.value, dvv.resource_selector, dvv.priority -FROM deployment_variable_value dvv -INNER JOIN deployment_variable dv ON dv.id = dvv.deployment_variable_id -INNER JOIN deployment d ON d.id = dv.deployment_id -WHERE d.workspace_id = $1; diff --git a/apps/workspace-engine/pkg/db/queries/resource_variables.sql b/apps/workspace-engine/pkg/db/queries/resource_variables.sql deleted file mode 100644 index 85370f574..000000000 --- a/apps/workspace-engine/pkg/db/queries/resource_variables.sql +++ /dev/null @@ -1,29 +0,0 @@ --- name: GetResourceVariable :one -SELECT resource_id, key, value -FROM resource_variable -WHERE resource_id = $1 AND key = $2; - --- name: UpsertResourceVariable :exec -INSERT INTO resource_variable (resource_id, key, value) -VALUES ($1, $2, $3) -ON CONFLICT (resource_id, key) DO UPDATE -SET value = EXCLUDED.value; - --- name: DeleteResourceVariable :exec -DELETE FROM resource_variable -WHERE resource_id = $1 AND key = $2; - --- name: ListResourceVariablesByResourceID :many -SELECT resource_id, key, value -FROM resource_variable -WHERE resource_id = $1; - --- name: DeleteResourceVariablesByResourceID :exec -DELETE FROM resource_variable -WHERE resource_id = $1; - --- name: ListResourceVariablesByWorkspaceID :many -SELECT rv.resource_id, rv.key, rv.value -FROM resource_variable rv -INNER JOIN resource r ON r.id = rv.resource_id -WHERE r.workspace_id = $1 AND r.deleted_at IS NULL; diff --git a/apps/workspace-engine/pkg/db/queries/schema.sql b/apps/workspace-engine/pkg/db/queries/schema.sql index e317258a9..68a235b1a 100644 --- a/apps/workspace-engine/pkg/db/queries/schema.sql +++ b/apps/workspace-engine/pkg/db/queries/schema.sql @@ -261,22 +261,6 @@ CREATE TABLE user_approval_record ( PRIMARY KEY (version_id, user_id, environment_id) ); -CREATE TABLE deployment_variable ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - deployment_id UUID NOT NULL REFERENCES deployment(id) ON DELETE CASCADE, - key TEXT NOT NULL, - description TEXT, - default_value JSONB -); - -CREATE TABLE deployment_variable_value ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - deployment_variable_id UUID NOT NULL REFERENCES deployment_variable(id) ON DELETE CASCADE, - value JSONB NOT NULL, - resource_selector TEXT, - priority BIGINT NOT NULL DEFAULT 0 -); - CREATE TABLE workflow ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, @@ -297,13 +281,6 @@ CREATE TABLE workflow_job ( job_id UUID NOT NULL REFERENCES job(id) ON DELETE CASCADE ); -CREATE TABLE resource_variable ( - resource_id UUID NOT NULL REFERENCES resource(id) ON DELETE CASCADE, - key TEXT NOT NULL, - value JSONB NOT NULL, - PRIMARY KEY (resource_id, key) -); - CREATE TABLE computed_deployment_resource ( deployment_id UUID NOT NULL REFERENCES deployment(id) ON DELETE CASCADE, resource_id UUID NOT NULL REFERENCES resource(id) ON DELETE CASCADE, @@ -511,6 +488,39 @@ CREATE TABLE variable_set ( updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); +CREATE TYPE variable_scope AS ENUM ('resource', 'deployment', 'job_agent'); + +CREATE TYPE variable_value_kind AS ENUM ('literal', 'ref', 'secret_ref'); + +CREATE TABLE variable ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + scope variable_scope NOT NULL, + resource_id UUID REFERENCES resource(id) ON DELETE CASCADE, + deployment_id UUID REFERENCES deployment(id) ON DELETE CASCADE, + job_agent_id UUID REFERENCES job_agent(id) ON DELETE CASCADE, + key TEXT NOT NULL, + is_sensitive BOOLEAN NOT NULL DEFAULT FALSE, + description TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE variable_value ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + variable_id UUID NOT NULL REFERENCES variable(id) ON DELETE CASCADE, + resource_selector TEXT, + priority BIGINT NOT NULL DEFAULT 0, + kind variable_value_kind NOT NULL, + literal_value JSONB, + ref_key TEXT, + ref_path TEXT[], + secret_provider TEXT, + secret_key TEXT, + secret_path TEXT[], + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + CREATE TABLE variable_set_variable ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), variable_set_id UUID NOT NULL REFERENCES variable_set(id) ON DELETE CASCADE, diff --git a/apps/workspace-engine/pkg/db/queries/variables.sql b/apps/workspace-engine/pkg/db/queries/variables.sql new file mode 100644 index 000000000..12430425a --- /dev/null +++ b/apps/workspace-engine/pkg/db/queries/variables.sql @@ -0,0 +1,102 @@ +-- name: ListVariablesWithValuesByDeploymentID :many +SELECT + v.id, + v.scope, + v.deployment_id, + v.resource_id, + v.job_agent_id, + v.key, + v.is_sensitive, + v.description, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', vv.id, + 'variableId', vv.variable_id, + 'resourceSelector', vv.resource_selector, + 'priority', vv.priority, + 'kind', vv.kind, + 'literalValue', vv.literal_value, + 'refKey', vv.ref_key, + 'refPath', vv.ref_path, + 'secretProvider', vv.secret_provider, + 'secretKey', vv.secret_key, + 'secretPath', vv.secret_path + ) + ) + FROM variable_value vv + WHERE vv.variable_id = v.id + ), + '[]'::json + ) AS values +FROM variable v +WHERE v.scope = 'deployment' AND v.deployment_id = $1; + +-- name: ListVariablesWithValuesByResourceID :many +SELECT + v.id, + v.scope, + v.deployment_id, + v.resource_id, + v.job_agent_id, + v.key, + v.is_sensitive, + v.description, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', vv.id, + 'variableId', vv.variable_id, + 'resourceSelector', vv.resource_selector, + 'priority', vv.priority, + 'kind', vv.kind, + 'literalValue', vv.literal_value, + 'refKey', vv.ref_key, + 'refPath', vv.ref_path, + 'secretProvider', vv.secret_provider, + 'secretKey', vv.secret_key, + 'secretPath', vv.secret_path + ) + ) + FROM variable_value vv + WHERE vv.variable_id = v.id + ), + '[]'::json + ) AS values +FROM variable v +WHERE v.scope = 'resource' AND v.resource_id = $1; + +-- name: ListResourceVariablesWithValuesByWorkspaceID :many +SELECT + v.id, + v.scope, + v.resource_id, + v.key, + v.is_sensitive, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', vv.id, + 'variableId', vv.variable_id, + 'resourceSelector', vv.resource_selector, + 'priority', vv.priority, + 'kind', vv.kind, + 'literalValue', vv.literal_value, + 'refKey', vv.ref_key, + 'refPath', vv.ref_path, + 'secretProvider', vv.secret_provider, + 'secretKey', vv.secret_key, + 'secretPath', vv.secret_path + ) + ) + FROM variable_value vv + WHERE vv.variable_id = v.id + ), + '[]'::json + ) AS values +FROM variable v +INNER JOIN resource r ON r.id = v.resource_id +WHERE v.scope = 'resource' AND r.workspace_id = $1 AND r.deleted_at IS NULL; diff --git a/apps/workspace-engine/pkg/db/resource_variables.sql.go b/apps/workspace-engine/pkg/db/resource_variables.sql.go deleted file mode 100644 index 7e63a835f..000000000 --- a/apps/workspace-engine/pkg/db/resource_variables.sql.go +++ /dev/null @@ -1,126 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.30.0 -// source: resource_variables.sql - -package db - -import ( - "context" - - "github.com/google/uuid" -) - -const deleteResourceVariable = `-- name: DeleteResourceVariable :exec -DELETE FROM resource_variable -WHERE resource_id = $1 AND key = $2 -` - -type DeleteResourceVariableParams struct { - ResourceID uuid.UUID - Key string -} - -func (q *Queries) DeleteResourceVariable(ctx context.Context, arg DeleteResourceVariableParams) error { - _, err := q.db.Exec(ctx, deleteResourceVariable, arg.ResourceID, arg.Key) - return err -} - -const deleteResourceVariablesByResourceID = `-- name: DeleteResourceVariablesByResourceID :exec -DELETE FROM resource_variable -WHERE resource_id = $1 -` - -func (q *Queries) DeleteResourceVariablesByResourceID(ctx context.Context, resourceID uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteResourceVariablesByResourceID, resourceID) - return err -} - -const getResourceVariable = `-- name: GetResourceVariable :one -SELECT resource_id, key, value -FROM resource_variable -WHERE resource_id = $1 AND key = $2 -` - -type GetResourceVariableParams struct { - ResourceID uuid.UUID - Key string -} - -func (q *Queries) GetResourceVariable(ctx context.Context, arg GetResourceVariableParams) (ResourceVariable, error) { - row := q.db.QueryRow(ctx, getResourceVariable, arg.ResourceID, arg.Key) - var i ResourceVariable - err := row.Scan(&i.ResourceID, &i.Key, &i.Value) - return i, err -} - -const listResourceVariablesByResourceID = `-- name: ListResourceVariablesByResourceID :many -SELECT resource_id, key, value -FROM resource_variable -WHERE resource_id = $1 -` - -func (q *Queries) ListResourceVariablesByResourceID(ctx context.Context, resourceID uuid.UUID) ([]ResourceVariable, error) { - rows, err := q.db.Query(ctx, listResourceVariablesByResourceID, resourceID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []ResourceVariable - for rows.Next() { - var i ResourceVariable - if err := rows.Scan(&i.ResourceID, &i.Key, &i.Value); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const listResourceVariablesByWorkspaceID = `-- name: ListResourceVariablesByWorkspaceID :many -SELECT rv.resource_id, rv.key, rv.value -FROM resource_variable rv -INNER JOIN resource r ON r.id = rv.resource_id -WHERE r.workspace_id = $1 AND r.deleted_at IS NULL -` - -func (q *Queries) ListResourceVariablesByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) ([]ResourceVariable, error) { - rows, err := q.db.Query(ctx, listResourceVariablesByWorkspaceID, workspaceID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []ResourceVariable - for rows.Next() { - var i ResourceVariable - if err := rows.Scan(&i.ResourceID, &i.Key, &i.Value); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const upsertResourceVariable = `-- name: UpsertResourceVariable :exec -INSERT INTO resource_variable (resource_id, key, value) -VALUES ($1, $2, $3) -ON CONFLICT (resource_id, key) DO UPDATE -SET value = EXCLUDED.value -` - -type UpsertResourceVariableParams struct { - ResourceID uuid.UUID - Key string - Value []byte -} - -func (q *Queries) UpsertResourceVariable(ctx context.Context, arg UpsertResourceVariableParams) error { - _, err := q.db.Exec(ctx, upsertResourceVariable, arg.ResourceID, arg.Key, arg.Value) - return err -} diff --git a/apps/workspace-engine/pkg/db/sqlc.yaml b/apps/workspace-engine/pkg/db/sqlc.yaml index a619b7100..849da6811 100644 --- a/apps/workspace-engine/pkg/db/sqlc.yaml +++ b/apps/workspace-engine/pkg/db/sqlc.yaml @@ -20,8 +20,7 @@ sql: - queries/changelog.sql - queries/policies.sql - queries/user_approval_records.sql - - queries/resource_variables.sql - - queries/deployment_variables.sql + - queries/variables.sql - queries/workflows.sql - queries/policy_skips.sql - queries/computed_resources.sql @@ -138,10 +137,16 @@ sql: go_type: type: "map[string]any" - # ResourceVariable - - column: "resource_variable.value" + # VariableValue + - column: "variable_value.literal_value" go_type: type: "[]byte" + - column: "variable_value.ref_path" + go_type: + type: "[]string" + - column: "variable_value.secret_path" + go_type: + type: "[]string" # VariableSet - column: "variable_set.metadata" @@ -153,16 +158,6 @@ sql: go_type: type: "[]byte" - # DeploymentVariable - - column: "deployment_variable.default_value" - go_type: - type: "[]byte" - - # DeploymentVariableValue - - column: "deployment_variable_value.value" - go_type: - type: "[]byte" - # Workflow - column: "workflow.inputs" go_type: diff --git a/apps/workspace-engine/pkg/db/variables.sql.go b/apps/workspace-engine/pkg/db/variables.sql.go new file mode 100644 index 000000000..a3f3f9652 --- /dev/null +++ b/apps/workspace-engine/pkg/db/variables.sql.go @@ -0,0 +1,239 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: variables.sql + +package db + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const listResourceVariablesWithValuesByWorkspaceID = `-- name: ListResourceVariablesWithValuesByWorkspaceID :many +SELECT + v.id, + v.scope, + v.resource_id, + v.key, + v.is_sensitive, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', vv.id, + 'variableId', vv.variable_id, + 'resourceSelector', vv.resource_selector, + 'priority', vv.priority, + 'kind', vv.kind, + 'literalValue', vv.literal_value, + 'refKey', vv.ref_key, + 'refPath', vv.ref_path, + 'secretProvider', vv.secret_provider, + 'secretKey', vv.secret_key, + 'secretPath', vv.secret_path + ) + ) + FROM variable_value vv + WHERE vv.variable_id = v.id + ), + '[]'::json + ) AS values +FROM variable v +INNER JOIN resource r ON r.id = v.resource_id +WHERE v.scope = 'resource' AND r.workspace_id = $1 AND r.deleted_at IS NULL +` + +type ListResourceVariablesWithValuesByWorkspaceIDRow struct { + ID uuid.UUID + Scope VariableScope + ResourceID uuid.UUID + Key string + IsSensitive bool + Values []byte +} + +func (q *Queries) ListResourceVariablesWithValuesByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) ([]ListResourceVariablesWithValuesByWorkspaceIDRow, error) { + rows, err := q.db.Query(ctx, listResourceVariablesWithValuesByWorkspaceID, workspaceID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListResourceVariablesWithValuesByWorkspaceIDRow + for rows.Next() { + var i ListResourceVariablesWithValuesByWorkspaceIDRow + if err := rows.Scan( + &i.ID, + &i.Scope, + &i.ResourceID, + &i.Key, + &i.IsSensitive, + &i.Values, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listVariablesWithValuesByDeploymentID = `-- name: ListVariablesWithValuesByDeploymentID :many +SELECT + v.id, + v.scope, + v.deployment_id, + v.resource_id, + v.job_agent_id, + v.key, + v.is_sensitive, + v.description, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', vv.id, + 'variableId', vv.variable_id, + 'resourceSelector', vv.resource_selector, + 'priority', vv.priority, + 'kind', vv.kind, + 'literalValue', vv.literal_value, + 'refKey', vv.ref_key, + 'refPath', vv.ref_path, + 'secretProvider', vv.secret_provider, + 'secretKey', vv.secret_key, + 'secretPath', vv.secret_path + ) + ) + FROM variable_value vv + WHERE vv.variable_id = v.id + ), + '[]'::json + ) AS values +FROM variable v +WHERE v.scope = 'deployment' AND v.deployment_id = $1 +` + +type ListVariablesWithValuesByDeploymentIDRow struct { + ID uuid.UUID + Scope VariableScope + DeploymentID uuid.UUID + ResourceID uuid.UUID + JobAgentID uuid.UUID + Key string + IsSensitive bool + Description pgtype.Text + Values []byte +} + +func (q *Queries) ListVariablesWithValuesByDeploymentID(ctx context.Context, deploymentID uuid.UUID) ([]ListVariablesWithValuesByDeploymentIDRow, error) { + rows, err := q.db.Query(ctx, listVariablesWithValuesByDeploymentID, deploymentID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListVariablesWithValuesByDeploymentIDRow + for rows.Next() { + var i ListVariablesWithValuesByDeploymentIDRow + if err := rows.Scan( + &i.ID, + &i.Scope, + &i.DeploymentID, + &i.ResourceID, + &i.JobAgentID, + &i.Key, + &i.IsSensitive, + &i.Description, + &i.Values, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listVariablesWithValuesByResourceID = `-- name: ListVariablesWithValuesByResourceID :many +SELECT + v.id, + v.scope, + v.deployment_id, + v.resource_id, + v.job_agent_id, + v.key, + v.is_sensitive, + v.description, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', vv.id, + 'variableId', vv.variable_id, + 'resourceSelector', vv.resource_selector, + 'priority', vv.priority, + 'kind', vv.kind, + 'literalValue', vv.literal_value, + 'refKey', vv.ref_key, + 'refPath', vv.ref_path, + 'secretProvider', vv.secret_provider, + 'secretKey', vv.secret_key, + 'secretPath', vv.secret_path + ) + ) + FROM variable_value vv + WHERE vv.variable_id = v.id + ), + '[]'::json + ) AS values +FROM variable v +WHERE v.scope = 'resource' AND v.resource_id = $1 +` + +type ListVariablesWithValuesByResourceIDRow struct { + ID uuid.UUID + Scope VariableScope + DeploymentID uuid.UUID + ResourceID uuid.UUID + JobAgentID uuid.UUID + Key string + IsSensitive bool + Description pgtype.Text + Values []byte +} + +func (q *Queries) ListVariablesWithValuesByResourceID(ctx context.Context, resourceID uuid.UUID) ([]ListVariablesWithValuesByResourceIDRow, error) { + rows, err := q.db.Query(ctx, listVariablesWithValuesByResourceID, resourceID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListVariablesWithValuesByResourceIDRow + for rows.Next() { + var i ListVariablesWithValuesByResourceIDRow + if err := rows.Scan( + &i.ID, + &i.Scope, + &i.DeploymentID, + &i.ResourceID, + &i.JobAgentID, + &i.Key, + &i.IsSensitive, + &i.Description, + &i.Values, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/apps/workspace-engine/pkg/oapi/oapi.gen.go b/apps/workspace-engine/pkg/oapi/oapi.gen.go index 90b569b33..a56502d7e 100644 --- a/apps/workspace-engine/pkg/oapi/oapi.gen.go +++ b/apps/workspace-engine/pkg/oapi/oapi.gen.go @@ -332,11 +332,10 @@ type DeploymentDependencyRule struct { // DeploymentVariable defines model for DeploymentVariable. type DeploymentVariable struct { - DefaultValue *LiteralValue `json:"defaultValue,omitempty"` - DeploymentId string `json:"deploymentId"` - Description *string `json:"description,omitempty"` - Id string `json:"id"` - Key string `json:"key"` + DeploymentId string `json:"deploymentId"` + Description *string `json:"description,omitempty"` + Id string `json:"id"` + Key string `json:"key"` } // DeploymentVariableValue defines model for DeploymentVariableValue. @@ -1052,8 +1051,12 @@ type ResourceSummary struct { // ResourceVariable defines model for ResourceVariable. type ResourceVariable struct { Key string `json:"key"` + Priority int64 `json:"priority"` ResourceId string `json:"resourceId"` - Value Value `json:"value"` + + // ResourceSelector A CEL expression to select which resources this value applies to + ResourceSelector *string `json:"resourceSelector,omitempty"` + Value Value `json:"value"` } // ResourceVariablesBulkUpdateEvent defines model for ResourceVariablesBulkUpdateEvent. diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go index e8369b675..077567e69 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go @@ -260,19 +260,18 @@ func TestPostgresGetter_GetDeploymentVariables(t *testing.T) { t.Run("returns variable with values", func(t *testing.T) { varID := uuid.New() - defaultVal, _ := json.Marshal("default-value") _, err := pool.Exec(ctx, - `INSERT INTO deployment_variable (id, deployment_id, key, description, default_value) - VALUES ($1, $2, $3, $4, $5)`, - varID, f.deploymentID, "IMAGE_TAG", "The image tag", defaultVal) + `INSERT INTO variable (id, scope, deployment_id, key, description) + VALUES ($1, 'deployment', $2, $3, $4)`, + varID, f.deploymentID, "IMAGE_TAG", "The image tag") require.NoError(t, err) valID := uuid.New() valData, _ := json.Marshal("override-value") _, err = pool.Exec( ctx, - `INSERT INTO deployment_variable_value (id, deployment_variable_id, value, resource_selector, priority) - VALUES ($1, $2, $3, $4, $5)`, + `INSERT INTO variable_value (id, variable_id, literal_value, resource_selector, priority, kind) + VALUES ($1, $2, $3, $4, $5, 'literal')`, valID, varID, valData, @@ -287,7 +286,6 @@ func TestPostgresGetter_GetDeploymentVariables(t *testing.T) { assert.Len(t, vars, 1) assert.Equal(t, "IMAGE_TAG", vars[0].Variable.Key) assert.Equal(t, f.deploymentID.String(), vars[0].Variable.DeploymentId) - require.NotNil(t, vars[0].Variable.DefaultValue) desc := "The image tag" assert.Equal(t, &desc, vars[0].Variable.Description) @@ -299,11 +297,10 @@ func TestPostgresGetter_GetDeploymentVariables(t *testing.T) { t.Run("variable with no values returns empty values slice", func(t *testing.T) { varID := uuid.New() - defaultVal, _ := json.Marshal("solo-default") _, err := pool.Exec(ctx, - `INSERT INTO deployment_variable (id, deployment_id, key, description, default_value) - VALUES ($1, $2, $3, $4, $5)`, - varID, f.deploymentID, "STANDALONE_VAR", "no overrides", defaultVal) + `INSERT INTO variable (id, scope, deployment_id, key, description) + VALUES ($1, 'deployment', $2, $3, $4)`, + varID, f.deploymentID, "STANDALONE_VAR", "no overrides") require.NoError(t, err) vars, err := getter.GetDeploymentVariables(ctx, f.deploymentID.String()) @@ -400,34 +397,41 @@ func TestPostgresGetter_GetResourceVariables(t *testing.T) { assert.Empty(t, vars) }) - t.Run("returns variables keyed by their key", func(t *testing.T) { - valData, _ := json.Marshal("my-resource-value") + insertResourceVar := func(key string, literal []byte) { + varID := uuid.New() _, err := pool.Exec(ctx, - `INSERT INTO resource_variable (resource_id, key, value) VALUES ($1, $2, $3)`, - f.resourceID, "REGION", valData) + `INSERT INTO variable (id, scope, resource_id, key) VALUES ($1, 'resource', $2, $3)`, + varID, f.resourceID, key) + require.NoError(t, err) + _, err = pool.Exec( + ctx, + `INSERT INTO variable_value (variable_id, priority, kind, literal_value) VALUES ($1, 0, 'literal', $2)`, + varID, + literal, + ) require.NoError(t, err) + } + + t.Run("returns variables keyed by their key", func(t *testing.T) { + valData, _ := json.Marshal("my-resource-value") + insertResourceVar("REGION", valData) vars, err := getter.GetResourceVariables(ctx, f.resourceID.String()) require.NoError(t, err) assert.Len(t, vars, 1) - rv, ok := vars["REGION"] + rvs, ok := vars["REGION"] require.True(t, ok) - assert.Equal(t, f.resourceID.String(), rv.ResourceId) - assert.Equal(t, "REGION", rv.Key) + require.Len(t, rvs, 1) + assert.Equal(t, f.resourceID.String(), rvs[0].ResourceId) + assert.Equal(t, "REGION", rvs[0].Key) }) t.Run("returns multiple variables each under their own key", func(t *testing.T) { valA, _ := json.Marshal("us-east-1") valB, _ := json.Marshal("prod") - _, err := pool.Exec(ctx, - `INSERT INTO resource_variable (resource_id, key, value) VALUES ($1, $2, $3)`, - f.resourceID, "AWS_REGION", valA) - require.NoError(t, err) - _, err = pool.Exec(ctx, - `INSERT INTO resource_variable (resource_id, key, value) VALUES ($1, $2, $3)`, - f.resourceID, "STAGE", valB) - require.NoError(t, err) + insertResourceVar("AWS_REGION", valA) + insertResourceVar("STAGE", valB) vars, err := getter.GetResourceVariables(ctx, f.resourceID.String()) require.NoError(t, err) diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go index 66a1161ec..d9bc94dd3 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go @@ -24,7 +24,7 @@ type mockReconcileGetter struct { policySkips []*oapi.PolicySkip deployVars []oapi.DeploymentVariableWithValues - resourceVar map[string]oapi.ResourceVariable + resourceVar map[string][]oapi.ResourceVariable rtExists bool } @@ -74,7 +74,7 @@ func (m *mockReconcileGetter) GetDeploymentVariables( func (m *mockReconcileGetter) GetResourceVariables( _ context.Context, _ string, -) (map[string]oapi.ResourceVariable, error) { +) (map[string][]oapi.ResourceVariable, error) { return m.resourceVar, nil } diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters.go index 7df1e2408..0474ddb67 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters.go @@ -19,7 +19,7 @@ type Getter interface { GetResourceVariables( ctx context.Context, resourceID string, - ) (map[string]oapi.ResourceVariable, error) + ) (map[string][]oapi.ResourceVariable, error) GetVariableSetsWithVariables( ctx context.Context, workspaceID uuid.UUID, diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go index d89dc69e0..fe5275810 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go @@ -2,6 +2,7 @@ package variableresolver import ( "context" + "encoding/json" "fmt" "github.com/google/uuid" @@ -115,25 +116,29 @@ func (g *PostgresGetter) GetDeploymentVariables( if err != nil { return nil, fmt.Errorf("parse deployment id: %w", err) } - vars, err := q.ListDeploymentVariablesByDeploymentID(ctx, deploymentIDUUID) + rows, err := q.ListVariablesWithValuesByDeploymentID(ctx, deploymentIDUUID) if err != nil { return nil, fmt.Errorf("list deployment variables for %s: %w", deploymentID, err) } - result := make([]oapi.DeploymentVariableWithValues, 0, len(vars)) - for _, v := range vars { - values, err := q.ListDeploymentVariableValuesByVariableID(ctx, v.ID) - if err != nil { - return nil, fmt.Errorf("list values for variable %s: %w", v.ID, err) + result := make([]oapi.DeploymentVariableWithValues, 0, len(rows)) + for _, row := range rows { + var aggs []db.VariableValueAggRow + if err := json.Unmarshal(row.Values, &aggs); err != nil { + return nil, fmt.Errorf("unmarshal values for variable %s: %w", row.ID, err) } - oapiValues := make([]oapi.DeploymentVariableValue, 0, len(values)) - for _, val := range values { - oapiValues = append(oapiValues, db.ToOapiDeploymentVariableValue(val)) + oapiValues := make([]oapi.DeploymentVariableValue, 0, len(aggs)) + for _, a := range aggs { + val, err := db.ToOapiDeploymentVariableValueFromAgg(a) + if err != nil { + return nil, fmt.Errorf("map value %s: %w", a.ID, err) + } + oapiValues = append(oapiValues, val) } result = append(result, oapi.DeploymentVariableWithValues{ - Variable: db.ToOapiDeploymentVariable(v), + Variable: db.ToOapiDeploymentVariable(row), Values: oapiValues, }) } @@ -143,19 +148,27 @@ func (g *PostgresGetter) GetDeploymentVariables( func (g *PostgresGetter) GetResourceVariables( ctx context.Context, resourceID string, -) (map[string]oapi.ResourceVariable, error) { +) (map[string][]oapi.ResourceVariable, error) { resourceIDUUID, err := uuid.Parse(resourceID) if err != nil { return nil, fmt.Errorf("parse resource id: %w", err) } - rows, err := db.GetQueries(ctx).ListResourceVariablesByResourceID(ctx, resourceIDUUID) + rows, err := db.GetQueries(ctx).ListVariablesWithValuesByResourceID(ctx, resourceIDUUID) if err != nil { return nil, fmt.Errorf("list resource variables for %s: %w", resourceID, err) } - result := make(map[string]oapi.ResourceVariable, len(rows)) + result := make(map[string][]oapi.ResourceVariable, len(rows)) for _, row := range rows { - result[row.Key] = db.ToOapiResourceVariable(row) + var aggs []db.VariableValueAggRow + if err := json.Unmarshal(row.Values, &aggs); err != nil { + return nil, fmt.Errorf("unmarshal values for variable %s: %w", row.ID, err) + } + rvs, err := db.ToOapiResourceVariablesFromAgg(row.ResourceID, row.Key, aggs) + if err != nil { + return nil, fmt.Errorf("map resource variable %s: %w", row.ID, err) + } + result[row.Key] = rvs } return result, nil } @@ -342,12 +355,37 @@ func resourceRowToMap( return m } +// effectiveValue picks the null-selector, highest-priority value for +// projecting a resource variable into the CEL evaluation context. Selector +// matching is not available here because the CEL context is built without a +// target resource. +func effectiveValue(aggs []db.VariableValueAggRow) (oapi.Value, bool) { + var best *db.VariableValueAggRow + for i := range aggs { + a := &aggs[i] + if a.ResourceSelector != nil && *a.ResourceSelector != "" { + continue + } + if best == nil || a.Priority > best.Priority { + best = a + } + } + if best == nil { + return oapi.Value{}, false + } + v, err := db.ToOapiDeploymentVariableValueFromAgg(*best) + if err != nil { + return oapi.Value{}, false + } + return v.Value, true +} + func loadResourceVariables( ctx context.Context, q *db.Queries, resourceID uuid.UUID, ) (map[string]oapi.Value, error) { - rows, err := q.ListResourceVariablesByResourceID(ctx, resourceID) + rows, err := q.ListVariablesWithValuesByResourceID(ctx, resourceID) if err != nil { return nil, fmt.Errorf("list variables for resource %s: %w", resourceID, err) } @@ -356,8 +394,13 @@ func loadResourceVariables( } vars := make(map[string]oapi.Value, len(rows)) for _, row := range rows { - v := db.ToOapiResourceVariable(row) - vars[v.Key] = v.Value + var aggs []db.VariableValueAggRow + if err := json.Unmarshal(row.Values, &aggs); err != nil { + return nil, fmt.Errorf("unmarshal values for variable %s: %w", row.ID, err) + } + if v, ok := effectiveValue(aggs); ok { + vars[row.Key] = v + } } return vars, nil } @@ -367,19 +410,26 @@ func loadResourceVariablesByWorkspace( q *db.Queries, workspaceID uuid.UUID, ) (map[uuid.UUID]map[string]oapi.Value, error) { - rows, err := q.ListResourceVariablesByWorkspaceID(ctx, workspaceID) + rows, err := q.ListResourceVariablesWithValuesByWorkspaceID(ctx, workspaceID) if err != nil { return nil, fmt.Errorf("list variables for workspace %s: %w", workspaceID, err) } result := make(map[uuid.UUID]map[string]oapi.Value) for _, row := range rows { - v := db.ToOapiResourceVariable(row) + var aggs []db.VariableValueAggRow + if err := json.Unmarshal(row.Values, &aggs); err != nil { + return nil, fmt.Errorf("unmarshal values for variable %s: %w", row.ID, err) + } + v, ok := effectiveValue(aggs) + if !ok { + continue + } m := result[row.ResourceID] if m == nil { m = make(map[string]oapi.Value) result[row.ResourceID] = m } - m[v.Key] = v.Value + m[row.Key] = v } return result, nil } diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve.go index be9c164d3..ab5a5290c 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve.go @@ -104,7 +104,7 @@ func Resolve( entity := NewResourceEntity(scope.Resource) resolved := make(map[string]oapi.LiteralValue, len(deploymentVars)) - var fromResource, fromValue, fromVariableSet, fromDefault int + var fromResource, fromValue, fromVariableSet int for _, dv := range deploymentVars { key := dv.Variable.Key @@ -115,6 +115,7 @@ func Resolve( resourceID, key, resourceVars, + scope.Resource, entity, ); lv != nil { resolved[key] = *lv @@ -148,10 +149,6 @@ func Resolve( continue } - if dv.Variable.DefaultValue != nil { - resolved[key] = *dv.Variable.DefaultValue - fromDefault++ - } } span.SetAttributes( @@ -159,7 +156,6 @@ func Resolve( attribute.Int("resolved.from_resource", fromResource), attribute.Int("resolved.from_value", fromValue), attribute.Int("resolved.from_variable_set", fromVariableSet), - attribute.Int("resolved.from_default", fromDefault), ) return resolved, nil } @@ -246,25 +242,48 @@ func (r *realtimeResolver) ResolveRelated( return result, nil } -// resolveFromResource checks if a resource variable exists for the given key -// and resolves it. +// resolveFromResource finds the highest-priority resource-variable value +// whose resource selector matches the target resource, then resolves it. +// A nil/empty selector always matches. func resolveFromResource( ctx context.Context, resolver RelatedEntityResolver, resourceID string, key string, - resourceVars map[string]oapi.ResourceVariable, + resourceVars map[string][]oapi.ResourceVariable, + resource *oapi.Resource, entity *oapi.RelatableEntity, ) *oapi.LiteralValue { - rv, ok := resourceVars[key] - if !ok { + candidates, ok := resourceVars[key] + if !ok || len(candidates) == 0 { return nil } - lv, err := ResolveValue(ctx, resolver, resourceID, entity, &rv.Value) - if err != nil { + + matched := make([]oapi.ResourceVariable, 0, len(candidates)) + for _, rv := range candidates { + if rv.ResourceSelector == nil || *rv.ResourceSelector == "" { + matched = append(matched, rv) + continue + } + if ok, _ := selector.Match(ctx, *rv.ResourceSelector, resource); ok { + matched = append(matched, rv) + } + } + if len(matched) == 0 { return nil } - return lv + + sort.Slice(matched, func(i, j int) bool { + return matched[i].Priority > matched[j].Priority + }) + + for _, rv := range matched { + lv, err := ResolveValue(ctx, resolver, resourceID, entity, &rv.Value) + if err == nil && lv != nil { + return lv + } + } + return nil } // resolveFromValues finds the highest-priority deployment variable value diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go index 0e546bfab..a7979da87 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go @@ -33,12 +33,36 @@ func (m *mockResolver) ResolveRelated( type mockGetter struct { deploymentVars []oapi.DeploymentVariableWithValues - resourceVars map[string]oapi.ResourceVariable + resourceVars map[string][]oapi.ResourceVariable variableSets []oapi.VariableSetWithVariables rules []eval.Rule candidates map[string][]eval.EntityData } +// defaultOnlyVar synthesizes a DeploymentVariableWithValues whose only value +// is a null-selector, priority-0 literal — the post-migration substitute for +// the dropped `deployment_variable.default_value` column. +func defaultOnlyVar( + key string, + lv *oapi.LiteralValue, + deploymentID string, +) oapi.DeploymentVariableWithValues { + depVarID := uuid.New().String() + return oapi.DeploymentVariableWithValues{ + Variable: oapi.DeploymentVariable{ + Id: depVarID, + DeploymentId: deploymentID, + Key: key, + }, + Values: []oapi.DeploymentVariableValue{{ + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: *oapi.NewValueFromLiteral(lv), + Priority: 0, + }}, + } +} + func (m *mockGetter) GetDeploymentVariables( _ context.Context, _ string, @@ -49,7 +73,7 @@ func (m *mockGetter) GetDeploymentVariables( func (m *mockGetter) GetResourceVariables( _ context.Context, _ string, -) (map[string]oapi.ResourceVariable, error) { +) (map[string][]oapi.ResourceVariable, error) { return m.resourceVars, nil } @@ -345,6 +369,60 @@ func TestResolveValue_Reference_BadPath(t *testing.T) { // Resolve tests — priority: resource var wins // --------------------------------------------------------------------------- +// TestResolve_ResourceVariableSelectorPriority asserts the post-migration +// behavior: resource variables carry a resource selector + priority, and the +// highest-priority matching value wins over a lower-priority null-selector +// fallback. +func TestResolve_ResourceVariableSelectorPriority(t *testing.T) { + scope := newScope() + scope.Resource.Metadata = map[string]string{"region": "us-east-1"} + + matchingSelector := `resource.metadata.region == "us-east-1"` + depVarID := uuid.New().String() + + getter := &mockGetter{ + deploymentVars: []oapi.DeploymentVariableWithValues{{ + Variable: oapi.DeploymentVariable{ + Id: depVarID, + DeploymentId: scope.Deployment.Id, + Key: "tier", + }, + Values: []oapi.DeploymentVariableValue{}, + }}, + resourceVars: map[string][]oapi.ResourceVariable{ + "tier": { + { + Key: "tier", + ResourceId: scope.Resource.Id, + Value: literalStringValue("fallback"), + Priority: 0, + ResourceSelector: nil, + }, + { + Key: "tier", + ResourceId: scope.Resource.Id, + Value: literalStringValue("winner"), + Priority: 10, + ResourceSelector: &matchingSelector, + }, + }, + }, + } + + resolved, err := Resolve( + context.Background(), + getter, + scope, + scope.Deployment.Id, + scope.Resource.Id, + ) + require.NoError(t, err) + require.Contains(t, resolved, "tier") + s, err := resolved["tier"].AsStringValue() + require.NoError(t, err) + assert.Equal(t, "winner", s) +} + func TestResolve_ResourceVarWins(t *testing.T) { scope := newScope() depVarID := uuid.New().String() @@ -355,7 +433,6 @@ func TestResolve_ResourceVarWins(t *testing.T) { Id: depVarID, DeploymentId: scope.Deployment.Id, Key: "region", - DefaultValue: oapi.NewLiteralValue("default-region"), }, Values: []oapi.DeploymentVariableValue{{ Id: uuid.New().String(), @@ -364,12 +441,12 @@ func TestResolve_ResourceVarWins(t *testing.T) { Priority: 1, }}, }}, - resourceVars: map[string]oapi.ResourceVariable{ - "region": { + resourceVars: map[string][]oapi.ResourceVariable{ + "region": {{ Key: "region", ResourceId: scope.Resource.Id, Value: literalStringValue("resource-region"), - }, + }}, }, } @@ -401,7 +478,6 @@ func TestResolve_DeploymentVariableValueUsedWhenNoResourceVar(t *testing.T) { Id: depVarID, DeploymentId: scope.Deployment.Id, Key: "image", - DefaultValue: oapi.NewLiteralValue("default-image"), }, Values: []oapi.DeploymentVariableValue{{ Id: uuid.New().String(), @@ -410,7 +486,7 @@ func TestResolve_DeploymentVariableValueUsedWhenNoResourceVar(t *testing.T) { Priority: 10, }}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, } resolved, err := Resolve( @@ -433,18 +509,23 @@ func TestResolve_DeploymentVariableValueUsedWhenNoResourceVar(t *testing.T) { func TestResolve_DefaultValueFallback(t *testing.T) { scope := newScope() + depVarID := uuid.New().String() getter := &mockGetter{ deploymentVars: []oapi.DeploymentVariableWithValues{{ Variable: oapi.DeploymentVariable{ - Id: uuid.New().String(), + Id: depVarID, DeploymentId: scope.Deployment.Id, Key: "replicas", - DefaultValue: oapi.NewLiteralValue(3), }, - Values: []oapi.DeploymentVariableValue{}, + Values: []oapi.DeploymentVariableValue{{ + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: *oapi.NewValueFromLiteral(oapi.NewLiteralValue(3)), + Priority: 0, + }}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, } resolved, err := Resolve( @@ -477,7 +558,7 @@ func TestResolve_NoMatchNoDefault_KeyAbsent(t *testing.T) { }, Values: []oapi.DeploymentVariableValue{}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, } resolved, err := Resolve( @@ -527,7 +608,7 @@ func TestResolve_HighestPriorityValueWins(t *testing.T) { }, }, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, } resolved, err := Resolve( @@ -552,35 +633,11 @@ func TestResolve_MultipleVariables(t *testing.T) { getter := &mockGetter{ deploymentVars: []oapi.DeploymentVariableWithValues{ - { - Variable: oapi.DeploymentVariable{ - Id: uuid.New().String(), - DeploymentId: scope.Deployment.Id, - Key: "region", - DefaultValue: oapi.NewLiteralValue("us-west-2"), - }, - Values: []oapi.DeploymentVariableValue{}, - }, - { - Variable: oapi.DeploymentVariable{ - Id: uuid.New().String(), - DeploymentId: scope.Deployment.Id, - Key: "replicas", - DefaultValue: oapi.NewLiteralValue(2), - }, - Values: []oapi.DeploymentVariableValue{}, - }, - { - Variable: oapi.DeploymentVariable{ - Id: uuid.New().String(), - DeploymentId: scope.Deployment.Id, - Key: "debug", - DefaultValue: oapi.NewLiteralValue(false), - }, - Values: []oapi.DeploymentVariableValue{}, - }, + defaultOnlyVar("region", oapi.NewLiteralValue("us-west-2"), scope.Deployment.Id), + defaultOnlyVar("replicas", oapi.NewLiteralValue(2), scope.Deployment.Id), + defaultOnlyVar("debug", oapi.NewLiteralValue(false), scope.Deployment.Id), }, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, } resolved, err := Resolve( @@ -643,12 +700,12 @@ func TestResolve_ResourceVar_WithReference(t *testing.T) { Key: "db_host", }, }}, - resourceVars: map[string]oapi.ResourceVariable{ - "db_host": { + resourceVars: map[string][]oapi.ResourceVariable{ + "db_host": {{ Key: "db_host", ResourceId: scope.Resource.Id, Value: referenceValue("database", "metadata", "host"), - }, + }}, }, rules: []eval.Rule{ { @@ -730,7 +787,7 @@ func TestResolve_DeploymentVarValue_WithReference(t *testing.T) { Priority: 1, }}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, rules: []eval.Rule{ { ID: ruleID, @@ -827,7 +884,7 @@ func TestResolve_MixedLiteralAndReference(t *testing.T) { }}, }, }, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, rules: []eval.Rule{ { ID: ruleID, @@ -908,12 +965,12 @@ func TestResolve_ResourceVarRefFails_FallsToDeploymentValue(t *testing.T) { Priority: 1, }}, }}, - resourceVars: map[string]oapi.ResourceVariable{ - "db_host": { + resourceVars: map[string][]oapi.ResourceVariable{ + "db_host": {{ Key: "db_host", ResourceId: scope.Resource.Id, Value: referenceValue("nonexistent_ref", "name"), - }, + }}, }, rules: []eval.Rule{}, } @@ -1019,7 +1076,7 @@ func TestResolve_VariableSet_SimpleInjection(t *testing.T) { }, Values: []oapi.DeploymentVariableValue{}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, variableSets: []oapi.VariableSetWithVariables{ makeVariableSet( "prod-defaults", @@ -1063,12 +1120,12 @@ func TestResolve_VariableSet_DoesNotOverwriteResourceVar(t *testing.T) { }, Values: []oapi.DeploymentVariableValue{}, }}, - resourceVars: map[string]oapi.ResourceVariable{ - "log_level": { + resourceVars: map[string][]oapi.ResourceVariable{ + "log_level": {{ Key: "log_level", ResourceId: scope.Resource.Id, Value: literalStringValue("debug"), - }, + }}, }, variableSets: []oapi.VariableSetWithVariables{ makeVariableSet( @@ -1119,7 +1176,7 @@ func TestResolve_VariableSet_DoesNotOverwriteDeploymentVarValue(t *testing.T) { Priority: 1, }}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, variableSets: []oapi.VariableSetWithVariables{ makeVariableSet( "prod-defaults", @@ -1163,7 +1220,7 @@ func TestResolve_VariableSet_HighestPriorityWins(t *testing.T) { }, Values: []oapi.DeploymentVariableValue{}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, variableSets: []oapi.VariableSetWithVariables{ makeVariableSet( "low-priority", @@ -1223,7 +1280,7 @@ func TestResolve_VariableSet_UnrelatedDoNotMatch(t *testing.T) { }, Values: []oapi.DeploymentVariableValue{}, }}, - resourceVars: map[string]oapi.ResourceVariable{}, + resourceVars: map[string][]oapi.ResourceVariable{}, variableSets: []oapi.VariableSetWithVariables{ makeVariableSet( "prod-only", diff --git a/apps/workspace-engine/test/controllers/harness/mocks.go b/apps/workspace-engine/test/controllers/harness/mocks.go index 4ef0ea080..f617b7d66 100644 --- a/apps/workspace-engine/test/controllers/harness/mocks.go +++ b/apps/workspace-engine/test/controllers/harness/mocks.go @@ -117,7 +117,7 @@ type DesiredReleaseGetter struct { PolicySkips []*oapi.PolicySkip DeploymentVars []oapi.DeploymentVariableWithValues - ResourceVars map[string]oapi.ResourceVariable + ResourceVars map[string][]oapi.ResourceVariable VariableSets []oapi.VariableSetWithVariables RelationshipRules []eval.Rule Candidates map[string][]eval.EntityData @@ -222,7 +222,7 @@ func (g *DesiredReleaseGetter) GetDeploymentVariables( func (g *DesiredReleaseGetter) GetResourceVariables( _ context.Context, _ string, -) (map[string]oapi.ResourceVariable, error) { +) (map[string][]oapi.ResourceVariable, error) { return g.ResourceVars, nil } diff --git a/apps/workspace-engine/test/controllers/harness/pipeline.go b/apps/workspace-engine/test/controllers/harness/pipeline.go index e49984654..bd63e027d 100644 --- a/apps/workspace-engine/test/controllers/harness/pipeline.go +++ b/apps/workspace-engine/test/controllers/harness/pipeline.go @@ -76,7 +76,7 @@ type ScenarioState struct { JobAgents []oapi.JobAgent DeploymentVars []oapi.DeploymentVariableWithValues - ResourceVars map[string]oapi.ResourceVariable + ResourceVars map[string][]oapi.ResourceVariable RelationshipRules []eval.Rule Candidates map[string][]eval.EntityData } diff --git a/apps/workspace-engine/test/controllers/harness/pipeline_opts.go b/apps/workspace-engine/test/controllers/harness/pipeline_opts.go index e53196d58..56abe565d 100644 --- a/apps/workspace-engine/test/controllers/harness/pipeline_opts.go +++ b/apps/workspace-engine/test/controllers/harness/pipeline_opts.go @@ -512,10 +512,20 @@ func WithDeploymentVariable(key string, opts ...DeploymentVarOption) PipelineOpt } } -// DefaultValue sets the default literal value on a deployment variable. +// DefaultValue appends a null-selector, negative-priority literal value to +// the deployment variable. The negative priority ensures any other value +// (including WithVariableValue's default priority 0) shadows it, matching +// the pre-migration semantics of `deployment_variable.default_value` being +// a last-resort fallback. func DefaultValue(val any) DeploymentVarOption { return func(dv *oapi.DeploymentVariableWithValues) { - dv.Variable.DefaultValue = oapi.NewLiteralValue(val) + lv := oapi.NewLiteralValue(val) + dv.Values = append(dv.Values, oapi.DeploymentVariableValue{ + Id: uuid.New().String(), + DeploymentVariableId: dv.Variable.Id, + Value: *oapi.NewValueFromLiteral(lv), + Priority: -1, + }) } } @@ -550,20 +560,23 @@ func ValueSelector(cel string) VariableValueOption { // WithResourceVariable adds a resource variable to the scenario. The variable // is keyed by the given key and applies to the first resource in the scenario. +// The value uses null selector + priority 0 (equivalent to the old flat +// key/value model). func WithResourceVariable(key string, value oapi.Value) PipelineOption { return func(sc *ScenarioState) { if sc.ResourceVars == nil { - sc.ResourceVars = make(map[string]oapi.ResourceVariable) + sc.ResourceVars = make(map[string][]oapi.ResourceVariable) } resourceID := "" if len(sc.Resources) > 0 { resourceID = sc.Resources[0].ID.String() } - sc.ResourceVars[key] = oapi.ResourceVariable{ + sc.ResourceVars[key] = append(sc.ResourceVars[key], oapi.ResourceVariable{ Key: key, ResourceId: resourceID, Value: value, - } + Priority: 0, + }) } } diff --git a/apps/workspace-engine/test/controllers/variable_test.go b/apps/workspace-engine/test/controllers/variable_test.go index 3db8ccf1b..c518bb82d 100644 --- a/apps/workspace-engine/test/controllers/variable_test.go +++ b/apps/workspace-engine/test/controllers/variable_test.go @@ -350,14 +350,21 @@ func TestVariable_Dynamic_ChangeVariableBetweenRuns(t *testing.T) { p.AssertReleaseCreated(t) p.AssertReleaseVariableEquals(t, 0, "image", "nginx:1.0") - // Change the default value and re-run. + // Change the default value and re-run. A null-selector priority-0 value is + // the post-migration substitute for the dropped `default_value` column. + depVarID := uuid.New().String() p.ReleaseGetter.DeploymentVars = []oapi.DeploymentVariableWithValues{{ Variable: oapi.DeploymentVariable{ - Id: uuid.New().String(), + Id: depVarID, DeploymentId: p.Scenario.DeploymentID.String(), Key: "image", - DefaultValue: oapi.NewLiteralValue("nginx:2.0"), }, + Values: []oapi.DeploymentVariableValue{{ + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: *oapi.NewValueFromLiteral(oapi.NewLiteralValue("nginx:2.0")), + Priority: 0, + }}, }} p.EnqueueSelectorEval() @@ -385,12 +392,12 @@ func TestVariable_Dynamic_AddResourceVarOverride(t *testing.T) { p.AssertReleaseVariableEquals(t, 0, "region", "us-west-2") // Round 2: add resource variable override. - p.ReleaseGetter.ResourceVars = map[string]oapi.ResourceVariable{ - "region": { + p.ReleaseGetter.ResourceVars = map[string][]oapi.ResourceVariable{ + "region": {{ Key: "region", ResourceId: p.Scenario.Resources[0].ID.String(), Value: LiteralValue("eu-central-1"), - }, + }}, } p.EnqueueSelectorEval() diff --git a/packages/db/drizzle/0188_backfill_variables.sql b/packages/db/drizzle/0188_backfill_variables.sql new file mode 100644 index 000000000..d97e1a717 --- /dev/null +++ b/packages/db/drizzle/0188_backfill_variables.sql @@ -0,0 +1,53 @@ +INSERT INTO "variable" (id, scope, deployment_id, key, is_sensitive, description) +SELECT + dv.id, + 'deployment'::variable_scope, + dv.deployment_id, + dv.key, + false, + dv.description +FROM deployment_variable dv +ON CONFLICT (id) DO NOTHING; +--> statement-breakpoint + +INSERT INTO "variable_value" ( + id, variable_id, resource_selector, priority, kind, literal_value +) +SELECT + dvv.id, + dvv.deployment_variable_id, + dvv.resource_selector, + dvv.priority, + 'literal'::variable_value_kind, + dvv.value +FROM deployment_variable_value dvv +ON CONFLICT (id) DO NOTHING; +--> statement-breakpoint + +INSERT INTO "variable" (scope, resource_id, key, is_sensitive) +SELECT + 'resource'::variable_scope, + rv.resource_id, + rv.key, + false +FROM resource_variable rv +ON CONFLICT (resource_id, key) WHERE resource_id IS NOT NULL DO NOTHING; +--> statement-breakpoint + +INSERT INTO "variable_value" (variable_id, priority, kind, literal_value) +SELECT + v.id, + 0, + 'literal'::variable_value_kind, + rv.value +FROM resource_variable rv +JOIN "variable" v + ON v.scope = 'resource' + AND v.resource_id = rv.resource_id + AND v.key = rv.key +WHERE NOT EXISTS ( + SELECT 1 FROM "variable_value" vv + WHERE vv.variable_id = v.id + AND vv.resource_selector IS NULL + AND vv.priority = 0 +); diff --git a/packages/db/drizzle/meta/0188_snapshot.json b/packages/db/drizzle/meta/0188_snapshot.json new file mode 100644 index 000000000..8ed22c446 --- /dev/null +++ b/packages/db/drizzle/meta/0188_snapshot.json @@ -0,0 +1,7265 @@ +{ + "id": "a3bc781d-0c9b-4a72-a20a-0892ee85973b", + "prevId": "071d2fd0-a17a-4ebc-826a-9d728d97b563", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "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 + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp with time zone", + "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 + }, + "password": { + "name": "password", + "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": true, + "default": "now()" + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "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": true + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_session_token_unique": { + "name": "session_session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "session_token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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()" + }, + "updated_at": { + "name": "updated_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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.changelog_entry": { + "name": "changelog_entry", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_data": { + "name": "entity_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "changelog_entry_workspace_id_workspace_id_fk": { + "name": "changelog_entry_workspace_id_workspace_id_fk", + "tableFrom": "changelog_entry", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "changelog_entry_workspace_id_entity_type_entity_id_pk": { + "name": "changelog_entry_workspace_id_entity_type_entity_id_pk", + "columns": [ + "workspace_id", + "entity_type", + "entity_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan": { + "name": "deployment_plan", + "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 + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_tag": { + "name": "version_tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version_name": { + "name": "version_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version_config": { + "name": "version_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "version_job_agent_config": { + "name": "version_job_agent_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "version_metadata": { + "name": "version_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "deployment_plan_workspace_id_index": { + "name": "deployment_plan_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_plan_deployment_id_index": { + "name": "deployment_plan_deployment_id_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_plan_expires_at_index": { + "name": "deployment_plan_expires_at_index", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_workspace_id_workspace_id_fk": { + "name": "deployment_plan_workspace_id_workspace_id_fk", + "tableFrom": "deployment_plan", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_deployment_id_deployment_id_fk": { + "name": "deployment_plan_deployment_id_deployment_id_fk", + "tableFrom": "deployment_plan", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan_target": { + "name": "deployment_plan_target", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "plan_id": { + "name": "plan_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "current_release_id": { + "name": "current_release_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_plan_target_plan_id_index": { + "name": "deployment_plan_target_plan_id_index", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_plan_target_plan_id_environment_id_resource_id_index": { + "name": "deployment_plan_target_plan_id_environment_id_resource_id_index", + "columns": [ + { + "expression": "plan_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_target_plan_id_deployment_plan_id_fk": { + "name": "deployment_plan_target_plan_id_deployment_plan_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "deployment_plan", + "columnsFrom": [ + "plan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_target_environment_id_environment_id_fk": { + "name": "deployment_plan_target_environment_id_environment_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_target_resource_id_resource_id_fk": { + "name": "deployment_plan_target_resource_id_resource_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_plan_target_current_release_id_release_id_fk": { + "name": "deployment_plan_target_current_release_id_release_id_fk", + "tableFrom": "deployment_plan_target", + "tableTo": "release", + "columnsFrom": [ + "current_release_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan_target_result": { + "name": "deployment_plan_target_result", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "target_id": { + "name": "target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "dispatch_context": { + "name": "dispatch_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "agent_state": { + "name": "agent_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deployment_plan_target_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'computing'" + }, + "has_changes": { + "name": "has_changes", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current": { + "name": "current", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "proposed": { + "name": "proposed", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_plan_target_result_target_id_index": { + "name": "deployment_plan_target_result_target_id_index", + "columns": [ + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_target_result_target_id_deployment_plan_target_id_fk": { + "name": "deployment_plan_target_result_target_id_deployment_plan_target_id_fk", + "tableFrom": "deployment_plan_target_result", + "tableTo": "deployment_plan_target", + "columnsFrom": [ + "target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_plan_target_variable": { + "name": "deployment_plan_target_variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "target_id": { + "name": "target_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 + }, + "encrypted": { + "name": "encrypted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "deployment_plan_target_variable_target_id_key_index": { + "name": "deployment_plan_target_variable_target_id_key_index", + "columns": [ + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_plan_target_variable_target_id_deployment_plan_target_id_fk": { + "name": "deployment_plan_target_variable_target_id_deployment_plan_target_id_fk", + "tableFrom": "deployment_plan_target_variable", + "tableTo": "deployment_plan_target", + "columnsFrom": [ + "target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_trace_span": { + "name": "deployment_trace_span", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "trace_id": { + "name": "trace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "span_id": { + "name": "span_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_span_id": { + "name": "parent_span_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "release_target_key": { + "name": "release_target_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "release_id": { + "name": "release_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parent_trace_id": { + "name": "parent_trace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "node_type": { + "name": "node_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "depth": { + "name": "depth", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sequence": { + "name": "sequence", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "attributes": { + "name": "attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "events": { + "name": "events", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "deployment_trace_span_trace_span_idx": { + "name": "deployment_trace_span_trace_span_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "span_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_trace_id_idx": { + "name": "deployment_trace_span_trace_id_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_parent_span_id_idx": { + "name": "deployment_trace_span_parent_span_id_idx", + "columns": [ + { + "expression": "parent_span_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_workspace_id_idx": { + "name": "deployment_trace_span_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_release_target_key_idx": { + "name": "deployment_trace_span_release_target_key_idx", + "columns": [ + { + "expression": "release_target_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_release_id_idx": { + "name": "deployment_trace_span_release_id_idx", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_job_id_idx": { + "name": "deployment_trace_span_job_id_idx", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_parent_trace_id_idx": { + "name": "deployment_trace_span_parent_trace_id_idx", + "columns": [ + { + "expression": "parent_trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_created_at_idx": { + "name": "deployment_trace_span_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_phase_idx": { + "name": "deployment_trace_span_phase_idx", + "columns": [ + { + "expression": "phase", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_node_type_idx": { + "name": "deployment_trace_span_node_type_idx", + "columns": [ + { + "expression": "node_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "deployment_trace_span_status_idx": { + "name": "deployment_trace_span_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_trace_span_workspace_id_workspace_id_fk": { + "name": "deployment_trace_span_workspace_id_workspace_id_fk", + "tableFrom": "deployment_trace_span", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_variable": { + "name": "deployment_variable", + "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 + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "default_value": { + "name": "default_value", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_variable_deployment_id_index": { + "name": "deployment_variable_deployment_id_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployment_variable_deployment_id_key_unique": { + "name": "deployment_variable_deployment_id_key_unique", + "nullsNotDistinct": false, + "columns": [ + "deployment_id", + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment_variable_value": { + "name": "deployment_variable_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "deployment_variable_id": { + "name": "deployment_variable_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "deployment_variable_value_deployment_variable_id_index": { + "name": "deployment_variable_value_deployment_variable_id_index", + "columns": [ + { + "expression": "deployment_variable_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_variable_value_deployment_variable_id_deployment_variable_id_fk": { + "name": "deployment_variable_value_deployment_variable_id_deployment_variable_id_fk", + "tableFrom": "deployment_variable_value", + "tableTo": "deployment_variable", + "columnsFrom": [ + "deployment_variable_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "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_workspace_id_workspace_id_fk": { + "name": "deployment_version_workspace_id_workspace_id_fk", + "tableFrom": "deployment_version", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_deployment_resource": { + "name": "computed_deployment_resource", + "schema": "", + "columns": { + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_evaluated_at": { + "name": "last_evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "computed_deployment_resource_deployment_id_deployment_id_fk": { + "name": "computed_deployment_resource_deployment_id_deployment_id_fk", + "tableFrom": "computed_deployment_resource", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_deployment_resource_resource_id_resource_id_fk": { + "name": "computed_deployment_resource_resource_id_resource_id_fk", + "tableFrom": "computed_deployment_resource", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "computed_deployment_resource_deployment_id_resource_id_pk": { + "name": "computed_deployment_resource_deployment_id_resource_id_pk", + "columns": [ + "deployment_id", + "resource_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "job_agent_selector": { + "name": "job_agent_selector", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'false'" + }, + "job_agent_config": { + "name": "job_agent_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "deployment_workspace_id_index": { + "name": "deployment_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deployment_workspace_id_workspace_id_fk": { + "name": "deployment_workspace_id_workspace_id_fk", + "tableFrom": "deployment", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_environment_resource": { + "name": "computed_environment_resource", + "schema": "", + "columns": { + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_evaluated_at": { + "name": "last_evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "computed_environment_resource_environment_id_environment_id_fk": { + "name": "computed_environment_resource_environment_id_environment_id_fk", + "tableFrom": "computed_environment_resource", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_environment_resource_resource_id_resource_id_fk": { + "name": "computed_environment_resource_resource_id_resource_id_fk", + "tableFrom": "computed_environment_resource", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "computed_environment_resource_environment_id_resource_id_pk": { + "name": "computed_environment_resource_environment_id_resource_id_pk", + "columns": [ + "environment_id", + "resource_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "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": "''" + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "environment_workspace_id_index": { + "name": "environment_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "environment_workspace_id_workspace_id_fk": { + "name": "environment_workspace_id_workspace_id_fk", + "tableFrom": "environment", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.event": { + "name": "event", + "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 + }, + "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": { + "event_workspace_id_workspace_id_fk": { + "name": "event_workspace_id_workspace_id_fk", + "tableFrom": "event", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "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": {} + }, + "resource_workspace_id_active_idx": { + "name": "resource_workspace_id_active_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resource_workspace_id_deleted_at_index": { + "name": "resource_workspace_id_deleted_at_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resource_aggregate": { + "name": "resource_aggregate", + "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": 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 + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "filter": { + "name": "filter", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'true'" + }, + "group_by": { + "name": "group_by", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "resource_aggregate_workspace_id_index": { + "name": "resource_aggregate_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resource_aggregate_workspace_id_workspace_id_fk": { + "name": "resource_aggregate_workspace_id_workspace_id_fk", + "tableFrom": "resource_aggregate", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "resource_aggregate_created_by_user_id_fk": { + "name": "resource_aggregate_created_by_user_id_fk", + "tableFrom": "resource_aggregate", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "indexes": { + "system_workspace_id_index": { + "name": "system_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_deployment": { + "name": "system_deployment", + "schema": "", + "columns": { + "system_id": { + "name": "system_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_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": { + "system_deployment_system_id_system_id_fk": { + "name": "system_deployment_system_id_system_id_fk", + "tableFrom": "system_deployment", + "tableTo": "system", + "columnsFrom": [ + "system_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "system_deployment_deployment_id_deployment_id_fk": { + "name": "system_deployment_deployment_id_deployment_id_fk", + "tableFrom": "system_deployment", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "system_deployment_system_id_deployment_id_pk": { + "name": "system_deployment_system_id_deployment_id_pk", + "columns": [ + "system_id", + "deployment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_environment": { + "name": "system_environment", + "schema": "", + "columns": { + "system_id": { + "name": "system_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 with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "system_environment_system_id_system_id_fk": { + "name": "system_environment_system_id_system_id_fk", + "tableFrom": "system_environment", + "tableTo": "system", + "columnsFrom": [ + "system_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "system_environment_environment_id_environment_id_fk": { + "name": "system_environment_environment_id_environment_id_fk", + "tableFrom": "system_environment", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "system_environment_system_id_environment_id_pk": { + "name": "system_environment_system_id_environment_id_pk", + "columns": [ + "system_id", + "environment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "trace_token": { + "name": "trace_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dispatch_context": { + "name": "dispatch_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "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": {} + }, + "job_external_id_idx": { + "name": "job_external_id_idx", + "columns": [ + { + "expression": "external_id", + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {} + }, + "job_metadata_job_id_idx": { + "name": "job_metadata_job_id_idx", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": false + }, + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "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" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release": { + "name": "release", + "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 + }, + "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": { + "release_resource_id_environment_id_deployment_id_index": { + "name": "release_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": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_deployment_id_index": { + "name": "release_deployment_id_index", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_resource_id_resource_id_fk": { + "name": "release_resource_id_resource_id_fk", + "tableFrom": "release", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_environment_id_environment_id_fk": { + "name": "release_environment_id_environment_id_fk", + "tableFrom": "release", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_deployment_id_deployment_id_fk": { + "name": "release_deployment_id_deployment_id_fk", + "tableFrom": "release", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_version_id_deployment_version_id_fk": { + "name": "release_version_id_deployment_version_id_fk", + "tableFrom": "release", + "tableTo": "deployment_version", + "columnsFrom": [ + "version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_job": { + "name": "release_job", + "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 + }, + "release_id": { + "name": "release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "release_job_release_id_job_id_index": { + "name": "release_job_release_id_job_id_index", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_job_job_id_index": { + "name": "release_job_job_id_index", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "release_job_release_id_index": { + "name": "release_job_release_id_index", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "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" + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_target_desired_release": { + "name": "release_target_desired_release", + "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 + } + }, + "indexes": { + "release_target_desired_release_resource_id_environment_id_deployment_id_index": { + "name": "release_target_desired_release_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_desired_release_resource_id_resource_id_fk": { + "name": "release_target_desired_release_resource_id_resource_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_environment_id_environment_id_fk": { + "name": "release_target_desired_release_environment_id_environment_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_deployment_id_deployment_id_fk": { + "name": "release_target_desired_release_deployment_id_deployment_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "release_target_desired_release_desired_release_id_release_id_fk": { + "name": "release_target_desired_release_desired_release_id_release_id_fk", + "tableFrom": "release_target_desired_release", + "tableTo": "release", + "columnsFrom": [ + "desired_release_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.release_variable": { + "name": "release_variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release_id": { + "name": "release_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "encrypted": { + "name": "encrypted", + "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": { + "release_variable_release_id_key_index": { + "name": "release_variable_release_id_key_index", + "columns": [ + { + "expression": "release_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "release_variable_release_id_release_id_fk": { + "name": "release_variable_release_id_release_id_fk", + "tableFrom": "release_variable", + "tableTo": "release", + "columnsFrom": [ + "release_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reconcile_work_scope": { + "name": "reconcile_work_scope", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "byDefault", + "name": "reconcile_work_scope_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "9223372036854775807", + "cache": "1", + "cycle": false + } + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope_type": { + "name": "scope_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "scope_id": { + "name": "scope_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "event_ts": { + "name": "event_ts", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "priority": { + "name": "priority", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": 100 + }, + "not_before": { + "name": "not_before", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "attempt_count": { + "name": "attempt_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_by": { + "name": "claimed_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claimed_until": { + "name": "claimed_until", + "type": "timestamp with time zone", + "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": true, + "default": "now()" + } + }, + "indexes": { + "reconcile_work_scope_workspace_id_kind_scope_type_scope_id_index": { + "name": "reconcile_work_scope_workspace_id_kind_scope_type_scope_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scope_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "reconcile_work_scope_unclaimed_idx": { + "name": "reconcile_work_scope_unclaimed_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_ts", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"reconcile_work_scope\".\"claimed_until\" is null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "reconcile_work_scope_expired_claims_idx": { + "name": "reconcile_work_scope_expired_claims_idx", + "columns": [ + { + "expression": "claimed_until", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"reconcile_work_scope\".\"claimed_until\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "selector": { + "name": "selector", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'true'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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()" + } + }, + "indexes": { + "policy_workspace_id_index": { + "name": "policy_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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 + }, + "min_approvals": { + "name": "min_approvals", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_deployment_dependency": { + "name": "policy_rule_deployment_dependency", + "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 + }, + "depends_on": { + "name": "depends_on", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_deployment_dependency_policy_id_policy_id_fk": { + "name": "policy_rule_deployment_dependency_policy_id_policy_id_fk", + "tableFrom": "policy_rule_deployment_dependency", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_deployment_window": { + "name": "policy_rule_deployment_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 + }, + "allow_window": { + "name": "allow_window", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "duration_minutes": { + "name": "duration_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rrule": { + "name": "rrule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_deployment_window_policy_id_policy_id_fk": { + "name": "policy_rule_deployment_window_policy_id_policy_id_fk", + "tableFrom": "policy_rule_deployment_window", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_environment_progression": { + "name": "policy_rule_environment_progression", + "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 + }, + "depends_on_environment_selector": { + "name": "depends_on_environment_selector", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "maximum_age_hours": { + "name": "maximum_age_hours", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "minimum_soak_time_minutes": { + "name": "minimum_soak_time_minutes", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "minimum_success_percentage": { + "name": "minimum_success_percentage", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "success_statuses": { + "name": "success_statuses", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "require_verification_passed": { + "name": "require_verification_passed", + "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": {}, + "foreignKeys": { + "policy_rule_environment_progression_policy_id_policy_id_fk": { + "name": "policy_rule_environment_progression_policy_id_policy_id_fk", + "tableFrom": "policy_rule_environment_progression", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_gradual_rollout": { + "name": "policy_rule_gradual_rollout", + "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 + }, + "rollout_type": { + "name": "rollout_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "time_scale_interval": { + "name": "time_scale_interval", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_gradual_rollout_policy_id_policy_id_fk": { + "name": "policy_rule_gradual_rollout_policy_id_policy_id_fk", + "tableFrom": "policy_rule_gradual_rollout", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_retry": { + "name": "policy_rule_retry", + "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 + }, + "max_retries": { + "name": "max_retries", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "backoff_seconds": { + "name": "backoff_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "backoff_strategy": { + "name": "backoff_strategy", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_backoff_seconds": { + "name": "max_backoff_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "retry_on_statuses": { + "name": "retry_on_statuses", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_retry_policy_id_policy_id_fk": { + "name": "policy_rule_retry_policy_id_policy_id_fk", + "tableFrom": "policy_rule_retry", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_rollback": { + "name": "policy_rule_rollback", + "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 + }, + "on_job_statuses": { + "name": "on_job_statuses", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "on_verification_failure": { + "name": "on_verification_failure", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_rollback_policy_id_policy_id_fk": { + "name": "policy_rule_rollback_policy_id_policy_id_fk", + "tableFrom": "policy_rule_rollback", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_verification": { + "name": "policy_rule_verification", + "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 + }, + "metrics": { + "name": "metrics", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "trigger_on": { + "name": "trigger_on", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_verification_policy_id_policy_id_fk": { + "name": "policy_rule_verification_policy_id_policy_id_fk", + "tableFrom": "policy_rule_verification", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_version_cooldown": { + "name": "policy_rule_version_cooldown", + "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 + }, + "interval_seconds": { + "name": "interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_version_cooldown_policy_id_policy_id_fk": { + "name": "policy_rule_version_cooldown_policy_id_policy_id_fk", + "tableFrom": "policy_rule_version_cooldown", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_version_selector": { + "name": "policy_rule_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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "selector": { + "name": "selector", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_version_selector_policy_id_policy_id_fk": { + "name": "policy_rule_version_selector_policy_id_policy_id_fk", + "tableFrom": "policy_rule_version_selector", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_approval_record": { + "name": "user_approval_record", + "schema": "", + "columns": { + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "user_approval_record_version_id_user_id_environment_id_pk": { + "name": "user_approval_record_version_id_user_id_environment_id_pk", + "columns": [ + "version_id", + "user_id", + "environment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resource_variable": { + "name": "resource_variable", + "schema": "", + "columns": { + "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 + } + }, + "indexes": {}, + "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": { + "resource_variable_resource_id_key_pk": { + "name": "resource_variable_resource_id_key_pk", + "columns": [ + "resource_id", + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inputs": { + "name": "inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "job_agents": { + "name": "job_agents", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "workspace_id": { + "name": "workspace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_job": { + "name": "workflow_job", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_run_id": { + "name": "workflow_run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_job_workflow_run_id_workflow_run_id_fk": { + "name": "workflow_job_workflow_run_id_workflow_run_id_fk", + "tableFrom": "workflow_job", + "tableTo": "workflow_run", + "columnsFrom": [ + "workflow_run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_job_job_id_job_id_fk": { + "name": "workflow_job_job_id_job_id_fk", + "tableFrom": "workflow_job", + "tableTo": "job", + "columnsFrom": [ + "job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_run": { + "name": "workflow_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "inputs": { + "name": "inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_workflow_id_workflow_id_fk": { + "name": "workflow_run_workflow_id_workflow_id_fk", + "tableFrom": "workflow_run", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_skip": { + "name": "policy_skip", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_policy_release_target": { + "name": "computed_policy_release_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 + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "computed_at": { + "name": "computed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "computed_policy_release_target_policy_id_environment_id_deployment_id_resource_id_index": { + "name": "computed_policy_release_target_policy_id_environment_id_deployment_id_resource_id_index", + "columns": [ + { + "expression": "policy_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" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "computed_policy_release_target_policy_id_index": { + "name": "computed_policy_release_target_policy_id_index", + "columns": [ + { + "expression": "policy_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "computed_policy_release_target_resource_id_environment_id_deployment_id_index": { + "name": "computed_policy_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": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "computed_policy_release_target_policy_id_policy_id_fk": { + "name": "computed_policy_release_target_policy_id_policy_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_policy_release_target_environment_id_environment_id_fk": { + "name": "computed_policy_release_target_environment_id_environment_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_policy_release_target_deployment_id_deployment_id_fk": { + "name": "computed_policy_release_target_deployment_id_deployment_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "computed_policy_release_target_resource_id_resource_id_fk": { + "name": "computed_policy_release_target_resource_id_resource_id_fk", + "tableFrom": "computed_policy_release_target", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_evaluation": { + "name": "policy_rule_evaluation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "rule_type": { + "name": "rule_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version_id": { + "name": "version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "allowed": { + "name": "allowed", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "action_required": { + "name": "action_required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "action_type": { + "name": "action_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "satisfied_at": { + "name": "satisfied_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "next_evaluation_at": { + "name": "next_evaluation_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "evaluated_at": { + "name": "evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "policy_rule_evaluation_rule_id_environment_id_version_id_resource_id_index": { + "name": "policy_rule_evaluation_rule_id_environment_id_version_id_resource_id_index", + "columns": [ + { + "expression": "rule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "policy_rule_evaluation_environment_id_version_id_resource_id_rule_type_index": { + "name": "policy_rule_evaluation_environment_id_version_id_resource_id_rule_type_index", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "rule_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "policy_rule_evaluation_environment_id_environment_id_fk": { + "name": "policy_rule_evaluation_environment_id_environment_id_fk", + "tableFrom": "policy_rule_evaluation", + "tableTo": "environment", + "columnsFrom": [ + "environment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_evaluation_version_id_deployment_version_id_fk": { + "name": "policy_rule_evaluation_version_id_deployment_version_id_fk", + "tableFrom": "policy_rule_evaluation", + "tableTo": "deployment_version", + "columnsFrom": [ + "version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "policy_rule_evaluation_resource_id_resource_id_fk": { + "name": "policy_rule_evaluation_resource_id_resource_id_fk", + "tableFrom": "policy_rule_evaluation", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_verification_metric_measurement": { + "name": "job_verification_metric_measurement", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "job_verification_metric_status_id": { + "name": "job_verification_metric_status_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "measured_at": { + "name": "measured_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "status": { + "name": "status", + "type": "job_verification_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "job_verification_metric_measurement_job_verification_metric_status_id_index": { + "name": "job_verification_metric_measurement_job_verification_metric_status_id_index", + "columns": [ + { + "expression": "job_verification_metric_status_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_verification_metric_measurement_job_verification_metric_status_id_job_verification_metric_id_fk": { + "name": "job_verification_metric_measurement_job_verification_metric_status_id_job_verification_metric_id_fk", + "tableFrom": "job_verification_metric_measurement", + "tableTo": "job_verification_metric", + "columnsFrom": [ + "job_verification_metric_status_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_verification_metric": { + "name": "job_verification_metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "policy_rule_verification_metric_id": { + "name": "policy_rule_verification_metric_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "interval_seconds": { + "name": "interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "success_threshold": { + "name": "success_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "failure_condition": { + "name": "failure_condition", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "failure_threshold": { + "name": "failure_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": { + "job_verification_metric_job_id_index": { + "name": "job_verification_metric_job_id_index", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_verification_metric_policy_rule_verification_metric_id_index": { + "name": "job_verification_metric_policy_rule_verification_metric_id_index", + "columns": [ + { + "expression": "policy_rule_verification_metric_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_verification_metric_policy_rule_verification_metric_id_policy_rule_job_verification_metric_id_fk": { + "name": "job_verification_metric_policy_rule_verification_metric_id_policy_rule_job_verification_metric_id_fk", + "tableFrom": "job_verification_metric", + "tableTo": "policy_rule_job_verification_metric", + "columnsFrom": [ + "policy_rule_verification_metric_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policy_rule_job_verification_metric": { + "name": "policy_rule_job_verification_metric", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "trigger_on": { + "name": "trigger_on", + "type": "job_verification_trigger_on", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'jobSuccess'" + }, + "policy_id": { + "name": "policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "interval_seconds": { + "name": "interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "success_threshold": { + "name": "success_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "failure_condition": { + "name": "failure_condition", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'false'" + }, + "failure_threshold": { + "name": "failure_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "policy_rule_job_verification_metric_policy_id_policy_id_fk": { + "name": "policy_rule_job_verification_metric_policy_id_policy_id_fk", + "tableFrom": "policy_rule_job_verification_metric", + "tableTo": "policy", + "columnsFrom": [ + "policy_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.computed_entity_relationship": { + "name": "computed_entity_relationship", + "schema": "", + "columns": { + "rule_id": { + "name": "rule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "from_entity_type": { + "name": "from_entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_entity_id": { + "name": "from_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "to_entity_type": { + "name": "to_entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "to_entity_id": { + "name": "to_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "last_evaluated_at": { + "name": "last_evaluated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "computed_entity_relationship_from_idx": { + "name": "computed_entity_relationship_from_idx", + "columns": [ + { + "expression": "from_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "from_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "computed_entity_relationship_to_idx": { + "name": "computed_entity_relationship_to_idx", + "columns": [ + { + "expression": "to_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "to_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "computed_entity_relationship_rule_id_relationship_rule_id_fk": { + "name": "computed_entity_relationship_rule_id_relationship_rule_id_fk", + "tableFrom": "computed_entity_relationship", + "tableTo": "relationship_rule", + "columnsFrom": [ + "rule_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "computed_entity_relationship_rule_id_from_entity_type_from_entity_id_to_entity_type_to_entity_id_pk": { + "name": "computed_entity_relationship_rule_id_from_entity_type_from_entity_id_to_entity_type_to_entity_id_pk", + "columns": [ + "rule_id", + "from_entity_type", + "from_entity_id", + "to_entity_type", + "to_entity_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.relationship_rule": { + "name": "relationship_rule", + "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": true + }, + "reference": { + "name": "reference", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cel": { + "name": "cel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + } + }, + "indexes": { + "relationship_rule_workspace_id_reference_index": { + "name": "relationship_rule_workspace_id_reference_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "reference", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "relationship_rule_workspace_id_index": { + "name": "relationship_rule_workspace_id_index", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "relationship_rule_workspace_id_workspace_id_fk": { + "name": "relationship_rule_workspace_id_workspace_id_fk", + "tableFrom": "relationship_rule", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "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": true, + "default": "''" + }, + "selector": { + "name": "selector", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "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": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "variable_set_workspace_id_workspace_id_fk": { + "name": "variable_set_workspace_id_workspace_id_fk", + "tableFrom": "variable_set", + "tableTo": "workspace", + "columnsFrom": [ + "workspace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.variable_set_variable": { + "name": "variable_set_variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "variable_set_id": { + "name": "variable_set_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "variable_set_variable_variable_set_id_variable_set_id_fk": { + "name": "variable_set_variable_variable_set_id_variable_set_id_fk", + "tableFrom": "variable_set_variable", + "tableTo": "variable_set", + "columnsFrom": [ + "variable_set_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "variable_set_variable_variable_set_id_key_unique": { + "name": "variable_set_variable_variable_set_id_key_unique", + "nullsNotDistinct": false, + "columns": [ + "variable_set_id", + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.variable": { + "name": "variable", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "scope": { + "name": "scope", + "type": "variable_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "deployment_id": { + "name": "deployment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "job_agent_id": { + "name": "job_agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_sensitive": { + "name": "is_sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "description": { + "name": "description", + "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": true, + "default": "now()" + } + }, + "indexes": { + "variable_resource_key_uniq": { + "name": "variable_resource_key_uniq", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"variable\".\"resource_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_deployment_key_uniq": { + "name": "variable_deployment_key_uniq", + "columns": [ + { + "expression": "deployment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"variable\".\"deployment_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_job_agent_key_uniq": { + "name": "variable_job_agent_key_uniq", + "columns": [ + { + "expression": "job_agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"variable\".\"job_agent_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_scope_idx": { + "name": "variable_scope_idx", + "columns": [ + { + "expression": "scope", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_resource_id_resource_id_fk": { + "name": "variable_resource_id_resource_id_fk", + "tableFrom": "variable", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "variable_deployment_id_deployment_id_fk": { + "name": "variable_deployment_id_deployment_id_fk", + "tableFrom": "variable", + "tableTo": "deployment", + "columnsFrom": [ + "deployment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "variable_job_agent_id_job_agent_id_fk": { + "name": "variable_job_agent_id_job_agent_id_fk", + "tableFrom": "variable", + "tableTo": "job_agent", + "columnsFrom": [ + "job_agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "variable_scope_target_check": { + "name": "variable_scope_target_check", + "value": "\n (\n \"variable\".\"scope\" = 'resource'\n and \"variable\".\"resource_id\" is not null\n and \"variable\".\"deployment_id\" is null\n and \"variable\".\"job_agent_id\" is null\n )\n or\n (\n \"variable\".\"scope\" = 'deployment'\n and \"variable\".\"deployment_id\" is not null\n and \"variable\".\"resource_id\" is null\n and \"variable\".\"job_agent_id\" is null\n )\n or\n (\n \"variable\".\"scope\" = 'job_agent'\n and \"variable\".\"job_agent_id\" is not null\n and \"variable\".\"resource_id\" is null\n and \"variable\".\"deployment_id\" is null\n )\n " + } + }, + "isRLSEnabled": false + }, + "public.variable_value": { + "name": "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 + }, + "resource_selector": { + "name": "resource_selector", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "kind": { + "name": "kind", + "type": "variable_value_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "literal_value": { + "name": "literal_value", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ref_key": { + "name": "ref_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ref_path": { + "name": "ref_path", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "secret_provider": { + "name": "secret_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_key": { + "name": "secret_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_path": { + "name": "secret_path", + "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": true, + "default": "now()" + } + }, + "indexes": { + "variable_value_variable_priority_idx": { + "name": "variable_value_variable_priority_idx", + "columns": [ + { + "expression": "variable_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_value_kind_idx": { + "name": "variable_value_kind_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "variable_value_resolution_uniq": { + "name": "variable_value_resolution_uniq", + "columns": [ + { + "expression": "variable_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"resource_selector\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "variable_value_variable_id_variable_id_fk": { + "name": "variable_value_variable_id_variable_id_fk", + "tableFrom": "variable_value", + "tableTo": "variable", + "columnsFrom": [ + "variable_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "variable_value_kind_shape_check": { + "name": "variable_value_kind_shape_check", + "value": "\n (\n \"variable_value\".\"kind\" = 'literal'\n and \"variable_value\".\"literal_value\" is not null\n and \"variable_value\".\"ref_key\" is null\n and \"variable_value\".\"ref_path\" is null\n and \"variable_value\".\"secret_provider\" is null\n and \"variable_value\".\"secret_key\" is null\n and \"variable_value\".\"secret_path\" is null\n )\n or\n (\n \"variable_value\".\"kind\" = 'ref'\n and \"variable_value\".\"literal_value\" is null\n and \"variable_value\".\"ref_key\" is not null\n and \"variable_value\".\"secret_provider\" is null\n and \"variable_value\".\"secret_key\" is null\n and \"variable_value\".\"secret_path\" is null\n )\n or\n (\n \"variable_value\".\"kind\" = 'secret_ref'\n and \"variable_value\".\"literal_value\" is null\n and \"variable_value\".\"ref_key\" is null\n and \"variable_value\".\"ref_path\" is null\n and \"variable_value\".\"secret_provider\" is not null\n and \"variable_value\".\"secret_key\" is not null\n )\n " + } + }, + "isRLSEnabled": false + } + }, + "enums": { + "public.system_role": { + "name": "system_role", + "schema": "public", + "values": [ + "user", + "admin" + ] + }, + "public.deployment_plan_target_status": { + "name": "deployment_plan_target_status", + "schema": "public", + "values": [ + "computing", + "completed", + "errored", + "unsupported" + ] + }, + "public.deployment_version_status": { + "name": "deployment_version_status", + "schema": "public", + "values": [ + "unspecified", + "building", + "ready", + "failed", + "rejected", + "paused" + ] + }, + "public.job_reason": { + "name": "job_reason", + "schema": "public", + "values": [ + "policy_passing", + "policy_override", + "env_policy_override", + "config_policy_override", + "redeploy" + ] + }, + "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", + "resource", + "resourceProvider", + "workspace", + "environment", + "system", + "deployment" + ] + }, + "public.job_verification_status": { + "name": "job_verification_status", + "schema": "public", + "values": [ + "failed", + "inconclusive", + "passed" + ] + }, + "public.job_verification_trigger_on": { + "name": "job_verification_trigger_on", + "schema": "public", + "values": [ + "jobCreated", + "jobStarted", + "jobSuccess", + "jobFailure" + ] + }, + "public.variable_scope": { + "name": "variable_scope", + "schema": "public", + "values": [ + "resource", + "deployment", + "job_agent" + ] + }, + "public.variable_value_kind": { + "name": "variable_value_kind", + "schema": "public", + "values": [ + "literal", + "ref", + "secret_ref" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index 3fab01602..f6c58d155 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -1317,6 +1317,13 @@ "when": 1776692328153, "tag": "0187_dry_quicksilver", "breakpoints": true + }, + { + "idx": 188, + "version": "7", + "when": 1776692400000, + "tag": "0188_backfill_variables", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/trpc/src/routes/_variables.ts b/packages/trpc/src/routes/_variables.ts new file mode 100644 index 000000000..9adb4b0cd --- /dev/null +++ b/packages/trpc/src/routes/_variables.ts @@ -0,0 +1,22 @@ +import type * as schema from "@ctrlplane/db/schema"; + +type VariableValueRow = typeof schema.variableValue.$inferSelect; + +export const flattenVariableValue = (v: VariableValueRow): unknown => { + if (v.kind === "literal") return v.literalValue; + if (v.kind === "ref") + return { reference: v.refKey, path: v.refPath ?? [] }; + return { + provider: v.secretProvider, + key: v.secretKey, + path: v.secretPath ?? [], + }; +}; + +export const toClientVariableValue = (v: VariableValueRow) => ({ + id: v.id, + deploymentVariableId: v.variableId, + value: flattenVariableValue(v), + resourceSelector: v.resourceSelector, + priority: v.priority, +}); diff --git a/packages/trpc/src/routes/deployments.ts b/packages/trpc/src/routes/deployments.ts index c39e878b8..1de45b0f6 100644 --- a/packages/trpc/src/routes/deployments.ts +++ b/packages/trpc/src/routes/deployments.ts @@ -15,6 +15,7 @@ import { getClientFor } from "@ctrlplane/workspace-engine-sdk"; import { protectedProcedure, router } from "../trpc.js"; import { deploymentPlansRouter } from "./deployment-plans.js"; +import { toClientVariableValue } from "./_variables.js"; export const deploymentsRouter = router({ plans: deploymentPlansRouter, @@ -278,34 +279,39 @@ export const deploymentsRouter = router({ variables: protectedProcedure .input(z.object({ workspaceId: z.uuid(), deploymentId: z.string() })) .query(async ({ input, ctx }) => { - const variables = await ctx.db.query.deploymentVariable.findMany({ - where: eq(schema.deploymentVariable.deploymentId, input.deploymentId), + const variables = await ctx.db.query.variable.findMany({ + where: and( + eq(schema.variable.scope, "deployment"), + eq(schema.variable.deploymentId, input.deploymentId), + ), }); const variableIds = variables.map((v) => v.id); const values = variableIds.length > 0 - ? await ctx.db.query.deploymentVariableValue.findMany({ - where: inArray( - schema.deploymentVariableValue.deploymentVariableId, - variableIds, - ), + ? await ctx.db.query.variableValue.findMany({ + where: inArray(schema.variableValue.variableId, variableIds), }) : []; const valuesByVarId = new Map< string, - (typeof schema.deploymentVariableValue.$inferSelect)[] + (typeof schema.variableValue.$inferSelect)[] >(); for (const val of values) { - const arr = valuesByVarId.get(val.deploymentVariableId) ?? []; + const arr = valuesByVarId.get(val.variableId) ?? []; arr.push(val); - valuesByVarId.set(val.deploymentVariableId, arr); + valuesByVarId.set(val.variableId, arr); } - return variables.map((variable) => ({ - variable, - values: valuesByVarId.get(variable.id) ?? [], + return variables.map((v) => ({ + variable: { + id: v.id, + deploymentId: v.deploymentId!, + key: v.key, + description: v.description, + }, + values: (valuesByVarId.get(v.id) ?? []).map(toClientVariableValue), })); }), @@ -375,10 +381,11 @@ export const deploymentsRouter = router({ .mutation(async ({ input, ctx }) => { const { workspaceId, deploymentId, variableId } = input; - const variable = await ctx.db.query.deploymentVariable.findFirst({ + const variable = await ctx.db.query.variable.findFirst({ where: and( - eq(schema.deploymentVariable.id, variableId), - eq(schema.deploymentVariable.deploymentId, deploymentId), + eq(schema.variable.id, variableId), + eq(schema.variable.scope, "deployment"), + eq(schema.variable.deploymentId, deploymentId), ), }); @@ -389,8 +396,8 @@ export const deploymentsRouter = router({ }); await ctx.db - .delete(schema.deploymentVariable) - .where(eq(schema.deploymentVariable.id, variableId)); + .delete(schema.variable) + .where(eq(schema.variable.id, variableId)); await enqueueReleaseTargetsForDeployment( ctx.db, diff --git a/packages/trpc/src/routes/resources.ts b/packages/trpc/src/routes/resources.ts index c28469567..b6eaeff58 100644 --- a/packages/trpc/src/routes/resources.ts +++ b/packages/trpc/src/routes/resources.ts @@ -455,12 +455,22 @@ export const resourcesRouter = router({ const rows = await ctx.db .select({ - resourceId: schema.resourceVariable.resourceId, - key: schema.resourceVariable.key, - value: schema.resourceVariable.value, + resourceId: schema.variable.resourceId, + key: schema.variable.key, + value: schema.variableValue.literalValue, }) - .from(schema.resourceVariable) - .where(eq(schema.resourceVariable.resourceId, resource.id)); + .from(schema.variable) + .innerJoin( + schema.variableValue, + eq(schema.variableValue.variableId, schema.variable.id), + ) + .where( + and( + eq(schema.variable.scope, "resource"), + eq(schema.variable.resourceId, resource.id), + eq(schema.variableValue.kind, "literal"), + ), + ); return rows; }), @@ -485,15 +495,39 @@ export const resourcesRouter = router({ const formattedValue = typeof value === "object" ? { object: value } : value; - const resourceVariable = await ctx.db - .insert(schema.resourceVariable) - .values({ + const resourceVariable = await ctx.db.transaction(async (tx) => { + const v = await tx + .insert(schema.variable) + .values({ scope: "resource" as const, resourceId, key }) + .onConflictDoUpdate({ + target: [schema.variable.resourceId, schema.variable.key], + targetWhere: sql`${schema.variable.resourceId} is not null`, + set: { key }, + }) + .returning() + .then(takeFirst); + + await tx + .delete(schema.variableValue) + .where(eq(schema.variableValue.variableId, v.id)); + + const val = await tx + .insert(schema.variableValue) + .values({ + variableId: v.id, + priority: 0, + kind: "literal" as const, + literalValue: formattedValue, + }) + .returning() + .then(takeFirst); + + return { resourceId, key, - value: formattedValue, - }) - .returning() - .then(takeFirst); + value: val.literalValue, + }; + }); await enqueueReleaseTargetsForResource(ctx.db, workspaceId, resourceId); diff --git a/packages/workspace-engine-sdk/src/schema.ts b/packages/workspace-engine-sdk/src/schema.ts index ebaaa9d09..5a4ff5690 100644 --- a/packages/workspace-engine-sdk/src/schema.ts +++ b/packages/workspace-engine-sdk/src/schema.ts @@ -4,1779 +4,1711 @@ */ export interface paths { - "/v1/deployments/{deploymentId}/job-agents": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** Get job agents matching a deployment selector */ - get: operations["getJobAgentsForDeployment"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/deployments/{deploymentId}/release-targets": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** List release targets for a deployment */ - get: operations["listReleaseTargets"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/jobs/{jobId}/verification-status": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** Get aggregate verification status for a job */ - get: operations["getJobVerificationStatus"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/validate/resource-selector": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** Validate a resource selector */ - post: operations["validateResourceSelector"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/workspaces/{workspaceId}/deployments": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** - * List deployments - * @description Returns a paginated list of deployments for a workspace. Optionally filter with a CEL expression using the "deployment" variable. - */ - get: operations["listDeployments"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/workspaces/{workspaceId}/release-targets/{releaseTargetKey}/state": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** Get the state of a release target */ - get: operations["getReleaseTargetState"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/workspaces/{workspaceId}/resources/aggregates": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** - * Compute resource aggregate - * @description Filters resources by a CEL expression and groups them by specified properties, returning counts per group. - */ - post: operations["computeAggergate"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/workspaces/{workspaceId}/resources/query": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** - * Query resources with CEL expression - * @description Returns paginated resources that match the provided CEL expression. Use the "resource" variable in your expression to access resource properties. - */ - post: operations["queryResources"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/v1/workspaces/{workspaceId}/workflows/{workflowId}/runs": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** - * Create a workflow run - * @description Creates a new run for the specified workflow with the provided inputs. - */ - post: operations["createWorkflowRun"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; -} -export type webhooks = Record; -export interface components { - schemas: { - AnyApprovalRule: { - /** Format: int32 */ - minApprovals: number; - }; - /** @enum {string} */ - ApprovalStatus: "approved" | "rejected"; - ArgoCDJobAgentConfig: { - /** @description ArgoCD API token. */ - apiKey: string; - /** @description ArgoCD server address (host[:port] or URL). */ - serverUrl: string; - /** @description ArgoCD application template. */ - template: string; - }; - /** @description WorkflowTemplate reference execution */ - ArgoWorkflowJobAgentConfig: { - /** @description ArgoWorkflow API token. */ - apiKey: string; - /** - * @description ArgoWorkClient http(s) connection configuration setting - * @default false - */ - httpInsecure: boolean; - /** @description ArgoWorkflow job name */ - name: string; - /** @description ArgoWorkflow server address (host[:port] or URL). */ - serverUrl: string; - /** @description WorkflowTemplate name. */ - template: string; - /** @description ArgoEvents webhookSecret */ - webhookSecret: string; - }; - BasicResource: { - id: string; - identifier: string; - kind: string; - name: string; - version: string; - workspaceId: string; - }; - BooleanValue: boolean; - CelMatcher: { - cel: string; - }; - DatadogMetricProvider: { - /** - * @description Datadog aggregator - * @default last - * @enum {string} - */ - aggregator: - | "avg" - | "min" - | "max" - | "sum" - | "last" - | "percentile" - | "mean" - | "l2norm" - | "area"; - /** - * @description Datadog API key (supports Go templates for variable references) - * @example {{.variables.dd_api_key}} - */ - apiKey: string; - /** - * @description Datadog Application key (supports Go templates for variable references) - * @example {{.variables.dd_app_key}} - */ - appKey: string; - /** @description Datadog formula (supports Go templates) */ - formula?: string; - /** - * Format: int64 - * @example 30 - */ - intervalSeconds?: number; - /** - * @description Datadog metrics queries (supports Go templates) - * @example { - * "q": "sum:requests.error.rate{service:{{.resource.name}}}" - * } - */ - queries: { - [key: string]: string; - }; - /** - * @description Datadog site URL (e.g., datadoghq.com, datadoghq.eu, us3.datadoghq.com) - * @default datadoghq.com - */ - site: string; - /** - * @description Provider type (enum property replaced by openapi-typescript) - * @enum {string} - */ - type: "datadog"; - }; - DeployDecision: { - policyResults: components["schemas"]["PolicyEvaluation"][]; - }; - Deployment: { - description?: string; - id: string; - jobAgentConfig: components["schemas"]["JobAgentConfig"]; - /** @description CEL expression to match job agents */ - jobAgentSelector: string; - metadata: { - [key: string]: string; - }; - name: string; - /** @description CEL expression to determine if the deployment should be used */ - resourceSelector?: string; - slug: string; - }; - DeploymentAndSystems: { - deployment: components["schemas"]["Deployment"]; - systems: components["schemas"]["System"][]; - }; - DeploymentDependencyRule: { - /** @description CEL expression to match upstream deployment(s) that must have a successful release before this deployment can proceed. The expression can reference both deployment properties (deployment.id, deployment.name, deployment.slug, deployment.metadata) and the currently deployed version properties (version.id, version.tag, version.name, version.status, version.metadata, version.createdAt). For example: deployment.name == 'db-migration' && version.tag.startsWith('v2.'). */ - dependsOn: string; - }; - DeploymentVariable: { - defaultValue?: components["schemas"]["LiteralValue"]; - deploymentId: string; - description?: string; - id: string; - key: string; - }; - DeploymentVariableValue: { - deploymentVariableId: string; - id: string; - /** Format: int64 */ - priority: number; - /** @description CEL expression to determine if the deployment variable value should be used */ - resourceSelector?: string; - value: components["schemas"]["Value"]; - }; - DeploymentVariableWithValues: { - values: components["schemas"]["DeploymentVariableValue"][]; - variable: components["schemas"]["DeploymentVariable"]; - }; - DeploymentVersion: { - config: { - [key: string]: unknown; - }; - /** Format: date-time */ - createdAt: string; - deploymentId: string; - id: string; - jobAgentConfig: components["schemas"]["JobAgentConfig"]; - message?: string; - metadata: { - [key: string]: string; - }; - name: string; - status: components["schemas"]["DeploymentVersionStatus"]; - tag: string; - }; - /** @enum {string} */ - DeploymentVersionStatus: - | "unspecified" - | "building" - | "ready" - | "failed" - | "rejected" - | "paused"; - DeploymentWindowRule: { - /** - * @description If true, deployments are only allowed during the window. If false, deployments are blocked during the window (deny window) - * @default true - */ - allowWindow: boolean; - /** - * Format: int32 - * @description Duration of each deployment window in minutes - */ - durationMinutes: number; - /** @description RFC 5545 recurrence rule defining when deployment windows start (e.g., FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;BYHOUR=9) */ - rrule: string; - /** @description IANA timezone for the rrule (e.g., America/New_York). Defaults to UTC if not specified */ - timezone?: string; - }; - DeploymentWithVariablesAndSystems: { - deployment: components["schemas"]["Deployment"]; - systems: components["schemas"]["System"][]; - variables: components["schemas"]["DeploymentVariableWithValues"][]; - }; - DispatchContext: { - deployment?: components["schemas"]["Deployment"]; - environment?: components["schemas"]["Environment"]; - /** @description Resolved input values for the workflow run. */ - inputs?: { - [key: string]: unknown; - }; - jobAgent: components["schemas"]["JobAgent"]; - jobAgentConfig: components["schemas"]["JobAgentConfig"]; - release?: components["schemas"]["Release"]; - resource?: components["schemas"]["Resource"]; - variables?: { - [key: string]: components["schemas"]["LiteralValue"]; - }; - version?: components["schemas"]["DeploymentVersion"]; - workflow?: components["schemas"]["Workflow"]; - workflowJob?: components["schemas"]["WorkflowJob"]; - workflowRun?: components["schemas"]["WorkflowRun"]; - }; - EntityRelation: { - direction: components["schemas"]["RelationDirection"]; - entity: components["schemas"]["RelatableEntity"]; - /** @description ID of the related entity */ - entityId: string; - entityType: components["schemas"]["RelatableEntityType"]; - rule: components["schemas"]["RelationshipRule"]; - }; - Environment: { - /** Format: date-time */ - createdAt: string; - description?: string; - id: string; - metadata: { - [key: string]: string; - }; - name: string; - /** @description CEL expression to determine if the environment should be used */ - resourceSelector?: string; - workspaceId: string; - }; - EnvironmentProgressionRule: { - /** @description CEL expression to determine if the environment progression rule should be used */ - dependsOnEnvironmentSelector: string; - /** - * Format: int32 - * @description Maximum age of dependency deployment before blocking progression (prevents stale promotions) - */ - maximumAgeHours?: number; - /** - * Format: int32 - * @description Minimum time to wait after the depends on environment is in a success state before the current environment can be deployed - * @default 0 - */ - minimumSoakTimeMinutes: number; - /** - * Format: float - * @default 100 - */ - minimumSuccessPercentage: number; - /** - * @description If true, jobs must also have passed verification to count toward the success percentage - * @default false - */ - requireVerificationPassed: boolean; - successStatuses?: components["schemas"]["JobStatus"][]; - }; - EnvironmentSummary: { - id: string; - name: string; - }; - EnvironmentWithSystems: components["schemas"]["Environment"] & { - systems: components["schemas"]["System"][]; - }; - ErrorResponse: { - /** @example Workspace not found */ - error?: string; - }; - EvaluateReleaseTargetRequest: { - releaseTarget: components["schemas"]["ReleaseTarget"]; - version: components["schemas"]["DeploymentVersion"]; - }; - EvaluationScope: { - environmentId?: string; - versionId?: string; - }; - GithubEntity: { - installationId: number; - slug: string; - }; - GithubJobAgentConfig: { - /** - * Format: int - * @description GitHub app installation ID. - */ - installationId: number; - /** @description GitHub repository owner. */ - owner: string; - /** @description Git ref to run the workflow on (defaults to "main" if omitted). */ - ref?: string; - /** @description GitHub repository name. */ - repo: string; - /** - * Format: int64 - * @description GitHub Actions workflow ID. - */ - workflowId: number; - }; - GradualRolloutRule: { - /** - * @description Strategy for scheduling deployments to release targets. "linear": Each target is deployed at a fixed interval of timeScaleInterval seconds. "linear-normalized": Deployments are spaced evenly so that the last target is scheduled at or before timeScaleInterval seconds. See rolloutType algorithm documentation for details. - * @enum {string} - */ - rolloutType: "linear" | "linear-normalized"; - /** - * Format: int32 - * @description Base time interval in seconds used to compute the delay between deployments to release targets. - */ - timeScaleInterval: number; - }; - HTTPMetricProvider: { - /** @description Request body (supports Go templates) */ - body?: string; - /** @description HTTP headers (values support Go templates) */ - headers?: { - [key: string]: string; - }; - /** - * @description HTTP method - * @default GET - * @enum {string} - */ - method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS"; - /** - * @description Request timeout (duration string, e.g., "30s") - * @default 30s - */ - timeout: string; - /** - * @description Provider type (enum property replaced by openapi-typescript) - * @enum {string} - */ - type: "http"; - /** - * @description HTTP endpoint URL (supports Go templates) - * @example http://{{ .resource.name }}.{{ .environment.name }}/health - */ - url: string; - }; - IntegerValue: number; - Job: { - /** Format: date-time */ - completedAt?: string; - /** Format: date-time */ - createdAt: string; - dispatchContext?: components["schemas"]["DispatchContext"]; - externalId?: string; - id: string; - jobAgentConfig: components["schemas"]["JobAgentConfig"]; - jobAgentId: string; - message?: string; - metadata: { - [key: string]: string; - }; - releaseId: string; - /** Format: date-time */ - startedAt?: string; - status: components["schemas"]["JobStatus"]; - traceToken?: string; - /** Format: date-time */ - updatedAt: string; - workflowJobId: string; - }; - JobAgent: { - config: components["schemas"]["JobAgentConfig"]; - id: string; - metadata?: { - [key: string]: string; - }; - name: string; - type: string; - workspaceId: string; - }; - JobAgentConfig: { - [key: string]: unknown; - }; - /** @enum {string} */ - JobStatus: - | "cancelled" - | "skipped" - | "inProgress" - | "actionRequired" - | "pending" - | "failure" - | "invalidJobAgent" - | "invalidIntegration" - | "externalRunNotFound" - | "successful"; - JobSummary: { - id: string; - /** @description External links extracted from job metadata */ - links?: { - [key: string]: string; - }; - message?: string; - status: components["schemas"]["JobStatus"]; - verifications: components["schemas"]["JobVerification"][]; - }; - JobUpdateEvent: { - agentId?: string; - externalId?: string; - fieldsToUpdate?: ( - | "completedAt" - | "createdAt" - | "dispatchContext" - | "externalId" - | "id" - | "jobAgentConfig" - | "jobAgentId" - | "message" - | "metadata" - | "releaseId" - | "startedAt" - | "status" - | "traceToken" - | "updatedAt" - | "workflowJobId" - )[]; - id?: string; - job: components["schemas"]["Job"]; - } & (unknown | unknown); - JobVerification: { - /** - * Format: date-time - * @description When verification was created - */ - createdAt: string; - id: string; - jobId: string; - /** @description Summary message of verification result */ - message?: string; - /** @description Metrics associated with this verification */ - metrics: components["schemas"]["VerificationMetricStatus"][]; - }; - /** @enum {string} */ - JobVerificationStatus: "running" | "passed" | "failed" | "cancelled"; - JobWithRelease: { - deployment?: components["schemas"]["Deployment"]; - environment?: components["schemas"]["Environment"]; - job: components["schemas"]["Job"]; - release: components["schemas"]["Release"]; - resource?: components["schemas"]["Resource"]; - }; - JobWithVerifications: { - job: components["schemas"]["Job"]; - verifications: components["schemas"]["JobVerification"][]; - }; - LiteralValue: - | components["schemas"]["BooleanValue"] - | components["schemas"]["NumberValue"] - | components["schemas"]["IntegerValue"] - | components["schemas"]["StringValue"] - | components["schemas"]["ObjectValue"] - | components["schemas"]["NullValue"]; - MetricProvider: - | components["schemas"]["HTTPMetricProvider"] - | components["schemas"]["SleepMetricProvider"] - | components["schemas"]["DatadogMetricProvider"] - | components["schemas"]["PrometheusMetricProvider"] - | components["schemas"]["TerraformCloudRunMetricProvider"]; - /** @enum {boolean} */ - NullValue: true; - NumberValue: number; - ObjectValue: { - object: { - [key: string]: unknown; - }; - }; - Policy: { - createdAt: string; - description?: string; - enabled: boolean; - id: string; - /** @description Arbitrary metadata for the policy (record) */ - metadata: { - [key: string]: string; - }; - name: string; - priority: number; - rules: components["schemas"]["PolicyRule"][]; - /** @description CEL expression for matching release targets. Use "true" to match all targets. */ - selector: string; - workspaceId: string; - }; - PolicyEvaluation: { - policy?: components["schemas"]["Policy"]; - ruleResults: components["schemas"]["RuleEvaluation"][]; - summary?: string; - }; - PolicyRule: { - anyApproval?: components["schemas"]["AnyApprovalRule"]; - createdAt: string; - deploymentDependency?: components["schemas"]["DeploymentDependencyRule"]; - deploymentWindow?: components["schemas"]["DeploymentWindowRule"]; - environmentProgression?: components["schemas"]["EnvironmentProgressionRule"]; - gradualRollout?: components["schemas"]["GradualRolloutRule"]; - id: string; - policyId: string; - retry?: components["schemas"]["RetryRule"]; - rollback?: components["schemas"]["RollbackRule"]; - verification?: components["schemas"]["VerificationRule"]; - versionCooldown?: components["schemas"]["VersionCooldownRule"]; - versionSelector?: components["schemas"]["VersionSelectorRule"]; - }; - PolicySkip: { - /** - * Format: date-time - * @description When this skip was created - */ - createdAt: string; - /** @description User ID who created this skip */ - createdBy: string; - /** @description Environment this skip applies to. If null, applies to all environments. */ - environmentId?: string; - /** - * Format: date-time - * @description When this skip expires. If null, skip never expires. - */ - expiresAt?: string; - /** @description Unique identifier for the skip */ - id: string; - /** @description Required reason for why this skip is needed (e.g., incident ticket, emergency situation) */ - reason: string; - /** @description Resource this skip applies to. If null, applies to all resources (in the environment if specified, or globally). */ - resourceId?: string; - /** @description Rule ID this skip applies to */ - ruleId: string; - /** @description Deployment version this skip applies to */ - versionId: string; - /** @description Workspace this skip belongs to */ - workspaceId: string; - }; - PrometheusMetricProvider: { - /** - * @description Prometheus server address (supports Go templates) - * @example http://prometheus.example.com:9090 - */ - address: string; - /** @description Authentication configuration for Prometheus */ - authentication?: { + "/v1/deployments/{deploymentId}/job-agents": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get job agents matching a deployment selector */ + get: operations["getJobAgentsForDeployment"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/deployments/{deploymentId}/release-targets": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List release targets for a deployment */ + get: operations["listReleaseTargets"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/jobs/{jobId}/verification-status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get aggregate verification status for a job */ + get: operations["getJobVerificationStatus"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/validate/resource-selector": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Validate a resource selector */ + post: operations["validateResourceSelector"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/workspaces/{workspaceId}/deployments": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; /** - * @description Bearer token for authentication (supports Go templates for variable references) - * @example {{.variables.prometheus_token}} + * List deployments + * @description Returns a paginated list of deployments for a workspace. Optionally filter with a CEL expression using the "deployment" variable. */ - bearerToken?: string; - /** @description OAuth2 client credentials flow */ - oauth2?: { - /** @description OAuth2 client ID (supports Go templates) */ - clientId: string; - /** @description OAuth2 client secret (supports Go templates) */ - clientSecret: string; - /** @description OAuth2 scopes */ - scopes?: string[]; - /** @description Token endpoint URL */ - tokenUrl: string; - }; - }; - /** @description Additional HTTP headers for the Prometheus request (values support Go templates) */ - headers?: { - /** @example X-Scope-OrgID */ - key: string; - /** @example tenant_a */ - value: string; - }[]; - /** - * @description Skip TLS certificate verification - * @default false - */ - insecure: boolean; - /** - * @description PromQL query expression (supports Go templates) - * @example sum(irate(istio_requests_total{reporter="source",destination_service=~"{{.resource.name}}",response_code!~"5.*"}[5m])) - */ - query: string; - /** @description If provided, a range query (/api/v1/query_range) is used instead of an instant query (/api/v1/query) */ - rangeQuery?: { + get: operations["listDeployments"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/workspaces/{workspaceId}/release-targets/{releaseTargetKey}/state": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get the state of a release target */ + get: operations["getReleaseTargetState"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/workspaces/{workspaceId}/resources/aggregates": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; /** - * @description How far back from now for the query end, as a Prometheus duration (e.g., "0s" for now, "1m" for 1 minute ago). Defaults to "0s" (now) if unset. - * @example 0s + * Compute resource aggregate + * @description Filters resources by a CEL expression and groups them by specified properties, returning counts per group. */ - end?: string; + post: operations["computeAggergate"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/workspaces/{workspaceId}/resources/query": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; /** - * @description How far back from now to start the query, as a Prometheus duration (e.g., "5m", "1h"). Defaults to 10 * step if unset. - * @example 5m + * Query resources with CEL expression + * @description Returns paginated resources that match the provided CEL expression. Use the "resource" variable in your expression to access resource properties. */ - start?: string; + post: operations["queryResources"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v1/workspaces/{workspaceId}/workflows/{workflowId}/runs": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a workflow run + * @description Creates a new run for the specified workflow with the provided inputs. + */ + post: operations["createWorkflowRun"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + AnyApprovalRule: { + /** Format: int32 */ + minApprovals: number; + }; + /** @enum {string} */ + ApprovalStatus: "approved" | "rejected"; + ArgoCDJobAgentConfig: { + /** @description ArgoCD API token. */ + apiKey: string; + /** @description ArgoCD server address (host[:port] or URL). */ + serverUrl: string; + /** @description ArgoCD application template. */ + template: string; + }; + /** @description WorkflowTemplate reference execution */ + ArgoWorkflowJobAgentConfig: { + /** @description ArgoWorkflow API token. */ + apiKey: string; + /** + * @description ArgoWorkClient http(s) connection configuration setting + * @default false + */ + httpInsecure: boolean; + /** @description ArgoWorkflow job name */ + name: string; + /** @description ArgoWorkflow server address (host[:port] or URL). */ + serverUrl: string; + /** @description WorkflowTemplate name. */ + template: string; + /** @description ArgoEvents webhookSecret */ + webhookSecret: string; + }; + BasicResource: { + id: string; + identifier: string; + kind: string; + name: string; + version: string; + workspaceId: string; + }; + BooleanValue: boolean; + CelMatcher: { + cel: string; + }; + DatadogMetricProvider: { + /** + * @description Datadog aggregator + * @default last + * @enum {string} + */ + aggregator: "avg" | "min" | "max" | "sum" | "last" | "percentile" | "mean" | "l2norm" | "area"; + /** + * @description Datadog API key (supports Go templates for variable references) + * @example {{.variables.dd_api_key}} + */ + apiKey: string; + /** + * @description Datadog Application key (supports Go templates for variable references) + * @example {{.variables.dd_app_key}} + */ + appKey: string; + /** @description Datadog formula (supports Go templates) */ + formula?: string; + /** + * Format: int64 + * @example 30 + */ + intervalSeconds?: number; + /** + * @description Datadog metrics queries (supports Go templates) + * @example { + * "q": "sum:requests.error.rate{service:{{.resource.name}}}" + * } + */ + queries: { + [key: string]: string; + }; + /** + * @description Datadog site URL (e.g., datadoghq.com, datadoghq.eu, us3.datadoghq.com) + * @default datadoghq.com + */ + site: string; + /** + * @description Provider type (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: "datadog"; + }; + DeployDecision: { + policyResults: components["schemas"]["PolicyEvaluation"][]; + }; + Deployment: { + description?: string; + id: string; + jobAgentConfig: components["schemas"]["JobAgentConfig"]; + /** @description CEL expression to match job agents */ + jobAgentSelector: string; + metadata: { + [key: string]: string; + }; + name: string; + /** @description CEL expression to determine if the deployment should be used */ + resourceSelector?: string; + slug: string; + }; + DeploymentAndSystems: { + deployment: components["schemas"]["Deployment"]; + systems: components["schemas"]["System"][]; + }; + DeploymentDependencyRule: { + /** @description CEL expression to match upstream deployment(s) that must have a successful release before this deployment can proceed. The expression can reference both deployment properties (deployment.id, deployment.name, deployment.slug, deployment.metadata) and the currently deployed version properties (version.id, version.tag, version.name, version.status, version.metadata, version.createdAt). For example: deployment.name == 'db-migration' && version.tag.startsWith('v2.'). */ + dependsOn: string; + }; + DeploymentVariable: { + defaultValue?: components["schemas"]["LiteralValue"]; + deploymentId: string; + description?: string; + id: string; + key: string; + }; + DeploymentVariableValue: { + deploymentVariableId: string; + id: string; + /** Format: int64 */ + priority: number; + /** @description CEL expression to determine if the deployment variable value should be used */ + resourceSelector?: string; + value: components["schemas"]["Value"]; + }; + DeploymentVariableWithValues: { + values: components["schemas"]["DeploymentVariableValue"][]; + variable: components["schemas"]["DeploymentVariable"]; + }; + DeploymentVersion: { + config: { + [key: string]: unknown; + }; + /** Format: date-time */ + createdAt: string; + deploymentId: string; + id: string; + jobAgentConfig: components["schemas"]["JobAgentConfig"]; + message?: string; + metadata: { + [key: string]: string; + }; + name: string; + status: components["schemas"]["DeploymentVersionStatus"]; + tag: string; + }; + /** @enum {string} */ + DeploymentVersionStatus: "unspecified" | "building" | "ready" | "failed" | "rejected" | "paused"; + DeploymentWindowRule: { + /** + * @description If true, deployments are only allowed during the window. If false, deployments are blocked during the window (deny window) + * @default true + */ + allowWindow: boolean; + /** + * Format: int32 + * @description Duration of each deployment window in minutes + */ + durationMinutes: number; + /** @description RFC 5545 recurrence rule defining when deployment windows start (e.g., FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;BYHOUR=9) */ + rrule: string; + /** @description IANA timezone for the rrule (e.g., America/New_York). Defaults to UTC if not specified */ + timezone?: string; + }; + DeploymentWithVariablesAndSystems: { + deployment: components["schemas"]["Deployment"]; + systems: components["schemas"]["System"][]; + variables: components["schemas"]["DeploymentVariableWithValues"][]; + }; + DispatchContext: { + deployment?: components["schemas"]["Deployment"]; + environment?: components["schemas"]["Environment"]; + /** @description Resolved input values for the workflow run. */ + inputs?: { + [key: string]: unknown; + }; + jobAgent: components["schemas"]["JobAgent"]; + jobAgentConfig: components["schemas"]["JobAgentConfig"]; + release?: components["schemas"]["Release"]; + resource?: components["schemas"]["Resource"]; + variables?: { + [key: string]: components["schemas"]["LiteralValue"]; + }; + version?: components["schemas"]["DeploymentVersion"]; + workflow?: components["schemas"]["Workflow"]; + workflowJob?: components["schemas"]["WorkflowJob"]; + workflowRun?: components["schemas"]["WorkflowRun"]; + }; + EntityRelation: { + direction: components["schemas"]["RelationDirection"]; + entity: components["schemas"]["RelatableEntity"]; + /** @description ID of the related entity */ + entityId: string; + entityType: components["schemas"]["RelatableEntityType"]; + rule: components["schemas"]["RelationshipRule"]; + }; + Environment: { + /** Format: date-time */ + createdAt: string; + description?: string; + id: string; + metadata: { + [key: string]: string; + }; + name: string; + /** @description CEL expression to determine if the environment should be used */ + resourceSelector?: string; + workspaceId: string; + }; + EnvironmentProgressionRule: { + /** @description CEL expression to determine if the environment progression rule should be used */ + dependsOnEnvironmentSelector: string; + /** + * Format: int32 + * @description Maximum age of dependency deployment before blocking progression (prevents stale promotions) + */ + maximumAgeHours?: number; + /** + * Format: int32 + * @description Minimum time to wait after the depends on environment is in a success state before the current environment can be deployed + * @default 0 + */ + minimumSoakTimeMinutes: number; + /** + * Format: float + * @default 100 + */ + minimumSuccessPercentage: number; + /** + * @description If true, jobs must also have passed verification to count toward the success percentage + * @default false + */ + requireVerificationPassed: boolean; + successStatuses?: components["schemas"]["JobStatus"][]; + }; + EnvironmentSummary: { + id: string; + name: string; + }; + EnvironmentWithSystems: components["schemas"]["Environment"] & { + systems: components["schemas"]["System"][]; + }; + ErrorResponse: { + /** @example Workspace not found */ + error?: string; + }; + EvaluateReleaseTargetRequest: { + releaseTarget: components["schemas"]["ReleaseTarget"]; + version: components["schemas"]["DeploymentVersion"]; + }; + EvaluationScope: { + environmentId?: string; + versionId?: string; + }; + GithubEntity: { + installationId: number; + slug: string; + }; + GithubJobAgentConfig: { + /** + * Format: int + * @description GitHub app installation ID. + */ + installationId: number; + /** @description GitHub repository owner. */ + owner: string; + /** @description Git ref to run the workflow on (defaults to "main" if omitted). */ + ref?: string; + /** @description GitHub repository name. */ + repo: string; + /** + * Format: int64 + * @description GitHub Actions workflow ID. + */ + workflowId: number; + }; + GradualRolloutRule: { + /** + * @description Strategy for scheduling deployments to release targets. "linear": Each target is deployed at a fixed interval of timeScaleInterval seconds. "linear-normalized": Deployments are spaced evenly so that the last target is scheduled at or before timeScaleInterval seconds. See rolloutType algorithm documentation for details. + * @enum {string} + */ + rolloutType: "linear" | "linear-normalized"; + /** + * Format: int32 + * @description Base time interval in seconds used to compute the delay between deployments to release targets. + */ + timeScaleInterval: number; + }; + HTTPMetricProvider: { + /** @description Request body (supports Go templates) */ + body?: string; + /** @description HTTP headers (values support Go templates) */ + headers?: { + [key: string]: string; + }; + /** + * @description HTTP method + * @default GET + * @enum {string} + */ + method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS"; + /** + * @description Request timeout (duration string, e.g., "30s") + * @default 30s + */ + timeout: string; + /** + * @description Provider type (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: "http"; + /** + * @description HTTP endpoint URL (supports Go templates) + * @example http://{{ .resource.name }}.{{ .environment.name }}/health + */ + url: string; + }; + IntegerValue: number; + Job: { + /** Format: date-time */ + completedAt?: string; + /** Format: date-time */ + createdAt: string; + dispatchContext?: components["schemas"]["DispatchContext"]; + externalId?: string; + id: string; + jobAgentConfig: components["schemas"]["JobAgentConfig"]; + jobAgentId: string; + message?: string; + metadata: { + [key: string]: string; + }; + releaseId: string; + /** Format: date-time */ + startedAt?: string; + status: components["schemas"]["JobStatus"]; + traceToken?: string; + /** Format: date-time */ + updatedAt: string; + workflowJobId: string; + }; + JobAgent: { + config: components["schemas"]["JobAgentConfig"]; + id: string; + metadata?: { + [key: string]: string; + }; + name: string; + type: string; + workspaceId: string; + }; + JobAgentConfig: { + [key: string]: unknown; + }; + /** @enum {string} */ + JobStatus: "cancelled" | "skipped" | "inProgress" | "actionRequired" | "pending" | "failure" | "invalidJobAgent" | "invalidIntegration" | "externalRunNotFound" | "successful"; + JobSummary: { + id: string; + /** @description External links extracted from job metadata */ + links?: { + [key: string]: string; + }; + message?: string; + status: components["schemas"]["JobStatus"]; + verifications: components["schemas"]["JobVerification"][]; + }; + JobUpdateEvent: { + agentId?: string; + externalId?: string; + fieldsToUpdate?: ("completedAt" | "createdAt" | "dispatchContext" | "externalId" | "id" | "jobAgentConfig" | "jobAgentId" | "message" | "metadata" | "releaseId" | "startedAt" | "status" | "traceToken" | "updatedAt" | "workflowJobId")[]; + id?: string; + job: components["schemas"]["Job"]; + } & (unknown | unknown); + JobVerification: { + /** + * Format: date-time + * @description When verification was created + */ + createdAt: string; + id: string; + jobId: string; + /** @description Summary message of verification result */ + message?: string; + /** @description Metrics associated with this verification */ + metrics: components["schemas"]["VerificationMetricStatus"][]; + }; + /** @enum {string} */ + JobVerificationStatus: "running" | "passed" | "failed" | "cancelled"; + JobWithRelease: { + deployment?: components["schemas"]["Deployment"]; + environment?: components["schemas"]["Environment"]; + job: components["schemas"]["Job"]; + release: components["schemas"]["Release"]; + resource?: components["schemas"]["Resource"]; + }; + JobWithVerifications: { + job: components["schemas"]["Job"]; + verifications: components["schemas"]["JobVerification"][]; + }; + LiteralValue: components["schemas"]["BooleanValue"] | components["schemas"]["NumberValue"] | components["schemas"]["IntegerValue"] | components["schemas"]["StringValue"] | components["schemas"]["ObjectValue"] | components["schemas"]["NullValue"]; + MetricProvider: components["schemas"]["HTTPMetricProvider"] | components["schemas"]["SleepMetricProvider"] | components["schemas"]["DatadogMetricProvider"] | components["schemas"]["PrometheusMetricProvider"] | components["schemas"]["TerraformCloudRunMetricProvider"]; + /** @enum {boolean} */ + NullValue: true; + NumberValue: number; + ObjectValue: { + object: { + [key: string]: unknown; + }; + }; + Policy: { + createdAt: string; + description?: string; + enabled: boolean; + id: string; + /** @description Arbitrary metadata for the policy (record) */ + metadata: { + [key: string]: string; + }; + name: string; + priority: number; + rules: components["schemas"]["PolicyRule"][]; + /** @description CEL expression for matching release targets. Use "true" to match all targets. */ + selector: string; + workspaceId: string; + }; + PolicyEvaluation: { + policy?: components["schemas"]["Policy"]; + ruleResults: components["schemas"]["RuleEvaluation"][]; + summary?: string; + }; + PolicyRule: { + anyApproval?: components["schemas"]["AnyApprovalRule"]; + createdAt: string; + deploymentDependency?: components["schemas"]["DeploymentDependencyRule"]; + deploymentWindow?: components["schemas"]["DeploymentWindowRule"]; + environmentProgression?: components["schemas"]["EnvironmentProgressionRule"]; + gradualRollout?: components["schemas"]["GradualRolloutRule"]; + id: string; + policyId: string; + retry?: components["schemas"]["RetryRule"]; + rollback?: components["schemas"]["RollbackRule"]; + verification?: components["schemas"]["VerificationRule"]; + versionCooldown?: components["schemas"]["VersionCooldownRule"]; + versionSelector?: components["schemas"]["VersionSelectorRule"]; + }; + PolicySkip: { + /** + * Format: date-time + * @description When this skip was created + */ + createdAt: string; + /** @description User ID who created this skip */ + createdBy: string; + /** @description Environment this skip applies to. If null, applies to all environments. */ + environmentId?: string; + /** + * Format: date-time + * @description When this skip expires. If null, skip never expires. + */ + expiresAt?: string; + /** @description Unique identifier for the skip */ + id: string; + /** @description Required reason for why this skip is needed (e.g., incident ticket, emergency situation) */ + reason: string; + /** @description Resource this skip applies to. If null, applies to all resources (in the environment if specified, or globally). */ + resourceId?: string; + /** @description Rule ID this skip applies to */ + ruleId: string; + /** @description Deployment version this skip applies to */ + versionId: string; + /** @description Workspace this skip belongs to */ + workspaceId: string; + }; + PrometheusMetricProvider: { + /** + * @description Prometheus server address (supports Go templates) + * @example http://prometheus.example.com:9090 + */ + address: string; + /** @description Authentication configuration for Prometheus */ + authentication?: { + /** + * @description Bearer token for authentication (supports Go templates for variable references) + * @example {{.variables.prometheus_token}} + */ + bearerToken?: string; + /** @description OAuth2 client credentials flow */ + oauth2?: { + /** @description OAuth2 client ID (supports Go templates) */ + clientId: string; + /** @description OAuth2 client secret (supports Go templates) */ + clientSecret: string; + /** @description OAuth2 scopes */ + scopes?: string[]; + /** @description Token endpoint URL */ + tokenUrl: string; + }; + }; + /** @description Additional HTTP headers for the Prometheus request (values support Go templates) */ + headers?: { + /** @example X-Scope-OrgID */ + key: string; + /** @example tenant_a */ + value: string; + }[]; + /** + * @description Skip TLS certificate verification + * @default false + */ + insecure: boolean; + /** + * @description PromQL query expression (supports Go templates) + * @example sum(irate(istio_requests_total{reporter="source",destination_service=~"{{.resource.name}}",response_code!~"5.*"}[5m])) + */ + query: string; + /** @description If provided, a range query (/api/v1/query_range) is used instead of an instant query (/api/v1/query) */ + rangeQuery?: { + /** + * @description How far back from now for the query end, as a Prometheus duration (e.g., "0s" for now, "1m" for 1 minute ago). Defaults to "0s" (now) if unset. + * @example 0s + */ + end?: string; + /** + * @description How far back from now to start the query, as a Prometheus duration (e.g., "5m", "1h"). Defaults to 10 * step if unset. + * @example 5m + */ + start?: string; + /** + * @description Query resolution step width as a Prometheus duration (e.g., "15s", "1m", "500ms") + * @example 1m + */ + step: string; + }; + /** + * Format: int64 + * @description Query timeout in seconds + * @example 30 + */ + timeout?: number; + /** + * @description Provider type (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: "prometheus"; + }; + PropertiesMatcher: { + properties: components["schemas"]["PropertyMatcher"][]; + }; + PropertyMatcher: { + fromProperty: string[]; + /** @enum {string} */ + operator: "equals" | "notEquals" | "contains" | "startsWith" | "endsWith" | "regex"; + toProperty: string[]; + }; + ReferenceValue: { + path: string[]; + reference: string; + }; + RelatableEntity: components["schemas"]["Deployment"] | components["schemas"]["Environment"] | components["schemas"]["Resource"]; + /** @enum {string} */ + RelatableEntityType: "deployment" | "environment" | "resource"; + /** @enum {string} */ + RelationDirection: "from" | "to"; + RelationshipRule: { + description?: string; + /** @description CEL expression to determine if the relationship rule should be used */ + fromSelector?: string; + fromType: components["schemas"]["RelatableEntityType"]; + id: string; + matcher: components["schemas"]["CelMatcher"] | components["schemas"]["PropertiesMatcher"]; + metadata: { + [key: string]: string; + }; + name: string; + reference: string; + relationshipType: string; + /** @description CEL expression to determine if the relationship rule should be used */ + toSelector?: string; + toType: components["schemas"]["RelatableEntityType"]; + workspaceId: string; + }; + Release: { + createdAt: string; + encryptedVariables: string[]; + /** Format: uuid */ + id: string; + releaseTarget: components["schemas"]["ReleaseTarget"]; + variables: { + [key: string]: components["schemas"]["LiteralValue"]; + }; + version: components["schemas"]["DeploymentVersion"]; + }; + ReleaseTarget: { + deploymentId: string; + environmentId: string; + resourceId: string; + }; + ReleaseTargetAndState: { + releaseTarget: components["schemas"]["ReleaseTarget"]; + state: components["schemas"]["ReleaseTargetState"]; + }; + ReleaseTargetItem: { + currentVersion?: { + id: string; + name: string; + tag: string; + } | null; + desiredVersion?: { + id: string; + name: string; + tag: string; + } | null; + environment: { + id: string; + name: string; + }; + latestJob?: { + /** Format: date-time */ + completedAt?: string; + /** Format: date-time */ + createdAt: string; + id: string; + message?: string; + metadata: { + [key: string]: string; + }; + status: components["schemas"]["JobStatus"]; + verifications: { + id: string; + jobId: string; + metrics: { + count: number; + failureCondition: string | null; + failureThreshold: number | null; + id: string; + jobId?: string; + name: string; + policyRuleVerificationMetricId?: string; + provider: { + [key: string]: unknown; + }; + successCondition: string; + successThreshold: number | null; + }[]; + }[]; + } | null; + releaseTarget: { + deploymentId: string; + environmentId: string; + resourceId: string; + }; + resource: { + id: string; + identifier: string; + kind: string; + name: string; + version: string; + }; + }; + ReleaseTargetPreview: { + deployment: components["schemas"]["Deployment"]; + environment: components["schemas"]["Environment"]; + system: components["schemas"]["System"]; + }; + ReleaseTargetState: { + currentRelease?: components["schemas"]["Release"]; + desiredRelease?: components["schemas"]["Release"]; + latestJob?: components["schemas"]["JobWithVerifications"]; + }; + ReleaseTargetStateResponse: { + currentRelease?: components["schemas"]["Release"]; + desiredRelease?: components["schemas"]["Release"]; + latestJob?: { + job: components["schemas"]["Job"]; + verifications: { + /** Format: date-time */ + createdAt: string; + id: string; + jobId: string; + message?: string; + metrics: components["schemas"]["VerificationMetricStatus"][]; + /** @description Computed aggregate status of this verification */ + status: string; + }[]; + }; + }; + ReleaseTargetSummary: { + currentVersion?: components["schemas"]["VersionSummary"]; + desiredVersion?: components["schemas"]["VersionSummary"]; + environment: components["schemas"]["EnvironmentSummary"]; + latestJob?: components["schemas"]["JobSummary"]; + releaseTarget: components["schemas"]["ReleaseTarget"]; + resource: components["schemas"]["ResourceSummary"]; + }; + ReleaseTargetWithState: { + deployment: components["schemas"]["Deployment"]; + environment: components["schemas"]["Environment"]; + releaseTarget: components["schemas"]["ReleaseTarget"]; + resource: components["schemas"]["Resource"]; + state: components["schemas"]["ReleaseTargetState"]; + }; + ResolvedPolicy: { + environmentIds: string[]; + policy: components["schemas"]["Policy"]; + releaseTargets: components["schemas"]["ReleaseTarget"][]; + }; + Resource: { + config: { + [key: string]: unknown; + }; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + deletedAt?: string; + id: string; + identifier: string; + kind: string; + /** Format: date-time */ + lockedAt?: string; + metadata: { + [key: string]: string; + }; + name: string; + providerId?: string; + /** Format: date-time */ + updatedAt?: string; + variables?: { + [key: string]: components["schemas"]["Value"]; + }; + version: string; + workspaceId: string; + }; + ResourcePreviewRequest: { + config: { + [key: string]: unknown; + }; + identifier: string; + kind: string; + metadata: { + [key: string]: string; + }; + name: string; + version: string; + }; + ResourceProvider: { + /** Format: date-time */ + createdAt: string; + id: string; + metadata: { + [key: string]: string; + }; + name: string; + /** Format: uuid */ + workspaceId: string; + }; + ResourceSummary: { + id: string; + identifier: string; + kind: string; + name: string; + version: string; + }; + ResourceVariable: { + key: string; + resourceId: string; + value: components["schemas"]["Value"]; + }; + ResourceVariablesBulkUpdateEvent: { + resourceId: string; + variables: { + [key: string]: unknown; + }; + }; + RetryRule: { + /** + * Format: int32 + * @description Minimum seconds to wait between retry attempts. If null, retries are allowed immediately after job completion. + */ + backoffSeconds?: number; + /** + * @description Backoff strategy: "linear" uses constant backoffSeconds delay, "exponential" doubles the delay with each retry (backoffSeconds * 2^(attempt-1)). + * @default linear + * @enum {string} + */ + backoffStrategy: "linear" | "exponential"; + /** + * Format: int32 + * @description Maximum backoff time in seconds (cap for exponential backoff). If null, no maximum is enforced. + */ + maxBackoffSeconds?: number; + /** + * Format: int32 + * @description Maximum number of retries allowed. 0 means no retries (1 attempt total), 3 means up to 4 attempts (1 initial + 3 retries). + */ + maxRetries: number; + /** @description Job statuses that count toward the retry limit. If null or empty, defaults to ["failure", "invalidIntegration", "invalidJobAgent"] for maxRetries > 0, or ["failure", "invalidIntegration", "invalidJobAgent", "successful"] for maxRetries = 0. Cancelled and skipped jobs never count by default (allows redeployment after cancellation). Example: ["failure", "cancelled"] will only count failed/cancelled jobs. */ + retryOnStatuses?: components["schemas"]["JobStatus"][]; + }; + RollbackRule: { + /** @description Job statuses that will trigger a rollback */ + onJobStatuses?: components["schemas"]["JobStatus"][]; + /** + * @description If true, a release target will be rolled back if the verification fails + * @default false + */ + onVerificationFailure: boolean; + }; + RuleEvaluation: { + /** @description Whether the rule requires an action (e.g., approval, wait) */ + actionRequired: boolean; + /** + * @description Type of action required + * @enum {string} + */ + actionType?: "approval" | "wait"; + /** @description Whether the rule allows the deployment */ + allowed: boolean; + /** @description Additional details about the rule evaluation */ + details: { + [key: string]: unknown; + }; + /** @description Human-readable explanation of the rule result */ + message: string; + /** + * Format: date-time + * @description The time when this rule should be re-evaluated (e.g., when soak time will be complete, when gradual rollout schedule is due) + */ + nextEvaluationTime?: string; + /** @description The ID of the rule that was evaluated */ + ruleId: string; + /** + * Format: date-time + * @description The time when the rule requirement was satisfied (e.g., when approvals were met, soak time completed) + */ + satisfiedAt?: string; + }; + SensitiveValue: { + valueHash: string; + }; + SleepMetricProvider: { + /** + * Format: int32 + * @example 30 + */ + durationSeconds: number; + /** + * @description Provider type (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: "sleep"; + }; + StringValue: string; + System: { + description?: string; + id: string; + metadata?: { + [key: string]: string; + }; + name: string; + workspaceId: string; + }; + SystemDeploymentLink: { + deploymentId: string; + systemId: string; + }; + SystemEnvironmentLink: { + environmentId: string; + systemId: string; + }; + TerraformCloudJobAgentConfig: { + /** @description Terraform Cloud address (e.g. https://app.terraform.io). */ + address: string; + /** @description Terraform Cloud organization name. */ + organization: string; + /** @description Terraform Cloud workspace template. */ + template: string; + /** @description Terraform Cloud API token. */ + token: string; + /** + * @description Whether to create a TFC run on dispatch. When false, only the workspace and variables are synced. + * @default true + */ + triggerRunOnChange: boolean; + /** @description The ctrlplane API endpoint for TFC webhook notifications (e.g. https://ctrlplane.example.com/api/tfe/webhook). */ + webhookUrl: string; + }; + TerraformCloudRunMetricProvider: { + /** + * @description Terraform Cloud address + * @example https://app.terraform.io + */ + address: string; + /** + * @description Terraform Cloud run ID + * @example run-1234567890 + */ + runId: string; + /** + * @description Terraform Cloud token + * @example {{.variables.terraform_cloud_token}} + */ + token: string; + /** + * @description Provider type (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: "terraformCloudRun"; + }; + TestRunnerJobAgentConfig: { + /** + * Format: int + * @description Delay in seconds before resolving the job. + */ + delaySeconds?: number; + /** @description Optional message to include in the job output. */ + message?: string; + /** @description Final status to set (e.g. "successful", "failure"). */ + status?: string; + }; + UserApprovalRecord: { + createdAt: string; + environmentId: string; + reason?: string; + status: components["schemas"]["ApprovalStatus"]; + userId: string; + versionId: string; + }; + Value: components["schemas"]["LiteralValue"] | components["schemas"]["ReferenceValue"] | components["schemas"]["SensitiveValue"]; + VariableSet: { + /** + * Format: date-time + * @description The timestamp when the variable set was created + */ + createdAt: string; + /** @description The description of the variable set */ + description: string; + /** Format: uuid */ + id: string; + /** @description The name of the variable set */ + name: string; + /** + * Format: int64 + * @description The priority of the variable set + */ + priority: number; + /** @description A CEL expression to select which resources this value applies to */ + selector: string; + /** + * Format: date-time + * @description The timestamp when the variable set was last updated + */ + updatedAt: string; + }; + VariableSetVariable: { + /** + * Format: uuid + * @description The ID of the variable + */ + id: string; + /** @description The key of the variable, unique within the variable set */ + key: string; + value: components["schemas"]["Value"]; + /** + * Format: uuid + * @description The ID of the variable set this variable belongs to + */ + variableSetId: string; + }; + VariableSetWithVariables: components["schemas"]["VariableSet"] & { + variables: components["schemas"]["VariableSetVariable"][]; + }; + VerificationMeasurement: { + /** @description Raw measurement data */ + data: { + [key: string]: unknown; + }; + /** + * Format: date-time + * @description When measurement was taken + */ + measuredAt: string; + /** @description Measurement result message */ + message?: string; + status: components["schemas"]["VerificationMeasurementStatus"]; + }; /** - * @description Query resolution step width as a Prometheus duration (e.g., "15s", "1m", "500ms") - * @example 1m + * @description Status of a verification measurement + * @enum {string} */ - step: string; - }; - /** - * Format: int64 - * @description Query timeout in seconds - * @example 30 - */ - timeout?: number; - /** - * @description Provider type (enum property replaced by openapi-typescript) - * @enum {string} - */ - type: "prometheus"; - }; - PropertiesMatcher: { - properties: components["schemas"]["PropertyMatcher"][]; - }; - PropertyMatcher: { - fromProperty: string[]; - /** @enum {string} */ - operator: - | "equals" - | "notEquals" - | "contains" - | "startsWith" - | "endsWith" - | "regex"; - toProperty: string[]; - }; - ReferenceValue: { - path: string[]; - reference: string; - }; - RelatableEntity: - | components["schemas"]["Deployment"] - | components["schemas"]["Environment"] - | components["schemas"]["Resource"]; - /** @enum {string} */ - RelatableEntityType: "deployment" | "environment" | "resource"; - /** @enum {string} */ - RelationDirection: "from" | "to"; - RelationshipRule: { - description?: string; - /** @description CEL expression to determine if the relationship rule should be used */ - fromSelector?: string; - fromType: components["schemas"]["RelatableEntityType"]; - id: string; - matcher: - | components["schemas"]["CelMatcher"] - | components["schemas"]["PropertiesMatcher"]; - metadata: { - [key: string]: string; - }; - name: string; - reference: string; - relationshipType: string; - /** @description CEL expression to determine if the relationship rule should be used */ - toSelector?: string; - toType: components["schemas"]["RelatableEntityType"]; - workspaceId: string; - }; - Release: { - createdAt: string; - encryptedVariables: string[]; - /** Format: uuid */ - id: string; - releaseTarget: components["schemas"]["ReleaseTarget"]; - variables: { - [key: string]: components["schemas"]["LiteralValue"]; - }; - version: components["schemas"]["DeploymentVersion"]; - }; - ReleaseTarget: { - deploymentId: string; - environmentId: string; - resourceId: string; - }; - ReleaseTargetAndState: { - releaseTarget: components["schemas"]["ReleaseTarget"]; - state: components["schemas"]["ReleaseTargetState"]; - }; - ReleaseTargetItem: { - currentVersion?: { - id: string; - name: string; - tag: string; - } | null; - desiredVersion?: { - id: string; - name: string; - tag: string; - } | null; - environment: { - id: string; - name: string; - }; - latestJob?: { - /** Format: date-time */ - completedAt?: string; - /** Format: date-time */ - createdAt: string; - id: string; - message?: string; - metadata: { - [key: string]: string; - }; - status: components["schemas"]["JobStatus"]; - verifications: { - id: string; - jobId: string; - metrics: { + VerificationMeasurementStatus: "passed" | "failed" | "inconclusive"; + VerificationMetricSpec: { + /** @description Number of measurements to take */ count: number; - failureCondition: string | null; - failureThreshold: number | null; - id: string; - jobId?: string; + /** + * @description CEL expression to evaluate measurement failure (e.g., "result.statusCode == 500"), if not provided, a failure is just the opposite of the success condition + * @example result.statusCode == 500 + */ + failureCondition?: string; + /** + * @description Stop after this many consecutive failures (0 = no limit) + * @default 0 + */ + failureThreshold: number; + /** + * Format: int32 + * @description Interval between measurements in seconds + * @example 30 + */ + intervalSeconds: number; + /** @description Name of the verification metric */ name: string; - policyRuleVerificationMetricId?: string; - provider: { - [key: string]: unknown; - }; + provider: components["schemas"]["MetricProvider"]; + /** + * @description CEL expression to evaluate measurement success (e.g., "result.statusCode == 200") + * @example result.statusCode == 200 + */ successCondition: string; - successThreshold: number | null; - }[]; - }[]; - } | null; - releaseTarget: { - deploymentId: string; - environmentId: string; - resourceId: string; - }; - resource: { - id: string; - identifier: string; - kind: string; - name: string; - version: string; - }; - }; - ReleaseTargetPreview: { - deployment: components["schemas"]["Deployment"]; - environment: components["schemas"]["Environment"]; - system: components["schemas"]["System"]; - }; - ReleaseTargetState: { - currentRelease?: components["schemas"]["Release"]; - desiredRelease?: components["schemas"]["Release"]; - latestJob?: components["schemas"]["JobWithVerifications"]; - }; - ReleaseTargetStateResponse: { - currentRelease?: components["schemas"]["Release"]; - desiredRelease?: components["schemas"]["Release"]; - latestJob?: { - job: components["schemas"]["Job"]; - verifications: { - /** Format: date-time */ - createdAt: string; - id: string; - jobId: string; - message?: string; - metrics: components["schemas"]["VerificationMetricStatus"][]; - /** @description Computed aggregate status of this verification */ - status: string; - }[]; - }; - }; - ReleaseTargetSummary: { - currentVersion?: components["schemas"]["VersionSummary"]; - desiredVersion?: components["schemas"]["VersionSummary"]; - environment: components["schemas"]["EnvironmentSummary"]; - latestJob?: components["schemas"]["JobSummary"]; - releaseTarget: components["schemas"]["ReleaseTarget"]; - resource: components["schemas"]["ResourceSummary"]; - }; - ReleaseTargetWithState: { - deployment: components["schemas"]["Deployment"]; - environment: components["schemas"]["Environment"]; - releaseTarget: components["schemas"]["ReleaseTarget"]; - resource: components["schemas"]["Resource"]; - state: components["schemas"]["ReleaseTargetState"]; - }; - ResolvedPolicy: { - environmentIds: string[]; - policy: components["schemas"]["Policy"]; - releaseTargets: components["schemas"]["ReleaseTarget"][]; - }; - Resource: { - config: { - [key: string]: unknown; - }; - /** Format: date-time */ - createdAt: string; - /** Format: date-time */ - deletedAt?: string; - id: string; - identifier: string; - kind: string; - /** Format: date-time */ - lockedAt?: string; - metadata: { - [key: string]: string; - }; - name: string; - providerId?: string; - /** Format: date-time */ - updatedAt?: string; - version: string; - workspaceId: string; - }; - ResourcePreviewRequest: { - config: { - [key: string]: unknown; - }; - identifier: string; - kind: string; - metadata: { - [key: string]: string; - }; - name: string; - version: string; - }; - ResourceProvider: { - /** Format: date-time */ - createdAt: string; - id: string; - metadata: { - [key: string]: string; - }; - name: string; - /** Format: uuid */ - workspaceId: string; - }; - ResourceSummary: { - id: string; - identifier: string; - kind: string; - name: string; - version: string; - }; - ResourceVariable: { - key: string; - resourceId: string; - value: components["schemas"]["Value"]; - }; - ResourceVariablesBulkUpdateEvent: { - resourceId: string; - variables: { - [key: string]: unknown; - }; - }; - RetryRule: { - /** - * Format: int32 - * @description Minimum seconds to wait between retry attempts. If null, retries are allowed immediately after job completion. - */ - backoffSeconds?: number; - /** - * @description Backoff strategy: "linear" uses constant backoffSeconds delay, "exponential" doubles the delay with each retry (backoffSeconds * 2^(attempt-1)). - * @default linear - * @enum {string} - */ - backoffStrategy: "linear" | "exponential"; - /** - * Format: int32 - * @description Maximum backoff time in seconds (cap for exponential backoff). If null, no maximum is enforced. - */ - maxBackoffSeconds?: number; - /** - * Format: int32 - * @description Maximum number of retries allowed. 0 means no retries (1 attempt total), 3 means up to 4 attempts (1 initial + 3 retries). - */ - maxRetries: number; - /** @description Job statuses that count toward the retry limit. If null or empty, defaults to ["failure", "invalidIntegration", "invalidJobAgent"] for maxRetries > 0, or ["failure", "invalidIntegration", "invalidJobAgent", "successful"] for maxRetries = 0. Cancelled and skipped jobs never count by default (allows redeployment after cancellation). Example: ["failure", "cancelled"] will only count failed/cancelled jobs. */ - retryOnStatuses?: components["schemas"]["JobStatus"][]; - }; - RollbackRule: { - /** @description Job statuses that will trigger a rollback */ - onJobStatuses?: components["schemas"]["JobStatus"][]; - /** - * @description If true, a release target will be rolled back if the verification fails - * @default false - */ - onVerificationFailure: boolean; - }; - RuleEvaluation: { - /** @description Whether the rule requires an action (e.g., approval, wait) */ - actionRequired: boolean; - /** - * @description Type of action required - * @enum {string} - */ - actionType?: "approval" | "wait"; - /** @description Whether the rule allows the deployment */ - allowed: boolean; - /** @description Additional details about the rule evaluation */ - details: { - [key: string]: unknown; - }; - /** @description Human-readable explanation of the rule result */ - message: string; - /** - * Format: date-time - * @description The time when this rule should be re-evaluated (e.g., when soak time will be complete, when gradual rollout schedule is due) - */ - nextEvaluationTime?: string; - /** @description The ID of the rule that was evaluated */ - ruleId: string; - /** - * Format: date-time - * @description The time when the rule requirement was satisfied (e.g., when approvals were met, soak time completed) - */ - satisfiedAt?: string; - }; - SensitiveValue: { - valueHash: string; - }; - SleepMetricProvider: { - /** - * Format: int32 - * @example 30 - */ - durationSeconds: number; - /** - * @description Provider type (enum property replaced by openapi-typescript) - * @enum {string} - */ - type: "sleep"; - }; - StringValue: string; - System: { - description?: string; - id: string; - metadata?: { - [key: string]: string; - }; - name: string; - workspaceId: string; - }; - SystemDeploymentLink: { - deploymentId: string; - systemId: string; - }; - SystemEnvironmentLink: { - environmentId: string; - systemId: string; - }; - TerraformCloudJobAgentConfig: { - /** @description Terraform Cloud address (e.g. https://app.terraform.io). */ - address: string; - /** @description Terraform Cloud organization name. */ - organization: string; - /** @description Terraform Cloud workspace template. */ - template: string; - /** @description Terraform Cloud API token. */ - token: string; - /** - * @description Whether to create a TFC run on dispatch. When false, only the workspace and variables are synced. - * @default true - */ - triggerRunOnChange: boolean; - /** @description The ctrlplane API endpoint for TFC webhook notifications (e.g. https://ctrlplane.example.com/api/tfe/webhook). */ - webhookUrl: string; - }; - TerraformCloudRunMetricProvider: { - /** - * @description Terraform Cloud address - * @example https://app.terraform.io - */ - address: string; - /** - * @description Terraform Cloud run ID - * @example run-1234567890 - */ - runId: string; - /** - * @description Terraform Cloud token - * @example {{.variables.terraform_cloud_token}} - */ - token: string; - /** - * @description Provider type (enum property replaced by openapi-typescript) - * @enum {string} - */ - type: "terraformCloudRun"; - }; - TestRunnerJobAgentConfig: { - /** - * Format: int - * @description Delay in seconds before resolving the job. - */ - delaySeconds?: number; - /** @description Optional message to include in the job output. */ - message?: string; - /** @description Final status to set (e.g. "successful", "failure"). */ - status?: string; - }; - UserApprovalRecord: { - createdAt: string; - environmentId: string; - reason?: string; - status: components["schemas"]["ApprovalStatus"]; - userId: string; - versionId: string; - }; - Value: - | components["schemas"]["LiteralValue"] - | components["schemas"]["ReferenceValue"] - | components["schemas"]["SensitiveValue"]; - VariableSet: { - /** - * Format: date-time - * @description The timestamp when the variable set was created - */ - createdAt: string; - /** @description The description of the variable set */ - description: string; - /** Format: uuid */ - id: string; - /** @description The name of the variable set */ - name: string; - /** - * Format: int64 - * @description The priority of the variable set - */ - priority: number; - /** @description A CEL expression to select which resources this value applies to */ - selector: string; - /** - * Format: date-time - * @description The timestamp when the variable set was last updated - */ - updatedAt: string; - }; - VariableSetVariable: { - /** - * Format: uuid - * @description The ID of the variable - */ - id: string; - /** @description The key of the variable, unique within the variable set */ - key: string; - value: components["schemas"]["Value"]; - /** - * Format: uuid - * @description The ID of the variable set this variable belongs to - */ - variableSetId: string; - }; - VariableSetWithVariables: components["schemas"]["VariableSet"] & { - variables: components["schemas"]["VariableSetVariable"][]; - }; - VerificationMeasurement: { - /** @description Raw measurement data */ - data: { - [key: string]: unknown; - }; - /** - * Format: date-time - * @description When measurement was taken - */ - measuredAt: string; - /** @description Measurement result message */ - message?: string; - status: components["schemas"]["VerificationMeasurementStatus"]; - }; - /** - * @description Status of a verification measurement - * @enum {string} - */ - VerificationMeasurementStatus: "passed" | "failed" | "inconclusive"; - VerificationMetricSpec: { - /** @description Number of measurements to take */ - count: number; - /** - * @description CEL expression to evaluate measurement failure (e.g., "result.statusCode == 500"), if not provided, a failure is just the opposite of the success condition - * @example result.statusCode == 500 - */ - failureCondition?: string; - /** - * @description Stop after this many consecutive failures (0 = no limit) - * @default 0 - */ - failureThreshold: number; - /** - * Format: int32 - * @description Interval between measurements in seconds - * @example 30 - */ - intervalSeconds: number; - /** @description Name of the verification metric */ - name: string; - provider: components["schemas"]["MetricProvider"]; - /** - * @description CEL expression to evaluate measurement success (e.g., "result.statusCode == 200") - * @example result.statusCode == 200 - */ - successCondition: string; - /** - * @description Minimum number of consecutive successful measurements required to consider the metric successful - * @example 0 - */ - successThreshold?: number; - }; - VerificationMetricStatus: components["schemas"]["VerificationMetricSpec"] & { - id: string; - /** @description Individual verification measurements taken for this metric */ - measurements: components["schemas"]["VerificationMeasurement"][]; - }; - VerificationRule: { - /** @description Metrics to verify */ - metrics: components["schemas"]["VerificationMetricSpec"][]; - /** - * @description When to trigger verification - * @default jobSuccess - * @enum {string} - */ - triggerOn: "jobCreated" | "jobStarted" | "jobSuccess" | "jobFailure"; - }; - VersionCooldownRule: { - /** - * Format: int32 - * @description Minimum time in seconds that must pass since the currently deployed (or in-progress) version was created before allowing another deployment. This enables batching of frequent upstream releases into periodic deployments. - */ - intervalSeconds: number; - }; - VersionSelectorRule: { - /** @description Human-readable description of what this version selector does. Example: "Only deploy v2.x versions to staging environments" */ - description?: string; - /** @description CEL expression to determine if the version selector should be used */ - selector: string; - }; - VersionSummary: { - id: string; - name: string; - tag: string; - }; - Workflow: { - id: string; - inputs: components["schemas"]["WorkflowInput"][]; - jobs: components["schemas"]["WorkflowJobAgent"][]; - name: string; - }; - WorkflowArrayInput: components["schemas"]["WorkflowManualArrayInput"]; - WorkflowBooleanInput: { - default?: boolean; - key: string; - /** @enum {string} */ - type: "boolean"; - }; - WorkflowInput: - | components["schemas"]["WorkflowStringInput"] - | components["schemas"]["WorkflowNumberInput"] - | components["schemas"]["WorkflowBooleanInput"] - | components["schemas"]["WorkflowArrayInput"] - | components["schemas"]["WorkflowObjectInput"]; - WorkflowJob: { - /** @description Configuration for the job agent */ - config: { - [key: string]: unknown; - }; - id: string; - index: number; - /** @description Reference to the job agent */ - ref: string; - workflowRunId: string; - }; - WorkflowJobAgent: { - /** @description Configuration for the job agent */ - config: { - [key: string]: unknown; - }; - name: string; - /** @description Reference to the job agent */ - ref: string; - /** @description CEL expression to determine if the job agent should dispatch a job */ - selector: string; - }; - WorkflowManualArrayInput: { - default?: { - [key: string]: unknown; - }[]; - key: string; - /** @enum {string} */ - type: "array"; - }; - WorkflowNumberInput: { - default?: number; - key: string; - /** @enum {string} */ - type: "number"; - }; - WorkflowObjectInput: { - default?: { - [key: string]: unknown; - }; - key: string; - /** @enum {string} */ - type: "object"; - }; - WorkflowRun: { - id: string; - inputs: { - [key: string]: unknown; - }; - workflowId: string; - }; - WorkflowStringInput: { - default?: string; - key: string; - /** @enum {string} */ - type: "string"; - }; - }; - responses: never; - parameters: { - /** @description Type of the entity (deployment, environment, or resource) */ - relatableEntityType: components["schemas"]["RelatableEntityType"]; - }; - requestBodies: never; - headers: never; - pathItems: never; -} -export type $defs = Record; -export interface operations { - getJobAgentsForDeployment: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the deployment */ - deploymentId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Job agents matching the deployment selector */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - items: components["schemas"]["JobAgent"][]; - }; - }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; - /** @description Resource not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; - }; - }; - listReleaseTargets: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the deployment */ - deploymentId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description List of release targets for the deployment */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - items: components["schemas"]["ReleaseTargetItem"][]; - }; - }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; - }; - }; - getJobVerificationStatus: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the job */ - jobId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Aggregate verification status for the job */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { /** - * @description Aggregate verification status + * @description Minimum number of consecutive successful measurements required to consider the metric successful + * @example 0 + */ + successThreshold?: number; + }; + VerificationMetricStatus: components["schemas"]["VerificationMetricSpec"] & { + id: string; + /** @description Individual verification measurements taken for this metric */ + measurements: components["schemas"]["VerificationMeasurement"][]; + }; + VerificationRule: { + /** @description Metrics to verify */ + metrics: components["schemas"]["VerificationMetricSpec"][]; + /** + * @description When to trigger verification + * @default jobSuccess * @enum {string} */ - status: "passed" | "running" | "failed" | ""; - }; + triggerOn: "jobCreated" | "jobStarted" | "jobSuccess" | "jobFailure"; }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; + VersionCooldownRule: { + /** + * Format: int32 + * @description Minimum time in seconds that must pass since the currently deployed (or in-progress) version was created before allowing another deployment. This enables batching of frequent upstream releases into periodic deployments. + */ + intervalSeconds: number; }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; + VersionSelectorRule: { + /** @description Human-readable description of what this version selector does. Example: "Only deploy v2.x versions to staging environments" */ + description?: string; + /** @description CEL expression to determine if the version selector should be used */ + selector: string; }; - }; - }; - }; - validateResourceSelector: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: { - content: { - "application/json": { - /** @description CEL expression to validate. */ - resourceSelector: string; + VersionSummary: { + id: string; + name: string; + tag: string; + }; + Workflow: { + id: string; + inputs: components["schemas"]["WorkflowInput"][]; + jobs: components["schemas"]["WorkflowJobAgent"][]; + name: string; + }; + WorkflowArrayInput: components["schemas"]["WorkflowManualArrayInput"]; + WorkflowBooleanInput: { + default?: boolean; + key: string; + /** @enum {string} */ + type: "boolean"; + }; + WorkflowInput: components["schemas"]["WorkflowStringInput"] | components["schemas"]["WorkflowNumberInput"] | components["schemas"]["WorkflowBooleanInput"] | components["schemas"]["WorkflowArrayInput"] | components["schemas"]["WorkflowObjectInput"]; + WorkflowJob: { + /** @description Configuration for the job agent */ + config: { + [key: string]: unknown; + }; + id: string; + index: number; + /** @description Reference to the job agent */ + ref: string; + workflowRunId: string; + }; + WorkflowJobAgent: { + /** @description Configuration for the job agent */ + config: { + [key: string]: unknown; + }; + name: string; + /** @description Reference to the job agent */ + ref: string; + /** @description CEL expression to determine if the job agent should dispatch a job */ + selector: string; + }; + WorkflowManualArrayInput: { + default?: { + [key: string]: unknown; + }[]; + key: string; + /** @enum {string} */ + type: "array"; + }; + WorkflowNumberInput: { + default?: number; + key: string; + /** @enum {string} */ + type: "number"; + }; + WorkflowObjectInput: { + default?: { + [key: string]: unknown; + }; + key: string; + /** @enum {string} */ + type: "object"; + }; + WorkflowRun: { + id: string; + inputs: { + [key: string]: unknown; + }; + workflowId: string; + }; + WorkflowStringInput: { + default?: string; + key: string; + /** @enum {string} */ + type: "string"; }; - }; - }; - responses: { - /** @description The validated resource selector */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - errors: string[]; - valid: boolean; - }; - }; - }; - }; - }; - listDeployments: { - parameters: { - query?: { - /** @description Maximum number of items to return */ - limit?: number; - /** @description Number of items to skip */ - offset?: number; - /** @description CEL expression to filter the results */ - cel?: string; - }; - header?: never; - path: { - /** @description ID of the workspace */ - workspaceId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Paginated list of items */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - items: components["schemas"]["DeploymentAndSystems"][]; - /** @description Maximum number of items returned */ - limit: number; - /** @description Number of items skipped */ - offset: number; - /** @description Total number of items available */ - total: number; - }; - }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; }; - }; - getReleaseTargetState: { + responses: never; parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the workspace */ - workspaceId: string; - /** @description Key of the release target */ - releaseTargetKey: string; - }; - cookie?: never; + /** @description Type of the entity (deployment, environment, or resource) */ + relatableEntityType: components["schemas"]["RelatableEntityType"]; }; - requestBody?: never; - responses: { - /** @description Release target state */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ReleaseTargetStateResponse"]; - }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; - /** @description Resource not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + getJobAgentsForDeployment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the deployment */ + deploymentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Job agents matching the deployment selector */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items: components["schemas"]["JobAgent"][]; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + }; }; - }; - computeAggergate: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the workspace */ - workspaceId: string; - }; - cookie?: never; + listReleaseTargets: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the deployment */ + deploymentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of release targets for the deployment */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items: components["schemas"]["ReleaseTargetItem"][]; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + }; }; - requestBody: { - content: { - "application/json": { - /** @description CEL expression to filter resources. Defaults to "true" (all resources). */ - filter?: string; - groupBy?: { - /** @description Label for this grouping */ - name: string; - /** @description Dot-path property to group by (e.g. kind, metadata.region) */ - property: string; - }[]; + getJobVerificationStatus: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the job */ + jobId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Aggregate verification status for the job */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description Aggregate verification status + * @enum {string} + */ + status: "passed" | "running" | "failed" | ""; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; }; - }; }; - responses: { - /** @description OK response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - groups: { - /** @description Number of resources in this group */ - count: number; - /** @description Map of grouping name to its value for this bucket */ - key: { - [key: string]: string; - }; - }[]; - /** @description Total number of matching resources */ - total: number; - }; + validateResourceSelector: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; + requestBody?: { + content: { + "application/json": { + /** @description CEL expression to validate. */ + resourceSelector: string; + }; + }; }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; + responses: { + /** @description The validated resource selector */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + errors: string[]; + valid: boolean; + }; + }; + }; }; - }; - }; - }; - queryResources: { - parameters: { - query?: { - /** @description Maximum number of items to return */ - limit?: number; - /** @description Number of items to skip */ - offset?: number; - }; - header?: never; - path: { - /** @description ID of the workspace */ - workspaceId: string; - }; - cookie?: never; }; - requestBody: { - content: { - "application/json": { - /** @description CEL expression to filter resources. Defaults to "true" (all resources). */ - filter?: string; + listDeployments: { + parameters: { + query?: { + /** @description Maximum number of items to return */ + limit?: number; + /** @description Number of items to skip */ + offset?: number; + /** @description CEL expression to filter the results */ + cel?: string; + }; + header?: never; + path: { + /** @description ID of the workspace */ + workspaceId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of items */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items: components["schemas"]["DeploymentAndSystems"][]; + /** @description Maximum number of items returned */ + limit: number; + /** @description Number of items skipped */ + offset: number; + /** @description Total number of items available */ + total: number; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; }; - }; }; - responses: { - /** @description Paginated list of items */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - items: components["schemas"]["Resource"][]; - /** @description Maximum number of items returned */ - limit: number; - /** @description Number of items skipped */ - offset: number; - /** @description Total number of items available */ - total: number; - }; - }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; + getReleaseTargetState: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the workspace */ + workspaceId: string; + /** @description Key of the release target */ + releaseTargetKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Release target state */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ReleaseTargetStateResponse"]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + }; }; - }; - createWorkflowRun: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the workspace */ - workspaceId: string; - /** @description ID of the workflow */ - workflowId: string; - }; - cookie?: never; + computeAggergate: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the workspace */ + workspaceId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description CEL expression to filter resources. Defaults to "true" (all resources). */ + filter?: string; + groupBy?: { + /** @description Label for this grouping */ + name: string; + /** @description Dot-path property to group by (e.g. kind, metadata.region) */ + property: string; + }[]; + }; + }; + }; + responses: { + /** @description OK response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + groups: { + /** @description Number of resources in this group */ + count: number; + /** @description Map of grouping name to its value for this bucket */ + key: { + [key: string]: string; + }; + }[]; + /** @description Total number of matching resources */ + total: number; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + }; }; - requestBody: { - content: { - "application/json": { - /** @description Input values for the workflow run. */ - inputs: { - [key: string]: unknown; - }; + queryResources: { + parameters: { + query?: { + /** @description Maximum number of items to return */ + limit?: number; + /** @description Number of items to skip */ + offset?: number; + }; + header?: never; + path: { + /** @description ID of the workspace */ + workspaceId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description CEL expression to filter resources. Defaults to "true" (all resources). */ + filter?: string; + }; + }; + }; + responses: { + /** @description Paginated list of items */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items: components["schemas"]["Resource"][]; + /** @description Maximum number of items returned */ + limit: number; + /** @description Number of items skipped */ + offset: number; + /** @description Total number of items available */ + total: number; + }; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; }; - }; }; - responses: { - /** @description OK response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["WorkflowRun"]; - }; - }; - /** @description Invalid request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; - /** @description Resource not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ErrorResponse"]; - }; - }; + createWorkflowRun: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the workspace */ + workspaceId: string; + /** @description ID of the workflow */ + workflowId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Input values for the workflow run. */ + inputs: { + [key: string]: unknown; + }; + }; + }; + }; + responses: { + /** @description OK response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WorkflowRun"]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponse"]; + }; + }; + }; }; - }; } From 0509bc8e7d6deb1b5279af1bcba1e0cf527ea0b7 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 13:14:58 -0400 Subject: [PATCH 03/14] fix: update generated sdk --- packages/workspace-engine-sdk/src/schema.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/workspace-engine-sdk/src/schema.ts b/packages/workspace-engine-sdk/src/schema.ts index 5a4ff5690..f46179cab 100644 --- a/packages/workspace-engine-sdk/src/schema.ts +++ b/packages/workspace-engine-sdk/src/schema.ts @@ -287,7 +287,6 @@ export interface components { dependsOn: string; }; DeploymentVariable: { - defaultValue?: components["schemas"]["LiteralValue"]; deploymentId: string; description?: string; id: string; @@ -941,7 +940,11 @@ export interface components { }; ResourceVariable: { key: string; + /** Format: int64 */ + priority: number; resourceId: string; + /** @description A CEL expression to select which resources this value applies to */ + resourceSelector?: string; value: components["schemas"]["Value"]; }; ResourceVariablesBulkUpdateEvent: { From 8a401e0b05d701aa0358ee36438f24835f657171 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 13:21:32 -0400 Subject: [PATCH 04/14] fix(cell-compile): bug in cell expr check * short-circuit celEnv.Compile when options.CEL == "" --- .../pkg/store/resources/get_resources.go | 12 ++++-- .../desiredrelease/getters_postgres_test.go | 22 +++++------ .../variableresolver/getters_postgres_test.go | 37 ++++++++++--------- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/apps/workspace-engine/pkg/store/resources/get_resources.go b/apps/workspace-engine/pkg/store/resources/get_resources.go index 7c7a284c8..70be2fd0b 100644 --- a/apps/workspace-engine/pkg/store/resources/get_resources.go +++ b/apps/workspace-engine/pkg/store/resources/get_resources.go @@ -6,6 +6,7 @@ import ( "time" "github.com/charmbracelet/log" + "github.com/google/cel-go/cel" "github.com/google/uuid" "go.opentelemetry.io/otel" "workspace-engine/pkg/celutil" @@ -71,9 +72,12 @@ func (p *PostgresGetResources) GetResources( } defer rows.Close() - program, err := celEnv.Compile(options.CEL) - if err != nil { - return nil, fmt.Errorf("compile CEL program: %w", err) + var program cel.Program + if options.CEL != "" { + program, err = celEnv.Compile(options.CEL) + if err != nil { + return nil, fmt.Errorf("compile CEL program: %w", err) + } } var resources []*oapi.Resource @@ -88,7 +92,7 @@ func (p *PostgresGetResources) GetResources( } resource := db.ToOapiResource(r) - if options.CEL == "" { + if program == nil { resources = append(resources, resource) continue } diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go index 077567e69..c559a4a03 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/getters_postgres_test.go @@ -319,25 +319,23 @@ func TestPostgresGetter_GetDeploymentVariables(t *testing.T) { t.Run("multiple variables each get their own values", func(t *testing.T) { varA := uuid.New() varB := uuid.New() - valA, _ := json.Marshal("a-default") - valB, _ := json.Marshal("b-default") _, err := pool.Exec(ctx, - `INSERT INTO deployment_variable (id, deployment_id, key, default_value) - VALUES ($1, $2, $3, $4)`, - varA, f.deploymentID, "VAR_A", valA) + `INSERT INTO variable (id, scope, deployment_id, key) + VALUES ($1, 'deployment', $2, $3)`, + varA, f.deploymentID, "VAR_A") require.NoError(t, err) _, err = pool.Exec(ctx, - `INSERT INTO deployment_variable (id, deployment_id, key, default_value) - VALUES ($1, $2, $3, $4)`, - varB, f.deploymentID, "VAR_B", valB) + `INSERT INTO variable (id, scope, deployment_id, key) + VALUES ($1, 'deployment', $2, $3)`, + varB, f.deploymentID, "VAR_B") require.NoError(t, err) overrideA, _ := json.Marshal("a-override") _, err = pool.Exec( ctx, - `INSERT INTO deployment_variable_value (id, deployment_variable_id, value, resource_selector, priority) - VALUES ($1, $2, $3, $4, $5)`, + `INSERT INTO variable_value (id, variable_id, literal_value, resource_selector, priority, kind) + VALUES ($1, $2, $3, $4, $5, 'literal')`, uuid.New(), varA, overrideA, @@ -349,8 +347,8 @@ func TestPostgresGetter_GetDeploymentVariables(t *testing.T) { overrideB, _ := json.Marshal("b-override") _, err = pool.Exec( ctx, - `INSERT INTO deployment_variable_value (id, deployment_variable_id, value, resource_selector, priority) - VALUES ($1, $2, $3, $4, $5)`, + `INSERT INTO variable_value (id, variable_id, literal_value, resource_selector, priority, kind) + VALUES ($1, $2, $3, $4, $5, 'literal')`, uuid.New(), varB, overrideB, diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go index 794425e4e..24a4350c6 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go @@ -403,15 +403,24 @@ func TestPostgresGetter_ResourceVariablesAttachedToRaw(t *testing.T) { getter := variableresolver.NewPostgresGetter(nil) - _, err := pool.Exec(ctx, - `INSERT INTO resource_variable (resource_id, key, value) VALUES ($1, $2, $3)`, - f.resourceID, "db_url", []byte(`"postgres://db.internal/app"`)) - require.NoError(t, err) - t.Cleanup(func() { - _, _ = pool.Exec(context.Background(), - `DELETE FROM resource_variable WHERE resource_id = $1 AND key = $2`, - f.resourceID, "db_url") - }) + insertResourceVar := func(t *testing.T, resourceID uuid.UUID, key string, literal []byte) { + t.Helper() + varID := uuid.New() + _, err := pool.Exec(ctx, + `INSERT INTO variable (id, scope, resource_id, key) VALUES ($1, 'resource', $2, $3)`, + varID, resourceID, key) + require.NoError(t, err) + _, err = pool.Exec(ctx, + `INSERT INTO variable_value (variable_id, priority, kind, literal_value) VALUES ($1, 0, 'literal', $2)`, + varID, literal) + require.NoError(t, err) + t.Cleanup(func() { + _, _ = pool.Exec(context.Background(), + `DELETE FROM variable WHERE id = $1`, varID) + }) + } + + insertResourceVar(t, f.resourceID, "db_url", []byte(`"postgres://db.internal/app"`)) assertDBURL := func(t *testing.T, raw map[string]any) { t.Helper() @@ -469,18 +478,10 @@ func TestPostgresGetter_ResourceVariablesAttachedToRaw(t *testing.T) { ) require.NoError(t, err) - _, err = pool.Exec(ctx, - `INSERT INTO resource_variable (resource_id, key, value) VALUES ($1, $2, $3)`, - deletedID, "ghost", []byte(`"should-not-appear"`)) - require.NoError(t, err) + insertResourceVar(t, deletedID, "ghost", []byte(`"should-not-appear"`)) t.Cleanup(func() { cleanCtx := context.Background() - _, _ = pool.Exec( - cleanCtx, - `DELETE FROM resource_variable WHERE resource_id = $1`, - deletedID, - ) _, _ = pool.Exec(cleanCtx, `DELETE FROM resource WHERE id = $1`, deletedID) }) From 11e962ee4a4795ad65798ad7cac727cf44fc5cd6 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 13:28:09 -0400 Subject: [PATCH 05/14] fix: prettier format --- packages/db/drizzle/meta/0187_snapshot.json | 879 +++++--------------- packages/db/drizzle/meta/0188_snapshot.json | 879 +++++--------------- packages/db/drizzle/meta/_journal.json | 2 +- 3 files changed, 429 insertions(+), 1331 deletions(-) diff --git a/packages/db/drizzle/meta/0187_snapshot.json b/packages/db/drizzle/meta/0187_snapshot.json index 88e6063f4..eabe84a2b 100644 --- a/packages/db/drizzle/meta/0187_snapshot.json +++ b/packages/db/drizzle/meta/0187_snapshot.json @@ -112,12 +112,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -205,12 +201,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -220,9 +212,7 @@ "session_session_token_unique": { "name": "session_session_token_unique", "nullsNotDistinct": false, - "columns": [ - "session_token" - ] + "columns": ["session_token"] } }, "policies": {}, @@ -308,12 +298,8 @@ "name": "user_active_workspace_id_workspace_id_fk", "tableFrom": "user", "tableTo": "workspace", - "columnsFrom": [ - "active_workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["active_workspace_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -400,12 +386,8 @@ "name": "user_api_key_user_id_user_id_fk", "tableFrom": "user_api_key", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -525,12 +507,8 @@ "name": "changelog_entry_workspace_id_workspace_id_fk", "tableFrom": "changelog_entry", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -538,11 +516,7 @@ "compositePrimaryKeys": { "changelog_entry_workspace_id_entity_type_entity_id_pk": { "name": "changelog_entry_workspace_id_entity_type_entity_id_pk", - "columns": [ - "workspace_id", - "entity_type", - "entity_id" - ] + "columns": ["workspace_id", "entity_type", "entity_id"] } }, "uniqueConstraints": {}, @@ -599,12 +573,8 @@ "name": "dashboard_workspace_id_workspace_id_fk", "tableFrom": "dashboard", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -683,12 +653,8 @@ "name": "dashboard_widget_dashboard_id_dashboard_id_fk", "tableFrom": "dashboard_widget", "tableTo": "dashboard", - "columnsFrom": [ - "dashboard_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["dashboard_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -834,12 +800,8 @@ "name": "deployment_plan_workspace_id_workspace_id_fk", "tableFrom": "deployment_plan", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -847,12 +809,8 @@ "name": "deployment_plan_deployment_id_deployment_id_fk", "tableFrom": "deployment_plan", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -948,12 +906,8 @@ "name": "deployment_plan_target_plan_id_deployment_plan_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "deployment_plan", - "columnsFrom": [ - "plan_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["plan_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -961,12 +915,8 @@ "name": "deployment_plan_target_environment_id_environment_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -974,12 +924,8 @@ "name": "deployment_plan_target_resource_id_resource_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -987,12 +933,8 @@ "name": "deployment_plan_target_current_release_id_release_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "release", - "columnsFrom": [ - "current_release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["current_release_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1106,12 +1048,8 @@ "name": "deployment_plan_target_result_target_id_deployment_plan_target_id_fk", "tableFrom": "deployment_plan_target_result", "tableTo": "deployment_plan_target", - "columnsFrom": [ - "target_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["target_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1187,12 +1125,8 @@ "name": "deployment_plan_target_variable_target_id_deployment_plan_target_id_fk", "tableFrom": "deployment_plan_target_variable", "tableTo": "deployment_plan_target", - "columnsFrom": [ - "target_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["target_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1523,12 +1457,8 @@ "name": "deployment_trace_span_workspace_id_workspace_id_fk", "tableFrom": "deployment_trace_span", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1597,12 +1527,8 @@ "name": "deployment_variable_deployment_id_deployment_id_fk", "tableFrom": "deployment_variable", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1612,10 +1538,7 @@ "deployment_variable_deployment_id_key_unique": { "name": "deployment_variable_deployment_id_key_unique", "nullsNotDistinct": false, - "columns": [ - "deployment_id", - "key" - ] + "columns": ["deployment_id", "key"] } }, "policies": {}, @@ -1681,12 +1604,8 @@ "name": "deployment_variable_value_deployment_variable_id_deployment_variable_id_fk", "tableFrom": "deployment_variable_value", "tableTo": "deployment_variable", - "columnsFrom": [ - "deployment_variable_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_variable_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1818,12 +1737,8 @@ "name": "deployment_version_workspace_id_workspace_id_fk", "tableFrom": "deployment_version", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1870,12 +1785,8 @@ "name": "computed_deployment_resource_deployment_id_deployment_id_fk", "tableFrom": "computed_deployment_resource", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1883,12 +1794,8 @@ "name": "computed_deployment_resource_resource_id_resource_id_fk", "tableFrom": "computed_deployment_resource", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1896,10 +1803,7 @@ "compositePrimaryKeys": { "computed_deployment_resource_deployment_id_resource_id_pk": { "name": "computed_deployment_resource_deployment_id_resource_id_pk", - "columns": [ - "deployment_id", - "resource_id" - ] + "columns": ["deployment_id", "resource_id"] } }, "uniqueConstraints": {}, @@ -1987,12 +1891,8 @@ "name": "deployment_workspace_id_workspace_id_fk", "tableFrom": "deployment", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2039,12 +1939,8 @@ "name": "computed_environment_resource_environment_id_environment_id_fk", "tableFrom": "computed_environment_resource", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2052,12 +1948,8 @@ "name": "computed_environment_resource_resource_id_resource_id_fk", "tableFrom": "computed_environment_resource", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2065,10 +1957,7 @@ "compositePrimaryKeys": { "computed_environment_resource_environment_id_resource_id_pk": { "name": "computed_environment_resource_environment_id_resource_id_pk", - "columns": [ - "environment_id", - "resource_id" - ] + "columns": ["environment_id", "resource_id"] } }, "uniqueConstraints": {}, @@ -2150,12 +2039,8 @@ "name": "environment_workspace_id_workspace_id_fk", "tableFrom": "environment", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2209,12 +2094,8 @@ "name": "event_workspace_id_workspace_id_fk", "tableFrom": "event", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2370,12 +2251,8 @@ "name": "resource_provider_id_resource_provider_id_fk", "tableFrom": "resource", "tableTo": "resource_provider", - "columnsFrom": [ - "provider_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["provider_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2383,12 +2260,8 @@ "name": "resource_workspace_id_workspace_id_fk", "tableFrom": "resource", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2483,12 +2356,8 @@ "name": "resource_aggregate_workspace_id_workspace_id_fk", "tableFrom": "resource_aggregate", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -2496,12 +2365,8 @@ "name": "resource_aggregate_created_by_user_id_fk", "tableFrom": "resource_aggregate", "tableTo": "user", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["created_by"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2582,12 +2447,8 @@ "name": "resource_schema_workspace_id_workspace_id_fk", "tableFrom": "resource_schema", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2664,12 +2525,8 @@ "name": "resource_provider_workspace_id_workspace_id_fk", "tableFrom": "resource_provider", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2740,12 +2597,8 @@ "name": "system_workspace_id_workspace_id_fk", "tableFrom": "system", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2786,12 +2639,8 @@ "name": "system_deployment_system_id_system_id_fk", "tableFrom": "system_deployment", "tableTo": "system", - "columnsFrom": [ - "system_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["system_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2799,12 +2648,8 @@ "name": "system_deployment_deployment_id_deployment_id_fk", "tableFrom": "system_deployment", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2812,10 +2657,7 @@ "compositePrimaryKeys": { "system_deployment_system_id_deployment_id_pk": { "name": "system_deployment_system_id_deployment_id_pk", - "columns": [ - "system_id", - "deployment_id" - ] + "columns": ["system_id", "deployment_id"] } }, "uniqueConstraints": {}, @@ -2853,12 +2695,8 @@ "name": "system_environment_system_id_system_id_fk", "tableFrom": "system_environment", "tableTo": "system", - "columnsFrom": [ - "system_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["system_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2866,12 +2704,8 @@ "name": "system_environment_environment_id_environment_id_fk", "tableFrom": "system_environment", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2879,10 +2713,7 @@ "compositePrimaryKeys": { "system_environment_system_id_environment_id_pk": { "name": "system_environment_system_id_environment_id_pk", - "columns": [ - "system_id", - "environment_id" - ] + "columns": ["system_id", "environment_id"] } }, "uniqueConstraints": {}, @@ -2920,12 +2751,8 @@ "name": "team_workspace_id_workspace_id_fk", "tableFrom": "team", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2988,12 +2815,8 @@ "name": "team_member_team_id_team_id_fk", "tableFrom": "team_member", "tableTo": "team", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["team_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3001,12 +2824,8 @@ "name": "team_member_user_id_user_id_fk", "tableFrom": "team_member", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3161,12 +2980,8 @@ "name": "job_job_agent_id_job_agent_id_fk", "tableFrom": "job", "tableTo": "job_agent", - "columnsFrom": [ - "job_agent_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_agent_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -3250,12 +3065,8 @@ "name": "job_metadata_job_id_job_id_fk", "tableFrom": "job_metadata", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3331,12 +3142,8 @@ "name": "job_variable_job_id_job_id_fk", "tableFrom": "job_variable", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3385,9 +3192,7 @@ "workspace_slug_unique": { "name": "workspace_slug_unique", "nullsNotDistinct": false, - "columns": [ - "slug" - ] + "columns": ["slug"] } }, "policies": {}, @@ -3478,12 +3283,8 @@ "name": "workspace_email_domain_matching_workspace_id_workspace_id_fk", "tableFrom": "workspace_email_domain_matching", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3491,12 +3292,8 @@ "name": "workspace_email_domain_matching_role_id_role_id_fk", "tableFrom": "workspace_email_domain_matching", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3556,12 +3353,8 @@ "name": "workspace_invite_token_role_id_role_id_fk", "tableFrom": "workspace_invite_token", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3569,12 +3362,8 @@ "name": "workspace_invite_token_workspace_id_workspace_id_fk", "tableFrom": "workspace_invite_token", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3582,12 +3371,8 @@ "name": "workspace_invite_token_created_by_user_id_fk", "tableFrom": "workspace_invite_token", "tableTo": "user", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["created_by"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3597,9 +3382,7 @@ "workspace_invite_token_token_unique": { "name": "workspace_invite_token_token_unique", "nullsNotDistinct": false, - "columns": [ - "token" - ] + "columns": ["token"] } }, "policies": {}, @@ -3696,12 +3479,8 @@ "name": "entity_role_role_id_role_id_fk", "tableFrom": "entity_role", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3748,12 +3527,8 @@ "name": "role_workspace_id_workspace_id_fk", "tableFrom": "role", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3816,12 +3591,8 @@ "name": "role_permission_role_id_role_id_fk", "tableFrom": "role_permission", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3924,12 +3695,8 @@ "name": "release_resource_id_resource_id_fk", "tableFrom": "release", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3937,12 +3704,8 @@ "name": "release_environment_id_environment_id_fk", "tableFrom": "release", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3950,12 +3713,8 @@ "name": "release_deployment_id_deployment_id_fk", "tableFrom": "release", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3963,12 +3722,8 @@ "name": "release_version_id_deployment_version_id_fk", "tableFrom": "release", "tableTo": "deployment_version", - "columnsFrom": [ - "version_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["version_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4061,12 +3816,8 @@ "name": "release_job_job_id_job_id_fk", "tableFrom": "release_job", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4074,12 +3825,8 @@ "name": "release_job_release_id_release_id_fk", "tableFrom": "release_job", "tableTo": "release", - "columnsFrom": [ - "release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["release_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4160,12 +3907,8 @@ "name": "release_target_desired_release_resource_id_resource_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4173,12 +3916,8 @@ "name": "release_target_desired_release_environment_id_environment_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4186,12 +3925,8 @@ "name": "release_target_desired_release_deployment_id_deployment_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4199,12 +3934,8 @@ "name": "release_target_desired_release_desired_release_id_release_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "release", - "columnsFrom": [ - "desired_release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["desired_release_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -4287,12 +4018,8 @@ "name": "release_variable_release_id_release_id_fk", "tableFrom": "release_variable", "tableTo": "release", - "columnsFrom": [ - "release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["release_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4590,12 +4317,8 @@ "name": "policy_workspace_id_workspace_id_fk", "tableFrom": "policy", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4643,12 +4366,8 @@ "name": "policy_rule_any_approval_policy_id_policy_id_fk", "tableFrom": "policy_rule_any_approval", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4696,12 +4415,8 @@ "name": "policy_rule_deployment_dependency_policy_id_policy_id_fk", "tableFrom": "policy_rule_deployment_dependency", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4767,12 +4482,8 @@ "name": "policy_rule_deployment_window_policy_id_policy_id_fk", "tableFrom": "policy_rule_deployment_window", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4851,12 +4562,8 @@ "name": "policy_rule_environment_progression_policy_id_policy_id_fk", "tableFrom": "policy_rule_environment_progression", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4910,12 +4617,8 @@ "name": "policy_rule_gradual_rollout_policy_id_policy_id_fk", "tableFrom": "policy_rule_gradual_rollout", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4987,12 +4690,8 @@ "name": "policy_rule_retry_policy_id_policy_id_fk", "tableFrom": "policy_rule_retry", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5046,12 +4745,8 @@ "name": "policy_rule_rollback_policy_id_policy_id_fk", "tableFrom": "policy_rule_rollback", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5106,12 +4801,8 @@ "name": "policy_rule_verification_policy_id_policy_id_fk", "tableFrom": "policy_rule_verification", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5159,12 +4850,8 @@ "name": "policy_rule_version_cooldown_policy_id_policy_id_fk", "tableFrom": "policy_rule_version_cooldown", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5218,12 +4905,8 @@ "name": "policy_rule_version_selector_policy_id_policy_id_fk", "tableFrom": "policy_rule_version_selector", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5281,11 +4964,7 @@ "compositePrimaryKeys": { "user_approval_record_version_id_user_id_environment_id_pk": { "name": "user_approval_record_version_id_user_id_environment_id_pk", - "columns": [ - "version_id", - "user_id", - "environment_id" - ] + "columns": ["version_id", "user_id", "environment_id"] } }, "uniqueConstraints": {}, @@ -5322,12 +5001,8 @@ "name": "resource_variable_resource_id_resource_id_fk", "tableFrom": "resource_variable", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5335,10 +5010,7 @@ "compositePrimaryKeys": { "resource_variable_resource_id_key_pk": { "name": "resource_variable_resource_id_key_pk", - "columns": [ - "resource_id", - "key" - ] + "columns": ["resource_id", "key"] } }, "uniqueConstraints": {}, @@ -5390,12 +5062,8 @@ "name": "workflow_workspace_id_workspace_id_fk", "tableFrom": "workflow", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5436,12 +5104,8 @@ "name": "workflow_job_workflow_run_id_workflow_run_id_fk", "tableFrom": "workflow_job", "tableTo": "workflow_run", - "columnsFrom": [ - "workflow_run_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workflow_run_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5449,12 +5113,8 @@ "name": "workflow_job_job_id_job_id_fk", "tableFrom": "workflow_job", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5496,12 +5156,8 @@ "name": "workflow_run_workflow_id_workflow_id_fk", "tableFrom": "workflow_run", "tableTo": "workflow", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5708,12 +5364,8 @@ "name": "computed_policy_release_target_policy_id_policy_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5721,12 +5373,8 @@ "name": "computed_policy_release_target_environment_id_environment_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5734,12 +5382,8 @@ "name": "computed_policy_release_target_deployment_id_deployment_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5747,12 +5391,8 @@ "name": "computed_policy_release_target_resource_id_resource_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5929,12 +5569,8 @@ "name": "policy_rule_evaluation_environment_id_environment_id_fk", "tableFrom": "policy_rule_evaluation", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5942,12 +5578,8 @@ "name": "policy_rule_evaluation_version_id_deployment_version_id_fk", "tableFrom": "policy_rule_evaluation", "tableTo": "deployment_version", - "columnsFrom": [ - "version_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["version_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5955,12 +5587,8 @@ "name": "policy_rule_evaluation_resource_id_resource_id_fk", "tableFrom": "policy_rule_evaluation", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6039,12 +5667,8 @@ "name": "job_verification_metric_measurement_job_verification_metric_status_id_job_verification_metric_id_fk", "tableFrom": "job_verification_metric_measurement", "tableTo": "job_verification_metric", - "columnsFrom": [ - "job_verification_metric_status_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_verification_metric_status_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6174,12 +5798,8 @@ "name": "job_verification_metric_policy_rule_verification_metric_id_policy_rule_job_verification_metric_id_fk", "tableFrom": "job_verification_metric", "tableTo": "policy_rule_job_verification_metric", - "columnsFrom": [ - "policy_rule_verification_metric_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_rule_verification_metric_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -6273,12 +5893,8 @@ "name": "policy_rule_job_verification_metric_policy_id_policy_id_fk", "tableFrom": "policy_rule_job_verification_metric", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6380,12 +5996,8 @@ "name": "computed_entity_relationship_rule_id_relationship_rule_id_fk", "tableFrom": "computed_entity_relationship", "tableTo": "relationship_rule", - "columnsFrom": [ - "rule_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["rule_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6499,12 +6111,8 @@ "name": "relationship_rule_workspace_id_workspace_id_fk", "tableFrom": "relationship_rule", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6580,12 +6188,8 @@ "name": "job_agent_workspace_id_workspace_id_fk", "tableFrom": "job_agent", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6667,12 +6271,8 @@ "name": "variable_set_workspace_id_workspace_id_fk", "tableFrom": "variable_set", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6719,12 +6319,8 @@ "name": "variable_set_variable_variable_set_id_variable_set_id_fk", "tableFrom": "variable_set_variable", "tableTo": "variable_set", - "columnsFrom": [ - "variable_set_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["variable_set_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6734,10 +6330,7 @@ "variable_set_variable_variable_set_id_key_unique": { "name": "variable_set_variable_variable_set_id_key_unique", "nullsNotDistinct": false, - "columns": [ - "variable_set_id", - "key" - ] + "columns": ["variable_set_id", "key"] } }, "policies": {}, @@ -6902,12 +6495,8 @@ "name": "variable_resource_id_resource_id_fk", "tableFrom": "variable", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -6915,12 +6504,8 @@ "name": "variable_deployment_id_deployment_id_fk", "tableFrom": "variable", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -6928,12 +6513,8 @@ "name": "variable_job_agent_id_job_agent_id_fk", "tableFrom": "variable", "tableTo": "job_agent", - "columnsFrom": [ - "job_agent_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_agent_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -7113,12 +6694,8 @@ "name": "variable_value_variable_id_variable_id_fk", "tableFrom": "variable_value", "tableTo": "variable", - "columnsFrom": [ - "variable_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["variable_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -7139,20 +6716,12 @@ "public.system_role": { "name": "system_role", "schema": "public", - "values": [ - "user", - "admin" - ] + "values": ["user", "admin"] }, "public.deployment_plan_target_status": { "name": "deployment_plan_target_status", "schema": "public", - "values": [ - "computing", - "completed", - "errored", - "unsupported" - ] + "values": ["computing", "completed", "errored", "unsupported"] }, "public.deployment_version_status": { "name": "deployment_version_status", @@ -7196,10 +6765,7 @@ "public.entity_type": { "name": "entity_type", "schema": "public", - "values": [ - "user", - "team" - ] + "values": ["user", "team"] }, "public.scope_type": { "name": "scope_type", @@ -7217,39 +6783,22 @@ "public.job_verification_status": { "name": "job_verification_status", "schema": "public", - "values": [ - "failed", - "inconclusive", - "passed" - ] + "values": ["failed", "inconclusive", "passed"] }, "public.job_verification_trigger_on": { "name": "job_verification_trigger_on", "schema": "public", - "values": [ - "jobCreated", - "jobStarted", - "jobSuccess", - "jobFailure" - ] + "values": ["jobCreated", "jobStarted", "jobSuccess", "jobFailure"] }, "public.variable_scope": { "name": "variable_scope", "schema": "public", - "values": [ - "resource", - "deployment", - "job_agent" - ] + "values": ["resource", "deployment", "job_agent"] }, "public.variable_value_kind": { "name": "variable_value_kind", "schema": "public", - "values": [ - "literal", - "ref", - "secret_ref" - ] + "values": ["literal", "ref", "secret_ref"] } }, "schemas": {}, @@ -7262,4 +6811,4 @@ "schemas": {}, "tables": {} } -} \ No newline at end of file +} diff --git a/packages/db/drizzle/meta/0188_snapshot.json b/packages/db/drizzle/meta/0188_snapshot.json index 8ed22c446..26b65dce9 100644 --- a/packages/db/drizzle/meta/0188_snapshot.json +++ b/packages/db/drizzle/meta/0188_snapshot.json @@ -112,12 +112,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -205,12 +201,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -220,9 +212,7 @@ "session_session_token_unique": { "name": "session_session_token_unique", "nullsNotDistinct": false, - "columns": [ - "session_token" - ] + "columns": ["session_token"] } }, "policies": {}, @@ -308,12 +298,8 @@ "name": "user_active_workspace_id_workspace_id_fk", "tableFrom": "user", "tableTo": "workspace", - "columnsFrom": [ - "active_workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["active_workspace_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -400,12 +386,8 @@ "name": "user_api_key_user_id_user_id_fk", "tableFrom": "user_api_key", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -525,12 +507,8 @@ "name": "changelog_entry_workspace_id_workspace_id_fk", "tableFrom": "changelog_entry", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -538,11 +516,7 @@ "compositePrimaryKeys": { "changelog_entry_workspace_id_entity_type_entity_id_pk": { "name": "changelog_entry_workspace_id_entity_type_entity_id_pk", - "columns": [ - "workspace_id", - "entity_type", - "entity_id" - ] + "columns": ["workspace_id", "entity_type", "entity_id"] } }, "uniqueConstraints": {}, @@ -599,12 +573,8 @@ "name": "dashboard_workspace_id_workspace_id_fk", "tableFrom": "dashboard", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -683,12 +653,8 @@ "name": "dashboard_widget_dashboard_id_dashboard_id_fk", "tableFrom": "dashboard_widget", "tableTo": "dashboard", - "columnsFrom": [ - "dashboard_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["dashboard_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -834,12 +800,8 @@ "name": "deployment_plan_workspace_id_workspace_id_fk", "tableFrom": "deployment_plan", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -847,12 +809,8 @@ "name": "deployment_plan_deployment_id_deployment_id_fk", "tableFrom": "deployment_plan", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -948,12 +906,8 @@ "name": "deployment_plan_target_plan_id_deployment_plan_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "deployment_plan", - "columnsFrom": [ - "plan_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["plan_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -961,12 +915,8 @@ "name": "deployment_plan_target_environment_id_environment_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -974,12 +924,8 @@ "name": "deployment_plan_target_resource_id_resource_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -987,12 +933,8 @@ "name": "deployment_plan_target_current_release_id_release_id_fk", "tableFrom": "deployment_plan_target", "tableTo": "release", - "columnsFrom": [ - "current_release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["current_release_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1106,12 +1048,8 @@ "name": "deployment_plan_target_result_target_id_deployment_plan_target_id_fk", "tableFrom": "deployment_plan_target_result", "tableTo": "deployment_plan_target", - "columnsFrom": [ - "target_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["target_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1187,12 +1125,8 @@ "name": "deployment_plan_target_variable_target_id_deployment_plan_target_id_fk", "tableFrom": "deployment_plan_target_variable", "tableTo": "deployment_plan_target", - "columnsFrom": [ - "target_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["target_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1523,12 +1457,8 @@ "name": "deployment_trace_span_workspace_id_workspace_id_fk", "tableFrom": "deployment_trace_span", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1597,12 +1527,8 @@ "name": "deployment_variable_deployment_id_deployment_id_fk", "tableFrom": "deployment_variable", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1612,10 +1538,7 @@ "deployment_variable_deployment_id_key_unique": { "name": "deployment_variable_deployment_id_key_unique", "nullsNotDistinct": false, - "columns": [ - "deployment_id", - "key" - ] + "columns": ["deployment_id", "key"] } }, "policies": {}, @@ -1681,12 +1604,8 @@ "name": "deployment_variable_value_deployment_variable_id_deployment_variable_id_fk", "tableFrom": "deployment_variable_value", "tableTo": "deployment_variable", - "columnsFrom": [ - "deployment_variable_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_variable_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1818,12 +1737,8 @@ "name": "deployment_version_workspace_id_workspace_id_fk", "tableFrom": "deployment_version", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -1870,12 +1785,8 @@ "name": "computed_deployment_resource_deployment_id_deployment_id_fk", "tableFrom": "computed_deployment_resource", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1883,12 +1794,8 @@ "name": "computed_deployment_resource_resource_id_resource_id_fk", "tableFrom": "computed_deployment_resource", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1896,10 +1803,7 @@ "compositePrimaryKeys": { "computed_deployment_resource_deployment_id_resource_id_pk": { "name": "computed_deployment_resource_deployment_id_resource_id_pk", - "columns": [ - "deployment_id", - "resource_id" - ] + "columns": ["deployment_id", "resource_id"] } }, "uniqueConstraints": {}, @@ -1987,12 +1891,8 @@ "name": "deployment_workspace_id_workspace_id_fk", "tableFrom": "deployment", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2039,12 +1939,8 @@ "name": "computed_environment_resource_environment_id_environment_id_fk", "tableFrom": "computed_environment_resource", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2052,12 +1948,8 @@ "name": "computed_environment_resource_resource_id_resource_id_fk", "tableFrom": "computed_environment_resource", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2065,10 +1957,7 @@ "compositePrimaryKeys": { "computed_environment_resource_environment_id_resource_id_pk": { "name": "computed_environment_resource_environment_id_resource_id_pk", - "columns": [ - "environment_id", - "resource_id" - ] + "columns": ["environment_id", "resource_id"] } }, "uniqueConstraints": {}, @@ -2150,12 +2039,8 @@ "name": "environment_workspace_id_workspace_id_fk", "tableFrom": "environment", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2209,12 +2094,8 @@ "name": "event_workspace_id_workspace_id_fk", "tableFrom": "event", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2370,12 +2251,8 @@ "name": "resource_provider_id_resource_provider_id_fk", "tableFrom": "resource", "tableTo": "resource_provider", - "columnsFrom": [ - "provider_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["provider_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2383,12 +2260,8 @@ "name": "resource_workspace_id_workspace_id_fk", "tableFrom": "resource", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2483,12 +2356,8 @@ "name": "resource_aggregate_workspace_id_workspace_id_fk", "tableFrom": "resource_aggregate", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, @@ -2496,12 +2365,8 @@ "name": "resource_aggregate_created_by_user_id_fk", "tableFrom": "resource_aggregate", "tableTo": "user", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["created_by"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2582,12 +2447,8 @@ "name": "resource_schema_workspace_id_workspace_id_fk", "tableFrom": "resource_schema", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } @@ -2664,12 +2525,8 @@ "name": "resource_provider_workspace_id_workspace_id_fk", "tableFrom": "resource_provider", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2740,12 +2597,8 @@ "name": "system_workspace_id_workspace_id_fk", "tableFrom": "system", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2786,12 +2639,8 @@ "name": "system_deployment_system_id_system_id_fk", "tableFrom": "system_deployment", "tableTo": "system", - "columnsFrom": [ - "system_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["system_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2799,12 +2648,8 @@ "name": "system_deployment_deployment_id_deployment_id_fk", "tableFrom": "system_deployment", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2812,10 +2657,7 @@ "compositePrimaryKeys": { "system_deployment_system_id_deployment_id_pk": { "name": "system_deployment_system_id_deployment_id_pk", - "columns": [ - "system_id", - "deployment_id" - ] + "columns": ["system_id", "deployment_id"] } }, "uniqueConstraints": {}, @@ -2853,12 +2695,8 @@ "name": "system_environment_system_id_system_id_fk", "tableFrom": "system_environment", "tableTo": "system", - "columnsFrom": [ - "system_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["system_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2866,12 +2704,8 @@ "name": "system_environment_environment_id_environment_id_fk", "tableFrom": "system_environment", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2879,10 +2713,7 @@ "compositePrimaryKeys": { "system_environment_system_id_environment_id_pk": { "name": "system_environment_system_id_environment_id_pk", - "columns": [ - "system_id", - "environment_id" - ] + "columns": ["system_id", "environment_id"] } }, "uniqueConstraints": {}, @@ -2920,12 +2751,8 @@ "name": "team_workspace_id_workspace_id_fk", "tableFrom": "team", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2988,12 +2815,8 @@ "name": "team_member_team_id_team_id_fk", "tableFrom": "team_member", "tableTo": "team", - "columnsFrom": [ - "team_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["team_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3001,12 +2824,8 @@ "name": "team_member_user_id_user_id_fk", "tableFrom": "team_member", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3161,12 +2980,8 @@ "name": "job_job_agent_id_job_agent_id_fk", "tableFrom": "job", "tableTo": "job_agent", - "columnsFrom": [ - "job_agent_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_agent_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -3250,12 +3065,8 @@ "name": "job_metadata_job_id_job_id_fk", "tableFrom": "job_metadata", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3331,12 +3142,8 @@ "name": "job_variable_job_id_job_id_fk", "tableFrom": "job_variable", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3385,9 +3192,7 @@ "workspace_slug_unique": { "name": "workspace_slug_unique", "nullsNotDistinct": false, - "columns": [ - "slug" - ] + "columns": ["slug"] } }, "policies": {}, @@ -3478,12 +3283,8 @@ "name": "workspace_email_domain_matching_workspace_id_workspace_id_fk", "tableFrom": "workspace_email_domain_matching", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3491,12 +3292,8 @@ "name": "workspace_email_domain_matching_role_id_role_id_fk", "tableFrom": "workspace_email_domain_matching", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3556,12 +3353,8 @@ "name": "workspace_invite_token_role_id_role_id_fk", "tableFrom": "workspace_invite_token", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3569,12 +3362,8 @@ "name": "workspace_invite_token_workspace_id_workspace_id_fk", "tableFrom": "workspace_invite_token", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3582,12 +3371,8 @@ "name": "workspace_invite_token_created_by_user_id_fk", "tableFrom": "workspace_invite_token", "tableTo": "user", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["created_by"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3597,9 +3382,7 @@ "workspace_invite_token_token_unique": { "name": "workspace_invite_token_token_unique", "nullsNotDistinct": false, - "columns": [ - "token" - ] + "columns": ["token"] } }, "policies": {}, @@ -3696,12 +3479,8 @@ "name": "entity_role_role_id_role_id_fk", "tableFrom": "entity_role", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3748,12 +3527,8 @@ "name": "role_workspace_id_workspace_id_fk", "tableFrom": "role", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3816,12 +3591,8 @@ "name": "role_permission_role_id_role_id_fk", "tableFrom": "role_permission", "tableTo": "role", - "columnsFrom": [ - "role_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["role_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -3924,12 +3695,8 @@ "name": "release_resource_id_resource_id_fk", "tableFrom": "release", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3937,12 +3704,8 @@ "name": "release_environment_id_environment_id_fk", "tableFrom": "release", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3950,12 +3713,8 @@ "name": "release_deployment_id_deployment_id_fk", "tableFrom": "release", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -3963,12 +3722,8 @@ "name": "release_version_id_deployment_version_id_fk", "tableFrom": "release", "tableTo": "deployment_version", - "columnsFrom": [ - "version_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["version_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4061,12 +3816,8 @@ "name": "release_job_job_id_job_id_fk", "tableFrom": "release_job", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4074,12 +3825,8 @@ "name": "release_job_release_id_release_id_fk", "tableFrom": "release_job", "tableTo": "release", - "columnsFrom": [ - "release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["release_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4160,12 +3907,8 @@ "name": "release_target_desired_release_resource_id_resource_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4173,12 +3916,8 @@ "name": "release_target_desired_release_environment_id_environment_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4186,12 +3925,8 @@ "name": "release_target_desired_release_deployment_id_deployment_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -4199,12 +3934,8 @@ "name": "release_target_desired_release_desired_release_id_release_id_fk", "tableFrom": "release_target_desired_release", "tableTo": "release", - "columnsFrom": [ - "desired_release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["desired_release_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -4287,12 +4018,8 @@ "name": "release_variable_release_id_release_id_fk", "tableFrom": "release_variable", "tableTo": "release", - "columnsFrom": [ - "release_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["release_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4590,12 +4317,8 @@ "name": "policy_workspace_id_workspace_id_fk", "tableFrom": "policy", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4643,12 +4366,8 @@ "name": "policy_rule_any_approval_policy_id_policy_id_fk", "tableFrom": "policy_rule_any_approval", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4696,12 +4415,8 @@ "name": "policy_rule_deployment_dependency_policy_id_policy_id_fk", "tableFrom": "policy_rule_deployment_dependency", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4767,12 +4482,8 @@ "name": "policy_rule_deployment_window_policy_id_policy_id_fk", "tableFrom": "policy_rule_deployment_window", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4851,12 +4562,8 @@ "name": "policy_rule_environment_progression_policy_id_policy_id_fk", "tableFrom": "policy_rule_environment_progression", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4910,12 +4617,8 @@ "name": "policy_rule_gradual_rollout_policy_id_policy_id_fk", "tableFrom": "policy_rule_gradual_rollout", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -4987,12 +4690,8 @@ "name": "policy_rule_retry_policy_id_policy_id_fk", "tableFrom": "policy_rule_retry", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5046,12 +4745,8 @@ "name": "policy_rule_rollback_policy_id_policy_id_fk", "tableFrom": "policy_rule_rollback", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5106,12 +4801,8 @@ "name": "policy_rule_verification_policy_id_policy_id_fk", "tableFrom": "policy_rule_verification", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5159,12 +4850,8 @@ "name": "policy_rule_version_cooldown_policy_id_policy_id_fk", "tableFrom": "policy_rule_version_cooldown", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5218,12 +4905,8 @@ "name": "policy_rule_version_selector_policy_id_policy_id_fk", "tableFrom": "policy_rule_version_selector", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5281,11 +4964,7 @@ "compositePrimaryKeys": { "user_approval_record_version_id_user_id_environment_id_pk": { "name": "user_approval_record_version_id_user_id_environment_id_pk", - "columns": [ - "version_id", - "user_id", - "environment_id" - ] + "columns": ["version_id", "user_id", "environment_id"] } }, "uniqueConstraints": {}, @@ -5322,12 +5001,8 @@ "name": "resource_variable_resource_id_resource_id_fk", "tableFrom": "resource_variable", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5335,10 +5010,7 @@ "compositePrimaryKeys": { "resource_variable_resource_id_key_pk": { "name": "resource_variable_resource_id_key_pk", - "columns": [ - "resource_id", - "key" - ] + "columns": ["resource_id", "key"] } }, "uniqueConstraints": {}, @@ -5390,12 +5062,8 @@ "name": "workflow_workspace_id_workspace_id_fk", "tableFrom": "workflow", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5436,12 +5104,8 @@ "name": "workflow_job_workflow_run_id_workflow_run_id_fk", "tableFrom": "workflow_job", "tableTo": "workflow_run", - "columnsFrom": [ - "workflow_run_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workflow_run_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5449,12 +5113,8 @@ "name": "workflow_job_job_id_job_id_fk", "tableFrom": "workflow_job", "tableTo": "job", - "columnsFrom": [ - "job_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5496,12 +5156,8 @@ "name": "workflow_run_workflow_id_workflow_id_fk", "tableFrom": "workflow_run", "tableTo": "workflow", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5708,12 +5364,8 @@ "name": "computed_policy_release_target_policy_id_policy_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5721,12 +5373,8 @@ "name": "computed_policy_release_target_environment_id_environment_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5734,12 +5382,8 @@ "name": "computed_policy_release_target_deployment_id_deployment_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5747,12 +5391,8 @@ "name": "computed_policy_release_target_resource_id_resource_id_fk", "tableFrom": "computed_policy_release_target", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -5929,12 +5569,8 @@ "name": "policy_rule_evaluation_environment_id_environment_id_fk", "tableFrom": "policy_rule_evaluation", "tableTo": "environment", - "columnsFrom": [ - "environment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5942,12 +5578,8 @@ "name": "policy_rule_evaluation_version_id_deployment_version_id_fk", "tableFrom": "policy_rule_evaluation", "tableTo": "deployment_version", - "columnsFrom": [ - "version_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["version_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -5955,12 +5587,8 @@ "name": "policy_rule_evaluation_resource_id_resource_id_fk", "tableFrom": "policy_rule_evaluation", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6039,12 +5667,8 @@ "name": "job_verification_metric_measurement_job_verification_metric_status_id_job_verification_metric_id_fk", "tableFrom": "job_verification_metric_measurement", "tableTo": "job_verification_metric", - "columnsFrom": [ - "job_verification_metric_status_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_verification_metric_status_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6174,12 +5798,8 @@ "name": "job_verification_metric_policy_rule_verification_metric_id_policy_rule_job_verification_metric_id_fk", "tableFrom": "job_verification_metric", "tableTo": "policy_rule_job_verification_metric", - "columnsFrom": [ - "policy_rule_verification_metric_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_rule_verification_metric_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -6273,12 +5893,8 @@ "name": "policy_rule_job_verification_metric_policy_id_policy_id_fk", "tableFrom": "policy_rule_job_verification_metric", "tableTo": "policy", - "columnsFrom": [ - "policy_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["policy_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6380,12 +5996,8 @@ "name": "computed_entity_relationship_rule_id_relationship_rule_id_fk", "tableFrom": "computed_entity_relationship", "tableTo": "relationship_rule", - "columnsFrom": [ - "rule_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["rule_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6499,12 +6111,8 @@ "name": "relationship_rule_workspace_id_workspace_id_fk", "tableFrom": "relationship_rule", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6580,12 +6188,8 @@ "name": "job_agent_workspace_id_workspace_id_fk", "tableFrom": "job_agent", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6667,12 +6271,8 @@ "name": "variable_set_workspace_id_workspace_id_fk", "tableFrom": "variable_set", "tableTo": "workspace", - "columnsFrom": [ - "workspace_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6719,12 +6319,8 @@ "name": "variable_set_variable_variable_set_id_variable_set_id_fk", "tableFrom": "variable_set_variable", "tableTo": "variable_set", - "columnsFrom": [ - "variable_set_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["variable_set_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -6734,10 +6330,7 @@ "variable_set_variable_variable_set_id_key_unique": { "name": "variable_set_variable_variable_set_id_key_unique", "nullsNotDistinct": false, - "columns": [ - "variable_set_id", - "key" - ] + "columns": ["variable_set_id", "key"] } }, "policies": {}, @@ -6902,12 +6495,8 @@ "name": "variable_resource_id_resource_id_fk", "tableFrom": "variable", "tableTo": "resource", - "columnsFrom": [ - "resource_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["resource_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -6915,12 +6504,8 @@ "name": "variable_deployment_id_deployment_id_fk", "tableFrom": "variable", "tableTo": "deployment", - "columnsFrom": [ - "deployment_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["deployment_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -6928,12 +6513,8 @@ "name": "variable_job_agent_id_job_agent_id_fk", "tableFrom": "variable", "tableTo": "job_agent", - "columnsFrom": [ - "job_agent_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["job_agent_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -7113,12 +6694,8 @@ "name": "variable_value_variable_id_variable_id_fk", "tableFrom": "variable_value", "tableTo": "variable", - "columnsFrom": [ - "variable_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["variable_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -7139,20 +6716,12 @@ "public.system_role": { "name": "system_role", "schema": "public", - "values": [ - "user", - "admin" - ] + "values": ["user", "admin"] }, "public.deployment_plan_target_status": { "name": "deployment_plan_target_status", "schema": "public", - "values": [ - "computing", - "completed", - "errored", - "unsupported" - ] + "values": ["computing", "completed", "errored", "unsupported"] }, "public.deployment_version_status": { "name": "deployment_version_status", @@ -7196,10 +6765,7 @@ "public.entity_type": { "name": "entity_type", "schema": "public", - "values": [ - "user", - "team" - ] + "values": ["user", "team"] }, "public.scope_type": { "name": "scope_type", @@ -7217,39 +6783,22 @@ "public.job_verification_status": { "name": "job_verification_status", "schema": "public", - "values": [ - "failed", - "inconclusive", - "passed" - ] + "values": ["failed", "inconclusive", "passed"] }, "public.job_verification_trigger_on": { "name": "job_verification_trigger_on", "schema": "public", - "values": [ - "jobCreated", - "jobStarted", - "jobSuccess", - "jobFailure" - ] + "values": ["jobCreated", "jobStarted", "jobSuccess", "jobFailure"] }, "public.variable_scope": { "name": "variable_scope", "schema": "public", - "values": [ - "resource", - "deployment", - "job_agent" - ] + "values": ["resource", "deployment", "job_agent"] }, "public.variable_value_kind": { "name": "variable_value_kind", "schema": "public", - "values": [ - "literal", - "ref", - "secret_ref" - ] + "values": ["literal", "ref", "secret_ref"] } }, "schemas": {}, @@ -7262,4 +6811,4 @@ "schemas": {}, "tables": {} } -} \ No newline at end of file +} diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json index f6c58d155..4fb569c72 100644 --- a/packages/db/drizzle/meta/_journal.json +++ b/packages/db/drizzle/meta/_journal.json @@ -1326,4 +1326,4 @@ "breakpoints": true } ] -} \ No newline at end of file +} From e7b0c00dc004ec543418017141c841404a60b647 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 14:14:52 -0400 Subject: [PATCH 06/14] fix: go format --- .../variableresolver/getters_postgres_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go index 24a4350c6..7f92ab3e6 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres_test.go @@ -410,9 +410,12 @@ func TestPostgresGetter_ResourceVariablesAttachedToRaw(t *testing.T) { `INSERT INTO variable (id, scope, resource_id, key) VALUES ($1, 'resource', $2, $3)`, varID, resourceID, key) require.NoError(t, err) - _, err = pool.Exec(ctx, + _, err = pool.Exec( + ctx, `INSERT INTO variable_value (variable_id, priority, kind, literal_value) VALUES ($1, 0, 'literal', $2)`, - varID, literal) + varID, + literal, + ) require.NoError(t, err) t.Cleanup(func() { _, _ = pool.Exec(context.Background(), From cfdc9b6b6814d03a9097e8b626b2fe779dfe7271 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 14:21:27 -0400 Subject: [PATCH 07/14] fix: trpc formatting --- packages/trpc/src/routes/_variables.ts | 3 +-- packages/trpc/src/routes/deployments.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/trpc/src/routes/_variables.ts b/packages/trpc/src/routes/_variables.ts index 9adb4b0cd..aa1e91a13 100644 --- a/packages/trpc/src/routes/_variables.ts +++ b/packages/trpc/src/routes/_variables.ts @@ -4,8 +4,7 @@ type VariableValueRow = typeof schema.variableValue.$inferSelect; export const flattenVariableValue = (v: VariableValueRow): unknown => { if (v.kind === "literal") return v.literalValue; - if (v.kind === "ref") - return { reference: v.refKey, path: v.refPath ?? [] }; + if (v.kind === "ref") return { reference: v.refKey, path: v.refPath ?? [] }; return { provider: v.secretProvider, key: v.secretKey, diff --git a/packages/trpc/src/routes/deployments.ts b/packages/trpc/src/routes/deployments.ts index 1de45b0f6..7cb5ae653 100644 --- a/packages/trpc/src/routes/deployments.ts +++ b/packages/trpc/src/routes/deployments.ts @@ -14,8 +14,8 @@ import { Permission } from "@ctrlplane/validators/auth"; import { getClientFor } from "@ctrlplane/workspace-engine-sdk"; import { protectedProcedure, router } from "../trpc.js"; -import { deploymentPlansRouter } from "./deployment-plans.js"; import { toClientVariableValue } from "./_variables.js"; +import { deploymentPlansRouter } from "./deployment-plans.js"; export const deploymentsRouter = router({ plans: deploymentPlansRouter, From d7a837bb340eb2cd51833a45e7b74683f0895419 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 14:33:41 -0400 Subject: [PATCH 08/14] fix: migration to migrate references --- .../db/drizzle/0188_backfill_variables.sql | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/db/drizzle/0188_backfill_variables.sql b/packages/db/drizzle/0188_backfill_variables.sql index d97e1a717..589ea449b 100644 --- a/packages/db/drizzle/0188_backfill_variables.sql +++ b/packages/db/drizzle/0188_backfill_variables.sql @@ -10,6 +10,24 @@ FROM deployment_variable dv ON CONFLICT (id) DO NOTHING; --> statement-breakpoint +INSERT INTO "variable_value" ( + id, variable_id, resource_selector, priority, kind, ref_key, ref_path +) +SELECT + dvv.id, + dvv.deployment_variable_id, + dvv.resource_selector, + dvv.priority, + 'ref'::variable_value_kind, + dvv.value->>'reference', + ARRAY(SELECT jsonb_array_elements_text(dvv.value->'path')) +FROM deployment_variable_value dvv +WHERE jsonb_typeof(dvv.value) = 'object' + AND dvv.value ? 'reference' + AND dvv.value ? 'path' +ON CONFLICT (id) DO NOTHING; +--> statement-breakpoint + INSERT INTO "variable_value" ( id, variable_id, resource_selector, priority, kind, literal_value ) @@ -21,6 +39,11 @@ SELECT 'literal'::variable_value_kind, dvv.value FROM deployment_variable_value dvv +WHERE NOT ( + jsonb_typeof(dvv.value) = 'object' + AND dvv.value ? 'reference' + AND dvv.value ? 'path' +) ON CONFLICT (id) DO NOTHING; --> statement-breakpoint @@ -34,6 +57,29 @@ FROM resource_variable rv ON CONFLICT (resource_id, key) WHERE resource_id IS NOT NULL DO NOTHING; --> statement-breakpoint +INSERT INTO "variable_value" (variable_id, priority, kind, ref_key, ref_path) +SELECT + v.id, + 0, + 'ref'::variable_value_kind, + rv.value->>'reference', + ARRAY(SELECT jsonb_array_elements_text(rv.value->'path')) +FROM resource_variable rv +JOIN "variable" v + ON v.scope = 'resource' + AND v.resource_id = rv.resource_id + AND v.key = rv.key +WHERE jsonb_typeof(rv.value) = 'object' + AND rv.value ? 'reference' + AND rv.value ? 'path' + AND NOT EXISTS ( + SELECT 1 FROM "variable_value" vv + WHERE vv.variable_id = v.id + AND vv.resource_selector IS NULL + AND vv.priority = 0 + ); +--> statement-breakpoint + INSERT INTO "variable_value" (variable_id, priority, kind, literal_value) SELECT v.id, @@ -45,7 +91,12 @@ JOIN "variable" v ON v.scope = 'resource' AND v.resource_id = rv.resource_id AND v.key = rv.key -WHERE NOT EXISTS ( +WHERE NOT ( + jsonb_typeof(rv.value) = 'object' + AND rv.value ? 'reference' + AND rv.value ? 'path' +) +AND NOT EXISTS ( SELECT 1 FROM "variable_value" vv WHERE vv.variable_id = v.id AND vv.resource_selector IS NULL From 5f8bad0d2a688de1a8b9af40fbc5d007235e5984 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Mon, 20 Apr 2026 18:05:35 -0400 Subject: [PATCH 09/14] fix: coderabit comments * fixes coderabbit comments --- .../v1/workspaces/deployment-variables.ts | 57 ++++++-- .../api/src/routes/v1/workspaces/resources.ts | 49 ++++++- .../pkg/db/queries/variables.sql | 3 + apps/workspace-engine/pkg/db/variables.sql.go | 3 + .../variableresolver/getters_postgres.go | 24 +++- .../db/drizzle/0188_backfill_variables.sql | 122 ++++++++++++++---- packages/trpc/src/routes/deployments.ts | 62 +++++++-- packages/trpc/src/routes/resources.ts | 24 +++- 8 files changed, 276 insertions(+), 68 deletions(-) diff --git a/apps/api/src/routes/v1/workspaces/deployment-variables.ts b/apps/api/src/routes/v1/workspaces/deployment-variables.ts index 68681643f..7de66bd5a 100644 --- a/apps/api/src/routes/v1/workspaces/deployment-variables.ts +++ b/apps/api/src/routes/v1/workspaces/deployment-variables.ts @@ -13,8 +13,7 @@ type VariableValueRow = typeof variableValue.$inferSelect; const flattenVariableValue = (v: VariableValueRow): unknown => { if (v.kind === "literal") return v.literalValue; - if (v.kind === "ref") - return { reference: v.refKey, path: v.refPath ?? [] }; + if (v.kind === "ref") return { reference: v.refKey, path: v.refPath ?? [] }; return { provider: v.secretProvider, key: v.secretKey, @@ -79,19 +78,24 @@ const getDeploymentVariable: AsyncTypedHandler< "/v1/workspaces/{workspaceId}/deployment-variables/{variableId}", "get" > = async (req, res) => { - const { variableId } = req.params; + const { workspaceId, variableId } = req.params; - const v = await db - .select() + const row = await db + .select({ variable }) .from(variable) + .innerJoin(deployment, eq(variable.deploymentId, deployment.id)) .where( - and(eq(variable.id, variableId), eq(variable.scope, "deployment")), + and( + eq(variable.id, variableId), + eq(variable.scope, "deployment"), + eq(deployment.workspaceId, workspaceId), + ), ) .then(takeFirstOrNull); - if (v == null) - throw new ApiError("Deployment variable not found", 404); + if (row == null) throw new ApiError("Deployment variable not found", 404); + const v = row.variable; const values = await db .select() .from(variableValue) @@ -192,18 +196,25 @@ const getDeploymentVariableValue: AsyncTypedHandler< "/v1/workspaces/{workspaceId}/deployment-variable-values/{valueId}", "get" > = async (req, res) => { - const { valueId } = req.params; + const { workspaceId, valueId } = req.params; - const val = await db - .select() + const row = await db + .select({ variableValue }) .from(variableValue) - .where(eq(variableValue.id, valueId)) + .innerJoin(variable, eq(variableValue.variableId, variable.id)) + .innerJoin(deployment, eq(variable.deploymentId, deployment.id)) + .where( + and( + eq(variableValue.id, valueId), + eq(deployment.workspaceId, workspaceId), + ), + ) .then(takeFirstOrNull); - if (val == null) + if (row == null) throw new ApiError("Deployment variable value not found", 404); - res.json(toApiVariableValue(val)); + res.json(toApiVariableValue(row.variableValue)); }; const upsertDeploymentVariableValue: AsyncTypedHandler< @@ -239,6 +250,19 @@ const upsertDeploymentVariableValue: AsyncTypedHandler< return; } + const existing = await db + .select({ variableId: variableValue.variableId }) + .from(variableValue) + .where(eq(variableValue.id, valueId)) + .then(takeFirstOrNull); + + if (existing != null && existing.variableId !== deploymentVariableId) { + res.status(409).json({ + error: "Value id already belongs to a different deployment variable", + }); + return; + } + await db .insert(variableValue) .values({ @@ -256,6 +280,11 @@ const upsertDeploymentVariableValue: AsyncTypedHandler< resourceSelector: body.resourceSelector ?? null, kind: "literal", literalValue: body.value, + refKey: null, + refPath: null, + secretProvider: null, + secretKey: null, + secretPath: null, }, }); diff --git a/apps/api/src/routes/v1/workspaces/resources.ts b/apps/api/src/routes/v1/workspaces/resources.ts index ac5568d1e..7c3e11d3a 100644 --- a/apps/api/src/routes/v1/workspaces/resources.ts +++ b/apps/api/src/routes/v1/workspaces/resources.ts @@ -26,6 +26,27 @@ import * as schema from "@ctrlplane/db/schema"; import { validResourceSelector } from "../valid-selector.js"; import { extractMessageFromError } from "./utils.js"; +type VariableValueShape = { + kind: typeof schema.variableValue.kind.enumValues[number]; + literalValue: unknown; + refKey: string | null; + refPath: string[] | null; + secretProvider: string | null; + secretKey: string | null; + secretPath: string[] | null; +}; + +const flattenResourceVariableValue = (r: VariableValueShape): unknown => { + if (r.kind === "literal") return r.literalValue; + if (r.kind === "ref") + return { reference: r.refKey, path: r.refPath ?? [] }; + return { + provider: r.secretProvider, + key: r.secretKey, + path: r.secretPath ?? [], + }; +}; + const listResources: AsyncTypedHandler< "/v1/workspaces/{workspaceId}/resources", "get" @@ -169,7 +190,10 @@ const upsertResourceByIdentifier: AsyncTypedHandler< variableId: byKey.get(key)!, priority: 0, kind: "literal" as const, - literalValue: value, + literalValue: + value != null && typeof value === "object" + ? { object: value } + : value, })), ); } @@ -240,7 +264,13 @@ const getVariablesForResource: AsyncTypedHandler< .select({ resourceId: schema.variable.resourceId, key: schema.variable.key, - value: schema.variableValue.literalValue, + kind: schema.variableValue.kind, + literalValue: schema.variableValue.literalValue, + refKey: schema.variableValue.refKey, + refPath: schema.variableValue.refPath, + secretProvider: schema.variableValue.secretProvider, + secretKey: schema.variableValue.secretKey, + secretPath: schema.variableValue.secretPath, }) .from(schema.variable) .innerJoin( @@ -251,14 +281,16 @@ const getVariablesForResource: AsyncTypedHandler< and( eq(schema.variable.scope, "resource"), eq(schema.variable.resourceId, resource.id), - eq(schema.variableValue.kind, "literal"), ), ); - const total = rows.length; - const items = rows.slice(offset, offset + limit); + const items = rows.slice(offset, offset + limit).map((r) => ({ + resourceId: r.resourceId, + key: r.key, + value: flattenResourceVariableValue(r), + })); - res.status(200).json({ items, total, limit, offset }); + res.status(200).json({ items, total: rows.length, limit, offset }); }; const updateVariablesForResource: AsyncTypedHandler< @@ -303,7 +335,10 @@ const updateVariablesForResource: AsyncTypedHandler< variableId: byKey.get(key)!, priority: 0, kind: "literal" as const, - literalValue: value, + literalValue: + value != null && typeof value === "object" + ? { object: value } + : value, })), ); } diff --git a/apps/workspace-engine/pkg/db/queries/variables.sql b/apps/workspace-engine/pkg/db/queries/variables.sql index 12430425a..3d26b412b 100644 --- a/apps/workspace-engine/pkg/db/queries/variables.sql +++ b/apps/workspace-engine/pkg/db/queries/variables.sql @@ -24,6 +24,7 @@ SELECT 'secretKey', vv.secret_key, 'secretPath', vv.secret_path ) + ORDER BY vv.priority DESC, vv.id ASC ) FROM variable_value vv WHERE vv.variable_id = v.id @@ -59,6 +60,7 @@ SELECT 'secretKey', vv.secret_key, 'secretPath', vv.secret_path ) + ORDER BY vv.priority DESC, vv.id ASC ) FROM variable_value vv WHERE vv.variable_id = v.id @@ -91,6 +93,7 @@ SELECT 'secretKey', vv.secret_key, 'secretPath', vv.secret_path ) + ORDER BY vv.priority DESC, vv.id ASC ) FROM variable_value vv WHERE vv.variable_id = v.id diff --git a/apps/workspace-engine/pkg/db/variables.sql.go b/apps/workspace-engine/pkg/db/variables.sql.go index a3f3f9652..0d170f890 100644 --- a/apps/workspace-engine/pkg/db/variables.sql.go +++ b/apps/workspace-engine/pkg/db/variables.sql.go @@ -35,6 +35,7 @@ SELECT 'secretKey', vv.secret_key, 'secretPath', vv.secret_path ) + ORDER BY vv.priority DESC, vv.id ASC ) FROM variable_value vv WHERE vv.variable_id = v.id @@ -108,6 +109,7 @@ SELECT 'secretKey', vv.secret_key, 'secretPath', vv.secret_path ) + ORDER BY vv.priority DESC, vv.id ASC ) FROM variable_value vv WHERE vv.variable_id = v.id @@ -186,6 +188,7 @@ SELECT 'secretKey', vv.secret_key, 'secretPath', vv.secret_path ) + ORDER BY vv.priority DESC, vv.id ASC ) FROM variable_value vv WHERE vv.variable_id = v.id diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go index fe5275810..538b97af2 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/getters_postgres.go @@ -359,7 +359,12 @@ func resourceRowToMap( // projecting a resource variable into the CEL evaluation context. Selector // matching is not available here because the CEL context is built without a // target resource. -func effectiveValue(aggs []db.VariableValueAggRow) (oapi.Value, bool) { +// +// Returns (value, found, err): +// - found=false, err=nil: no null-selector candidate exists (normal absence). +// - found=false, err!=nil: a candidate was selected but conversion failed; +// callers must propagate rather than silently drop. +func effectiveValue(aggs []db.VariableValueAggRow) (oapi.Value, bool, error) { var best *db.VariableValueAggRow for i := range aggs { a := &aggs[i] @@ -371,13 +376,13 @@ func effectiveValue(aggs []db.VariableValueAggRow) (oapi.Value, bool) { } } if best == nil { - return oapi.Value{}, false + return oapi.Value{}, false, nil } v, err := db.ToOapiDeploymentVariableValueFromAgg(*best) if err != nil { - return oapi.Value{}, false + return oapi.Value{}, false, err } - return v.Value, true + return v.Value, true, nil } func loadResourceVariables( @@ -398,7 +403,11 @@ func loadResourceVariables( if err := json.Unmarshal(row.Values, &aggs); err != nil { return nil, fmt.Errorf("unmarshal values for variable %s: %w", row.ID, err) } - if v, ok := effectiveValue(aggs); ok { + v, ok, err := effectiveValue(aggs) + if err != nil { + return nil, fmt.Errorf("effective value for variable %s: %w", row.ID, err) + } + if ok { vars[row.Key] = v } } @@ -420,7 +429,10 @@ func loadResourceVariablesByWorkspace( if err := json.Unmarshal(row.Values, &aggs); err != nil { return nil, fmt.Errorf("unmarshal values for variable %s: %w", row.ID, err) } - v, ok := effectiveValue(aggs) + v, ok, err := effectiveValue(aggs) + if err != nil { + return nil, fmt.Errorf("effective value for variable %s: %w", row.ID, err) + } if !ok { continue } diff --git a/packages/db/drizzle/0188_backfill_variables.sql b/packages/db/drizzle/0188_backfill_variables.sql index 589ea449b..74fd0cebc 100644 --- a/packages/db/drizzle/0188_backfill_variables.sql +++ b/packages/db/drizzle/0188_backfill_variables.sql @@ -10,40 +10,104 @@ FROM deployment_variable dv ON CONFLICT (id) DO NOTHING; --> statement-breakpoint +WITH dvv_classified AS ( + SELECT + dvv.id, + dvv.deployment_variable_id, + dvv.resource_selector, + dvv.priority, + dvv.value, + CASE + WHEN jsonb_typeof(dvv.value) = 'object' + AND dvv.value ? 'reference' + AND ( + dvv.value->'path' IS NULL + OR jsonb_typeof(dvv.value->'path') = 'array' + ) + THEN 'ref' + ELSE 'literal' + END AS kind, + ROW_NUMBER() OVER ( + PARTITION BY + dvv.deployment_variable_id, + COALESCE(dvv.resource_selector, '<>'), + dvv.priority + ORDER BY dvv.id + ) AS rn + FROM deployment_variable_value dvv +) INSERT INTO "variable_value" ( id, variable_id, resource_selector, priority, kind, ref_key, ref_path ) SELECT - dvv.id, - dvv.deployment_variable_id, - dvv.resource_selector, - dvv.priority, + c.id, + c.deployment_variable_id, + c.resource_selector, + c.priority, 'ref'::variable_value_kind, - dvv.value->>'reference', - ARRAY(SELECT jsonb_array_elements_text(dvv.value->'path')) -FROM deployment_variable_value dvv -WHERE jsonb_typeof(dvv.value) = 'object' - AND dvv.value ? 'reference' - AND dvv.value ? 'path' + c.value->>'reference', + CASE + WHEN jsonb_typeof(c.value->'path') = 'array' + THEN ARRAY(SELECT jsonb_array_elements_text(c.value->'path')) + ELSE ARRAY[]::text[] + END +FROM dvv_classified c +WHERE c.kind = 'ref' + AND c.rn = 1 + AND NOT EXISTS ( + SELECT 1 FROM "variable_value" vv + WHERE vv.variable_id = c.deployment_variable_id + AND vv.resource_selector IS NOT DISTINCT FROM c.resource_selector + AND vv.priority = c.priority + ) ON CONFLICT (id) DO NOTHING; --> statement-breakpoint +WITH dvv_classified AS ( + SELECT + dvv.id, + dvv.deployment_variable_id, + dvv.resource_selector, + dvv.priority, + dvv.value, + CASE + WHEN jsonb_typeof(dvv.value) = 'object' + AND dvv.value ? 'reference' + AND ( + dvv.value->'path' IS NULL + OR jsonb_typeof(dvv.value->'path') = 'array' + ) + THEN 'ref' + ELSE 'literal' + END AS kind, + ROW_NUMBER() OVER ( + PARTITION BY + dvv.deployment_variable_id, + COALESCE(dvv.resource_selector, '<>'), + dvv.priority + ORDER BY dvv.id + ) AS rn + FROM deployment_variable_value dvv +) INSERT INTO "variable_value" ( id, variable_id, resource_selector, priority, kind, literal_value ) SELECT - dvv.id, - dvv.deployment_variable_id, - dvv.resource_selector, - dvv.priority, + c.id, + c.deployment_variable_id, + c.resource_selector, + c.priority, 'literal'::variable_value_kind, - dvv.value -FROM deployment_variable_value dvv -WHERE NOT ( - jsonb_typeof(dvv.value) = 'object' - AND dvv.value ? 'reference' - AND dvv.value ? 'path' -) + c.value +FROM dvv_classified c +WHERE c.kind = 'literal' + AND c.rn = 1 + AND NOT EXISTS ( + SELECT 1 FROM "variable_value" vv + WHERE vv.variable_id = c.deployment_variable_id + AND vv.resource_selector IS NOT DISTINCT FROM c.resource_selector + AND vv.priority = c.priority + ) ON CONFLICT (id) DO NOTHING; --> statement-breakpoint @@ -63,7 +127,11 @@ SELECT 0, 'ref'::variable_value_kind, rv.value->>'reference', - ARRAY(SELECT jsonb_array_elements_text(rv.value->'path')) + CASE + WHEN jsonb_typeof(rv.value->'path') = 'array' + THEN ARRAY(SELECT jsonb_array_elements_text(rv.value->'path')) + ELSE ARRAY[]::text[] + END FROM resource_variable rv JOIN "variable" v ON v.scope = 'resource' @@ -71,7 +139,10 @@ JOIN "variable" v AND v.key = rv.key WHERE jsonb_typeof(rv.value) = 'object' AND rv.value ? 'reference' - AND rv.value ? 'path' + AND ( + rv.value->'path' IS NULL + OR jsonb_typeof(rv.value->'path') = 'array' + ) AND NOT EXISTS ( SELECT 1 FROM "variable_value" vv WHERE vv.variable_id = v.id @@ -94,7 +165,10 @@ JOIN "variable" v WHERE NOT ( jsonb_typeof(rv.value) = 'object' AND rv.value ? 'reference' - AND rv.value ? 'path' + AND ( + rv.value->'path' IS NULL + OR jsonb_typeof(rv.value->'path') = 'array' + ) ) AND NOT EXISTS ( SELECT 1 FROM "variable_value" vv diff --git a/packages/trpc/src/routes/deployments.ts b/packages/trpc/src/routes/deployments.ts index 7cb5ae653..47d9c87a6 100644 --- a/packages/trpc/src/routes/deployments.ts +++ b/packages/trpc/src/routes/deployments.ts @@ -278,19 +278,38 @@ export const deploymentsRouter = router({ variables: protectedProcedure .input(z.object({ workspaceId: z.uuid(), deploymentId: z.string() })) + .meta({ + authorizationCheck: ({ canUser, input }) => + canUser + .perform(Permission.DeploymentGet) + .on({ type: "deployment", id: input.deploymentId }), + }) .query(async ({ input, ctx }) => { - const variables = await ctx.db.query.variable.findMany({ - where: and( - eq(schema.variable.scope, "deployment"), - eq(schema.variable.deploymentId, input.deploymentId), - ), - }); + const rows = await ctx.db + .select({ variable: schema.variable }) + .from(schema.variable) + .innerJoin( + schema.deployment, + eq(schema.variable.deploymentId, schema.deployment.id), + ) + .where( + and( + eq(schema.variable.scope, "deployment"), + eq(schema.variable.deploymentId, input.deploymentId), + eq(schema.deployment.workspaceId, input.workspaceId), + ), + ); + const variables = rows.map((r) => r.variable); const variableIds = variables.map((v) => v.id); const values = variableIds.length > 0 ? await ctx.db.query.variableValue.findMany({ where: inArray(schema.variableValue.variableId, variableIds), + orderBy: [ + desc(schema.variableValue.priority), + asc(schema.variableValue.id), + ], }) : []; @@ -378,18 +397,33 @@ export const deploymentsRouter = router({ variableId: z.string(), }), ) + .meta({ + authorizationCheck: ({ canUser, input }) => + canUser + .perform(Permission.DeploymentVariableDelete) + .on({ type: "deployment", id: input.deploymentId }), + }) .mutation(async ({ input, ctx }) => { const { workspaceId, deploymentId, variableId } = input; - const variable = await ctx.db.query.variable.findFirst({ - where: and( - eq(schema.variable.id, variableId), - eq(schema.variable.scope, "deployment"), - eq(schema.variable.deploymentId, deploymentId), - ), - }); + const row = await ctx.db + .select({ variable: schema.variable }) + .from(schema.variable) + .innerJoin( + schema.deployment, + eq(schema.variable.deploymentId, schema.deployment.id), + ) + .where( + and( + eq(schema.variable.id, variableId), + eq(schema.variable.scope, "deployment"), + eq(schema.variable.deploymentId, deploymentId), + eq(schema.deployment.workspaceId, workspaceId), + ), + ) + .limit(1); - if (variable == null) + if (row.length === 0) throw new TRPCError({ code: "NOT_FOUND", message: "Deployment variable not found", diff --git a/packages/trpc/src/routes/resources.ts b/packages/trpc/src/routes/resources.ts index b6eaeff58..3433231b7 100644 --- a/packages/trpc/src/routes/resources.ts +++ b/packages/trpc/src/routes/resources.ts @@ -12,6 +12,7 @@ import { Permission } from "@ctrlplane/validators/auth"; import { getClientFor } from "@ctrlplane/workspace-engine-sdk"; import { protectedProcedure, router } from "../trpc.js"; +import { flattenVariableValue } from "./_variables.js"; export const resourcesRouter = router({ create: protectedProcedure @@ -457,7 +458,13 @@ export const resourcesRouter = router({ .select({ resourceId: schema.variable.resourceId, key: schema.variable.key, - value: schema.variableValue.literalValue, + kind: schema.variableValue.kind, + literalValue: schema.variableValue.literalValue, + refKey: schema.variableValue.refKey, + refPath: schema.variableValue.refPath, + secretProvider: schema.variableValue.secretProvider, + secretKey: schema.variableValue.secretKey, + secretPath: schema.variableValue.secretPath, }) .from(schema.variable) .innerJoin( @@ -468,11 +475,22 @@ export const resourcesRouter = router({ and( eq(schema.variable.scope, "resource"), eq(schema.variable.resourceId, resource.id), - eq(schema.variableValue.kind, "literal"), ), ); - return rows; + return rows.map((r) => ({ + resourceId: r.resourceId, + key: r.key, + value: flattenVariableValue({ + kind: r.kind, + literalValue: r.literalValue, + refKey: r.refKey, + refPath: r.refPath, + secretProvider: r.secretProvider, + secretKey: r.secretKey, + secretPath: r.secretPath, + } as typeof schema.variableValue.$inferSelect), + })); }), setVariable: protectedProcedure From fc41aae09baf9cf025bef539192bd3dfeb391eba Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Tue, 21 Apr 2026 11:35:21 -0400 Subject: [PATCH 10/14] test(variable-priority): add tests for variable priroity * the use case of default values can now be replaced by variable prirority added tests to ensure that it works --- .../variableresolver/resolve_test.go | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go index a7979da87..4da4e7ad6 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go @@ -624,6 +624,103 @@ func TestResolve_HighestPriorityValueWins(t *testing.T) { assert.Equal(t, "high-priority", s) } +// --------------------------------------------------------------------------- +// Resolve tests — null-selector default with selector-gated override. +// Covers the "default everywhere unless resource matches selector" pattern. +// --------------------------------------------------------------------------- + +func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_MatchingResource(t *testing.T) { + scope := newScope() + scope.Resource.Metadata = map[string]string{"env": "special"} + + depVarID := uuid.New().String() + matchSpecial := `resource.metadata.env == "special"` + + getter := &mockGetter{ + deploymentVars: []oapi.DeploymentVariableWithValues{{ + Variable: oapi.DeploymentVariable{ + Id: depVarID, + DeploymentId: scope.Deployment.Id, + Key: "region", + }, + Values: []oapi.DeploymentVariableValue{ + { + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: literalStringValue("default"), + Priority: 0, + }, + { + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: literalStringValue("override"), + Priority: 10, + ResourceSelector: &matchSpecial, + }, + }, + }}, + resourceVars: map[string][]oapi.ResourceVariable{}, + } + + resolved, err := Resolve( + context.Background(), + getter, + scope, + scope.Deployment.Id, + scope.Resource.Id, + ) + require.NoError(t, err) + s, err := resolved["region"].AsStringValue() + require.NoError(t, err) + assert.Equal(t, "override", s, "matching-selector higher-priority override must win") +} + +func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_NonMatchingResource(t *testing.T) { + scope := newScope() + scope.Resource.Metadata = map[string]string{"env": "normal"} + + depVarID := uuid.New().String() + matchSpecial := `resource.metadata.env == "special"` + + getter := &mockGetter{ + deploymentVars: []oapi.DeploymentVariableWithValues{{ + Variable: oapi.DeploymentVariable{ + Id: depVarID, + DeploymentId: scope.Deployment.Id, + Key: "region", + }, + Values: []oapi.DeploymentVariableValue{ + { + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: literalStringValue("default"), + Priority: 0, + }, + { + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: literalStringValue("override"), + Priority: 10, + ResourceSelector: &matchSpecial, + }, + }, + }}, + resourceVars: map[string][]oapi.ResourceVariable{}, + } + + resolved, err := Resolve( + context.Background(), + getter, + scope, + scope.Deployment.Id, + scope.Resource.Id, + ) + require.NoError(t, err) + s, err := resolved["region"].AsStringValue() + require.NoError(t, err) + assert.Equal(t, "default", s, "non-matching resource must fall back to null-selector default") +} + // --------------------------------------------------------------------------- // Resolve tests — multiple variables resolved together // --------------------------------------------------------------------------- From 3051c590292862c9afcaf56746faad224b8f1871 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Tue, 21 Apr 2026 11:36:50 -0400 Subject: [PATCH 11/14] fix: formatting --- .../desiredrelease/variableresolver/resolve_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go index 4da4e7ad6..1749f538e 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go @@ -629,7 +629,9 @@ func TestResolve_HighestPriorityValueWins(t *testing.T) { // Covers the "default everywhere unless resource matches selector" pattern. // --------------------------------------------------------------------------- -func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_MatchingResource(t *testing.T) { +func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_MatchingResource( + t *testing.T, +) { scope := newScope() scope.Resource.Metadata = map[string]string{"env": "special"} @@ -675,7 +677,9 @@ func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_MatchingRes assert.Equal(t, "override", s, "matching-selector higher-priority override must win") } -func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_NonMatchingResource(t *testing.T) { +func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_NonMatchingResource( + t *testing.T, +) { scope := newScope() scope.Resource.Metadata = map[string]string{"env": "normal"} From 9aef06739712ae20b4a0826d15e0eb21f6b90699 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Tue, 21 Apr 2026 11:59:11 -0400 Subject: [PATCH 12/14] test: adding tests for migrated records --- .../variableresolver/resolve_test.go | 267 ++++++++++++------ 1 file changed, 185 insertions(+), 82 deletions(-) diff --git a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go index 1749f538e..4241c6e2a 100644 --- a/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go +++ b/apps/workspace-engine/svc/controllers/desiredrelease/variableresolver/resolve_test.go @@ -626,103 +626,206 @@ func TestResolve_HighestPriorityValueWins(t *testing.T) { // --------------------------------------------------------------------------- // Resolve tests — null-selector default with selector-gated override. -// Covers the "default everywhere unless resource matches selector" pattern. +// Covers the "default everywhere unless resource matches selector" pattern +// and the post-migration shape (MIN_BIGINT default + selector-gated ref). // --------------------------------------------------------------------------- -func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_MatchingResource( - t *testing.T, -) { - scope := newScope() - scope.Resource.Metadata = map[string]string{"env": "special"} +const minBigInt int64 = -9223372036854775808 - depVarID := uuid.New().String() +func TestResolve_DeploymentVarValue_DefaultAndSelectorGatedOverride(t *testing.T) { matchSpecial := `resource.metadata.env == "special"` + matchCluster := `resource.version == 'ctrlplane.dev/kubernetes/cluster/v1'` - getter := &mockGetter{ - deploymentVars: []oapi.DeploymentVariableWithValues{{ - Variable: oapi.DeploymentVariable{ - Id: depVarID, - DeploymentId: scope.Deployment.Id, - Key: "region", + type override struct { + value oapi.Value + priority int64 + selector *string + } + + cases := []struct { + name string + resourceVersion string + resourceMetadata map[string]string + defaultValue oapi.Value + defaultPriority int64 + override *override + rules []eval.Rule + buildCandidates func(scope *Scope) map[string][]eval.EntityData + expected string + }{ + { + name: "literal override wins when selector matches", + resourceVersion: "v1", + resourceMetadata: map[string]string{"env": "special"}, + defaultValue: literalStringValue("default"), + defaultPriority: 0, + override: &override{ + value: literalStringValue("override"), + priority: 10, + selector: &matchSpecial, }, - Values: []oapi.DeploymentVariableValue{ - { - Id: uuid.New().String(), - DeploymentVariableId: depVarID, - Value: literalStringValue("default"), - Priority: 0, - }, + expected: "override", + }, + { + name: "default wins when selector does not match", + resourceVersion: "v1", + resourceMetadata: map[string]string{"env": "normal"}, + defaultValue: literalStringValue("default"), + defaultPriority: 0, + override: &override{ + value: literalStringValue("override"), + priority: 10, + selector: &matchSpecial, + }, + expected: "default", + }, + // Migrated shape: default preserved at MIN_BIGINT literal, override is + // a priority-0 ref gated by cluster/v1 selector. Mirrors exactly the + // rows produced by 0188_backfill_variables.sql for a deployment var + // with a default_value plus a ref-kind deployment_variable_value. + { + name: "migrated ref + MIN_BIGINT default: ref resolves on cluster target", + resourceVersion: "ctrlplane.dev/kubernetes/cluster/v1", + resourceMetadata: map[string]string{}, + defaultValue: literalStringValue("small"), + defaultPriority: minBigInt, + override: &override{ + value: referenceValue("workspace", "metadata", "size"), + priority: 0, + selector: &matchCluster, + }, + rules: []eval.Rule{ { - Id: uuid.New().String(), - DeploymentVariableId: depVarID, - Value: literalStringValue("override"), - Priority: 10, - ResourceSelector: &matchSpecial, + ID: uuid.New(), + Reference: "workspace", + Cel: `from.type == "resource" && to.type == "resource" && to.kind == "Workspace"`, }, }, - }}, - resourceVars: map[string][]oapi.ResourceVariable{}, + buildCandidates: func(scope *Scope) map[string][]eval.EntityData { + resID := uuid.MustParse(scope.Resource.Id) + wsResID := uuid.New() + return map[string][]eval.EntityData{ + "resource": { + { + ID: resID, + WorkspaceID: uuid.MustParse(scope.Resource.WorkspaceId), + EntityType: "resource", + Raw: map[string]any{ + "type": "resource", + "id": resID.String(), + "name": scope.Resource.Name, + "kind": scope.Resource.Kind, + "version": scope.Resource.Version, + "identifier": scope.Resource.Identifier, + "config": scope.Resource.Config, + "metadata": map[string]any{}, + }, + }, + { + ID: wsResID, + WorkspaceID: uuid.MustParse(scope.Resource.WorkspaceId), + EntityType: "resource", + Raw: map[string]any{ + "type": "resource", + "id": wsResID.String(), + "name": "my-workspace", + "kind": "Workspace", + "version": "v1", + "identifier": "my-workspace", + "config": map[string]any{}, + "metadata": map[string]any{"size": "large"}, + }, + }, + }, + } + }, + expected: "large", + }, + { + name: "migrated ref + MIN_BIGINT default: ref has no related entity, falls back", + resourceVersion: "ctrlplane.dev/kubernetes/cluster/v1", + resourceMetadata: map[string]string{}, + defaultValue: literalStringValue("small"), + defaultPriority: minBigInt, + override: &override{ + value: referenceValue("workspace", "metadata", "size"), + priority: 0, + selector: &matchCluster, + }, + expected: "small", + }, + { + name: "migrated ref + MIN_BIGINT default: non-cluster target falls back", + resourceVersion: "ctrlplane.dev/kubernetes/node/v1", + resourceMetadata: map[string]string{}, + defaultValue: literalStringValue("small"), + defaultPriority: minBigInt, + override: &override{ + value: referenceValue("workspace", "metadata", "size"), + priority: 0, + selector: &matchCluster, + }, + expected: "small", + }, } - resolved, err := Resolve( - context.Background(), - getter, - scope, - scope.Deployment.Id, - scope.Resource.Id, - ) - require.NoError(t, err) - s, err := resolved["region"].AsStringValue() - require.NoError(t, err) - assert.Equal(t, "override", s, "matching-selector higher-priority override must win") -} - -func TestResolve_DeploymentVarValue_DefaultWithSelectorGatedOverride_NonMatchingResource( - t *testing.T, -) { - scope := newScope() - scope.Resource.Metadata = map[string]string{"env": "normal"} - - depVarID := uuid.New().String() - matchSpecial := `resource.metadata.env == "special"` + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + scope := newScope() + scope.Resource.Kind = "Server" + scope.Resource.Version = tc.resourceVersion + scope.Resource.Metadata = tc.resourceMetadata - getter := &mockGetter{ - deploymentVars: []oapi.DeploymentVariableWithValues{{ - Variable: oapi.DeploymentVariable{ - Id: depVarID, - DeploymentId: scope.Deployment.Id, - Key: "region", - }, - Values: []oapi.DeploymentVariableValue{ - { - Id: uuid.New().String(), - DeploymentVariableId: depVarID, - Value: literalStringValue("default"), - Priority: 0, - }, - { + depVarID := uuid.New().String() + values := []oapi.DeploymentVariableValue{{ + Id: uuid.New().String(), + DeploymentVariableId: depVarID, + Value: tc.defaultValue, + Priority: tc.defaultPriority, + }} + if tc.override != nil { + values = append(values, oapi.DeploymentVariableValue{ Id: uuid.New().String(), DeploymentVariableId: depVarID, - Value: literalStringValue("override"), - Priority: 10, - ResourceSelector: &matchSpecial, - }, - }, - }}, - resourceVars: map[string][]oapi.ResourceVariable{}, + Value: tc.override.value, + Priority: tc.override.priority, + ResourceSelector: tc.override.selector, + }) + } + + var candidates map[string][]eval.EntityData + if tc.buildCandidates != nil { + candidates = tc.buildCandidates(scope) + } + + getter := &mockGetter{ + deploymentVars: []oapi.DeploymentVariableWithValues{{ + Variable: oapi.DeploymentVariable{ + Id: depVarID, + DeploymentId: scope.Deployment.Id, + Key: "size", + }, + Values: values, + }}, + resourceVars: map[string][]oapi.ResourceVariable{}, + rules: tc.rules, + candidates: candidates, + } + + resolved, err := Resolve( + context.Background(), + getter, + scope, + scope.Deployment.Id, + scope.Resource.Id, + ) + require.NoError(t, err) + require.Contains(t, resolved, "size") + got, err := resolved["size"].AsStringValue() + require.NoError(t, err) + assert.Equal(t, tc.expected, string(got)) + }) } - - resolved, err := Resolve( - context.Background(), - getter, - scope, - scope.Deployment.Id, - scope.Resource.Id, - ) - require.NoError(t, err) - s, err := resolved["region"].AsStringValue() - require.NoError(t, err) - assert.Equal(t, "default", s, "non-matching resource must fall back to null-selector default") } // --------------------------------------------------------------------------- From 164019ab1ed85a3cbbdfcaa9f91515af0c916c51 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Tue, 21 Apr 2026 12:11:11 -0400 Subject: [PATCH 13/14] fix(migration): update migration for references and defaults --- .../db/drizzle/0188_backfill_variables.sql | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/db/drizzle/0188_backfill_variables.sql b/packages/db/drizzle/0188_backfill_variables.sql index 74fd0cebc..79b055e6b 100644 --- a/packages/db/drizzle/0188_backfill_variables.sql +++ b/packages/db/drizzle/0188_backfill_variables.sql @@ -10,6 +10,25 @@ FROM deployment_variable dv ON CONFLICT (id) DO NOTHING; --> statement-breakpoint +-- Preserve deployment_variable.default_value as a null-selector literal at +-- MIN_BIGINT priority so any real variable_value shadows it while non-matching +-- resources still fall through to the old default. +INSERT INTO "variable_value" (variable_id, priority, kind, literal_value) +SELECT + dv.id, + -9223372036854775808, + 'literal'::variable_value_kind, + dv.default_value +FROM deployment_variable dv +WHERE dv.default_value IS NOT NULL + AND NOT EXISTS ( + SELECT 1 FROM "variable_value" vv + WHERE vv.variable_id = dv.id + AND vv.resource_selector IS NULL + AND vv.priority = -9223372036854775808 + ); +--> statement-breakpoint + WITH dvv_classified AS ( SELECT dvv.id, From 9f092fd3c8e3278801273dc5dca771a81e323159 Mon Sep 17 00:00:00 2001 From: Michael Leone Date: Wed, 22 Apr 2026 16:37:25 -0400 Subject: [PATCH 14/14] fix(migration): don't use max negative int --- .../db/drizzle/0188_backfill_variables.sql | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/packages/db/drizzle/0188_backfill_variables.sql b/packages/db/drizzle/0188_backfill_variables.sql index 79b055e6b..924bc4309 100644 --- a/packages/db/drizzle/0188_backfill_variables.sql +++ b/packages/db/drizzle/0188_backfill_variables.sql @@ -1,3 +1,7 @@ +-- Backfill deployment variables. ON CONFLICT DO NOTHING (no target) catches +-- both PK and (deployment_id, key) partial-unique collisions so this is safe +-- to re-run when new rows have been added to the legacy tables after an +-- earlier backfill. INSERT INTO "variable" (id, scope, deployment_id, key, is_sensitive, description) SELECT dv.id, @@ -7,32 +11,41 @@ SELECT false, dv.description FROM deployment_variable dv -ON CONFLICT (id) DO NOTHING; +ON CONFLICT DO NOTHING; --> statement-breakpoint -- Preserve deployment_variable.default_value as a null-selector literal at -- MIN_BIGINT priority so any real variable_value shadows it while non-matching --- resources still fall through to the old default. +-- resources still fall through to the old default. Join via (deployment_id, +-- key) so the default attaches to whichever variable currently owns the key. INSERT INTO "variable_value" (variable_id, priority, kind, literal_value) SELECT - dv.id, - -9223372036854775808, + v.id, + -10, 'literal'::variable_value_kind, dv.default_value FROM deployment_variable dv +JOIN "variable" v + ON v.scope = 'deployment' + AND v.deployment_id = dv.deployment_id + AND v.key = dv.key WHERE dv.default_value IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM "variable_value" vv - WHERE vv.variable_id = dv.id + WHERE vv.variable_id = v.id AND vv.resource_selector IS NULL - AND vv.priority = -9223372036854775808 + AND vv.priority = -10 ); --> statement-breakpoint +-- Classify + dedupe deployment_variable_value rows, then insert refs. +-- Uses (deployment_id, key) mapping so values attach to the current owner of +-- the key even if the new `variable` row has a different id than the legacy +-- `deployment_variable` row. WITH dvv_classified AS ( SELECT dvv.id, - dvv.deployment_variable_id, + v.id AS variable_id, dvv.resource_selector, dvv.priority, dvv.value, @@ -48,19 +61,24 @@ WITH dvv_classified AS ( END AS kind, ROW_NUMBER() OVER ( PARTITION BY - dvv.deployment_variable_id, + v.id, COALESCE(dvv.resource_selector, '<>'), dvv.priority ORDER BY dvv.id ) AS rn FROM deployment_variable_value dvv + JOIN deployment_variable dv ON dv.id = dvv.deployment_variable_id + JOIN "variable" v + ON v.scope = 'deployment' + AND v.deployment_id = dv.deployment_id + AND v.key = dv.key ) INSERT INTO "variable_value" ( id, variable_id, resource_selector, priority, kind, ref_key, ref_path ) SELECT c.id, - c.deployment_variable_id, + c.variable_id, c.resource_selector, c.priority, 'ref'::variable_value_kind, @@ -75,17 +93,17 @@ WHERE c.kind = 'ref' AND c.rn = 1 AND NOT EXISTS ( SELECT 1 FROM "variable_value" vv - WHERE vv.variable_id = c.deployment_variable_id + WHERE vv.variable_id = c.variable_id AND vv.resource_selector IS NOT DISTINCT FROM c.resource_selector AND vv.priority = c.priority ) -ON CONFLICT (id) DO NOTHING; +ON CONFLICT DO NOTHING; --> statement-breakpoint WITH dvv_classified AS ( SELECT dvv.id, - dvv.deployment_variable_id, + v.id AS variable_id, dvv.resource_selector, dvv.priority, dvv.value, @@ -101,19 +119,24 @@ WITH dvv_classified AS ( END AS kind, ROW_NUMBER() OVER ( PARTITION BY - dvv.deployment_variable_id, + v.id, COALESCE(dvv.resource_selector, '<>'), dvv.priority ORDER BY dvv.id ) AS rn FROM deployment_variable_value dvv + JOIN deployment_variable dv ON dv.id = dvv.deployment_variable_id + JOIN "variable" v + ON v.scope = 'deployment' + AND v.deployment_id = dv.deployment_id + AND v.key = dv.key ) INSERT INTO "variable_value" ( id, variable_id, resource_selector, priority, kind, literal_value ) SELECT c.id, - c.deployment_variable_id, + c.variable_id, c.resource_selector, c.priority, 'literal'::variable_value_kind, @@ -123,11 +146,11 @@ WHERE c.kind = 'literal' AND c.rn = 1 AND NOT EXISTS ( SELECT 1 FROM "variable_value" vv - WHERE vv.variable_id = c.deployment_variable_id + WHERE vv.variable_id = c.variable_id AND vv.resource_selector IS NOT DISTINCT FROM c.resource_selector AND vv.priority = c.priority ) -ON CONFLICT (id) DO NOTHING; +ON CONFLICT DO NOTHING; --> statement-breakpoint INSERT INTO "variable" (scope, resource_id, key, is_sensitive) @@ -137,7 +160,7 @@ SELECT rv.key, false FROM resource_variable rv -ON CONFLICT (resource_id, key) WHERE resource_id IS NOT NULL DO NOTHING; +ON CONFLICT DO NOTHING; --> statement-breakpoint INSERT INTO "variable_value" (variable_id, priority, kind, ref_key, ref_path)