From fb90fe4822ee6971c042772b5b02897c5dd778cf Mon Sep 17 00:00:00 2001 From: HamChowderr Date: Tue, 28 Jul 2026 01:16:59 -0700 Subject: [PATCH] fix(db): declare the schema Mastra 1.53 creates at runtime; RLS the 4 new tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing was misconfigured — this is a design tension. Mastra's storage layer owns and migrates its own tables at boot, which is normal for a framework that manages its persistence. Foreman ALSO declares those tables (20260426000019_mastra.sql) so RLS can be applied (20260426000020_rls.sql) and so they appear in the generated types. Both are reasonable; they simply disagreed after the 1.53 bump. Captured the real difference with `supabase db diff` rather than guessing. FOUR tables Mastra creates at runtime that no migration declared: mastra_favorites mastra_notifications mastra_tool_provider_connections memory_messages_384 (PgVector 384-dim index, from the fastembed switch) Plus ~30 columns added across 11 existing mastra_* tables (browser, toolProviders, favoriteCount, visibility, suspend_payload, suspendedAt(Z), externalId, projectId, organizationId, toolMocks, candidateId/Key, batchId, datasetId, datasetItemId, toolMockReport, files), their indexes, and the trigger_set_timestamps function. SECURITY — the part that matters most: Those four tables had **RLS disabled and anon grants intact**. 20260426000020_rls.sql enables RLS on the 28 mastra_* tables that existed when it was written, and 20260428000000_revoke_anon_grants.sql revokes anon SELECT across the schema. Neither could touch these four, because Mastra creates them on first boot — after every migration has already run. So they silently sat outside the security posture applied to everything else. This migration enables RLS on all four and revokes anon SELECT/REFERENCES/TRIGGER/ TRUNCATE. Everything reaches these tables through the service_role client, which bypasses RLS, so enabling it costs nothing functionally. Verified on a FRESH database (`supabase db reset`, migrations only, server never booted — i.e. exactly what CI builds): - the migration applies cleanly from scratch - `db:types:check` exits 0 - direct pg query confirms relrowsecurity = true on all four tables and zero remaining anon grants - typecheck 0 errors, 405 tests pass Note this will drift again on future Mastra bumps — that is inherent to two systems declaring the same tables. `supabase db diff` is the tool to re-capture it; run it after any @mastra/* upgrade that touches storage. Co-Authored-By: Claude Opus 5 (1M context) --- .beads/export-state.json | 2 +- packages/agents/src/lib/db/database.types.ts | 306 +++++++++++++++ ...60728080530_mastra_1_53_runtime_schema.sql | 351 ++++++++++++++++++ 3 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 supabase/migrations/20260728080530_mastra_1_53_runtime_schema.sql diff --git a/.beads/export-state.json b/.beads/export-state.json index cebd70b9..b2bbc1d5 100644 --- a/.beads/export-state.json +++ b/.beads/export-state.json @@ -1 +1 @@ -{"last_dolt_commit":"mdgdp9ehdpmdjnhuh65j1fuj1vcj06vc","timestamp":"2026-07-27T22:34:49.6696687-07:00","issues":454,"memories":0} \ No newline at end of file +{"last_dolt_commit":"c7bb5qcv1ctkhf392dl3d1f974oogh1u","timestamp":"2026-07-28T00:44:28.7090854-07:00","issues":454,"memories":0} \ No newline at end of file diff --git a/packages/agents/src/lib/db/database.types.ts b/packages/agents/src/lib/db/database.types.ts index 0561f0a1..4b4d001d 100644 --- a/packages/agents/src/lib/db/database.types.ts +++ b/packages/agents/src/lib/db/database.types.ts @@ -1189,6 +1189,7 @@ export type Database = { Row: { agentId: string; agents: Json | null; + browser: Json | null; changedFields: Json | null; changeMessage: string | null; createdAt: string; @@ -1208,6 +1209,7 @@ export type Database = { scorers: Json | null; skills: Json | null; skillsFormat: string | null; + toolProviders: Json | null; tools: Json | null; versionNumber: number; workflows: Json | null; @@ -1216,6 +1218,7 @@ export type Database = { Insert: { agentId: string; agents?: Json | null; + browser?: Json | null; changedFields?: Json | null; changeMessage?: string | null; createdAt: string; @@ -1235,6 +1238,7 @@ export type Database = { scorers?: Json | null; skills?: Json | null; skillsFormat?: string | null; + toolProviders?: Json | null; tools?: Json | null; versionNumber: number; workflows?: Json | null; @@ -1243,6 +1247,7 @@ export type Database = { Update: { agentId?: string; agents?: Json | null; + browser?: Json | null; changedFields?: Json | null; changeMessage?: string | null; createdAt?: string; @@ -1262,6 +1267,7 @@ export type Database = { scorers?: Json | null; skills?: Json | null; skillsFormat?: string | null; + toolProviders?: Json | null; tools?: Json | null; versionNumber?: number; workflows?: Json | null; @@ -1275,33 +1281,39 @@ export type Database = { authorId: string | null; createdAt: string; createdAtZ: string | null; + favoriteCount: number | null; id: string; metadata: Json | null; status: string; updatedAt: string; updatedAtZ: string | null; + visibility: string | null; }; Insert: { activeVersionId?: string | null; authorId?: string | null; createdAt: string; createdAtZ?: string | null; + favoriteCount?: number | null; id: string; metadata?: Json | null; status: string; updatedAt: string; updatedAtZ?: string | null; + visibility?: string | null; }; Update: { activeVersionId?: string | null; authorId?: string | null; createdAt?: string; createdAtZ?: string | null; + favoriteCount?: number | null; id?: string; metadata?: Json | null; status?: string; updatedAt?: string; updatedAtZ?: string | null; + visibility?: string | null; }; Relationships: []; }; @@ -1470,6 +1482,9 @@ export type Database = { startedAt: string | null; startedAtZ: string | null; status: string; + suspend_payload: Json | null; + suspendedAt: string | null; + suspendedAtZ: string | null; thread_id: string | null; timeout_ms: number; tool_call_id: string; @@ -1492,6 +1507,9 @@ export type Database = { startedAt?: string | null; startedAtZ?: string | null; status: string; + suspend_payload?: Json | null; + suspendedAt?: string | null; + suspendedAtZ?: string | null; thread_id?: string | null; timeout_ms: number; tool_call_id: string; @@ -1514,6 +1532,9 @@ export type Database = { startedAt?: string | null; startedAtZ?: string | null; status?: string; + suspend_payload?: Json | null; + suspendedAt?: string | null; + suspendedAtZ?: string | null; thread_id?: string | null; timeout_ms?: number; tool_call_id?: string; @@ -1594,13 +1615,17 @@ export type Database = { datasetId: string; datasetVersion: number; expectedTrajectory: Json | null; + externalId: string | null; groundTruth: Json | null; id: string; input: Json; isDeleted: boolean; metadata: Json | null; + organizationId: string | null; + projectId: string | null; requestContext: Json | null; source: Json | null; + toolMocks: Json | null; updatedAt: string; updatedAtZ: string | null; validTo: number | null; @@ -1611,13 +1636,17 @@ export type Database = { datasetId: string; datasetVersion: number; expectedTrajectory?: Json | null; + externalId?: string | null; groundTruth?: Json | null; id: string; input: Json; isDeleted: boolean; metadata?: Json | null; + organizationId?: string | null; + projectId?: string | null; requestContext?: Json | null; source?: Json | null; + toolMocks?: Json | null; updatedAt: string; updatedAtZ?: string | null; validTo?: number | null; @@ -1628,13 +1657,17 @@ export type Database = { datasetId?: string; datasetVersion?: number; expectedTrajectory?: Json | null; + externalId?: string | null; groundTruth?: Json | null; id?: string; input?: Json; isDeleted?: boolean; metadata?: Json | null; + organizationId?: string | null; + projectId?: string | null; requestContext?: Json | null; source?: Json | null; + toolMocks?: Json | null; updatedAt?: string; updatedAtZ?: string | null; validTo?: number | null; @@ -1667,6 +1700,8 @@ export type Database = { }; mastra_datasets: { Row: { + candidateId: string | null; + candidateKey: string | null; createdAt: string; createdAtZ: string | null; description: string | null; @@ -1675,6 +1710,8 @@ export type Database = { inputSchema: Json | null; metadata: Json | null; name: string; + organizationId: string | null; + projectId: string | null; requestContextSchema: Json | null; scorerIds: Json | null; tags: Json | null; @@ -1685,6 +1722,8 @@ export type Database = { version: number; }; Insert: { + candidateId?: string | null; + candidateKey?: string | null; createdAt: string; createdAtZ?: string | null; description?: string | null; @@ -1693,6 +1732,8 @@ export type Database = { inputSchema?: Json | null; metadata?: Json | null; name: string; + organizationId?: string | null; + projectId?: string | null; requestContextSchema?: Json | null; scorerIds?: Json | null; tags?: Json | null; @@ -1703,6 +1744,8 @@ export type Database = { version: number; }; Update: { + candidateId?: string | null; + candidateKey?: string | null; createdAt?: string; createdAtZ?: string | null; description?: string | null; @@ -1711,6 +1754,8 @@ export type Database = { inputSchema?: Json | null; metadata?: Json | null; name?: string; + organizationId?: string | null; + projectId?: string | null; requestContextSchema?: Json | null; scorerIds?: Json | null; tags?: Json | null; @@ -1735,12 +1780,15 @@ export type Database = { input: Json; itemDatasetVersion: number | null; itemId: string; + organizationId: string | null; output: Json | null; + projectId: string | null; retryCount: number; startedAt: string; startedAtZ: string | null; status: string | null; tags: Json | null; + toolMockReport: Json | null; traceId: string | null; }; Insert: { @@ -1755,12 +1803,15 @@ export type Database = { input: Json; itemDatasetVersion?: number | null; itemId: string; + organizationId?: string | null; output?: Json | null; + projectId?: string | null; retryCount: number; startedAt: string; startedAtZ?: string | null; status?: string | null; tags?: Json | null; + toolMockReport?: Json | null; traceId?: string | null; }; Update: { @@ -1775,12 +1826,15 @@ export type Database = { input?: Json; itemDatasetVersion?: number | null; itemId?: string; + organizationId?: string | null; output?: Json | null; + projectId?: string | null; retryCount?: number; startedAt?: string; startedAtZ?: string | null; status?: string | null; tags?: Json | null; + toolMockReport?: Json | null; traceId?: string | null; }; Relationships: []; @@ -1799,6 +1853,8 @@ export type Database = { id: string; metadata: Json | null; name: string | null; + organizationId: string | null; + projectId: string | null; skippedCount: number; startedAt: string | null; startedAtZ: string | null; @@ -1823,6 +1879,8 @@ export type Database = { id: string; metadata?: Json | null; name?: string | null; + organizationId?: string | null; + projectId?: string | null; skippedCount: number; startedAt?: string | null; startedAtZ?: string | null; @@ -1847,6 +1905,8 @@ export type Database = { id?: string; metadata?: Json | null; name?: string | null; + organizationId?: string | null; + projectId?: string | null; skippedCount?: number; startedAt?: string | null; startedAtZ?: string | null; @@ -1860,6 +1920,30 @@ export type Database = { }; Relationships: []; }; + mastra_favorites: { + Row: { + createdAt: string; + createdAtZ: string | null; + entityId: string; + entityType: string; + userId: string; + }; + Insert: { + createdAt: string; + createdAtZ?: string | null; + entityId: string; + entityType: string; + userId: string; + }; + Update: { + createdAt?: string; + createdAtZ?: string | null; + entityId?: string; + entityType?: string; + userId?: string; + }; + Relationships: []; + }; mastra_mcp_client_versions: { Row: { changedFields: Json | null; @@ -2067,6 +2151,138 @@ export type Database = { }; Relationships: []; }; + mastra_notifications: { + Row: { + agentId: string | null; + archivedAt: string | null; + archivedAtZ: string | null; + attributes: Json | null; + coalescedCount: number; + coalesceKey: string | null; + createdAt: string; + createdAtZ: string | null; + dedupeKey: string | null; + deliverAt: string | null; + deliverAtZ: string | null; + deliveredAt: string | null; + deliveredAtZ: string | null; + deliveredSignalId: string | null; + deliveryAttempts: number; + deliveryReason: string | null; + discardedAt: string | null; + discardedAtZ: string | null; + dismissedAt: string | null; + dismissedAtZ: string | null; + id: string; + kind: string; + lastDeliveryAttemptAt: string | null; + lastDeliveryAttemptAtZ: string | null; + lastDeliveryError: string | null; + metadata: Json | null; + payload: Json | null; + priority: string; + resourceId: string | null; + seenAt: string | null; + seenAtZ: string | null; + source: string; + sourceId: string | null; + status: string; + summary: string; + summaryAt: string | null; + summaryAtZ: string | null; + summarySignalId: string | null; + threadId: string; + updatedAt: string; + updatedAtZ: string | null; + }; + Insert: { + agentId?: string | null; + archivedAt?: string | null; + archivedAtZ?: string | null; + attributes?: Json | null; + coalescedCount: number; + coalesceKey?: string | null; + createdAt: string; + createdAtZ?: string | null; + dedupeKey?: string | null; + deliverAt?: string | null; + deliverAtZ?: string | null; + deliveredAt?: string | null; + deliveredAtZ?: string | null; + deliveredSignalId?: string | null; + deliveryAttempts: number; + deliveryReason?: string | null; + discardedAt?: string | null; + discardedAtZ?: string | null; + dismissedAt?: string | null; + dismissedAtZ?: string | null; + id: string; + kind: string; + lastDeliveryAttemptAt?: string | null; + lastDeliveryAttemptAtZ?: string | null; + lastDeliveryError?: string | null; + metadata?: Json | null; + payload?: Json | null; + priority: string; + resourceId?: string | null; + seenAt?: string | null; + seenAtZ?: string | null; + source: string; + sourceId?: string | null; + status: string; + summary: string; + summaryAt?: string | null; + summaryAtZ?: string | null; + summarySignalId?: string | null; + threadId: string; + updatedAt: string; + updatedAtZ?: string | null; + }; + Update: { + agentId?: string | null; + archivedAt?: string | null; + archivedAtZ?: string | null; + attributes?: Json | null; + coalescedCount?: number; + coalesceKey?: string | null; + createdAt?: string; + createdAtZ?: string | null; + dedupeKey?: string | null; + deliverAt?: string | null; + deliverAtZ?: string | null; + deliveredAt?: string | null; + deliveredAtZ?: string | null; + deliveredSignalId?: string | null; + deliveryAttempts?: number; + deliveryReason?: string | null; + discardedAt?: string | null; + discardedAtZ?: string | null; + dismissedAt?: string | null; + dismissedAtZ?: string | null; + id?: string; + kind?: string; + lastDeliveryAttemptAt?: string | null; + lastDeliveryAttemptAtZ?: string | null; + lastDeliveryError?: string | null; + metadata?: Json | null; + payload?: Json | null; + priority?: string; + resourceId?: string | null; + seenAt?: string | null; + seenAtZ?: string | null; + source?: string; + sourceId?: string | null; + status?: string; + summary?: string; + summaryAt?: string | null; + summaryAtZ?: string | null; + summarySignalId?: string | null; + threadId?: string; + updatedAt?: string; + updatedAtZ?: string | null; + }; + Relationships: []; + }; mastra_observational_memory: { Row: { activeObservations: string; @@ -2453,6 +2669,8 @@ export type Database = { createdAtZ: string | null; id: string; metadata: Json | null; + organizationId: string | null; + projectId: string | null; status: string; updatedAt: string; updatedAtZ: string | null; @@ -2464,6 +2682,8 @@ export type Database = { createdAtZ?: string | null; id: string; metadata?: Json | null; + organizationId?: string | null; + projectId?: string | null; status: string; updatedAt: string; updatedAtZ?: string | null; @@ -2475,6 +2695,8 @@ export type Database = { createdAtZ?: string | null; id?: string; metadata?: Json | null; + organizationId?: string | null; + projectId?: string | null; status?: string; updatedAt?: string; updatedAtZ?: string | null; @@ -2486,8 +2708,11 @@ export type Database = { additionalContext: Json | null; analyzePrompt: string | null; analyzeStepResult: Json | null; + batchId: string | null; createdAt: string; createdAtZ: string | null; + datasetId: string | null; + datasetItemId: string | null; entity: Json | null; entityId: string | null; entityType: string | null; @@ -2498,9 +2723,11 @@ export type Database = { id: string; input: Json; metadata: Json | null; + organizationId: string | null; output: Json; preprocessPrompt: string | null; preprocessStepResult: Json | null; + projectId: string | null; reason: string | null; reasonPrompt: string | null; requestContext: Json | null; @@ -2520,8 +2747,11 @@ export type Database = { additionalContext?: Json | null; analyzePrompt?: string | null; analyzeStepResult?: Json | null; + batchId?: string | null; createdAt: string; createdAtZ?: string | null; + datasetId?: string | null; + datasetItemId?: string | null; entity?: Json | null; entityId?: string | null; entityType?: string | null; @@ -2532,9 +2762,11 @@ export type Database = { id: string; input: Json; metadata?: Json | null; + organizationId?: string | null; output: Json; preprocessPrompt?: string | null; preprocessStepResult?: Json | null; + projectId?: string | null; reason?: string | null; reasonPrompt?: string | null; requestContext?: Json | null; @@ -2554,8 +2786,11 @@ export type Database = { additionalContext?: Json | null; analyzePrompt?: string | null; analyzeStepResult?: Json | null; + batchId?: string | null; createdAt?: string; createdAtZ?: string | null; + datasetId?: string | null; + datasetItemId?: string | null; entity?: Json | null; entityId?: string | null; entityType?: string | null; @@ -2566,9 +2801,11 @@ export type Database = { id?: string; input?: Json; metadata?: Json | null; + organizationId?: string | null; output?: Json; preprocessPrompt?: string | null; preprocessStepResult?: Json | null; + projectId?: string | null; reason?: string | null; reasonPrompt?: string | null; requestContext?: Json | null; @@ -2622,6 +2859,7 @@ export type Database = { createdAt: string; createdAtZ: string | null; description: string; + files: Json | null; id: string; instructions: string; license: string | null; @@ -2642,6 +2880,7 @@ export type Database = { createdAt: string; createdAtZ?: string | null; description: string; + files?: Json | null; id: string; instructions: string; license?: string | null; @@ -2662,6 +2901,7 @@ export type Database = { createdAt?: string; createdAtZ?: string | null; description?: string; + files?: Json | null; id?: string; instructions?: string; license?: string | null; @@ -2682,30 +2922,36 @@ export type Database = { authorId: string | null; createdAt: string; createdAtZ: string | null; + favoriteCount: number | null; id: string; status: string; updatedAt: string; updatedAtZ: string | null; + visibility: string | null; }; Insert: { activeVersionId?: string | null; authorId?: string | null; createdAt: string; createdAtZ?: string | null; + favoriteCount?: number | null; id: string; status: string; updatedAt: string; updatedAtZ?: string | null; + visibility?: string | null; }; Update: { activeVersionId?: string | null; authorId?: string | null; createdAt?: string; createdAtZ?: string | null; + favoriteCount?: number | null; id?: string; status?: string; updatedAt?: string; updatedAtZ?: string | null; + visibility?: string | null; }; Relationships: []; }; @@ -2742,6 +2988,45 @@ export type Database = { }; Relationships: []; }; + mastra_tool_provider_connections: { + Row: { + authorId: string; + connectionId: string; + createdAt: string; + createdAtZ: string | null; + label: string | null; + providerId: string; + scope: string; + toolkit: string; + updatedAt: string; + updatedAtZ: string | null; + }; + Insert: { + authorId: string; + connectionId: string; + createdAt: string; + createdAtZ?: string | null; + label?: string | null; + providerId: string; + scope: string; + toolkit: string; + updatedAt: string; + updatedAtZ?: string | null; + }; + Update: { + authorId?: string; + connectionId?: string; + createdAt?: string; + createdAtZ?: string | null; + label?: string | null; + providerId?: string; + scope?: string; + toolkit?: string; + updatedAt?: string; + updatedAtZ?: string | null; + }; + Relationships: []; + }; mastra_workflow_snapshot: { Row: { createdAt: string; @@ -2871,6 +3156,27 @@ export type Database = { }; Relationships: []; }; + memory_messages_384: { + Row: { + embedding: string | null; + id: number; + metadata: Json | null; + vector_id: string; + }; + Insert: { + embedding?: string | null; + id?: number; + metadata?: Json | null; + vector_id: string; + }; + Update: { + embedding?: string | null; + id?: number; + metadata?: Json | null; + vector_id?: string; + }; + Relationships: []; + }; slack_installation: { Row: { bot_token: string; diff --git a/supabase/migrations/20260728080530_mastra_1_53_runtime_schema.sql b/supabase/migrations/20260728080530_mastra_1_53_runtime_schema.sql new file mode 100644 index 00000000..0a1ebe8e --- /dev/null +++ b/supabase/migrations/20260728080530_mastra_1_53_runtime_schema.sql @@ -0,0 +1,351 @@ +create extension if not exists "vector" with schema "public"; + +create sequence "public"."memory_messages_384_id_seq"; + + + create table "public"."mastra_favorites" ( + "userId" text not null, + "entityType" text not null, + "entityId" text not null, + "createdAt" timestamp without time zone not null, + "createdAtZ" timestamp with time zone default now() + ); + + + + create table "public"."mastra_notifications" ( + "id" text not null, + "threadId" text not null, + "source" text not null, + "kind" text not null, + "priority" text not null, + "status" text not null, + "summary" text not null, + "payload" jsonb, + "resourceId" text, + "agentId" text, + "sourceId" text, + "dedupeKey" text, + "coalesceKey" text, + "coalescedCount" integer not null, + "attributes" jsonb, + "createdAt" timestamp without time zone not null, + "updatedAt" timestamp without time zone not null, + "deliveredAt" timestamp without time zone, + "seenAt" timestamp without time zone, + "dismissedAt" timestamp without time zone, + "archivedAt" timestamp without time zone, + "discardedAt" timestamp without time zone, + "deliverAt" timestamp without time zone, + "summaryAt" timestamp without time zone, + "deliveryReason" text, + "deliveryAttempts" integer not null, + "lastDeliveryAttemptAt" timestamp without time zone, + "lastDeliveryError" text, + "deliveredSignalId" text, + "summarySignalId" text, + "metadata" jsonb, + "createdAtZ" timestamp with time zone default now(), + "updatedAtZ" timestamp with time zone default now(), + "deliveredAtZ" timestamp with time zone default now(), + "seenAtZ" timestamp with time zone default now(), + "dismissedAtZ" timestamp with time zone default now(), + "archivedAtZ" timestamp with time zone default now(), + "discardedAtZ" timestamp with time zone default now(), + "deliverAtZ" timestamp with time zone default now(), + "summaryAtZ" timestamp with time zone default now(), + "lastDeliveryAttemptAtZ" timestamp with time zone default now() + ); + + + + create table "public"."mastra_tool_provider_connections" ( + "authorId" text not null, + "providerId" text not null, + "connectionId" text not null, + "toolkit" text not null, + "label" text, + "scope" text not null, + "createdAt" timestamp without time zone not null, + "updatedAt" timestamp without time zone not null, + "createdAtZ" timestamp with time zone default now(), + "updatedAtZ" timestamp with time zone default now() + ); + + + + create table "public"."memory_messages_384" ( + "id" integer not null default nextval('public.memory_messages_384_id_seq'::regclass), + "vector_id" text not null, + "embedding" public.vector(384), + "metadata" jsonb default '{}'::jsonb + ); + + +alter table "public"."mastra_agent_versions" add column "browser" jsonb; + +alter table "public"."mastra_agent_versions" add column "toolProviders" jsonb; + +alter table "public"."mastra_agents" add column "favoriteCount" integer; + +alter table "public"."mastra_agents" add column "visibility" text; + +alter table "public"."mastra_background_tasks" add column "suspend_payload" jsonb; + +alter table "public"."mastra_background_tasks" add column "suspendedAt" timestamp without time zone; + +alter table "public"."mastra_background_tasks" add column "suspendedAtZ" timestamp with time zone default now(); + +alter table "public"."mastra_dataset_items" add column "externalId" text; + +alter table "public"."mastra_dataset_items" add column "organizationId" text; + +alter table "public"."mastra_dataset_items" add column "projectId" text; + +alter table "public"."mastra_dataset_items" add column "toolMocks" jsonb; + +alter table "public"."mastra_datasets" add column "candidateId" text; + +alter table "public"."mastra_datasets" add column "candidateKey" text; + +alter table "public"."mastra_datasets" add column "organizationId" text; + +alter table "public"."mastra_datasets" add column "projectId" text; + +alter table "public"."mastra_experiment_results" add column "organizationId" text; + +alter table "public"."mastra_experiment_results" add column "projectId" text; + +alter table "public"."mastra_experiment_results" add column "toolMockReport" jsonb; + +alter table "public"."mastra_experiments" add column "organizationId" text; + +alter table "public"."mastra_experiments" add column "projectId" text; + +alter table "public"."mastra_scorer_definitions" add column "organizationId" text; + +alter table "public"."mastra_scorer_definitions" add column "projectId" text; + +alter table "public"."mastra_scorers" add column "batchId" text; + +alter table "public"."mastra_scorers" add column "datasetId" text; + +alter table "public"."mastra_scorers" add column "datasetItemId" text; + +alter table "public"."mastra_scorers" add column "organizationId" text; + +alter table "public"."mastra_scorers" add column "projectId" text; + +alter table "public"."mastra_skill_versions" add column "files" jsonb; + +alter table "public"."mastra_skills" add column "favoriteCount" integer; + +alter table "public"."mastra_skills" add column "visibility" text; + +alter sequence "public"."memory_messages_384_id_seq" owned by "public"."memory_messages_384"."id"; + +CREATE INDEX idx_dataset_items_external_id_history ON public.mastra_dataset_items USING btree ("datasetId", "externalId", "datasetVersion"); + +CREATE INDEX idx_dataset_items_org_project ON public.mastra_dataset_items USING btree ("organizationId", "projectId"); + +CREATE INDEX idx_datasets_candidate ON public.mastra_datasets USING btree ("candidateKey", "candidateId"); + +CREATE INDEX idx_datasets_org_project ON public.mastra_datasets USING btree ("organizationId", "projectId"); + +CREATE INDEX idx_experiment_results_org_project ON public.mastra_experiment_results USING btree ("organizationId", "projectId"); + +CREATE INDEX idx_experiments_org_project ON public.mastra_experiments USING btree ("organizationId", "projectId"); + +CREATE INDEX idx_favorites_entity ON public.mastra_favorites USING btree ("entityType", "entityId"); + +CREATE INDEX idx_mastra_schedule_triggers_schedule_fire ON public.mastra_schedule_triggers USING btree (schedule_id, actual_fire_at DESC); + +CREATE INDEX idx_mastra_schedules_status_next_fire ON public.mastra_schedules USING btree (status, next_fire_at); + +CREATE INDEX idx_notifications_coalescing ON public.mastra_notifications USING btree ("threadId", source, kind, status, "agentId", "resourceId", "dedupeKey", "coalesceKey"); + +CREATE INDEX idx_notifications_due ON public.mastra_notifications USING btree (status, "deliverAt", "summaryAt"); + +CREATE INDEX idx_notifications_thread_status_updated ON public.mastra_notifications USING btree ("threadId", status, "updatedAt"); + +CREATE INDEX idx_tool_provider_connections_author ON public.mastra_tool_provider_connections USING btree ("authorId", "providerId", toolkit); + +CREATE UNIQUE INDEX mastra_favorites_pkey ON public.mastra_favorites USING btree ("userId", "entityType", "entityId"); + +CREATE UNIQUE INDEX mastra_tool_provider_connections_pkey ON public.mastra_tool_provider_connections USING btree ("authorId", "providerId", "connectionId"); + +CREATE INDEX memory_messages_384_md_57d95f6b_idx ON public.memory_messages_384 USING btree (((metadata ->> 'thread_id'::text))); + +CREATE INDEX memory_messages_384_md_5a823b81_idx ON public.memory_messages_384 USING btree (((metadata ->> 'resource_id'::text))); + +CREATE UNIQUE INDEX memory_messages_384_pkey ON public.memory_messages_384 USING btree (id); + +CREATE UNIQUE INDEX memory_messages_384_vector_id_key ON public.memory_messages_384 USING btree (vector_id); + +CREATE INDEX memory_messages_384_vector_idx ON public.memory_messages_384 USING ivfflat (embedding public.vector_cosine_ops) WITH (lists='100'); + +alter table "public"."mastra_favorites" add constraint "mastra_favorites_pkey" PRIMARY KEY using index "mastra_favorites_pkey"; + +alter table "public"."mastra_tool_provider_connections" add constraint "mastra_tool_provider_connections_pkey" PRIMARY KEY using index "mastra_tool_provider_connections_pkey"; + +alter table "public"."memory_messages_384" add constraint "memory_messages_384_pkey" PRIMARY KEY using index "memory_messages_384_pkey"; + +alter table "public"."memory_messages_384" add constraint "memory_messages_384_vector_id_key" UNIQUE using index "memory_messages_384_vector_id_key"; + +set check_function_bodies = off; + +CREATE OR REPLACE FUNCTION public.trigger_set_timestamps() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN + IF TG_OP = 'INSERT' THEN + NEW."createdAt" = NOW(); + NEW."updatedAt" = NOW(); + NEW."createdAtZ" = NOW(); + NEW."updatedAtZ" = NOW(); + ELSIF TG_OP = 'UPDATE' THEN + NEW."updatedAt" = NOW(); + NEW."updatedAtZ" = NOW(); + NEW."createdAt" = OLD."createdAt"; + NEW."createdAtZ" = OLD."createdAtZ"; + END IF; + RETURN NEW; +END; +$function$ +; + +grant references on table "public"."mastra_favorites" to "anon"; + +grant trigger on table "public"."mastra_favorites" to "anon"; + +grant truncate on table "public"."mastra_favorites" to "anon"; + +grant references on table "public"."mastra_favorites" to "authenticated"; + +grant trigger on table "public"."mastra_favorites" to "authenticated"; + +grant truncate on table "public"."mastra_favorites" to "authenticated"; + +grant delete on table "public"."mastra_favorites" to "service_role"; + +grant insert on table "public"."mastra_favorites" to "service_role"; + +grant references on table "public"."mastra_favorites" to "service_role"; + +grant select on table "public"."mastra_favorites" to "service_role"; + +grant trigger on table "public"."mastra_favorites" to "service_role"; + +grant truncate on table "public"."mastra_favorites" to "service_role"; + +grant update on table "public"."mastra_favorites" to "service_role"; + +grant references on table "public"."mastra_notifications" to "anon"; + +grant trigger on table "public"."mastra_notifications" to "anon"; + +grant truncate on table "public"."mastra_notifications" to "anon"; + +grant references on table "public"."mastra_notifications" to "authenticated"; + +grant trigger on table "public"."mastra_notifications" to "authenticated"; + +grant truncate on table "public"."mastra_notifications" to "authenticated"; + +grant delete on table "public"."mastra_notifications" to "service_role"; + +grant insert on table "public"."mastra_notifications" to "service_role"; + +grant references on table "public"."mastra_notifications" to "service_role"; + +grant select on table "public"."mastra_notifications" to "service_role"; + +grant trigger on table "public"."mastra_notifications" to "service_role"; + +grant truncate on table "public"."mastra_notifications" to "service_role"; + +grant update on table "public"."mastra_notifications" to "service_role"; + +grant references on table "public"."mastra_tool_provider_connections" to "anon"; + +grant trigger on table "public"."mastra_tool_provider_connections" to "anon"; + +grant truncate on table "public"."mastra_tool_provider_connections" to "anon"; + +grant references on table "public"."mastra_tool_provider_connections" to "authenticated"; + +grant trigger on table "public"."mastra_tool_provider_connections" to "authenticated"; + +grant truncate on table "public"."mastra_tool_provider_connections" to "authenticated"; + +grant delete on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant insert on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant references on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant select on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant trigger on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant truncate on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant update on table "public"."mastra_tool_provider_connections" to "service_role"; + +grant references on table "public"."memory_messages_384" to "anon"; + +grant trigger on table "public"."memory_messages_384" to "anon"; + +grant truncate on table "public"."memory_messages_384" to "anon"; + +grant references on table "public"."memory_messages_384" to "authenticated"; + +grant trigger on table "public"."memory_messages_384" to "authenticated"; + +grant truncate on table "public"."memory_messages_384" to "authenticated"; + +grant delete on table "public"."memory_messages_384" to "service_role"; + +grant insert on table "public"."memory_messages_384" to "service_role"; + +grant references on table "public"."memory_messages_384" to "service_role"; + +grant select on table "public"."memory_messages_384" to "service_role"; + +grant trigger on table "public"."memory_messages_384" to "service_role"; + +grant truncate on table "public"."memory_messages_384" to "service_role"; + +grant update on table "public"."memory_messages_384" to "service_role"; + + + +-- --------------------------------------------------------------------------- +-- Security parity for the four tables Mastra 1.53 creates at RUNTIME. +-- +-- 20260426000020_rls.sql enables RLS on the 28 mastra_* tables that existed +-- when it was written, and 20260428000000_revoke_anon_grants.sql revokes anon +-- SELECT across the schema. Neither could touch these four, because Mastra's +-- storage layer creates them on first boot — after every migration has run. +-- That left them with RLS disabled and anon grants intact. +-- +-- Everything here reaches these tables through the service_role client +-- (getSupabase()), which bypasses RLS, so enabling it costs nothing and closes +-- the hole for the anon/authenticated roles. +-- --------------------------------------------------------------------------- + +ALTER TABLE public.mastra_favorites ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.mastra_notifications ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.mastra_tool_provider_connections ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.memory_messages_384 ENABLE ROW LEVEL SECURITY; + +REVOKE SELECT ON TABLE public.mastra_favorites FROM anon; +REVOKE SELECT ON TABLE public.mastra_notifications FROM anon; +REVOKE SELECT ON TABLE public.mastra_tool_provider_connections FROM anon; +REVOKE SELECT ON TABLE public.memory_messages_384 FROM anon; + +REVOKE REFERENCES, TRIGGER, TRUNCATE ON TABLE public.mastra_favorites FROM anon; +REVOKE REFERENCES, TRIGGER, TRUNCATE ON TABLE public.mastra_notifications FROM anon; +REVOKE REFERENCES, TRIGGER, TRUNCATE ON TABLE public.mastra_tool_provider_connections FROM anon; +REVOKE REFERENCES, TRIGGER, TRUNCATE ON TABLE public.memory_messages_384 FROM anon;