From a1a6e9f538d4202f15ab19782d455570bd576f90 Mon Sep 17 00:00:00 2001 From: Ayush8923 <80516839+Ayush8923@users.noreply.github.com> Date: Sat, 18 Apr 2026 11:42:22 +0530 Subject: [PATCH 1/2] fix(*): guardrails authentication fixes --- app/(main)/guardrails/page.tsx | 17 ++++++++++------- app/components/guardrails/BanListField.tsx | 7 +++++-- app/components/guardrails/BanListModal.tsx | 4 ++++ app/components/guardrails/SavedConfigsList.tsx | 12 ++++-------- .../prompt-editor/ConfigEditorPane.tsx | 3 ++- app/lib/guardrailsClient.ts | 3 +++ 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/app/(main)/guardrails/page.tsx b/app/(main)/guardrails/page.tsx index 0eb337a..4d31775 100644 --- a/app/(main)/guardrails/page.tsx +++ b/app/(main)/guardrails/page.tsx @@ -22,7 +22,8 @@ import SavedConfigsList from "@/app/components/guardrails/SavedConfigsList"; export default function GuardrailsPage() { const { sidebarCollapsed } = useApp(); - const { isHydrated } = useAuth(); + const { isHydrated, activeKey } = useAuth(); + const apiKey = activeKey?.key ?? ""; const toast = useToast(); const [orgContext, setOrgContext] = useState(null); const [validators, setValidators] = useState([]); @@ -40,6 +41,7 @@ export default function GuardrailsPage() { if (!isHydrated) return; guardrailsFetch<{ data?: { organization_id: number; project_id: number } }>( "/api/apikeys/verify", //need to change this in backend to /auth/verify + apiKey, ) .then((data) => { const org_id = data?.data?.organization_id; @@ -53,11 +55,11 @@ export default function GuardrailsPage() { .catch((e: Error) => toast.error(e.message || "Session verification failed"), ); - }, [isHydrated]); + }, [isHydrated, apiKey]); useEffect(() => { setValidatorsLoading(true); - guardrailsFetch<{ validators?: Validator[] }>("/api/guardrails") + guardrailsFetch<{ validators?: Validator[] }>("/api/guardrails", apiKey) .then((data) => { const list: Validator[] = Array.isArray(data?.validators) ? data.validators @@ -66,7 +68,7 @@ export default function GuardrailsPage() { }) .catch(() => toast.error("Failed to load validators")) .finally(() => setValidatorsLoading(false)); - }, []); + }, [apiKey]); const configsQueryString = orgContext ? `?organization_id=${parseInt(String(orgContext.organization_id), 10)}&project_id=${parseInt(String(orgContext.project_id), 10)}` @@ -78,7 +80,7 @@ export default function GuardrailsPage() { guardrailsFetch<{ data?: { configs?: SavedValidatorConfig[] } | SavedValidatorConfig[]; configs?: SavedValidatorConfig[]; - }>(`/api/guardrails/validators/configs${configsQueryString}`) + }>(`/api/guardrails/validators/configs${configsQueryString}`, apiKey) .then((data) => { const nested = data?.data; const list: SavedValidatorConfig[] = Array.isArray( @@ -94,7 +96,7 @@ export default function GuardrailsPage() { }) .catch(() => toast.error("Failed to load saved configs")) .finally(() => setSavedConfigsLoading(false)); - }, [configsQueryString]); + }, [configsQueryString, apiKey]); useEffect(() => { fetchSavedConfigs(); @@ -115,6 +117,7 @@ export default function GuardrailsPage() { try { await guardrailsFetch( `/api/guardrails/validators/configs/${configId}${configsQueryString}`, + apiKey, { method: "DELETE" }, ); toast.success("Config deleted"); @@ -149,7 +152,7 @@ export default function GuardrailsPage() { const body = configValues; - await guardrailsFetch(url, { + await guardrailsFetch(url, apiKey, { method: isUpdate ? "PATCH" : "POST", body: JSON.stringify(body), }); diff --git a/app/components/guardrails/BanListField.tsx b/app/components/guardrails/BanListField.tsx index 4765385..d7430bf 100644 --- a/app/components/guardrails/BanListField.tsx +++ b/app/components/guardrails/BanListField.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from "react"; import BanListModal from "./BanListModal"; import { guardrailsFetch } from "@/app/lib/guardrailsClient"; +import { useAuth } from "@/app/lib/context/AuthContext"; import Select from "@/app/components/Select"; interface BanList { @@ -14,6 +15,8 @@ interface BanListFieldProps { } export default function BanListField({ value, onChange }: BanListFieldProps) { + const { activeKey } = useAuth(); + const apiKey = activeKey?.key ?? ""; const [banLists, setBanLists] = useState([]); const [loading, setLoading] = useState(true); const [fetchError, setFetchError] = useState(null); @@ -29,7 +32,7 @@ export default function BanListField({ value, onChange }: BanListFieldProps) { guardrailsFetch<{ data?: { ban_lists?: BanList[] } | BanList[]; ban_lists?: BanList[]; - }>("/api/guardrails/ban_lists") + }>("/api/guardrails/ban_lists", apiKey) .then((data) => { const nested = data?.data; const list: BanList[] = Array.isArray( @@ -57,7 +60,7 @@ export default function BanListField({ value, onChange }: BanListFieldProps) { guardrailsFetch<{ banned_words?: string[]; data?: { banned_words?: string[] }; - }>(`/api/guardrails/ban_lists/${id}`) + }>(`/api/guardrails/ban_lists/${id}`, apiKey) .then((data) => { const words: string[] = Array.isArray(data?.banned_words) ? data.banned_words! diff --git a/app/components/guardrails/BanListModal.tsx b/app/components/guardrails/BanListModal.tsx index d1917df..af441fc 100644 --- a/app/components/guardrails/BanListModal.tsx +++ b/app/components/guardrails/BanListModal.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import { guardrailsFetch } from "@/app/lib/guardrailsClient"; +import { useAuth } from "@/app/lib/context/AuthContext"; import Button from "@/app/components/Button"; import { CloseIcon } from "@/app/components/icons"; import Field from "@/app/components/Field"; @@ -13,6 +14,8 @@ export default function BanListModal({ onClose, onCreated, }: BanListModalProps) { + const { activeKey } = useAuth(); + const apiKey = activeKey?.key ?? ""; const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [bannedWords, setBannedWords] = useState(""); @@ -52,6 +55,7 @@ export default function BanListModal({ }; const data = await guardrailsFetch<{ id: string; name?: string }>( "/api/guardrails/ban_lists", + apiKey, { method: "POST", body: JSON.stringify(body) }, ); onCreated({ id: data.id, name: data.name ?? name.trim() }); diff --git a/app/components/guardrails/SavedConfigsList.tsx b/app/components/guardrails/SavedConfigsList.tsx index c8da577..27a6656 100644 --- a/app/components/guardrails/SavedConfigsList.tsx +++ b/app/components/guardrails/SavedConfigsList.tsx @@ -8,6 +8,7 @@ import { EditIcon, } from "@/app/components/icons"; import Button from "@/app/components/Button"; +import Loader from "@/app/components/Loader"; import { VALIDATOR_META_BY_TYPE } from "@/app/lib/utils/guardrails"; interface SavedConfigsListProps { @@ -47,13 +48,8 @@ export default function SavedConfigsList({
{isLoading ? ( -
- {[...Array(3)].map((_, i) => ( -
- ))} +
+
) : configs.length === 0 ? (
@@ -75,7 +71,7 @@ export default function SavedConfigsList({ return (
{ guardrailsFetch<{ data?: { organization_id: number; project_id: number } }>( "/api/apikeys/verify", + apiKey, ) .then((data) => { const org_id = data?.data?.organization_id; @@ -85,7 +86,7 @@ export default function ConfigEditorPane({ } }) .catch(() => {}); - }, []); + }, [apiKey]); const [isDropdownOpen, setIsDropdownOpen] = useState(false); const [expandedConfigId, setExpandedConfigId] = useState(null); diff --git a/app/lib/guardrailsClient.ts b/app/lib/guardrailsClient.ts index 97f617d..c7d90ea 100644 --- a/app/lib/guardrailsClient.ts +++ b/app/lib/guardrailsClient.ts @@ -57,16 +57,19 @@ export function guardrailsUserClient( /** * Client-side fetch helper for guardrails Next.js route handlers (/api/guardrails/*). + * Attaches X-API-KEY header and `credentials: "include"` for cookie-based auth. * Parses JSON and throws on non-OK responses. */ export async function guardrailsFetch( path: string, + apiKey: string, options: RequestInit = {}, ): Promise { const headers = new Headers(options.headers); if (!(options.body instanceof FormData) && !headers.has("Content-Type")) { if (options.body) headers.set("Content-Type", "application/json"); } + if (apiKey) headers.set("X-API-KEY", apiKey); const res = await fetch(path, { ...options, From eea3b4aef830d5d1abe16a67e22904275df19876 Mon Sep 17 00:00:00 2001 From: Ayush8923 <80516839+Ayush8923@users.noreply.github.com> Date: Sat, 18 Apr 2026 11:50:41 +0530 Subject: [PATCH 2/2] fix(*): border fixes --- app/components/guardrails/SavedConfigsList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/guardrails/SavedConfigsList.tsx b/app/components/guardrails/SavedConfigsList.tsx index 27a6656..d54918b 100644 --- a/app/components/guardrails/SavedConfigsList.tsx +++ b/app/components/guardrails/SavedConfigsList.tsx @@ -74,7 +74,7 @@ export default function SavedConfigsList({ className={`rounded-xl border-l-2 bg-bg-primary shadow-sm cursor-pointer transition-shadow hover:shadow-md ${ isSelected ? "border-l-status-success" - : "border-l-amber-600" + : "border-l-[rgb(220,207,195)]" }`} onClick={() => onSelectConfig(cfg)} >