mirror of
https://github.com/Significant-Gravitas/Auto-GPT.git
synced 2025-01-08 11:57:32 +08:00
Merge branch 'dev' into zamilmajdy/secrt-1000-add-capability-for-the-admin-to-log-in-as-other-users
This commit is contained in:
commit
f41379df45
4
.github/workflows/platform-frontend-ci.yml
vendored
4
.github/workflows/platform-frontend-ci.yml
vendored
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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]
|
||||
]
|
||||
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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:
|
||||
|
@ -37,7 +37,9 @@ export default function SupabaseProvider({
|
||||
if (event === "SIGNED_IN") {
|
||||
api.createUser();
|
||||
}
|
||||
router.refresh();
|
||||
if (event === "SIGNED_OUT") {
|
||||
router.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
|
@ -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}` +
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
46
autogpt_platform/frontend/src/tests/auth.spec.ts
Normal file
46
autogpt_platform/frontend/src/tests/auth.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
18
autogpt_platform/frontend/src/tests/fixtures/index.ts
vendored
Normal file
18
autogpt_platform/frontend/src/tests/fixtures/index.ts
vendored
Normal 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";
|
14
autogpt_platform/frontend/src/tests/fixtures/login-page.fixture.ts
vendored
Normal file
14
autogpt_platform/frontend/src/tests/fixtures/login-page.fixture.ts
vendored
Normal 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));
|
||||
};
|
83
autogpt_platform/frontend/src/tests/fixtures/test-user.fixture.ts
vendored
Normal file
83
autogpt_platform/frontend/src/tests/fixtures/test-user.fixture.ts
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
51
autogpt_platform/frontend/src/tests/pages/login.page.ts
Normal file
51
autogpt_platform/frontend/src/tests/pages/login.page.ts
Normal 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
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { test, expect } from "./fixtures";
|
||||
|
||||
test("has title", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { test, expect } from "./fixtures";
|
||||
import { setNestedProperty } from "../lib/utils";
|
||||
|
||||
const testCases = [
|
||||
|
@ -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(),
|
||||
};
|
||||
}
|
@ -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:
|
||||
|
8
autogpt_platform/market/poetry.lock
generated
8
autogpt_platform/market/poetry.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user