From 3b2cb3a699397eaf5207e5b9d27b030d57b8b3bb Mon Sep 17 00:00:00 2001 From: dotta Date: Mon, 23 Mar 2026 15:57:57 -0500 Subject: [PATCH] Show all companies' agents on instance heartbeats page The /instance/scheduler-heartbeats endpoint was filtering agents by the requesting user's company memberships, which meant non-member companies (like donchitos) were hidden. Since this is an instance-level admin page, it should show all agents across all companies. - Added assertInstanceAdmin to authz.ts for reuse - Replaced assertBoard + company filter with assertInstanceAdmin - Removed the companyIds-based WHERE clause since instance admins see all Co-Authored-By: Paperclip --- server/src/routes/agents.ts | 15 ++------------- server/src/routes/authz.ts | 8 ++++++++ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/server/src/routes/agents.ts b/server/src/routes/agents.ts index 6bacb46ef..5621d2593 100644 --- a/server/src/routes/agents.ts +++ b/server/src/routes/agents.ts @@ -43,7 +43,7 @@ import { workspaceOperationService, } from "../services/index.js"; import { conflict, forbidden, notFound, unprocessable } from "../errors.js"; -import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js"; +import { assertBoard, assertCompanyAccess, assertInstanceAdmin, getActorInfo } from "./authz.js"; import { findServerAdapter, listAdapterModels } from "../adapters/index.js"; import { redactEventPayload } from "../redaction.js"; import { redactCurrentUserValue } from "../log-redaction.js"; @@ -855,17 +855,7 @@ export function agentRoutes(db: Db) { }); router.get("/instance/scheduler-heartbeats", async (req, res) => { - assertBoard(req); - - const accessConditions = []; - if (req.actor.source !== "local_implicit" && !req.actor.isInstanceAdmin) { - const allowedCompanyIds = req.actor.companyIds ?? []; - if (allowedCompanyIds.length === 0) { - res.json([]); - return; - } - accessConditions.push(inArray(agentsTable.companyId, allowedCompanyIds)); - } + assertInstanceAdmin(req); const rows = await db .select({ @@ -883,7 +873,6 @@ export function agentRoutes(db: Db) { }) .from(agentsTable) .innerJoin(companies, eq(agentsTable.companyId, companies.id)) - .where(accessConditions.length > 0 ? and(...accessConditions) : undefined) .orderBy(companies.name, agentsTable.name); const items: InstanceSchedulerHeartbeatAgent[] = rows diff --git a/server/src/routes/authz.ts b/server/src/routes/authz.ts index 4782489b4..a881d4ff0 100644 --- a/server/src/routes/authz.ts +++ b/server/src/routes/authz.ts @@ -7,6 +7,14 @@ export function assertBoard(req: Request) { } } +export function assertInstanceAdmin(req: Request) { + assertBoard(req); + if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin) { + return; + } + throw forbidden("Instance admin access required"); +} + export function assertCompanyAccess(req: Request, companyId: string) { if (req.actor.type === "none") { throw unauthorized();