-
Notifications
You must be signed in to change notification settings - Fork 406
[stale] [poc] Improve trial user upgrade UX with dedicated continuation flow #2910
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
GitHub CI seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request represents a major refactoring and cleanup effort focused on simplifying the evaluation system, removing deprecated code, and improving code organization. The changes involve renaming entities (e.g., "Results/Metrics/Queues" to "Steps/Metrics"), removing unused migration files, simplifying authentication logic, and cleaning up test files.
Key changes:
- Refactored evaluation models to use simplified terminology (Step, Metric instead of Result, Metrics, Queue)
- Removed multiple deprecated database migration files and data migration utilities
- Deleted entire application/query routers and models that appear to be legacy code
- Simplified blocked email/domain checking by removing PostHog feature flag integration
- Cleaned up manual test files and notebooks
Reviewed Changes
Copilot reviewed 114 out of 2313 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| api/oss/src/apis/fastapi/evaluations/models.py | Renamed evaluation entities from Results/Metrics/Queues to Steps/Metrics, updated model names and field references |
| api/oss/src/apis/fastapi/applications/* | Removed legacy application router, models, and utility files entirely |
| api/oss/src/apis/fastapi/annotations/* | Major refactor adding new utility functions, expanding router with tracing integration |
| api/oss/src/init.py | Simplified blocked email/domain checking by removing PostHog integration and async logic |
| api/oss/docker/Dockerfile.* | Removed SDK installation and cron job setup from Docker builds |
| api/oss/databases/postgres/migrations/utils.py | Changed async database operations to synchronous |
| api/oss/databases/postgres/migrations/tracing/versions/fd77265d65dc_fix_spans.py | Simplified migration by removing conditional index operations |
| api/oss/databases/postgres/migrations/core/versions/* | Removed multiple deprecated migration files |
| api/entrypoint.py | Reorganized imports and router initialization, simplified lifespan function |
| api/ee/tests/manual/evaluations/sdk/* | Removed all manual test files and notebooks |
| api/ee/src/services/* | Updated service imports and renamed parameters (organization_id to org_id) |
| api/ee/src/models/shared_models.py | Consolidated and renamed permissions (e.g., VIEW_APPLICATIONS to VIEW_APPLICATION) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| span_type_enum = sa.Enum(SpanType, name="tracetype") | ||
| trace_type_enum = sa.Enum(TraceType, name="spantype") |
Copilot
AI
Nov 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The enum names are swapped: span_type_enum is created with name='tracetype' and trace_type_enum is created with name='spantype'. These should be swapped to match their variable names, or the original names should be 'spantype' and 'tracetype' respectively.
| span_type_enum = sa.Enum(SpanType, name="tracetype") | |
| trace_type_enum = sa.Enum(TraceType, name="spantype") | |
| span_type_enum = sa.Enum(SpanType, name="spantype") | |
| trace_type_enum = sa.Enum(TraceType, name="tracetype") |
| status_code=409, | ||
| detail="User is already a member of the workspace", | ||
| ) | ||
| raise Exception("User is already a member of the workspace") |
Copilot
AI
Nov 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed from HTTPException with status code 409 to a generic Exception. This loses important HTTP semantics and will not provide proper status codes to API clients. Should remain as HTTPException(status_code=409, detail='...').
| or env.POSTGRES_URI_CORE | ||
| or env.POSTGRES_URI_TRACING | ||
| or "postgresql+asyncpg://username:password@localhost:5432/agenta_oss" | ||
| or "postgresql://username:password@localhost:5432/agenta_oss" |
Copilot
AI
Nov 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default database URI has been changed from 'postgresql+asyncpg://...' to 'postgresql://...', removing the async driver. This is inconsistent with the comment on line 18 that uses .replace('+asyncpg', ''), suggesting asyncpg was expected. Verify this change is intentional and update the logic accordingly.
| or "postgresql://username:password@localhost:5432/agenta_oss" | |
| or "postgresql+asyncpg://username:password@localhost:5432/agenta_oss" |
| "Click the link below to accept the invitation:</p><br>" | ||
| f'<a href="{invite_link}">Accept Invitation</a>' | ||
| ), | ||
| call_to_action=f'Click the link below to accept the invitation:</p><br><a href="{env.AGENTA_WEB_URL}/auth?token={token}&email={email}&org_id={organization.id}&workspace_id={workspace.id}&project_id={project_id}">Accept Invitation</a>', |
Copilot
AI
Nov 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL parameters are not properly encoded. The token, email, organization.id, workspace.id, and project_id should be URL-encoded using urllib.parse.quote to prevent injection vulnerabilities and ensure special characters are handled correctly.
| create_org_payload = CreateOrganization( | ||
| name=user_dict["username"], | ||
| description="Default Organization", | ||
| description="My Default Organization", |
Copilot
AI
Nov 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Changed from 'Default Organization' to 'My Default Organization'. While minor, the added 'My' creates inconsistency with the organization type field which is set to 'default'. Consider keeping the original wording for consistency.
| description="My Default Organization", | |
| description="Default Organization", |
| from abc import ABC, abstractmethod | ||
| from typing import Optional, Union, Dict | ||
|
|
||
|
|
||
| class SystemSecretDAOInterface(ABC): |
Copilot
AI
Nov 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New file introduces an interface class but the __init__ method unconditionally raises NotImplementedError. Abstract base classes should not implement __init__ in this way - instead, allow subclasses to implement their own initialization or make __init__ abstract using @abstractmethod.
| const runRes = await axios.get( | ||
| `/preview/evaluations/runs/${evaluationTableId}?project_id=${projectId}`, | ||
| ) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To fix this vulnerability, we must validate and sanitize the evaluationTableId before using it to construct an API route.
Best general approach:
- Allow-list the format/content of
evaluationTableId. For instance, if IDs are strictly UUIDs, verify using a regex. - If not UUIDs, then check they only contain allowed characters (e.g., alphanumeric, dashes/underscores).
- If the value doesn't pass validation, avoid making the request or throw an error.
Implementation in this context:
- In
useEvaluationRunData, immediately validateevaluationTableId(before using it in the path). - If validation fails, throw an error or handle gracefully.
- For a robust pattern, create a helper function, e.g.,
isValidEvaluationId(), and use it before constructing/preview/evaluations/runs/${evaluationTableId}. - The helper can be defined adjacent to the affected code, and used both for fetchers and at the call-site if needed.
- Imports from external libraries are unnecessary, but if available, could use e.g.,
validator'sisUUID, otherwise a short regex suffices.
Files to edit:
- web/ee/src/lib/hooks/useEvaluationRunData/index.ts
-
Copy modified lines R24-R29 -
Copy modified lines R77-R79
| @@ -21,6 +21,12 @@ | ||
| import {evaluationRunStateAtom, loadingStateAtom, evalAtomStore} from "./assets/atoms" | ||
| import {buildRunIndex} from "./assets/helpers/buildRunIndex" | ||
|
|
||
| // Only allow UUIDs as valid evaluationTableId for SSRF/path traversal protection | ||
| function isValidEvaluationId(id: string | null | undefined): boolean { | ||
| // Accept only UUID v4, be strict, can be loosened if other formats are required | ||
| return typeof id === "string" && /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/.test(id); | ||
| } | ||
|
|
||
| const fetchLegacyScenariosData = async ( | ||
| evaluationId: string, | ||
| evaluationObj: Evaluation, | ||
| @@ -68,6 +74,9 @@ | ||
|
|
||
| // New fetcher for preview runs that fetches and enriches with testsetData | ||
| const fetchAndEnrichPreviewRun = useCallback(async () => { | ||
| if (!isValidEvaluationId(evaluationTableId)) { | ||
| throw new Error("Invalid evaluationTableId format."); | ||
| } | ||
| evalAtomStore().set(loadingStateAtom, (draft) => { | ||
| draft.isLoadingEvaluation = true | ||
| draft.activeStep = "eval-run" |
| export const fetchEvaluation = async (evaluationId: string) => { | ||
| const {projectId} = getCurrentProject() | ||
|
|
||
| const response = await axios.get(`/evaluations/${evaluationId}?project_id=${projectId}`) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
The
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To fix the SSRF vulnerability, the values provided as evaluationId (which ultimately come from the user query string) should be validated before being inserted into the request path. The best way is to ensure that only allowed strings are used — for example, if evaluationIds are UUIDs (or otherwise follow a known format), only allow strings matching that format to be passed to backend APIs. In the affected code:
- Before using any
evaluationIdin a request path (such as/evaluations/${evaluationId}), check if it matches the expected pattern (e.g. using a regex for UUIDs). - In the codebase, this means sanitizing the
evaluationIdsarray inEvaluationCompareModebefore passing it intofetchAllComparisonResults. - In the API methods that receive
evaluationId(such asfetchEvaluation,fetchAllEvaluationScenarios, etc.), validate the ID before including it in the axios request. - You may want to add a simple
isValidEvaluationId()function (e.g., a regex for UUIDs) and filter/sanitize input everywhere necessary. - The main changes will be in
web/ee/src/components/pages/evaluations/evaluationCompare/EvaluationCompare.tsx(whereevaluationIdsare used), and inweb/ee/src/services/evaluations/api/index.ts(where the API requests are made).
-
Copy modified lines R147-R148 -
Copy modified lines R151-R153 -
Copy modified lines R160-R162 -
Copy modified lines R198-R200
| @@ -144,16 +144,22 @@ | ||
| return response.data.map(evaluationTransformer) as _Evaluation[] | ||
| } | ||
|
|
||
| export const isValidEvaluationId = (id: string) => /^[a-fA-F0-9-]{36}$/.test(id) | ||
|
|
||
| export const fetchEvaluation = async (evaluationId: string) => { | ||
| const {projectId} = getCurrentProject() | ||
|
|
||
| if (!isValidEvaluationId(evaluationId)) { | ||
| throw new Error("Invalid evaluationId") | ||
| } | ||
| const response = await axios.get(`/evaluations/${evaluationId}?project_id=${projectId}`) | ||
| return evaluationTransformer(response.data) as _Evaluation | ||
| } | ||
|
|
||
| export const fetchEvaluationStatus = async (evaluationId: string) => { | ||
| const {projectId} = getCurrentProject() | ||
|
|
||
| if (!isValidEvaluationId(evaluationId)) { | ||
| throw new Error("Invalid evaluationId") | ||
| } | ||
| const response = await axios.get(`/evaluations/${evaluationId}/status?project_id=${projectId}`) | ||
| return response.data as {status: _Evaluation["status"]} | ||
| } | ||
| @@ -197,6 +195,9 @@ | ||
| // Evaluation Scenarios | ||
| export const fetchAllEvaluationScenarios = async (evaluationId: string) => { | ||
| const {projectId} = getCurrentProject() | ||
| if (!isValidEvaluationId(evaluationId)) { | ||
| throw new Error("Invalid evaluationId") | ||
| } | ||
|
|
||
| const [{data: evaluationScenarios}, evaluation] = await Promise.all([ | ||
| axios.get(`/evaluations/${evaluationId}/evaluation_scenarios?project_id=${projectId}`), |
-
Copy modified lines R79-R82 -
Copy modified lines R128-R132
| @@ -76,7 +76,10 @@ | ||
| const {appTheme} = useAppTheme() | ||
| const [evaluationIdsStr = ""] = useQueryParam("evaluations") | ||
| const evaluationIdsArray = evaluationIdsStr.split(",").filter((item) => !!item) | ||
| const [evalIds, setEvalIds] = useState(evaluationIdsArray) | ||
| const isValidEvaluationId = (id: string) => | ||
| /^[a-fA-F0-9-]{36}$/.test(id) | ||
| const validEvaluationIdsArray = evaluationIdsArray.filter(isValidEvaluationId) | ||
| const [evalIds, setEvalIds] = useState(validEvaluationIdsArray) | ||
| const [hiddenVariants, setHiddenVariants] = useState<string[]>([]) | ||
| const [fetching, setFetching] = useState(false) | ||
| const [scenarios, setScenarios] = useState<_Evaluation[]>([]) | ||
| @@ -122,7 +125,11 @@ | ||
| }, [variants]) | ||
|
|
||
| const evaluationIds = useMemo( | ||
| () => evaluationIdsStr.split(",").filter((item) => !!item), | ||
| () => | ||
| evaluationIdsStr | ||
| .split(",") | ||
| .filter((item) => !!item) | ||
| .filter(isValidEvaluationId), | ||
| [evaluationIdsStr], | ||
| ) | ||
|
|
| const {projectId} = getCurrentProject() | ||
|
|
||
| const [{data: evaluationScenarios}, evaluation] = await Promise.all([ | ||
| axios.get(`/evaluations/${evaluationId}/evaluation_scenarios?project_id=${projectId}`), |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
The
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To fix this problem, we need to ensure that the evaluationId values used to construct the API route are strictly validated as safe, predictable identifiers. Ideally, the input should be checked against a strict format (e.g., UUID or a list of known IDs) before it is used to assemble a URL. The best approach is to validate each element in evaluationIds before calling fetchAllEvaluationScenarios in fetchAllComparisonResults. We can implement a util function (e.g., isValidEvaluationId) that ensures the format is a valid UUID v4 (since uuidv4 is used in imports, suggesting that evaluation IDs are UUIDs). Before proceeding to fetch scenarios, we filter and/or throw on any invalid evaluation IDs.
Update fetchAllComparisonResults in web/ee/src/services/evaluations/api/index.ts to validate evaluationIds. Additionally, restrict usage of these IDs in all downstream API-calling functions. Only allow those that match a safe, expected pattern—here, UUID v4.
We’ll add a helper function for validation (UUID v4 regex), filter/throw on bad values, and edit usage accordingly.
-
Copy modified lines R226-R232 -
Copy modified lines R234-R238
| @@ -223,8 +223,19 @@ | ||
| } | ||
|
|
||
| // Comparison | ||
| // Helper: Validate UUID v4 format | ||
| const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; | ||
|
|
||
| function isValidEvaluationId(id: string) { | ||
| return UUID_V4_REGEX.test(id); | ||
| } | ||
|
|
||
| export const fetchAllComparisonResults = async (evaluationIds: string[]) => { | ||
| const scenarioGroups = await Promise.all(evaluationIds.map(fetchAllEvaluationScenarios)) | ||
| const safeEvaluationIds = evaluationIds.filter(isValidEvaluationId); | ||
| if (safeEvaluationIds.length !== evaluationIds.length) { | ||
| throw new Error("One or more invalid evaluation IDs detected."); | ||
| } | ||
| const scenarioGroups = await Promise.all(safeEvaluationIds.map(fetchAllEvaluationScenarios)) | ||
| const testset: TestSet = await fetchTestset(scenarioGroups[0][0].evaluation?.testset?.id) | ||
|
|
||
| const inputsNameSet = new Set<string>() |
| const res = await fetch( | ||
| `${apiUrl}/preview/evaluations/scenarios/${scenarioId}?project_id=${projectId}`, | ||
| { | ||
| headers: {Authorization: `Bearer ${jwt}`}, | ||
| }, | ||
| ) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To mitigate SSRF, we must ensure that untrusted user input (here, scenarioId) is validated before being interpolated into any remote URL. The safest way is to enforce a strict format on scenario IDs—ideally, they should be UUIDs.
The best fix in this context is to validate scenarioId against the expected pattern (e.g., using a UUID v4 regex) right at the start of updateScenarioStatusRemote, rejecting/ignoring invalid input. If scenarioId fails validation, do not proceed with the fetch. This is defensive programming: even if client/UI controls help, it ensures only well-formed IDs are used in outgoing requests.
Step-by-step changes:
-
In
web/ee/src/services/evaluations/workerUtils.ts'supdateScenarioStatusRemote:- Before using
scenarioId, validate it (use regex for UUID v4). - If invalid, early return or throw.
- Before using
-
Add the required regex and validation helper at the top of the file.
No additional dependencies are needed—native JS regex suffices.
All changes should be within the shown scope of workerUtils.ts; do not alter upstream (other files) logic.
-
Copy modified lines R6-R7 -
Copy modified lines R18-R22
| @@ -3,6 +3,8 @@ | ||
| import {EvaluationStatus} from "@/oss/lib/Types" | ||
| import {BaseResponse} from "@/oss/lib/Types" | ||
|
|
||
| // Strict v4 UUID regex | ||
| const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; | ||
| /** | ||
| * Update scenario status from a WebWorker / non-axios context. | ||
| */ | ||
| @@ -13,6 +15,11 @@ | ||
| status: EvaluationStatus, | ||
| projectId: string, | ||
| ): Promise<void> { | ||
| // SSRF defense: only proceed if scenarioId is a valid UUID v4 | ||
| if (!UUID_V4_REGEX.test(scenarioId)) { | ||
| // Optionally log/track rejection; here, we silently abort | ||
| return; | ||
| } | ||
| try { | ||
| // 1. fetch full scenario (backend requires full object on PATCH) | ||
| const res = await fetch( |
| return await axios | ||
| .get(`${getAgentaApiUrl()}/human-evaluations/${evaluationId}?project_id=${projectId}`) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
The
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To mitigate this vulnerability, user-controlled input should never directly form URL segments for outgoing server requests without validation. The best approach is to allow only expected, safe values for evaluationId. Since evaluationId appears to be a database/resource identifier (presumably a MongoDB ObjectId or similar), we should enforce a validation check prior to interpolating it into the URL.
- If you know the expected format (e.g., a 24-character hex string for MongoDB ObjectId), validate accordingly using a regex, and either reject or sanitize invalid input.
- If the format is not known, restrict it to a conservative character whitelist (e.g., alphanumeric plus
-/_). - Return
nullor throw an error if validation fails, preventing the unsafe HTTP request from being issued. - Make the change in
fetchLoadEvaluation(inweb/ee/src/services/human-evaluations/api/index.ts): validateevaluationIdbefore using it, and fail safely if validation does not pass. - Optionally, implement the validator inline or just above
fetchLoadEvaluation.
-
Copy modified lines R84-R88 -
Copy modified lines R91-R94
| @@ -81,8 +81,17 @@ | ||
| return results | ||
| } | ||
|
|
||
| // Helper to validate evaluationId: must be a 24-character hex string (e.g., for MongoDB ObjectId) | ||
| function isValidEvaluationId(evaluationId: string): boolean { | ||
| return /^[a-fA-F0-9]{24}$/.test(evaluationId); | ||
| } | ||
|
|
||
| export const fetchLoadEvaluation = async (evaluationId: string) => { | ||
| const {projectId} = getCurrentProject() | ||
| if (!isValidEvaluationId(evaluationId)) { | ||
| console.error("Invalid evaluationId provided to fetchLoadEvaluation:", evaluationId) | ||
| return null | ||
| } | ||
| try { | ||
| return await axios | ||
| .get(`${getAgentaApiUrl()}/human-evaluations/${evaluationId}?project_id=${projectId}`) |
| return fromEvaluationResponseToEvaluation(responseData.data) | ||
| }) | ||
| } catch (error) { | ||
| console.error(`Error fetching evaluation ${evaluationId}:`, error) |
Check failure
Code scanning / CodeQL
Use of externally-controlled format string High
user-provided value
Format string depends on a
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
To fix the problem in web/ee/src/services/human-evaluations/api/index.ts, you need to stop interpolating the user-provided value (evaluationId) directly into the template string of console.error. Instead, use a static string for the log message and pass any untrusted variable (here, evaluationId) as a separate argument to console.error. This prevents the possibility of user-controlled data being parsed as part of a format string.
How to fix:
On line 93, change
console.error(`Error fetching evaluation ${evaluationId}:`, error)to
console.error("Error fetching evaluation:", evaluationId, error)No additional imports or changes are necessary, as you only need to restructure the arguments to console.error.
-
Copy modified line R93
| @@ -90,7 +90,7 @@ | ||
| return fromEvaluationResponseToEvaluation(responseData.data) | ||
| }) | ||
| } catch (error) { | ||
| console.error(`Error fetching evaluation ${evaluationId}:`, error) | ||
| console.error("Error fetching evaluation:", evaluationId, error) | ||
| return null | ||
| } | ||
| } |
| return await axios | ||
| .get( | ||
| `${getAgentaApiUrl()}/human-evaluations/${evaluationTableId}/evaluation_scenarios?project_id=${projectId}`, | ||
| ) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
The
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
The correct way to mitigate this SSRF vulnerability is to restrict the evaluationTableId so only valid IDs are allowed to be interpolated into the API URL's path. Since it appears to be an identifier for an evaluation (likely a database ID), you should:
- Validate that
evaluationTableIdconforms to the type/format of a safe evaluation identifier (e.g., a strict alphanumeric string, UUID, MongoDB ObjectId, etc.). - Reject (or ignore) any value that does not match this pattern, either by returning early or raising an error/logging.
- Ideally, this validation should occur as soon as possible—i.e., in
fetchAllLoadEvaluationsScenarios, on the input parameter. - For the context shown, a simple regex check (e.g., /^[a-fA-F0-9]{24}$/ for Mongo ObjectId, or similar for UUID) should suffice.
- If you prefer, you can define a helper function
isValidEvaluationIdand use it to guard the axios call.
You only need to modify web/ee/src/services/human-evaluations/api/index.ts, where you should add input validation for evaluationTableId.
-
Copy modified lines R109-R114 -
Copy modified lines R121-R124
| @@ -106,12 +106,22 @@ | ||
| return response.data | ||
| } | ||
|
|
||
| // Helper function to validate evaluation ID - adjust regex as appropriate for your ID format | ||
| function isValidEvaluationId(id: string) { | ||
| // MongoDB ObjectId validation (24 hex characters) | ||
| return /^[a-fA-F0-9]{24}$/.test(id); | ||
| } | ||
|
|
||
| export const fetchAllLoadEvaluationsScenarios = async ( | ||
| evaluationTableId: string, | ||
| evaluation: Evaluation, | ||
| ) => { | ||
| const {projectId} = getCurrentProject() | ||
|
|
||
| if (!isValidEvaluationId(evaluationTableId)) { | ||
| throw new Error("Invalid evaluationTableId format."); | ||
| } | ||
|
|
||
| return await axios | ||
| .get( | ||
| `${getAgentaApiUrl()}/human-evaluations/${evaluationTableId}/evaluation_scenarios?project_id=${projectId}`, |
| const response = await axios.put( | ||
| `${getAgentaApiUrl()}/human-evaluations/${evaluationTableId}/evaluation_scenario/${evaluationScenarioId}/${evaluationType}?project_id=${projectId}`, | ||
| data, | ||
| ) |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 17 days ago
The best way to fix this problem is to validate and sanitize all user-provided data before using it to construct URLs for outgoing requests on the server. Specifically:
- Restrict
evaluationScenarioIdto only permitted values, ideally to those present in the set of known scenario IDs for the current evaluation (coming from the backend). - In the
updateEvaluationScenarioAPI function, before usingevaluationScenarioIdin the URL, verify it against an allow-list (e.g., check that it matches a strict regex for ID format such as UUID or that it exists in a locally-cached set of valid IDs for the current evaluation). - Throw or return an error if validation fails, preventing construction and execution of requests with untrusted path data.
The required edit is to add input validation for evaluationScenarioId at the beginning of the updateEvaluationScenario function in web/ee/src/services/human-evaluations/api/index.ts. This would involve:
- Adding a helper function to validate scenario IDs (e.g., check for non-empty strings and valid format).
- Using that function to validate user input before constructing the URL.
No external dependencies are needed, as basic validation can be written inline or with immediate regex.
-
Copy modified lines R186-R190 -
Copy modified lines R199-R203
| @@ -183,6 +183,11 @@ | ||
| return response.data | ||
| } | ||
|
|
||
| // Helper function: Validate that an ID is a non-empty string and matches a UUID pattern. | ||
| function isValidScenarioId(id: string): boolean { | ||
| return typeof id === "string" && /^[a-fA-F0-9-]{36}$/.test(id); // Adjust regex as needed for your format | ||
| } | ||
|
|
||
| export const updateEvaluationScenario = async ( | ||
| evaluationTableId: string, | ||
| evaluationScenarioId: string, | ||
| @@ -191,6 +196,11 @@ | ||
| ) => { | ||
| const {projectId} = getCurrentProject() | ||
|
|
||
| // SSRF Prevention: Only allow valid scenario IDs | ||
| if (!isValidScenarioId(evaluationScenarioId)) { | ||
| throw new Error("Invalid evaluationScenarioId"); | ||
| } | ||
|
|
||
| const response = await axios.put( | ||
| `${getAgentaApiUrl()}/human-evaluations/${evaluationTableId}/evaluation_scenario/${evaluationScenarioId}/${evaluationType}?project_id=${projectId}`, | ||
| data, |
[POC] feat: Improve trial user upgrade UX with dedicated continuation flow