-
Notifications
You must be signed in to change notification settings - Fork 8
Staging #915
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?
Staging #915
Changes from all commits
70f4bba
dc86024
4eea5a1
70935cb
a00b943
01a22ea
960c337
64e13c8
ceb0c21
9d94898
93984a2
1944c6f
7c603ca
4e0da61
06880ee
69df711
c33af8c
d0178c5
8fd266c
06b651e
10c1410
b72aa7d
7b3666d
47bdd30
fee2624
5ea1f29
42f4705
95231fb
d012ea4
94d5f22
9991fb3
aa510de
cf452b3
24946de
6a90632
d6e9cd0
ec0e59f
59bfa28
05b02a5
0617d3b
6496139
04ca161
b205f73
d957adf
cdeec7d
ddda45c
1b98e8e
e0e693f
f8cc54f
9988d41
4a81785
ba05b57
2fa1712
e353b1e
e544c38
8b82869
00c3abc
1a2e6de
632d259
f6494ac
4c4e36d
92087a0
370a0dc
63fff17
3567936
3473528
f23c3f5
b4a1286
7056b1b
25fe38c
67f6b47
4aa187c
6731a90
291a4e0
d56b781
f9b7314
b86d6cc
2fafbc9
c7e6af4
4a662e3
3a2d54f
e1cc3c3
2c91600
fe2fc1f
d974e00
fbe7f60
aabe700
1ac4087
eb73a7a
9d9d014
398a66e
f0c8387
a47d398
891e971
1201cba
e10b94d
b2a28de
cb3174d
2d8248b
4cc43b9
613682e
67be6d6
77f218f
989034f
8a0a800
697ac4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -9,20 +9,25 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { client } = session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { graph: graphId } = await params | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { graph } = await params | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const graph = client.selectGraph(graphId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const query = "MATCH (n) OPTIONAL MATCH (n)-[e]->() WITH count(n) as nodes, count(e) as edges RETURN nodes, edges" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { data } = await graph.query(query) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!data) throw new Error("Something went wrong") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const result = data.length === 0 ? { nodes: 0, edges: 0 } : data[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const result = await fetch(`${request.nextUrl.origin}/api/graph/${graph}/?query=${encodeURIComponent(query)}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
method: "GET", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
headers: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cookie: request.headers.get('cookie') || '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+17
to
+22
Check failureCode scanning / CodeQL Server-side request forgery
The [URL](1) of this request depends on a [user-provided value](2).
Copilot AutofixAI 2 days ago To fix the issue, we need to validate and sanitize the Steps to implement the fix:
Suggested changeset
1
app/api/graph/[graph]/count/route.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Positive FeedbackNegative Feedback
Refresh and try again.
Comment on lines
+17
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mitigate potential SSRF vulnerability by validating the graph parameter The URL of the fetch request is constructed using a user-provided value ( const { graph } = await params
+
+ // Validate graph parameter to prevent path traversal or injection
+ if (!graph || /[^a-zA-Z0-9_-]/.test(graph)) {
+ return NextResponse.json({ error: "Invalid graph name" }, { status: 400 })
+ }
try { 📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Check: CodeQL[failure] 17-22: Server-side request forgery 🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!result.ok) throw new Error("Something went wrong") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve error handling with specific error details The current error message is too generic, making debugging difficult. - if (!result.ok) throw new Error("Something went wrong")
+ if (!result.ok) {
+ const errorText = await result.text().catch(() => "Could not read error response");
+ throw new Error(`Failed to fetch graph data: ${result.status} ${result.statusText}. ${errorText}`);
+ } 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const json = await result.json() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const data = typeof json.result === "number" ? json.result : { data: [json.result.data[0] || { edges: 0, nodes: 0 }] } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix data transformation logic The current data transformation is incorrect and inconsistent. The ternary operator creates different data structures based on the type of - const data = typeof json.result === "number" ? json.result : { data: [json.result.data[0] || { edges: 0, nodes: 0 }] }
+ let data;
+ if (typeof json.result === "number") {
+ data = { data: [{ edges: 0, nodes: json.result }] };
+ } else if (json.result?.data?.[0]) {
+ data = { data: [json.result.data[0]] };
+ } else {
+ data = { data: [{ edges: 0, nodes: 0 }] };
+ } This ensures a consistent data structure regardless of the input format, and includes proper validation of nested properties. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.json({ result }, { status: 200 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.json({ result: data }, { status: 200 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log(error) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.json({ error: (error as Error).message }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,26 @@ | ||||||||||||||||||||||||||||||||||||||||
import { getClient } from "@/app/api/auth/[...nextauth]/options" | ||||||||||||||||||||||||||||||||||||||||
import { NextResponse, NextRequest } from "next/server" | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
// eslint-disable-next-line import/prefer-default-export | ||||||||||||||||||||||||||||||||||||||||
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ graph: string }> }) { | ||||||||||||||||||||||||||||||||||||||||
const session = await getClient() | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
if (session instanceof NextResponse) { | ||||||||||||||||||||||||||||||||||||||||
return session | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const { client } = session | ||||||||||||||||||||||||||||||||||||||||
const { graph: graphId } = await params | ||||||||||||||||||||||||||||||||||||||||
const sourceName = request.nextUrl.searchParams.get("sourceName") | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||
if (!sourceName) throw new Error("Missing parameter sourceName") | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
const result = await client.selectGraph(sourceName).copy(graphId) | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+16
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainConsider adding validation for target graph name The current implementation validates the source graph name but doesn't check if the target graph already exists. This could potentially lead to overwriting an existing graph. 🏁 Script executed: #!/bin/bash
# Check if there's any validation in the client.selectGraph().copy() method
# that prevents overwriting existing graphs
# Find any graph copy implementation in the codebase
rg -A 5 -B 5 "\.copy\(" --type ts Length of output: 1785 Add validation for target graph name to prevent overwriting Ensure you validate the • app/api/graph/[graph]/duplicate/route.tsx (around lines 16–19): Example diff: try {
- if (!sourceName) throw new Error("Missing parameter sourceName")
-
- const result = await client.selectGraph(sourceName).copy(graphId)
+ if (!sourceName) throw new Error("Missing parameter sourceName")
+
+ const graphId = request.nextUrl.searchParams.get("graphId")
+ if (!graphId) throw new Error("Missing parameter graphId")
+
+ // Prevent overwriting an existing graph
+ const exists = await client
+ .selectGraph(graphId)
+ .get()
+ .then(() => true)
+ .catch(err => err.message.includes("NotFound") ? false : Promise.reject(err))
+ if (exists) throw new Error(`Graph "${graphId}" already exists`)
+
+ const result = await client.selectGraph(sourceName).copy(graphId) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
return NextResponse.json({ result }) | ||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||
console.error(error) | ||||||||||||||||||||||||||||||||||||||||
return NextResponse.json({ error: (error as Error).message }, { status: 400 }) | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
} |
Uh oh!
There was an error while loading. Please reload this page.