Merge branch 'dev' into zamilmajdy/secrt-1000-add-capability-for-the-admin-to-log-in-as-other-users

This commit is contained in:
Aarushi 2024-11-20 20:29:45 +00:00 committed by GitHub
commit f41379df45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 679 additions and 236 deletions

View File

@ -69,6 +69,10 @@ jobs:
run: |
cp ../supabase/docker/.env.example ../.env
- name: Copy backend .env
run: |
cp ../backend/.env.example ../backend/.env
- name: Run docker compose
run: |
docker compose -f ../docker-compose.yml up -d

View File

@ -63,7 +63,7 @@ class AIMusicGeneratorBlock(Block):
placeholder="e.g., 'An upbeat electronic dance track with heavy bass'",
title="Prompt",
)
model_version: MusicGenModelVersion = SchemaField(
music_gen_model_version: MusicGenModelVersion = SchemaField(
description="Model to use for generation",
default=MusicGenModelVersion.STEREO_LARGE,
title="Model Version",
@ -118,7 +118,7 @@ class AIMusicGeneratorBlock(Block):
test_input={
"credentials": TEST_CREDENTIALS_INPUT,
"prompt": "An upbeat electronic dance track with heavy bass",
"model_version": MusicGenModelVersion.STEREO_LARGE,
"music_gen_model_version": MusicGenModelVersion.STEREO_LARGE,
"duration": 8,
"temperature": 1.0,
"top_k": 250,
@ -134,7 +134,7 @@ class AIMusicGeneratorBlock(Block):
),
],
test_mock={
"run_model": lambda api_key, model_version, prompt, duration, temperature, top_k, top_p, classifier_free_guidance, output_format, normalization_strategy: "https://replicate.com/output/generated-audio-url.wav",
"run_model": lambda api_key, music_gen_model_version, prompt, duration, temperature, top_k, top_p, classifier_free_guidance, output_format, normalization_strategy: "https://replicate.com/output/generated-audio-url.wav",
},
test_credentials=TEST_CREDENTIALS,
)
@ -153,7 +153,7 @@ class AIMusicGeneratorBlock(Block):
)
result = self.run_model(
api_key=credentials.api_key,
model_version=input_data.model_version,
music_gen_model_version=input_data.music_gen_model_version,
prompt=input_data.prompt,
duration=input_data.duration,
temperature=input_data.temperature,
@ -182,7 +182,7 @@ class AIMusicGeneratorBlock(Block):
def run_model(
self,
api_key: SecretStr,
model_version: MusicGenModelVersion,
music_gen_model_version: MusicGenModelVersion,
prompt: str,
duration: int,
temperature: float,
@ -200,7 +200,7 @@ class AIMusicGeneratorBlock(Block):
"meta/musicgen:671ac645ce5e552cc63a54a2bbff63fcf798043055d2dac5fc9e36a837eedcfb",
input={
"prompt": prompt,
"model_version": model_version,
"music_gen_model_version": music_gen_model_version,
"duration": duration,
"temperature": temperature,
"top_k": top_k,

View File

@ -9,6 +9,7 @@ from backend.util.settings import Config
# List of IP networks to block
BLOCKED_IP_NETWORKS = [
# --8<-- [start:BLOCKED_IP_NETWORKS]
ipaddress.ip_network("0.0.0.0/8"), # "This" Network
ipaddress.ip_network("10.0.0.0/8"), # Private-Use
ipaddress.ip_network("127.0.0.0/8"), # Loopback
@ -17,6 +18,7 @@ BLOCKED_IP_NETWORKS = [
ipaddress.ip_network("192.168.0.0/16"), # Private-Use
ipaddress.ip_network("224.0.0.0/4"), # Multicast
ipaddress.ip_network("240.0.0.0/4"), # Reserved for Future Use
# --8<-- [end:BLOCKED_IP_NETWORKS]
]

View File

@ -23,6 +23,7 @@
"defaults"
],
"dependencies": {
"@faker-js/faker": "^9.2.0",
"@hookform/resolvers": "^3.9.1",
"@next/third-parties": "^15.0.3",
"@radix-ui/react-avatar": "^1.1.1",
@ -31,17 +32,17 @@
"@radix-ui/react-context-menu": "^2.2.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-icons": "^1.3.1",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-radio-group": "^1.2.1",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.2.1",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-toast": "^1.2.2",
"@radix-ui/react-tooltip": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.4",
"@sentry/nextjs": "^8",
"@supabase/ssr": "^0.5.2",
"@supabase/supabase-js": "^2.46.1",
@ -54,13 +55,13 @@
"cookie": "1.0.1",
"date-fns": "^4.1.0",
"dotenv": "^16.4.5",
"elliptic": "6.6.0",
"lucide-react": "^0.456.0",
"elliptic": "6.6.1",
"lucide-react": "^0.460.0",
"moment": "^2.30.1",
"next": "^14.2.13",
"next-themes": "^0.4.3",
"react": "^18",
"react-day-picker": "^9.3.0",
"react-day-picker": "^9.3.2",
"react-dom": "^18",
"react-hook-form": "^7.53.2",
"react-icons": "^5.3.0",

View File

@ -4,10 +4,10 @@ import { defineConfig, devices } from "@playwright/test";
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
import dotenv from "dotenv";
import path from "path";
dotenv.config({ path: path.resolve(__dirname, ".env") });
dotenv.config({ path: path.resolve(__dirname, "../backend/.env") });
/**
* See https://playwright.dev/docs/test-configuration.
*/

View File

@ -89,7 +89,6 @@ const RunnerUIWrapper = forwardRef<RunnerUIWrapperRef, RunnerUIWrapperProps>(
const outputs = outputBlocks.map((node) => ({
id: node.id,
type: "output" as const,
outputSchema: node.data.outputSchema as BlockIORootSchema,
hardcodedValues: {
name: (node.data.hardcodedValues as any).name || "Output",
description:

View File

@ -37,7 +37,9 @@ export default function SupabaseProvider({
if (event === "SIGNED_IN") {
api.createUser();
}
router.refresh();
if (event === "SIGNED_OUT") {
router.refresh();
}
});
return () => {

View File

@ -10,7 +10,7 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Block, BlockUIType } from "@/lib/autogpt-server-api";
import { Block, BlockUIType, SpecialBlockID } from "@/lib/autogpt-server-api";
import { MagnifyingGlassIcon, PlusIcon } from "@radix-ui/react-icons";
import { IconToyBrick } from "@/components/ui/icons";
import { getPrimaryCategoryColor } from "@/lib/utils";
@ -57,7 +57,7 @@ export const BlocksControl: React.FC<BlocksControlProps> = ({
const agentList = flows.map(
(flow) =>
({
id: "e189baac-8c20-45a1-94a7-55177ea42565", // TODO: fetch this programmatically.
id: SpecialBlockID.AGENT,
name: flow.name,
description:
`Ver.${flow.version}` +

View File

@ -1,13 +1,20 @@
import React, { useCallback } from "react";
import AutoGPTServerAPI, { GraphMeta } from "@/lib/autogpt-server-api";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import AutoGPTServerAPI, {
BlockIORootSchema,
Graph,
GraphMeta,
NodeExecutionResult,
SpecialBlockID,
} from "@/lib/autogpt-server-api";
import { FlowRun } from "@/lib/types";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import Link from "next/link";
import { Button, buttonVariants } from "@/components/ui/button";
import { IconSquare } from "@/components/ui/icons";
import { Pencil2Icon } from "@radix-ui/react-icons";
import { ExitIcon, Pencil2Icon } from "@radix-ui/react-icons";
import moment from "moment/moment";
import { FlowRunStatusBadge } from "@/components/monitor/FlowRunStatusBadge";
import RunnerOutputUI, { BlockOutput } from "../runner-ui/RunnerOutputUI";
export const FlowRunInfo: React.FC<
React.HTMLAttributes<HTMLDivElement> & {
@ -15,6 +22,66 @@ export const FlowRunInfo: React.FC<
flowRun: FlowRun;
}
> = ({ flow, flowRun, ...props }) => {
const [isOutputOpen, setIsOutputOpen] = useState(false);
const [blockOutputs, setBlockOutputs] = useState<BlockOutput[]>([]);
const api = useMemo(() => new AutoGPTServerAPI(), []);
const fetchBlockResults = useCallback(async () => {
const executionResults = await api.getGraphExecutionInfo(
flow.id,
flowRun.id,
);
// Create a map of the latest COMPLETED execution results of output nodes by node_id
const latestCompletedResults = executionResults
.filter(
(result) =>
result.status === "COMPLETED" &&
result.block_id === SpecialBlockID.OUTPUT,
)
.reduce((acc, result) => {
const existing = acc.get(result.node_id);
// Compare dates if there's an existing result
if (existing) {
const existingDate = existing.end_time || existing.add_time;
const currentDate = result.end_time || result.add_time;
if (currentDate > existingDate) {
acc.set(result.node_id, result);
}
} else {
acc.set(result.node_id, result);
}
return acc;
}, new Map<string, NodeExecutionResult>());
// Transform results to BlockOutput format
setBlockOutputs(
Array.from(latestCompletedResults.values()).map((result) => ({
id: result.node_id,
type: "output" as const,
hardcodedValues: {
name: result.input_data.name || "Output",
description: result.input_data.description || "Output from the agent",
value: result.input_data.value,
},
// Change this line to extract the array directly
result: result.output_data?.output || undefined,
})),
);
}, [api, flow.id, flow.version, flowRun.id]);
// Fetch graph and execution data
useEffect(() => {
if (!isOutputOpen || blockOutputs.length > 0) {
return;
}
fetchBlockResults();
}, [isOutputOpen, blockOutputs]);
if (flowRun.graphID != flow.id) {
throw new Error(
`FlowRunInfo can't be used with non-matching flowRun.flowID and flow.id`,
@ -22,58 +89,67 @@ export const FlowRunInfo: React.FC<
}
const handleStopRun = useCallback(() => {
const api = new AutoGPTServerAPI();
api.stopGraphExecution(flow.id, flowRun.id);
}, [flow.id, flowRun.id]);
return (
<Card {...props}>
<CardHeader className="flex-row items-center justify-between space-x-3 space-y-0">
<div>
<CardTitle>
{flow.name} <span className="font-light">v{flow.version}</span>
</CardTitle>
<p className="mt-2">
Agent ID: <code>{flow.id}</code>
</p>
<p className="mt-1">
Run ID: <code>{flowRun.id}</code>
</p>
</div>
<div className="flex space-x-2">
{flowRun.status === "running" && (
<Button onClick={handleStopRun} variant="destructive">
<IconSquare className="mr-2" /> Stop Run
<>
<Card {...props}>
<CardHeader className="flex-row items-center justify-between space-x-3 space-y-0">
<div>
<CardTitle>
{flow.name} <span className="font-light">v{flow.version}</span>
</CardTitle>
<p className="mt-2">
Agent ID: <code>{flow.id}</code>
</p>
<p className="mt-1">
Run ID: <code>{flowRun.id}</code>
</p>
</div>
<div className="flex space-x-2">
{flowRun.status === "running" && (
<Button onClick={handleStopRun} variant="destructive">
<IconSquare className="mr-2" /> Stop Run
</Button>
)}
<Button onClick={() => setIsOutputOpen(true)} variant="outline">
<ExitIcon className="mr-2" /> View Outputs
</Button>
)}
<Link
className={buttonVariants({ variant: "default" })}
href={`/build?flowID=${flow.id}`}
>
<Pencil2Icon className="mr-2" /> Open in Builder
</Link>
</div>
</CardHeader>
<CardContent>
<div>
<strong>Status:</strong>{" "}
<FlowRunStatusBadge status={flowRun.status} />
</div>
<p>
<strong>Started:</strong>{" "}
{moment(flowRun.startTime).format("YYYY-MM-DD HH:mm:ss")}
</p>
<p>
<strong>Finished:</strong>{" "}
{moment(flowRun.endTime).format("YYYY-MM-DD HH:mm:ss")}
</p>
<p>
<strong>Duration (run time):</strong> {flowRun.duration} (
{flowRun.totalRunTime}) seconds
</p>
{/* <p><strong>Total cost:</strong> €1,23</p> */}
</CardContent>
</Card>
<Link
className={buttonVariants({ variant: "default" })}
href={`/build?flowID=${flow.id}`}
>
<Pencil2Icon className="mr-2" /> Open in Builder
</Link>
</div>
</CardHeader>
<CardContent>
<div>
<strong>Status:</strong>{" "}
<FlowRunStatusBadge status={flowRun.status} />
</div>
<p>
<strong>Started:</strong>{" "}
{moment(flowRun.startTime).format("YYYY-MM-DD HH:mm:ss")}
</p>
<p>
<strong>Finished:</strong>{" "}
{moment(flowRun.endTime).format("YYYY-MM-DD HH:mm:ss")}
</p>
<p>
<strong>Duration (run time):</strong> {flowRun.duration} (
{flowRun.totalRunTime}) seconds
</p>
</CardContent>
</Card>
<RunnerOutputUI
isOpen={isOutputOpen}
onClose={() => setIsOutputOpen(false)}
blockOutputs={blockOutputs}
/>
</>
);
};
export default FlowRunInfo;

View File

@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect, useRef } from "react";
import {
Sheet,
SheetContent,
@ -10,10 +10,12 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { BlockIORootSchema } from "@/lib/autogpt-server-api/types";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import { Clipboard } from "lucide-react";
import { useToast } from "@/components/ui/use-toast";
interface BlockOutput {
export interface BlockOutput {
id: string;
outputSchema: BlockIORootSchema;
hardcodedValues: {
name: string;
description: string;
@ -30,11 +32,20 @@ interface OutputModalProps {
const formatOutput = (output: any): string => {
if (typeof output === "object") {
try {
if (
Array.isArray(output) &&
output.every((item) => typeof item === "string")
) {
return output.join("\n").replace(/\\n/g, "\n");
}
return JSON.stringify(output, null, 2);
} catch (error) {
return `Error formatting output: ${(error as Error).message}`;
}
}
if (typeof output === "string") {
return output.replace(/\\n/g, "\n");
}
return String(output);
};
@ -43,11 +54,28 @@ export function RunnerOutputUI({
onClose,
blockOutputs,
}: OutputModalProps) {
const { toast } = useToast();
const copyOutput = (name: string, output: any) => {
const formattedOutput = formatOutput(output);
navigator.clipboard.writeText(formattedOutput).then(() => {
toast({
title: `"${name}" output copied to clipboard!`,
duration: 2000,
});
});
};
const adjustTextareaHeight = (textarea: HTMLTextAreaElement) => {
textarea.style.height = "auto";
textarea.style.height = `${textarea.scrollHeight}px`;
};
return (
<Sheet open={isOpen} onOpenChange={onClose}>
<SheetContent
side="right"
className="flex h-full w-full flex-col overflow-hidden sm:max-w-[500px]"
className="flex h-full w-full flex-col overflow-hidden sm:max-w-[600px]"
>
<SheetHeader className="px-2 py-2">
<SheetTitle className="text-xl">Run Outputs</SheetTitle>
@ -71,11 +99,38 @@ export function RunnerOutputUI({
</Label>
)}
<div className="rounded-md bg-gray-100 p-2">
<div className="group relative rounded-md bg-gray-100 p-2">
<Button
className="absolute right-1 top-1 z-10 m-1 hidden p-2 group-hover:block"
variant="outline"
size="icon"
onClick={() =>
copyOutput(
block.hardcodedValues.name || "Unnamed Output",
block.result,
)
}
title="Copy Output"
>
<Clipboard size={18} />
</Button>
<Textarea
readOnly
value={formatOutput(block.result ?? "No output yet")}
className="resize-none whitespace-pre-wrap break-words border-none bg-transparent text-sm"
className="w-full resize-none whitespace-pre-wrap break-words border-none bg-transparent text-sm"
style={{
height: "auto",
minHeight: "2.5rem",
maxHeight: "400px",
}}
ref={(el) => {
if (el) {
adjustTextareaHeight(el);
if (el.scrollHeight > 400) {
el.style.height = "400px";
}
}
}}
/>
</div>
</div>

View File

@ -241,11 +241,12 @@ export type GraphExecuteResponse = {
/* Mirror of backend/data/execution.py:ExecutionResult */
export type NodeExecutionResult = {
graph_exec_id: string;
node_exec_id: string;
graph_id: string;
graph_version: number;
graph_exec_id: string;
node_exec_id: string;
node_id: string;
block_id: string;
status: "INCOMPLETE" | "QUEUED" | "RUNNING" | "COMPLETED" | "FAILED";
input_data: { [key: string]: any };
output_data: { [key: string]: Array<any> };
@ -319,6 +320,12 @@ export enum BlockUIType {
AGENT = "Agent",
}
export enum SpecialBlockID {
AGENT = "e189baac-8c20-45a1-94a7-55177ea42565",
INPUT = "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b",
OUTPUT = "363ae599-353e-4804-937e-b2ee3cef3da4",
}
export type AnalyticsMetrics = {
metric_name: string;
metric_value: number;

View File

@ -0,0 +1,46 @@
import { test, expect } from "./fixtures";
test.describe("Authentication", () => {
test("user can login successfully", async ({ page, loginPage, testUser }) => {
await page.goto("/login"); // Make sure we're on the login page
await loginPage.login(testUser.email, testUser.password);
// expect to be redirected to the home page
await expect(page).toHaveURL("/");
// expect to see the Monitor text
await expect(page.getByText("Monitor")).toBeVisible();
});
test("user can logout successfully", async ({
page,
loginPage,
testUser,
}) => {
await page.goto("/login"); // Make sure we're on the login page
await loginPage.login(testUser.email, testUser.password);
// Expect to be on the home page
await expect(page).toHaveURL("/");
// Click on the user menu
await page.getByRole("button", { name: "CN" }).click();
// Click on the logout menu item
await page.getByRole("menuitem", { name: "Log out" }).click();
// Expect to be redirected to the login page
await expect(page).toHaveURL("/login");
});
test("login in, then out, then in again", async ({
page,
loginPage,
testUser,
}) => {
await page.goto("/login"); // Make sure we're on the login page
await loginPage.login(testUser.email, testUser.password);
await page.goto("/");
await page.getByRole("button", { name: "CN" }).click();
await page.getByRole("menuitem", { name: "Log out" }).click();
await expect(page).toHaveURL("/login");
await loginPage.login(testUser.email, testUser.password);
await expect(page).toHaveURL("/");
await expect(page.getByText("Monitor")).toBeVisible();
});
});

View File

@ -0,0 +1,18 @@
import { test as base } from "@playwright/test";
import { createTestUserFixture } from "./test-user.fixture";
import { createLoginPageFixture } from "./login-page.fixture";
import type { TestUser } from "./test-user.fixture";
import { LoginPage } from "../pages/login.page";
type Fixtures = {
testUser: TestUser;
loginPage: LoginPage;
};
// Combine fixtures
export const test = base.extend<Fixtures>({
testUser: createTestUserFixture,
loginPage: createLoginPageFixture,
});
export { expect } from "@playwright/test";

View File

@ -0,0 +1,14 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { test as base } from "@playwright/test";
import { LoginPage } from "../pages/login.page";
export const loginPageFixture = base.extend<{ loginPage: LoginPage }>({
loginPage: async ({ page }, use) => {
await use(new LoginPage(page));
},
});
// Export just the fixture function
export const createLoginPageFixture = async ({ page }, use) => {
await use(new LoginPage(page));
};

View File

@ -0,0 +1,83 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { faker } from "@faker-js/faker";
export type TestUser = {
email: string;
password: string;
id?: string;
};
let supabase: SupabaseClient;
function getSupabaseAdmin() {
if (!supabase) {
supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{
auth: {
autoRefreshToken: false,
persistSession: false,
},
},
);
}
return supabase;
}
async function createTestUser(userData: TestUser): Promise<TestUser> {
const supabase = getSupabaseAdmin();
const { data: authUser, error: authError } = await supabase.auth.signUp({
email: userData.email,
password: userData.password,
});
if (authError) {
throw new Error(`Failed to create test user: ${authError.message}`);
}
return {
...userData,
id: authUser.user?.id,
};
}
async function deleteTestUser(userId: string) {
const supabase = getSupabaseAdmin();
try {
const { error } = await supabase.auth.admin.deleteUser(userId);
if (error) {
console.warn(`Warning: Failed to delete test user: ${error.message}`);
}
} catch (error) {
console.warn(
`Warning: Error during user cleanup: ${(error as Error).message}`,
);
}
}
function generateUserData(): TestUser {
return {
email: `test.${faker.string.uuid()}@example.com`,
password: faker.internet.password({ length: 12 }),
};
}
// Export just the fixture function
export const createTestUserFixture = async ({}, use) => {
let user: TestUser | null = null;
try {
const userData = generateUserData();
user = await createTestUser(userData);
await use(user);
} finally {
if (user?.id) {
await deleteTestUser(user.id);
}
}
};

View File

@ -0,0 +1,51 @@
import { Page } from "@playwright/test";
export class LoginPage {
constructor(private page: Page) {}
async login(email: string, password: string) {
console.log("Attempting login with:", { email, password }); // Debug log
// Fill email
const emailInput = this.page.getByPlaceholder("user@email.com");
await emailInput.waitFor({ state: "visible" });
await emailInput.fill(email);
// Fill password
const passwordInput = this.page.getByPlaceholder("password");
await passwordInput.waitFor({ state: "visible" });
await passwordInput.fill(password);
// Check terms
const termsCheckbox = this.page.getByLabel("I agree to the Terms of Use");
await termsCheckbox.waitFor({ state: "visible" });
await termsCheckbox.click();
// TODO: This is a workaround to wait for the page to load after filling the email and password
const emailInput2 = this.page.getByPlaceholder("user@email.com");
await emailInput2.waitFor({ state: "visible" });
await emailInput2.fill(email);
// Fill password
const passwordInput2 = this.page.getByPlaceholder("password");
await passwordInput2.waitFor({ state: "visible" });
await passwordInput2.fill(password);
// Wait for the button to be ready
const loginButton = this.page.getByRole("button", { name: "Log in" });
await loginButton.waitFor({ state: "visible" });
// Start waiting for navigation before clicking
const navigationPromise = this.page.waitForURL("/", { timeout: 60000 });
console.log("About to click login button"); // Debug log
await loginButton.click();
console.log("Waiting for navigation"); // Debug log
await navigationPromise;
console.log("Navigation complete, waiting for network idle"); // Debug log
await this.page.waitForLoadState("networkidle", { timeout: 60000 });
console.log("Login process complete"); // Debug log
}
}

View File

@ -1,4 +1,4 @@
import { test, expect } from "@playwright/test";
import { test, expect } from "./fixtures";
test("has title", async ({ page }) => {
await page.goto("/");

View File

@ -1,4 +1,4 @@
import { test, expect } from "@playwright/test";
import { test, expect } from "./fixtures";
import { setNestedProperty } from "../lib/utils";
const testCases = [

View File

@ -0,0 +1,9 @@
import { faker } from "@faker-js/faker";
export function generateUser() {
return {
email: faker.internet.email(),
password: faker.internet.password(),
name: faker.person.fullName(),
};
}

View File

@ -1026,10 +1026,10 @@
react-confetti "^6.1.0"
strip-ansi "^7.1.0"
"@date-fns/tz@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@date-fns/tz/-/tz-1.1.2.tgz#c8036db48ae9e7165f40a951942a14070e0c6ec1"
integrity sha512-Xmg2cPmOPQieCLAdf62KtFPU9y7wbQDq1OAzrs/bEQFvhtCPXDiks1CHDE/sTXReRfh/MICVkw/vY6OANHUGiA==
"@date-fns/tz@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@date-fns/tz/-/tz-1.2.0.tgz#81cb3211693830babaf3b96aff51607e143030a6"
integrity sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==
"@emnapi/runtime@^1.2.0":
version "1.3.1"
@ -1202,6 +1202,11 @@
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz"
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
"@faker-js/faker@^9.2.0":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-9.2.0.tgz#269ee3a5d2442e88e10d984e106028422bcb9551"
integrity sha512-ulqQu4KMr1/sTFIYvqSdegHT8NIkt66tFAkugGnHA+1WAfEn6hMzNR+svjXGFRVLnapxvej67Z/LwchFrnLBUg==
"@floating-ui/core@^1.6.0":
version "1.6.7"
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz"
@ -1775,13 +1780,13 @@
dependencies:
"@opentelemetry/semantic-conventions" "1.27.0"
"@opentelemetry/instrumentation-amqplib@^0.42.0":
version "0.42.0"
resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.42.0.tgz"
integrity sha512-fiuU6OKsqHJiydHWgTRQ7MnIrJ2lEqsdgFtNIH4LbAUJl/5XmrIeoDzDnox+hfkgWK65jsleFuQDtYb5hW1koQ==
"@opentelemetry/instrumentation-amqplib@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.43.0.tgz#e18b7d763b69c605a7abf9869e1c278f9bfdc1eb"
integrity sha512-ALjfQC+0dnIEcvNYsbZl/VLh7D2P1HhFF4vicRKHhHFIUV3Shpg4kXgiek5PLhmeKSIPiUB25IYH5RIneclL4A==
dependencies:
"@opentelemetry/core" "^1.8.0"
"@opentelemetry/instrumentation" "^0.53.0"
"@opentelemetry/instrumentation" "^0.54.0"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@opentelemetry/instrumentation-connect@0.40.0":
@ -1877,6 +1882,14 @@
"@opentelemetry/instrumentation" "^0.54.0"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@opentelemetry/instrumentation-knex@0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.41.0.tgz#74d611489e823003a825097bac019c6c2ad061a5"
integrity sha512-OhI1SlLv5qnsnm2dOVrian/x3431P75GngSpnR7c4fcVFv7prXGYu29Z6ILRWJf/NJt6fkbySmwdfUUnFnHCTg==
dependencies:
"@opentelemetry/instrumentation" "^0.54.0"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@opentelemetry/instrumentation-koa@0.43.0":
version "0.43.0"
resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.43.0.tgz"
@ -1956,6 +1969,15 @@
"@opentelemetry/redis-common" "^0.36.2"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@opentelemetry/instrumentation-tedious@0.15.0":
version "0.15.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.15.0.tgz#da82f4d153fb6ff7d1f85d39872ac40bf9db12ea"
integrity sha512-Kb7yo8Zsq2TUwBbmwYgTAMPK0VbhoS8ikJ6Bup9KrDtCx2JC01nCb+M0VJWXt7tl0+5jARUbKWh5jRSoImxdCw==
dependencies:
"@opentelemetry/instrumentation" "^0.54.0"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@types/tedious" "^4.0.14"
"@opentelemetry/instrumentation-undici@0.6.0":
version "0.6.0"
resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.6.0.tgz"
@ -2223,10 +2245,10 @@
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-icons@^1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.3.1.tgz#462c85fd726a77854cd5956e29eb19a575aa7ce5"
integrity sha512-QvYompk0X+8Yjlo/Fv4McrzxohDdM5GgLHyQcPpcsPvlOSXCGFjdbuyGL5dzRbg0GpknAjQJJZzdiRK7iWVuFQ==
"@radix-ui/react-icons@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-icons/-/react-icons-1.3.2.tgz#09be63d178262181aeca5fb7f7bc944b10a7f441"
integrity sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==
"@radix-ui/react-id@1.1.0", "@radix-ui/react-id@^1.1.0":
version "1.1.0"
@ -2357,10 +2379,10 @@
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
"@radix-ui/react-scroll-area@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.0.tgz#d09fd693728b09c50145935bec6f91efc2661729"
integrity sha512-q2jMBdsJ9zB7QG6ngQNzNwlvxLQqONyL58QbEGwuyRZZb/ARQwk3uQVbCF7GvQVOtV6EU/pDxAw3zRzJZI3rpQ==
"@radix-ui/react-scroll-area@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.1.tgz#610c53e07d017e24b62bd73a0a6eb23fa7331b3b"
integrity sha512-FnM1fHfCtEZ1JkyfH/1oMiTcFBQvHKl4vD9WnpwkLgtF+UmnXMCad6ECPTaAjcDjam+ndOEJWgHyKDGNteWSHw==
dependencies:
"@radix-ui/number" "1.1.0"
"@radix-ui/primitive" "1.1.0"
@ -2444,10 +2466,10 @@
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-visually-hidden" "1.1.0"
"@radix-ui/react-tooltip@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.1.3.tgz#4250b14723f2d8477e7a3d0526c169f91d1f2f74"
integrity sha512-Z4w1FIS0BqVFI2c1jZvb/uDVJijJjJ2ZMuPV81oVgTZ7g3BZxobplnMVvXtFWgtozdvYJ+MFWtwkM5S2HnAong==
"@radix-ui/react-tooltip@^1.1.4":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.1.4.tgz#152d8485859b80d395d6b3229f676fef3cec56b3"
integrity sha512-QpObUH/ZlpaO4YgHSaYzrLO2VuO+ZBFFgGzjMUPwtiYnAzzNNDPJeEGRrT7qNOrWm/Jr08M1vlp+vTHtnSQ0Uw==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
@ -2553,61 +2575,61 @@
resolved "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.3.0.tgz"
integrity sha512-lHKK8M5CTcpFj2hZDB3wIjb0KAbEOgDmiJGDv1WBRfQgRm/a8/XMEkG/N1iM01xgbUDsPQwi42D+dFo1XPAKew==
"@sentry-internal/browser-utils@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.37.1.tgz#374028d8e37047aeda14b226707e6601de65996e"
integrity sha512-OSR/V5GCsSCG7iapWtXCT/y22uo3HlawdEgfM1NIKk1mkP15UyGQtGEzZDdih2H+SNuX1mp9jQLTjr5FFp1A5w==
"@sentry-internal/browser-utils@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.38.0.tgz#d7f6d398778906efb0c017e63d3c59d3203dfa7d"
integrity sha512-5QMVcssrAcmjKT0NdFYcX0b0wwZovGAZ9L2GajErXtHkBenjI2sgR2+5J7n+QZGuk2SC1qhGmT1O9i3p3UEwew==
dependencies:
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry-internal/feedback@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.37.1.tgz#e2d5fc934ca3b4925a5f5d0e63549830a1cf147e"
integrity sha512-Se25NXbSapgS2S+JssR5YZ48b3OY4UGmAuBOafgnMW91LXMxRNWRbehZuNUmjjHwuywABMxjgu+Yp5uJDATX+g==
"@sentry-internal/feedback@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.38.0.tgz#726661a01f7ff40b93c8ee05c985fd0436a1c033"
integrity sha512-AW5HCCAlc3T1jcSuNhbFVNO1CHyJ5g5tsGKEP4VKgu+D1Gg2kZ5S2eFatLBUP/BD5JYb1A7p6XPuzYp1XfMq0A==
dependencies:
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry-internal/replay-canvas@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.37.1.tgz#e8a5e350e486b16938b3dd99886be23b7b6eff18"
integrity sha512-1JLAaPtn1VL5vblB0BMELFV0D+KUm/iMGsrl4/JpRm0Ws5ESzQl33DhXVv1IX/ZAbx9i14EjR7MG9+Hj70tieQ==
"@sentry-internal/replay-canvas@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.38.0.tgz#26e9bc937dab73e1a26d57dc1015b7ff1f2d76c5"
integrity sha512-OxmlWzK9J8mRM+KxdSnQ5xuxq+p7TiBzTz70FT3HltxmeugvDkyp6803UcFqHOPHR35OYeVLOalym+FmvNn9kw==
dependencies:
"@sentry-internal/replay" "8.37.1"
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry-internal/replay" "8.38.0"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry-internal/replay@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.37.1.tgz#6dc2e3955879f6e7ab830db1ddee54e0a9b401f3"
integrity sha512-E/Plhisk/pXJjOdOU12sg8m/APTXTA21iEniidP6jW3/+O0tD/H/UovEqa4odNTqxPMa798xHQSQNt5loYiaLA==
"@sentry-internal/replay@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.38.0.tgz#9a9b945a3c066f5610a363774e3c99420c3f4fce"
integrity sha512-mQPShKnIab7oKwkwrRxP/D8fZYHSkDY+cvqORzgi+wAwgnunytJQjz9g6Ww2lJu98rHEkr5SH4V4rs6PZYZmnQ==
dependencies:
"@sentry-internal/browser-utils" "8.37.1"
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry-internal/browser-utils" "8.38.0"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry/babel-plugin-component-annotate@2.22.6":
version "2.22.6"
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.6.tgz#829d6caf2c95c1c46108336de4e1049e6521435e"
integrity sha512-V2g1Y1I5eSe7dtUVMBvAJr8BaLRr4CLrgNgtPaZyMT4Rnps82SrZ5zqmEkLXPumlXhLUWR6qzoMNN2u+RXVXfQ==
"@sentry/browser@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.37.1.tgz#2e6e4accc395ad9e6313e07b09415370c71e5874"
integrity sha512-5ym+iGiIpjIKKpMWi9S3/tXh9xneS+jqxwRTJqed3cb8i4ydfMAAP8sM3U8xMCWWABpWyIUW+fpewC0tkhE1aQ==
"@sentry/browser@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.38.0.tgz#c562accdc2bbe0b0074d98bfe7ff460e39ce3109"
integrity sha512-AZR+b0EteNZEGv6JSdBD22S9VhQ7nrljKsSnzxobBULf3BpwmhmCzTbDrqWszKDAIDYmL+yQJIR2glxbknneWQ==
dependencies:
"@sentry-internal/browser-utils" "8.37.1"
"@sentry-internal/feedback" "8.37.1"
"@sentry-internal/replay" "8.37.1"
"@sentry-internal/replay-canvas" "8.37.1"
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry-internal/browser-utils" "8.38.0"
"@sentry-internal/feedback" "8.38.0"
"@sentry-internal/replay" "8.38.0"
"@sentry-internal/replay-canvas" "8.38.0"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry/bundler-plugin-core@2.22.6":
version "2.22.6"
@ -2677,47 +2699,47 @@
"@sentry/cli-win32-i686" "2.38.2"
"@sentry/cli-win32-x64" "2.38.2"
"@sentry/core@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.37.1.tgz#4bafb25c762ec8680874056f6160df276c1cc7c6"
integrity sha512-82csXby589iDupM3VgCHJeWZagUyEEaDnbFcoZ/Z91QX2Sjq8FcF5OsforoXjw09i0XTFqlkFAnQVpDBmMXcpQ==
"@sentry/core@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.38.0.tgz#5d1b74770c79e489e786018a3e514cddeb777bcb"
integrity sha512-sGD+5TEHU9G7X7zpyaoJxpOtwjTjvOd1f/MKBrWW2vf9UbYK+GUJrOzLhMoSWp/pHSYgvObkJkDb/HwieQjvhQ==
dependencies:
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry/nextjs@^8":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-8.37.1.tgz#e4e64b6388e8ab7e2d8e4cb7981775865bc3ada9"
integrity sha512-MMe+W1Jd/liYA47RU8qCFSYATgnVEAcFoREnbK2L4ooIDB2RP7jB8AX9LWD9ZWg9MduyQdDoFsI9OPIO3WmfuQ==
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-8.38.0.tgz#e279ff08b8bbde338bc9d1ce2c40dc0649d8c8d6"
integrity sha512-axKkeAXbpiO8hQjVtDSLyXYqCN9ptnNHxNmKlYuRTJtwv4hPZ31AIhurEN2y7dUBvXv3QTBv+9kvEkdN8qHvXA==
dependencies:
"@opentelemetry/api" "^1.9.0"
"@opentelemetry/instrumentation-http" "0.53.0"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@rollup/plugin-commonjs" "26.0.1"
"@sentry-internal/browser-utils" "8.37.1"
"@sentry/core" "8.37.1"
"@sentry/node" "8.37.1"
"@sentry/opentelemetry" "8.37.1"
"@sentry/react" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/vercel-edge" "8.37.1"
"@sentry-internal/browser-utils" "8.38.0"
"@sentry/core" "8.38.0"
"@sentry/node" "8.38.0"
"@sentry/opentelemetry" "8.38.0"
"@sentry/react" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry/vercel-edge" "8.38.0"
"@sentry/webpack-plugin" "2.22.6"
chalk "3.0.0"
resolve "1.22.8"
rollup "3.29.5"
stacktrace-parser "^0.1.10"
"@sentry/node@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-8.37.1.tgz#d061bad391a53b3d20d3399d2a2c5466a6ec54f3"
integrity sha512-ACRZmqOBHRPKsyVhnDR4+RH1QQr7WMdH7RNl62VlKNZGLvraxW1CUqTSeNUFUuOwks3P6nozROSQs8VMSC/nVg==
"@sentry/node@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-8.38.0.tgz#a59883b2b1b4c5515f95c65af1965df20bc14d69"
integrity sha512-nwW0XqZFQseXYn0i6i6nKPkbjgHMBEFSF9TnK6mHHqJHHObHIZ6qu5CfvGKgxATia8JPIg9NN8XcyYOnQMi07w==
dependencies:
"@opentelemetry/api" "^1.9.0"
"@opentelemetry/context-async-hooks" "^1.25.1"
"@opentelemetry/core" "^1.25.1"
"@opentelemetry/instrumentation" "^0.54.0"
"@opentelemetry/instrumentation-amqplib" "^0.42.0"
"@opentelemetry/instrumentation-amqplib" "^0.43.0"
"@opentelemetry/instrumentation-connect" "0.40.0"
"@opentelemetry/instrumentation-dataloader" "0.12.0"
"@opentelemetry/instrumentation-express" "0.44.0"
@ -2729,6 +2751,7 @@
"@opentelemetry/instrumentation-http" "0.53.0"
"@opentelemetry/instrumentation-ioredis" "0.43.0"
"@opentelemetry/instrumentation-kafkajs" "0.4.0"
"@opentelemetry/instrumentation-knex" "0.41.0"
"@opentelemetry/instrumentation-koa" "0.43.0"
"@opentelemetry/instrumentation-lru-memoizer" "0.40.0"
"@opentelemetry/instrumentation-mongodb" "0.48.0"
@ -2738,58 +2761,59 @@
"@opentelemetry/instrumentation-nestjs-core" "0.40.0"
"@opentelemetry/instrumentation-pg" "0.44.0"
"@opentelemetry/instrumentation-redis-4" "0.42.0"
"@opentelemetry/instrumentation-tedious" "0.15.0"
"@opentelemetry/instrumentation-undici" "0.6.0"
"@opentelemetry/resources" "^1.26.0"
"@opentelemetry/sdk-trace-base" "^1.26.0"
"@opentelemetry/semantic-conventions" "^1.27.0"
"@prisma/instrumentation" "5.19.1"
"@sentry/core" "8.37.1"
"@sentry/opentelemetry" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/core" "8.38.0"
"@sentry/opentelemetry" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
import-in-the-middle "^1.11.2"
"@sentry/opentelemetry@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/opentelemetry/-/opentelemetry-8.37.1.tgz#366a86edf0c2d080e30eaddca367cd614a0ce850"
integrity sha512-P/Rp7R+qNiRYz9qtVMV12YL9CIrZjzXWGVUBZjJayHu37jdvMowCol5G850QPYy0E2O0AQnFtxBno2yeURn8QQ==
"@sentry/opentelemetry@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/opentelemetry/-/opentelemetry-8.38.0.tgz#b4bae78c56f72b4bdc2a921c59a53339e776582d"
integrity sha512-AfjmIf/v7+x2WplhkX66LyGKvrzzPeSgff9uJ0cFCC2s0yd1qA2VPuIwEyr5i/FOJOP5bvFr8tu/hz3LA4+F5Q==
dependencies:
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry/react@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.37.1.tgz#25ba2703b79436c9154e6f287959a8a3c040e8cb"
integrity sha512-HanDqBFTgIUhUsYztAHhSti+sEhQ8YopAymXgnpqkJ7j1PLHXZgQAre6M4Uvixu28WS5MDHC1onnAIBDgYRDYw==
"@sentry/react@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-8.38.0.tgz#513cbd9ba35bb0258d10b74d272800cbc5f05631"
integrity sha512-5396tewO00wbJFHUkmU+ikmp4A+wuBpStNc7UDyAm642jfbPajj51+GWld/ZYNFiQaZ/8I9tvvpHqVLnUh21gg==
dependencies:
"@sentry/browser" "8.37.1"
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/browser" "8.38.0"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
hoist-non-react-statics "^3.3.2"
"@sentry/types@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.37.1.tgz#e92a7d346cfa29116568f4ffb58f65caedee0149"
integrity sha512-ryMOTROLSLINKFEbHWvi7GigNrsQhsaScw2NddybJGztJQ5UhxIGESnxGxWCufBmWFDwd7+5u0jDPCVUJybp7w==
"@sentry/types@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.38.0.tgz#9c48734a8b4055bfd553a0141efec78e9680ed09"
integrity sha512-fP5H9ZX01W4Z/EYctk3mkSHi7d06cLcX2/UWqwdWbyPWI+pL2QpUPICeO/C+8SnmYx//wFj3qWDhyPCh1PdFAA==
"@sentry/utils@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.37.1.tgz#6e020cd222d56d79953ea9d4630d91b3e323ceda"
integrity sha512-Qtn2IfpII12K17txG/ZtTci35XYjYi4CxbQ3j7nXY7toGv/+MqPXwV5q2i9g94XaSXlE5Wy9/hoCZoZpZs/djA==
"@sentry/utils@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.38.0.tgz#2f91ca7d044f6e17b993c866ca02a981c4c1bc25"
integrity sha512-3X7MgIKIx+2q5Al7QkhaRB4wV6DvzYsaeIwdqKUzGLuRjXmNgJrLoU87TAwQRmZ6Wr3IoEpThZZMNrzYPXxArw==
dependencies:
"@sentry/types" "8.37.1"
"@sentry/types" "8.38.0"
"@sentry/vercel-edge@8.37.1":
version "8.37.1"
resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-8.37.1.tgz#cbd4690f420cb2696b41db40bd3238fbdfc07ce9"
integrity sha512-LBf1UFNermpDtV+n5tsOJgtc6b+9/uLsffvq64ktnx9x+Pz2/3sFAHauikB/fwmo0MLxYk9AIng5b2QL5+uv4Q==
"@sentry/vercel-edge@8.38.0":
version "8.38.0"
resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-8.38.0.tgz#e748dd3ddcc46ee87a9ae0bf539cdab1e24547b4"
integrity sha512-JckfcK/bZZj2CGOcHhgi4lcHAWpMqOnx8g9YcIWc8Bj8MfpavXciYBU+L0AnYiXwnW1v3E4M0pMrb+jccvGtEw==
dependencies:
"@opentelemetry/api" "^1.9.0"
"@sentry/core" "8.37.1"
"@sentry/types" "8.37.1"
"@sentry/utils" "8.37.1"
"@sentry/core" "8.38.0"
"@sentry/types" "8.38.0"
"@sentry/utils" "8.38.0"
"@sentry/webpack-plugin@2.22.6":
version "2.22.6"
@ -3735,6 +3759,13 @@
resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
"@types/tedious@^4.0.14":
version "4.0.14"
resolved "https://registry.yarnpkg.com/@types/tedious/-/tedious-4.0.14.tgz#868118e7a67808258c05158e9cad89ca58a2aec1"
integrity sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==
dependencies:
"@types/node" "*"
"@types/unist@*", "@types/unist@^3.0.0":
version "3.0.3"
resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz"
@ -5734,23 +5765,10 @@ electron-to-chromium@^1.5.28:
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.36.tgz"
integrity sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==
elliptic@6.6.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.0.tgz#5919ec723286c1edf28685aa89261d4761afa210"
integrity sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
hash.js "^1.0.0"
hmac-drbg "^1.0.1"
inherits "^2.0.4"
minimalistic-assert "^1.0.1"
minimalistic-crypto-utils "^1.0.1"
elliptic@^6.5.3, elliptic@^6.5.5:
version "6.5.7"
resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz"
integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
elliptic@6.6.1, elliptic@^6.5.3, elliptic@^6.5.5:
version "6.6.1"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06"
integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
@ -8188,10 +8206,10 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
lucide-react@^0.456.0:
version "0.456.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.456.0.tgz#14906c3355cc65d3380b7b2294b331aeda1bb392"
integrity sha512-DIIGJqTT5X05sbAsQ+OhA8OtJYyD4NsEMCA/HQW/Y6ToPQ7gwbtujIoeAaup4HpHzV35SQOarKAWH8LYglB6eA==
lucide-react@^0.460.0:
version "0.460.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.460.0.tgz#5681364b6bd94d1d475944f0385239c0b1408e35"
integrity sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==
lz-string@^1.5.0:
version "1.5.0"
@ -9550,12 +9568,12 @@ react-confetti@^6.1.0:
dependencies:
tween-functions "^1.2.0"
react-day-picker@^9.3.0:
version "9.3.0"
resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-9.3.0.tgz#00e979a495d98ce8886bb3625c51133ba5c2acc8"
integrity sha512-xXgZISTXlwQ1Igt4cBttXF+aK1Xvd00azcGVY74PNCAe8PxtULFVWGT1UfdavFiVScF04dyV8QcybKZAw570QQ==
react-day-picker@^9.3.2:
version "9.3.2"
resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-9.3.2.tgz#d507d99fbf52cfbbfa35b38f8a31d47a52322410"
integrity sha512-Rj2gPPVYKqZbSF8DxaLteHY+45zd6swf5yE3hmJ8m6VEqPI2ve9CuZsDvQ10tIt3ckRJ9hmLa5t0SsmLlXllhw==
dependencies:
"@date-fns/tz" "^1.1.2"
"@date-fns/tz" "^1.2.0"
date-fns "^4.1.0"
react-docgen-typescript@^2.2.2:

View File

@ -247,13 +247,13 @@ test = ["pytest (>=6)"]
[[package]]
name = "fastapi"
version = "0.115.4"
version = "0.115.5"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
optional = false
python-versions = ">=3.8"
files = [
{file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"},
{file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"},
{file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"},
{file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"},
]
[package.dependencies]
@ -1298,4 +1298,4 @@ watchmedo = ["PyYAML (>=3.10)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "4f7e4bbed535e40688e953dd0bfab80f704ba6017fc01360941f5cf858ef5f4c"
content-hash = "985f87e9d6e2b7232f880a476c69c626bc4227156d8a57d8f1867236b215f82f"

View File

@ -13,7 +13,7 @@ python = "^3.10"
prisma = "^0.15.0"
python-dotenv = "^1.0.1"
uvicorn = "^0.32.0"
fastapi = "^0.115.4"
fastapi = "^0.115.5"
sentry-sdk = { extras = ["fastapi"], version = "^2.18.0" }
fuzzywuzzy = "^0.18.0"
python-levenshtein = "^0.26.1"

View File

@ -1,5 +1,5 @@
# To boot the app run the following:
# docker-compose run auto-gpt
# docker compose run auto-gpt
version: '3.9'
services:

View File

@ -14,7 +14,7 @@ To print out debug logs:
.\autogpt.bat --debug # on Windows
docker-compose run --rm auto-gpt --debug # in Docker
docker compose run --rm auto-gpt --debug # in Docker
```
## Inspect and share logs

View File

@ -56,7 +56,7 @@ You can check if you have Docker installed by running the following command:
```bash
docker -v
docker-compose -v
docker compose -v
```
Once you have Docker and Docker Compose installed, you can proceed to the next step.

View File

@ -337,15 +337,73 @@ For the WikipediaSummaryBlock:
This approach allows us to test the block's logic comprehensively without relying on external services, while also accommodating non-deterministic outputs.
## Security Best Practices for SSRF Prevention
When creating blocks that handle external URL inputs or make network requests, it's crucial to use the platform's built-in SSRF protection mechanisms. The `backend.util.request` module provides a secure `Requests` wrapper class that should be used for all HTTP requests.
### Using the Secure Requests Wrapper
```python
from backend.util.request import requests
class MyNetworkBlock(Block):
def run(self, input_data: Input, **kwargs) -> BlockOutput:
try:
# The requests wrapper automatically validates URLs and blocks dangerous requests
response = requests.get(input_data.url)
yield "result", response.text
except ValueError as e:
# URL validation failed
raise RuntimeError(f"Invalid URL provided: {e}")
except requests.exceptions.RequestException as e:
# Request failed
raise RuntimeError(f"Request failed: {e}")
```
The `Requests` wrapper provides these security features:
1. **URL Validation**:
- Blocks requests to private IP ranges (RFC 1918)
- Validates URL format and protocol
- Resolves DNS and checks IP addresses
- Supports whitelisting trusted origins
2. **Secure Defaults**:
- Disables redirects by default
- Raises exceptions for non-200 status codes
- Supports custom headers and validators
3. **Protected IP Ranges**:
The wrapper denies requests to these networks:
```python title="backend/util/request.py"
--8<-- "autogpt_platform/backend/backend/util/request.py:BLOCKED_IP_NETWORKS"
```
### Custom Request Configuration
If you need to customize the request behavior:
```python
from backend.util.request import Requests
# Create a custom requests instance with specific trusted origins
custom_requests = Requests(
trusted_origins=["api.trusted-service.com"],
raise_for_status=True,
extra_headers={"User-Agent": "MyBlock/1.0"}
)
```
## Tips for Effective Block Testing
1. **Provide realistic test_input**: Ensure your test input covers typical use cases.
2. **Define appropriate test_output**:
- For deterministic outputs, use specific expected values.
- For non-deterministic outputs or when only the type matters, use Python types (e.g., `str`, `int`, `dict`).
- You can mix specific values and types, e.g., `("key1", str), ("key2", 42)`.
- For deterministic outputs, use specific expected values.
- For non-deterministic outputs or when only the type matters, use Python types (e.g., `str`, `int`, `dict`).
- You can mix specific values and types, e.g., `("key1", str), ("key2", 42)`.
3. **Use test_mock for network calls**: This prevents tests from failing due to network issues or API changes.