Skip to content

Commit 289bd40

Browse files
committed
fix(webapp): gate remaining webhook dashboard routes behind the feature flag
The webhook handler detail page and the deliveries-live and samples resource loaders were reachable by direct URL without the hasWebhooksAccess flag. Add the same org-flag guard the other webhook routes use, so the whole dashboard surface stays hidden until the flag is enabled (admins and impersonators still pass).
1 parent 026a292 commit 289bd40

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.webhooks.$webhookParam/route.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ import {
5252
} from "~/presenters/v3/WebhookDetailPresenter.server";
5353
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactoryInstance.server";
5454
import { requireUser } from "~/services/session.server";
55+
import { FEATURE_FLAG } from "~/v3/featureFlags";
56+
import { flag } from "~/v3/featureFlags.server";
5557
import {
5658
docsPath,
5759
EnvironmentParamSchema,
@@ -88,6 +90,19 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
8890
throw new Response("Environment not found", { status: 404 });
8991
}
9092

93+
if (!user.admin && !user.isImpersonating) {
94+
const org = await $replica.organization.findFirst({
95+
where: { id: project.organizationId },
96+
select: { featureFlags: true },
97+
});
98+
const enabled = await flag({
99+
key: FEATURE_FLAG.hasWebhooksAccess,
100+
defaultValue: false,
101+
overrides: (org?.featureFlags as Record<string, unknown>) ?? {},
102+
});
103+
if (!enabled) throw new Response("Not found", { status: 404 });
104+
}
105+
91106
const url = new URL(request.url);
92107
const period = url.searchParams.get("period") ?? undefined;
93108
const from = parseFiniteInt(url.searchParams.get("from"));

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.webhooks.deliveries.live.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { $replica, webhookReplica } from "~/db.server";
55
import { resolveDeliveryRunTargets } from "~/presenters/v3/WebhookDetailPresenter.server";
66
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactoryInstance.server";
77
import { loadProjectEnvironmentFromRequest } from "~/services/loadProjectEnvironmentFromRequest.server";
8+
import { requireUser } from "~/services/session.server";
9+
import { FEATURE_FLAG } from "~/v3/featureFlags";
10+
import { flag } from "~/v3/featureFlags.server";
811
import {
912
type ListedWebhookDelivery,
1013
webhookDeliveriesRepository,
@@ -75,6 +78,20 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
7578

7679
const { project, environment } = await loadProjectEnvironmentFromRequest(request, params);
7780

81+
const user = await requireUser(request);
82+
if (!user.admin && !user.isImpersonating) {
83+
const org = await $replica.organization.findFirst({
84+
where: { id: project.organizationId },
85+
select: { featureFlags: true },
86+
});
87+
const enabled = await flag({
88+
key: FEATURE_FLAG.hasWebhooksAccess,
89+
defaultValue: false,
90+
overrides: (org?.featureFlags as Record<string, unknown>) ?? {},
91+
});
92+
if (!enabled) throw new Response("Not found", { status: 404 });
93+
}
94+
7895
const clickhouse = await clickhouseFactory.getClickhouseForOrganization(
7996
project.organizationId,
8097
"standard"

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.webhooks.samples.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import {
77
} from "@internal/webhook-sources";
88
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
99
import { typedjson } from "remix-typedjson";
10+
import { $replica } from "~/db.server";
1011
import { findProjectBySlug } from "~/models/project.server";
1112
import { requireUser } from "~/services/session.server";
1213
import { EnvironmentParamSchema } from "~/utils/pathBuilder";
14+
import { FEATURE_FLAG } from "~/v3/featureFlags";
15+
import { flag } from "~/v3/featureFlags.server";
1316

1417
export type WebhookSampleMeta = {
1518
provider: string;
@@ -49,6 +52,19 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
4952
if (!project)
5053
return typedjson({ kind: "error", error: "Project not found" } as WebhookSamplesData);
5154

55+
if (!user.admin && !user.isImpersonating) {
56+
const org = await $replica.organization.findFirst({
57+
where: { id: project.organizationId },
58+
select: { featureFlags: true },
59+
});
60+
const enabled = await flag({
61+
key: FEATURE_FLAG.hasWebhooksAccess,
62+
defaultValue: false,
63+
overrides: (org?.featureFlags as Record<string, unknown>) ?? {},
64+
});
65+
if (!enabled) throw new Response("Not found", { status: 404 });
66+
}
67+
5268
const url = new URL(request.url);
5369
const provider = url.searchParams.get("provider") ?? undefined;
5470
const eventType = url.searchParams.get("eventType") ?? undefined;

0 commit comments

Comments
 (0)