Skip to content

Show sync status in the dashboard#133

Open
Yostra wants to merge 1 commit intomainfrom
dashboard_s
Open

Show sync status in the dashboard#133
Yostra wants to merge 1 commit intomainfrom
dashboard_s

Conversation

@Yostra
Copy link
Collaborator

@Yostra Yostra commented Mar 7, 2026

What kind of change does this PR introduce?

Adds a progress status in the dashboard

What is the current behavior?

After deployment there is just a text fields that says something like "syncing since..."

What is the new behavior?

Screenshot 2026-03-07 at 1 50 05 AM

Additional context

Add any other context or screenshots.

Comment on lines +34 to +44
const response = await fetch(
`https://api.supabase.com/v1/projects/${session.projectRef}/database/query`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${session.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: SYNC_PROGRESS_QUERY }),
}
)

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI about 17 hours ago

In general, the problem is that supabaseProjectRef (from the deploy request body) is stored as session.projectRef and later interpolated into a URL path without any validation. To fix this without changing the visible behavior, we should validate and normalize the project reference at the point of intake in packages/dashboard/src/app/api/deploy/route.ts, rejecting values that are clearly malformed, and store only this sanitized value in the session. That way, by the time sync-progress/route.ts reads session.projectRef, it is guaranteed to be a safe path segment for the Supabase API URL.

The single best fix here is:

  • In deploy/route.ts, add validation logic right after reading supabaseProjectRef from the request body:
    • Trim whitespace.
    • Ensure it matches a conservative pattern of allowed characters (e.g., lowercase letters, digits, and dashes), which aligns with typical Supabase project ref formats like abcd1234.
    • Optionally enforce a reasonable length bound.
    • If the value fails validation, return a 400 error.
  • Use the sanitized value (e.g., normalizedSupabaseProjectRef) in both:
    • The call to install({ supabaseProjectRef: ... }).
    • The call to createSession(...).
  • No change is required in sync-progress/route.ts because it will now only ever see a validated projectRef.

This keeps existing functionality (deploying and storing sessions) but prevents arbitrary, potentially dangerous path components from being persisted and later used to build request URLs. No new external dependencies are strictly necessary; we can implement validation with a simple regular expression.

Concretely:

  • Edit packages/dashboard/src/app/api/deploy/route.ts:
    • After destructuring supabaseAccessToken, supabaseProjectRef, stripeKey, add validation logic.
    • Introduce a new variable, e.g., const normalizedSupabaseProjectRef = supabaseProjectRef.trim(); then verify it with a regex like /^[a-z0-9-]{1,64}$/.
    • If invalid, return 400 with an error message.
    • Use normalizedSupabaseProjectRef instead of supabaseProjectRef when calling install and createSession.
  • No changes are needed in sessions.ts or sync-progress/route.ts because they operate on the sanitized value stored in the session.
Suggested changeset 1
packages/dashboard/src/app/api/deploy/route.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/dashboard/src/app/api/deploy/route.ts b/packages/dashboard/src/app/api/deploy/route.ts
--- a/packages/dashboard/src/app/api/deploy/route.ts
+++ b/packages/dashboard/src/app/api/deploy/route.ts
@@ -17,15 +17,22 @@
       return NextResponse.json({ error: 'Missing required fields' }, { status: 400 })
     }
 
+    const normalizedSupabaseProjectRef = supabaseProjectRef.trim()
+    // Allow only typical Supabase project ref characters to avoid unsafe URL path segments
+    const projectRefPattern = /^[a-z0-9-]{1,64}$/
+    if (!projectRefPattern.test(normalizedSupabaseProjectRef)) {
+      return NextResponse.json({ error: 'Invalid Supabase project reference' }, { status: 400 })
+    }
+
     await install({
       supabaseAccessToken,
-      supabaseProjectRef,
+      supabaseProjectRef: normalizedSupabaseProjectRef,
       stripeKey,
       workerIntervalSeconds: 30,
     })
 
     // Create session to store credentials server-side (for Management API queries)
-    const sessionId = createSession(supabaseProjectRef, supabaseAccessToken)
+    const sessionId = createSession(normalizedSupabaseProjectRef, supabaseAccessToken)
 
     return NextResponse.json({
       success: true,
EOF
@@ -17,15 +17,22 @@
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 })
}

const normalizedSupabaseProjectRef = supabaseProjectRef.trim()
// Allow only typical Supabase project ref characters to avoid unsafe URL path segments
const projectRefPattern = /^[a-z0-9-]{1,64}$/
if (!projectRefPattern.test(normalizedSupabaseProjectRef)) {
return NextResponse.json({ error: 'Invalid Supabase project reference' }, { status: 400 })
}

await install({
supabaseAccessToken,
supabaseProjectRef,
supabaseProjectRef: normalizedSupabaseProjectRef,
stripeKey,
workerIntervalSeconds: 30,
})

// Create session to store credentials server-side (for Management API queries)
const sessionId = createSession(supabaseProjectRef, supabaseAccessToken)
const sessionId = createSession(normalizedSupabaseProjectRef, supabaseAccessToken)

return NextResponse.json({
success: true,
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False positive, user provides a projectRef as intended

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant