From 737d63f3dc1211b6702b0d6bb3a684d8330d209f Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:00:40 +0530 Subject: [PATCH] fix(zero):scope core workspace queries --- surfsense_web/zero/queries/automations.ts | 8 ++++++-- surfsense_web/zero/queries/chat.ts | 22 ++++++++++++++++------ surfsense_web/zero/queries/documents.ts | 17 +++++++++++------ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/surfsense_web/zero/queries/automations.ts b/surfsense_web/zero/queries/automations.ts index 79772eb1f..5d79a9f09 100644 --- a/surfsense_web/zero/queries/automations.ts +++ b/surfsense_web/zero/queries/automations.ts @@ -1,12 +1,16 @@ import { defineQuery } from "@rocicorp/zero"; import { z } from "zod"; import { zql } from "../schema/index"; +import { constrainToAllowedSpaces } from "./authz"; // Mirrors chat byThread: client passes the parent id, the REST route still // authorizes via `automation_id -> search_space`. No search_space_id on the // table by design. export const automationRunQueries = { - byAutomation: defineQuery(z.object({ automationId: z.number() }), ({ args: { automationId } }) => - zql.automation_runs.where("automationId", automationId).orderBy("createdAt", "desc") + byAutomation: defineQuery(z.object({ automationId: z.number() }), ({ args: { automationId }, ctx }) => + zql.automation_runs + .where("automationId", automationId) + .whereExists("automation", (q) => constrainToAllowedSpaces(q, ctx)) + .orderBy("createdAt", "desc") ), }; diff --git a/surfsense_web/zero/queries/chat.ts b/surfsense_web/zero/queries/chat.ts index de8b13f8a..40e09a6ee 100644 --- a/surfsense_web/zero/queries/chat.ts +++ b/surfsense_web/zero/queries/chat.ts @@ -1,21 +1,31 @@ import { defineQuery } from "@rocicorp/zero"; import { z } from "zod"; import { zql } from "../schema/index"; +import { constrainToAllowedSpaces } from "./authz"; export const messageQueries = { - byThread: defineQuery(z.object({ threadId: z.number() }), ({ args: { threadId } }) => - zql.new_chat_messages.where("threadId", threadId).orderBy("createdAt", "asc") + byThread: defineQuery(z.object({ threadId: z.number() }), ({ args: { threadId }, ctx }) => + zql.new_chat_messages + .where("threadId", threadId) + .whereExists("thread", (q) => constrainToAllowedSpaces(q, ctx)) + .orderBy("createdAt", "asc") ), }; export const commentQueries = { - byThread: defineQuery(z.object({ threadId: z.number() }), ({ args: { threadId } }) => - zql.chat_comments.where("threadId", threadId).orderBy("createdAt", "asc") + byThread: defineQuery(z.object({ threadId: z.number() }), ({ args: { threadId }, ctx }) => + zql.chat_comments + .where("threadId", threadId) + .whereExists("thread", (q) => constrainToAllowedSpaces(q, ctx)) + .orderBy("createdAt", "asc") ), }; export const chatSessionQueries = { - byThread: defineQuery(z.object({ threadId: z.number() }), ({ args: { threadId } }) => - zql.chat_session_state.where("threadId", threadId).one() + byThread: defineQuery(z.object({ threadId: z.number() }), ({ args: { threadId }, ctx }) => + zql.chat_session_state + .where("threadId", threadId) + .whereExists("thread", (q) => constrainToAllowedSpaces(q, ctx)) + .one() ), }; diff --git a/surfsense_web/zero/queries/documents.ts b/surfsense_web/zero/queries/documents.ts index 97088945f..a38fedc33 100644 --- a/surfsense_web/zero/queries/documents.ts +++ b/surfsense_web/zero/queries/documents.ts @@ -1,15 +1,20 @@ import { defineQuery } from "@rocicorp/zero"; import { z } from "zod"; import { zql } from "../schema/index"; +import { canReadSpace, constrainToAllowedSpaces, denySpace } from "./authz"; export const documentQueries = { - bySpace: defineQuery(z.object({ searchSpaceId: z.number() }), ({ args: { searchSpaceId } }) => - zql.documents.where("searchSpaceId", searchSpaceId).orderBy("createdAt", "desc") - ), + bySpace: defineQuery(z.object({ searchSpaceId: z.number() }), ({ args: { searchSpaceId }, ctx }) => { + const query = zql.documents.where("searchSpaceId", searchSpaceId); + if (!canReadSpace(ctx, searchSpaceId)) return denySpace(query).orderBy("createdAt", "desc"); + return constrainToAllowedSpaces(query, ctx).orderBy("createdAt", "desc"); + }), }; export const connectorQueries = { - bySpace: defineQuery(z.object({ searchSpaceId: z.number() }), ({ args: { searchSpaceId } }) => - zql.search_source_connectors.where("searchSpaceId", searchSpaceId).orderBy("createdAt", "desc") - ), + bySpace: defineQuery(z.object({ searchSpaceId: z.number() }), ({ args: { searchSpaceId }, ctx }) => { + const query = zql.search_source_connectors.where("searchSpaceId", searchSpaceId); + if (!canReadSpace(ctx, searchSpaceId)) return denySpace(query).orderBy("createdAt", "desc"); + return constrainToAllowedSpaces(query, ctx).orderBy("createdAt", "desc"); + }), };