diff --git a/apps/webapp/app/presenters/v3/RunPresenter.server.ts b/apps/webapp/app/presenters/v3/RunPresenter.server.ts index 400e872a21..4ec0260e71 100644 --- a/apps/webapp/app/presenters/v3/RunPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/RunPresenter.server.ts @@ -28,7 +28,6 @@ export class RunPresenter { public async call({ userId, projectSlug, - organizationSlug, environmentSlug, runFriendlyId, showDeletedLogs, @@ -36,7 +35,6 @@ export class RunPresenter { }: { userId: string; projectSlug: string; - organizationSlug: string; environmentSlug: string; runFriendlyId: string; showDeletedLogs: boolean; @@ -93,6 +91,13 @@ export class RunPresenter { friendlyId: runFriendlyId, project: { slug: projectSlug, + organization: { + members: { + some: { + userId, + }, + }, + }, }, }, }); diff --git a/apps/webapp/app/presenters/v3/SpanPresenter.server.ts b/apps/webapp/app/presenters/v3/SpanPresenter.server.ts index 7919e075b2..94d10cb1c2 100644 --- a/apps/webapp/app/presenters/v3/SpanPresenter.server.ts +++ b/apps/webapp/app/presenters/v3/SpanPresenter.server.ts @@ -28,10 +28,12 @@ type GetSpanResult = NonNullable { const [error, result] = await tryCatch( presenter.call({ userId, - organizationSlug, showDeletedLogs: !!impersonationId, projectSlug: projectParam, runFriendlyId: runParam, diff --git a/apps/webapp/app/routes/orgs.$organizationSlug.projects.$projectParam.runs.$runParam.ts b/apps/webapp/app/routes/orgs.$organizationSlug.projects.$projectParam.runs.$runParam.ts index 29aa557797..63a89d7e0a 100644 --- a/apps/webapp/app/routes/orgs.$organizationSlug.projects.$projectParam.runs.$runParam.ts +++ b/apps/webapp/app/routes/orgs.$organizationSlug.projects.$projectParam.runs.$runParam.ts @@ -3,14 +3,14 @@ import { type LoaderFunctionArgs } from "@remix-run/server-runtime"; import { z } from "zod"; import { prisma } from "~/db.server"; import { requireUserId } from "~/services/session.server"; -import { ProjectParamSchema, v3DeploymentPath, v3RunPath } from "~/utils/pathBuilder"; +import { ProjectParamSchema, v3RunPath } from "~/utils/pathBuilder"; const ParamSchema = ProjectParamSchema.extend({ runParam: z.string(), }); export const loader = async ({ request, params }: LoaderFunctionArgs) => { - await requireUserId(request); + const userId = await requireUserId(request); const { organizationSlug, projectParam, runParam } = ParamSchema.parse(params); const run = await prisma.taskRun.findFirst({ @@ -18,6 +18,14 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { friendlyId: runParam, project: { slug: projectParam, + organization: { + slug: organizationSlug, + members: { + some: { + userId, + }, + }, + }, }, }, select: { diff --git a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx index 66d166294b..29a5cb873a 100644 --- a/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx +++ b/apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx @@ -78,8 +78,10 @@ import { } from "~/utils/pathBuilder"; import { createTimelineSpanEventsFromSpanEvents } from "~/utils/timelineSpanEvents"; import { CompleteWaitpointForm } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.waitpoints.$waitpointFriendlyId.complete/route"; +import { requireUserId } from "~/services/session.server"; export const loader = async ({ request, params }: LoaderFunctionArgs) => { + const userId = await requireUserId(request); const { projectParam, organizationSlug, envParam, runParam, spanParam } = v3SpanParamsSchema.parse(params); @@ -90,6 +92,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { projectSlug: projectParam, spanId: spanParam, runFriendlyId: runParam, + userId, }); return typedjson(result); diff --git a/apps/webapp/app/routes/resources.taskruns.$runParam.cancel.ts b/apps/webapp/app/routes/resources.taskruns.$runParam.cancel.ts index 676d4dabe2..240d7d3d8e 100644 --- a/apps/webapp/app/routes/resources.taskruns.$runParam.cancel.ts +++ b/apps/webapp/app/routes/resources.taskruns.$runParam.cancel.ts @@ -1,9 +1,10 @@ import { parse } from "@conform-to/zod"; -import { ActionFunction, json } from "@remix-run/node"; +import { type ActionFunction, json } from "@remix-run/node"; import { z } from "zod"; import { prisma } from "~/db.server"; import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server"; import { logger } from "~/services/logger.server"; +import { requireUserId } from "~/services/session.server"; import { CancelTaskRunService } from "~/v3/services/cancelTaskRun.server"; export const cancelSchema = z.object({ @@ -15,6 +16,7 @@ const ParamSchema = z.object({ }); export const action: ActionFunction = async ({ request, params }) => { + const userId = await requireUserId(request); const { runParam } = ParamSchema.parse(params); const formData = await request.formData(); @@ -25,9 +27,18 @@ export const action: ActionFunction = async ({ request, params }) => { } try { - const taskRun = await prisma.taskRun.findUnique({ + const taskRun = await prisma.taskRun.findFirst({ where: { friendlyId: runParam, + project: { + organization: { + members: { + some: { + userId, + }, + }, + }, + }, }, }); diff --git a/apps/webapp/app/routes/resources.taskruns.$runParam.debug.ts b/apps/webapp/app/routes/resources.taskruns.$runParam.debug.ts index ba48f7085a..d7acf18e51 100644 --- a/apps/webapp/app/routes/resources.taskruns.$runParam.debug.ts +++ b/apps/webapp/app/routes/resources.taskruns.$runParam.debug.ts @@ -1,4 +1,4 @@ -import { LoaderFunctionArgs } from "@remix-run/node"; +import { type LoaderFunctionArgs } from "@remix-run/node"; import { typedjson } from "remix-typedjson"; import { z } from "zod"; import { $replica } from "~/db.server"; diff --git a/apps/webapp/app/v3/eventRepository.server.ts b/apps/webapp/app/v3/eventRepository.server.ts index 263125ba75..d19a2963ee 100644 --- a/apps/webapp/app/v3/eventRepository.server.ts +++ b/apps/webapp/app/v3/eventRepository.server.ts @@ -970,22 +970,30 @@ export class EventRepository { // A Span can be cancelled if it is partial and has a parent that is cancelled // And a span's duration, if it is partial and has a cancelled parent, is the time between the start of the span and the time of the cancellation event of the parent - public async getSpan( - storeTable: TaskEventStoreTable, - spanId: string, - traceId: string, - startCreatedAt: Date, - endCreatedAt?: Date, - options?: { includeDebugLogs?: boolean } - ) { - return await startActiveSpan("getSpan", async (s) => { - const spanEvent = await this.#getSpanEvent( + public async getSpan({ + storeTable, + spanId, + environmentId, + startCreatedAt, + endCreatedAt, + options, + }: { + storeTable: TaskEventStoreTable; + spanId: string; + environmentId: string; + startCreatedAt: Date; + endCreatedAt?: Date; + options?: { includeDebugLogs?: boolean }; + }) { + return await startActiveSpan("getSpan", async () => { + const spanEvent = await this.#getSpanEvent({ storeTable, spanId, + environmentId, startCreatedAt, endCreatedAt, - options - ); + options, + }); if (!spanEvent) { return; @@ -996,6 +1004,7 @@ export class EventRepository { const span = await this.#createSpanFromEvent( storeTable, preparedEvent, + environmentId, startCreatedAt, endCreatedAt ); @@ -1081,6 +1090,7 @@ export class EventRepository { async #createSpanFromEvent( storeTable: TaskEventStoreTable, event: PreparedEvent, + environmentId: string, startCreatedAt: Date, endCreatedAt?: Date ) { @@ -1091,6 +1101,7 @@ export class EventRepository { await this.#walkSpanAncestors( storeTable, event, + environmentId, startCreatedAt, endCreatedAt, (ancestorEvent, level) => { @@ -1185,6 +1196,7 @@ export class EventRepository { async #walkSpanAncestors( storeTable: TaskEventStoreTable, event: PreparedEvent, + environmentId: string, startCreatedAt: Date, endCreatedAt: Date | undefined, callback: (event: PreparedEvent, level: number) => { stop: boolean } @@ -1195,12 +1207,13 @@ export class EventRepository { } await startActiveSpan("walkSpanAncestors", async (s) => { - let parentEvent = await this.#getSpanEvent( + let parentEvent = await this.#getSpanEvent({ storeTable, - parentId, + spanId: parentId, + environmentId, startCreatedAt, - endCreatedAt - ); + endCreatedAt, + }); let level = 1; while (parentEvent) { @@ -1216,29 +1229,38 @@ export class EventRepository { return; } - parentEvent = await this.#getSpanEvent( + parentEvent = await this.#getSpanEvent({ storeTable, - preparedParentEvent.parentId, + spanId: preparedParentEvent.parentId, + environmentId, startCreatedAt, - endCreatedAt - ); + endCreatedAt, + }); level++; } }); } - async #getSpanEvent( - storeTable: TaskEventStoreTable, - spanId: string, - startCreatedAt: Date, - endCreatedAt?: Date, - options?: { includeDebugLogs?: boolean } - ) { + async #getSpanEvent({ + storeTable, + spanId, + environmentId, + startCreatedAt, + endCreatedAt, + options, + }: { + storeTable: TaskEventStoreTable; + spanId: string; + environmentId: string; + startCreatedAt: Date; + endCreatedAt?: Date; + options?: { includeDebugLogs?: boolean }; + }) { return await startActiveSpan("getSpanEvent", async (s) => { const events = await this.taskEventStore.findMany( storeTable, - { spanId }, + { spanId, environmentId }, startCreatedAt, endCreatedAt, undefined,