feat(web): add GitHub OAuth to repo star video tool - #644
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Comp AI code review complete — no issues found. Commit |
|
Capy auto-review is paused for this organization because the usage-cycle auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews. |
|
React Doctor found no new issues. 🎉 Reviewed by React Doctor for commit |
| } | ||
|
|
||
| function encryptionKey(secret: string): Buffer { | ||
| return createHash("sha256").update(secret).digest(); |
Greptile SummaryAdds an optional cookie-backed GitHub OAuth flow to the Repo Star Video tool so connected visitors can use their own GitHub API quota.
Confidence Score: 4/5The PR needs fixes before merging because concurrent connected users can share the wrong credential-backed request, and a rejected visitor token can disable otherwise available public-repository lookups for up to seven days. The in-flight key does not isolate different OAuth credentials, while the token-present branch bypasses all shared fallback paths and persists rejected credentials without an application-level recovery mechanism. Files Needing Attention: apps/web/src/lib/star-video/load-repo.ts, apps/web/src/app/api/star-video/repo/route.ts, apps/web/src/lib/star-video/stargazers.ts Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant UI as Repo Star Video UI
participant Auth as OAuth Routes
participant GitHub
participant RepoAPI as Repo API
participant Cache as Shared Cache
User->>UI: Connect GitHub
UI->>Auth: GET /github/authorize
Auth->>GitHub: OAuth authorization + state
GitHub->>Auth: Callback with code + state
Auth->>GitHub: Exchange code
Auth-->>User: Encrypted token cookie
User->>RepoAPI: Look up repository
alt Connected cookie
RepoAPI->>GitHub: Uncached request with visitor token
else No token
RepoAPI->>Cache: Read shared result
RepoAPI->>GitHub: Fetch with shared token on miss
end
RepoAPI->>Cache: Write successful result
RepoAPI-->>UI: Repository star data
Reviews (1): Last reviewed commit: "feat(web): add GitHub OAuth to repo star..." | Re-trigger Greptile |
There was a problem hiding this comment.
No blocking issues found across the changed files.
1 other commit review still in progress for this PR — findings may follow.
Commit 755b7b3 · Posted by Comp AI Code Reviews.
| ): Promise<LoadRepoResult> { | ||
| const existing = inflight.get(id); | ||
| const inflightKey = token ? `${id}:user` : id; |
There was a problem hiding this comment.
Inflight requests cross OAuth credentials
If two connected visitors request the same repository concurrently, both calls use the same ${id}:user key, so the second visitor receives the result or failure produced with the first visitor's token and the first visitor's GitHub quota is charged for the shared request.
| if (!githubToken) { | ||
| const cached = await Effect.runPromise(getCachedRepoStarData(id)); | ||
| if (cached) { | ||
| return NextResponse.json(cached); | ||
| } | ||
| } | ||
|
|
||
| const result = await loadRepoStarData(owner, repo, id); | ||
| const result = await loadRepoStarData( | ||
| owner, | ||
| repo, | ||
| id, | ||
| githubToken ?? undefined |
There was a problem hiding this comment.
Rejected tokens disable lookup fallback
When a visitor's OAuth token is revoked, expired, or rate-limited, its still-valid cookie makes this branch skip Redis and query GitHub without the shared credential; the failure is returned as a 503 with no fallback, leaving public-repository lookups broken until the cookie expires or is manually removed.
There was a problem hiding this comment.
1 issue found across 1 file.
Prompt for AI agents (all issues)
Check whether each issue below is valid; if so, find the root cause and fix it. Read the referenced code to confirm the problem before changing it, and use sub-agents to handle independent issues in parallel.
<file name="apps/web/src/lib/star-video/github-connection.ts">
<issue n="1" at="apps/web/src/lib/star-video/github-connection.ts:11" severity="MEDIUM">getServerGithubConnected always returns false causing hydration mismatch — The `getServerGithubConnected()` function (L11) unconditionally returns `false`. This function is passed as the `getServerSnapshot` argument to `useSyncExternalStore` in `repo-input-form.tsx`. When a user has the `sv_github_connected=1` cookie set (from completing GitHub OAuth), `isGithubConnected()` (L8) reads `document.cookie` and returns `true` on the client, but the server snapshot is always `false`. This causes a React hydration mismatch: the server-rendered HTML shows the "Connect GitHub" link, then immediately re-renders to "GitHub connected" on the client. The `sv_github_connected` cookie is intentionally NOT httpOnly (so client JS can read it), meaning the server COULD read it from the request cookies during SSR — but `getServerGithubConnected` doesn't receive the request and just returns false. This is a UX/correctness bug, not a security issue. Fix: Either pass the initial connection state from a server component (reading `sv_github_connected` from request cookies) into the client component as a prop, or suppress hydration warnings for this specific value. Alternatively, accept the mismatch and use `useEffect` to sync the client state after mount instead of `useSyncExternalStore`.</issue>
</file>
Commit 142eaaf · Posted by Comp AI Code Reviews.
| return document.cookie.split("; ").includes(`${GITHUB_CONNECTED_COOKIE}=1`); | ||
| } | ||
|
|
||
| export function getServerGithubConnected(): boolean { |
There was a problem hiding this comment.
MEDIUM: getServerGithubConnected always returns false causing hydration mismatch
The getServerGithubConnected() function (L11) unconditionally returns false. This function is passed as the getServerSnapshot argument to useSyncExternalStore in repo-input-form.tsx. When a user has the sv_github_connected=1 cookie set (from completing GitHub OAuth), isGithubConnected() (L8) reads document.cookie and returns true on the client, but the server snapshot is always false. This causes a React hydration mismatch: the server-rendered HTML shows the "Connect GitHub" link, then immediately re-renders to "GitHub connected" on the client. The sv_github_connected cookie is intentionally NOT httpOnly (so client JS can read it), meaning the server COULD read it from the request cookies during SSR — but getServerGithubConnected doesn't receive the request and just returns false. This is a UX/correctness bug, not a security issue.
Suggestion: Either pass the initial connection state from a server component (reading sv_github_connected from request cookies) into the client component as a prop, or suppress hydration warnings for this specific value. Alternatively, accept the mismatch and use useEffect to sync the client state after mount instead of useSyncExternalStore.
Prompt for AI agents
Check whether this issue is valid; if so, find the root cause and fix it. Read the referenced code to confirm the problem before changing it.
<issue at="apps/web/src/lib/star-video/github-connection.ts:11" severity="MEDIUM">getServerGithubConnected always returns false causing hydration mismatch — The `getServerGithubConnected()` function (L11) unconditionally returns `false`. This function is passed as the `getServerSnapshot` argument to `useSyncExternalStore` in `repo-input-form.tsx`. When a user has the `sv_github_connected=1` cookie set (from completing GitHub OAuth), `isGithubConnected()` (L8) reads `document.cookie` and returns `true` on the client, but the server snapshot is always `false`. This causes a React hydration mismatch: the server-rendered HTML shows the "Connect GitHub" link, then immediately re-renders to "GitHub connected" on the client. The `sv_github_connected` cookie is intentionally NOT httpOnly (so client JS can read it), meaning the server COULD read it from the request cookies during SSR — but `getServerGithubConnected` doesn't receive the request and just returns false. This is a UX/correctness bug, not a security issue. Fix: Either pass the initial connection state from a server component (reading `sv_github_connected` from request cookies) into the client component as a prop, or suppress hydration warnings for this specific value. Alternatively, accept the mismatch and use `useEffect` to sync the client state after mount instead of `useSyncExternalStore`.</issue>
Commit 142eaaf.
What
Adds an optional "Connect GitHub" flow to the Repo Star Video tool so lookups can run against the visitor's own GitHub rate limit (5,000 req/hr) instead of relying solely on the shared `GITHUB_TOKEN` PAT, which has been flaky.
How it works
Env
New (optional; feature silently no-ops without them):
Requires a GitHub OAuth App with callback URL `/api/star-video/github/callback`.
Summary by cubic
Adds optional GitHub OAuth to the Repo Star Video tool so lookups use the visitor’s 5k/hr rate limit instead of the shared
GITHUB_TOKEN. Adds a simple “Connect GitHub” UI and uses an encrypted cookie to prefer the visitor token and return fresher stargazers.New Features
/api/star-video/github/authorizesets a 10‑min CSRF state cookie and redirects;/api/star-video/github/callbackverifies, exchanges the code, and stores the token AES‑256‑GCM encrypted in an httpOnly cookie (7 days), plussv_github_connected=1for the UI./api/star-video/repodecrypts the cookie, fetches withcache: "no-store"(bypasses cache reads for connected users), still writes to the shared cache, and falls back toGITHUB_TOKENif no cookie.repo).Migration
STAR_VIDEO_GITHUB_CLIENT_ID,STAR_VIDEO_GITHUB_CLIENT_SECRET. OAuth App callback:<site-url>/api/star-video/github/callback.turbo.jsonenv passthrough. Feature no‑ops if vars are unset.Written for commit 142eaaf. Summary will update on new commits.
Summary by Comp AI
1 issue found.
Written for commit
142eaaf. New commits will trigger a re-review. Generated by Comp AI.