-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Implement github link unfurling #15552
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
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| const fileMatch = url.match( | ||
| /https?:\/\/github\.com\/([\w-]+\/[\w-]+)\/blob\/([\w.-]+)\/(.*?)(?:#L(\d+)(?:-L(\d+))?)?$/ | ||
| ); |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
regular expression
a user-provided value
| const response = await fetch(apiUrl, { | ||
| headers, | ||
| next: {revalidate: 3600}, // Cache for 1 hour | ||
| }); |
Check failure
Code scanning / CodeQL
Server-side request forgery Critical
URL
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 2 days ago
To properly fix the issue, you should further validate the parsed components (repo, ref, and filePath) extracted from the user-supplied GitHub URL.
- General approach: After extracting the repo, ref, and filePath via regex, check that they contain only safe, expected characters (e.g., repo and ref are alphanumeric with allowed dashes/underscores/dots, filePath does NOT contain any suspicious segments like
.., backslashes, or repeated/leading slashes). - Enforce that:
- Repo matches the GitHub repository "owner/repo" pattern (letters, digits, dashes, underscores, no slashes in owner and repo except separator, etc.).
- Ref matches common branch, tag, or SHA formats (letters, digits, dashes, dots, underscores).
- Filepath is a relative path and does not involve path traversal or absolute paths.
- Ideally, centralize this validation immediately after the regex match, and error out with a clear message if validation fails.
- No change in external logic or API is needed—only server-side validation of intermediates.
- Implement the new validation in place after line 29 (extraction), before constructing and using the parsed variables. You may want a helper function to do this.
- Only referenced standard library/Node.js/TypeScript features are used; no third-party libraries.
-
Copy modified lines R31-R42 -
Copy modified lines R146-R176
| @@ -28,6 +28,18 @@ | ||
|
|
||
| const [, repo, ref, filePath, startLine, endLine] = fileMatch; | ||
|
|
||
| // Strict validation to minimize SSRF and confusions | ||
| if ( | ||
| !isValidRepo(repo) || | ||
| !isValidRef(ref) || | ||
| !isValidFilePath(filePath) | ||
| ) { | ||
| return NextResponse.json( | ||
| {error: 'Invalid repository, ref, or file path in GitHub URL'}, | ||
| {status: 400} | ||
| ); | ||
| } | ||
|
|
||
| try { | ||
| // Use GitHub API to fetch file content | ||
| const apiUrl = `https://api.github.com/repos/${repo}/contents/${filePath}?ref=${ref}`; | ||
| @@ -131,3 +143,34 @@ | ||
|
|
||
| return languageMap[ext || ''] || 'text'; | ||
| } | ||
|
|
||
| // Validate that repo is of the form "owner/repo" with safe characters | ||
| function isValidRepo(repo: string): boolean { | ||
| // Owner and repo: letters, numbers, -, _, . only (no / except separator) | ||
| const repoPattern = /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/; | ||
| return repoPattern.test(repo); | ||
| } | ||
|
|
||
| // Validate that ref is a safe branch/tag/SHA representation | ||
| function isValidRef(ref: string): boolean { | ||
| // Popular refs: allow letters, numbers, -, _, .; SHA is hex | ||
| const refPattern = /^[a-zA-Z0-9_.\-\/]+$/; | ||
| // Disallow empty | ||
| return refPattern.test(ref) && ref.length > 0; | ||
| } | ||
|
|
||
| // Validate file path is relative, no path traversal or backslash, no leading / | ||
| function isValidFilePath(filePath: string): boolean { | ||
| // Disallow path traversal, windows style backslash, or absolute paths | ||
| if ( | ||
| filePath.includes('..') || | ||
| filePath.startsWith('/') || | ||
| filePath.startsWith('\\') || | ||
| filePath.includes('\\') | ||
| ) { | ||
| return false; | ||
| } | ||
| // Allow alphanum, dashes, underscores, dots, slashes, and common folders | ||
| const filePathPattern = /^[\w\-./]+$/; | ||
| return filePathPattern.test(filePath); | ||
| } |
Co-authored-by: neel.shah <[email protected]>
Co-authored-by: neel.shah <[email protected]>
ab55d5b to
dcc99f4
Compare
Co-authored-by: neel.shah <[email protected]>
dcc99f4 to
a9ba62f
Compare
Bundle ReportChanges will decrease total bundle size by 447.25kB (-3.4%) ⬇️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: sentry-docs-server-cjsAssets Changed:
Files in
App Routes Affected:
|
Bundle ReportChanges will increase total bundle size by 237.94kB (1.02%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: sentry-docs-client-array-pushAssets Changed:
Files in
view changes for bundle: sentry-docs-server-cjsAssets Changed:
Files in
App Routes Affected:
|
DESCRIBE YOUR PR
This PR adds comprehensive developer documentation for implementing GitHub link unfurling to
develop-docs/integrations/github.mdx. This documentation guides developers on how to enable rich previews for Sentry links shared within GitHub, covering detection, data fetching, formatting options (comments or checks), and best practices. It also updates the integration table indocs/organization/integrations/index.mdxto reflect this new capability for GitHub and GitHub Enterprise.IS YOUR CHANGE URGENT?
Help us prioritize incoming PRs by letting us know when the change needs to go live.
SLA
Thanks in advance for your help!
PRE-MERGE CHECKLIST
Make sure you've checked the following before merging your changes:
LEGAL BOILERPLATE
Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.
EXTRA RESOURCES