Repository navigation
Conversation
No request had a timeout, and gunicorn runs with one worker, 4 threads and `--timeout 0`, so a hung connection to GitHub or Sentry tied up a thread indefinitely. Over the last 7 days the GitHub calls had a p99 of 165-390 ms but a max of 127-235 s, and Sentry ingest a p99 of 70 ms with a max of 5.4 s. Every request now uses a (5 s connect, 10 s read) timeout, which is well above normal latency. GitHub also stops waiting for a webhook response after 10 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uest forgery' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…uest forgery' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 446b3a2. Configure here.
Addresses review findings and the failing CodeQL check: - GITHUB_OWNER_PATTERN allowed 38 characters, but GitHub logins can be 39, so webhooks from such an owner failed with ValueError. - CodeQL still reported py/full-ssrf on _fetch_github, because the host checks in a separate function don't sanitize the URL that's requested. Only accept URLs under https://api.github.com/, and build the request URL on that constant base, which CodeQL recognizes. The token was also allowed to go to github.com, which _fetch_github never needs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolves the conflict with #117 in src/sentry_config.py: the request timeout and owner check now live in _fetch_dsn, behind #117's DSN cache. - #117's tests used `other_org`, which isn't a valid GitHub login, so the owner check rejected it. They now use `other-org`. - test_every_request_has_a_timeout no longer registers the workflow fetch, which #117 removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
|
||
| SENTRY_CONFIG_API_URL = ( | ||
| "https://api.github.com/repos/{owner}/.sentry/contents/sentry_config.ini" | ||
| ) |
There was a problem hiding this comment.
Bug: The regex validation for the org parameter uses $ which incorrectly matches strings with a trailing newline, potentially causing downstream API requests to fail.
Severity: LOW
Suggested Fix
Replace the $ anchor in the regex pattern with \Z. The \Z anchor ensures that the match must occur at the absolute end of the string, correctly rejecting any input with trailing newlines.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/sentry_config.py#L22
Potential issue: The regex validation for the GitHub organization name uses a `$`
anchor, which allows `re.fullmatch()` to successfully match strings that have a trailing
newline, such as `"myorg\n"`. If the `org` parameter from a webhook payload contained
such a newline, it would pass validation. The subsequent call to `quote(org, safe="")`
would URL-encode the newline to `%0A`, creating an invalid GitHub API URL. This would
cause the API request to fail, likely with a 404 or 422 error, leading to an unhandled
`HTTPError` and a 500 response from the service. While it is unlikely that a GitHub
webhook would contain a trailing newline, the validation logic is incorrect.
A review suggested `$` lets `"myorg\n"` through. It doesn't, because the check uses fullmatch, but only fullmatch prevents it: with match, the login would pass. Cover it so the check can't regress to match. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
joshuarli
approved these changes
Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

No outgoing request had a timeout. gunicorn runs with 1 worker, 4 threads and
--timeout 0(see theDockerfile), so a single hung connection to GitHub or Sentry could tie up a quarter of the app's capacity indefinitely.Request latency over the last 7 days, from this app's spans:
GETconfig (.sentry/sentry_config.ini)GETworkflow runPOSTinstallation access tokenDELETEinstallation tokenPOSTSentry envelopeChanges
REQUEST_TIMEOUT = (5, 10), i.e. 5 s to connect and 10 s between bytes read, insrc/__init__.py. It's passed to all fiverequestscalls insrc/.requests.exceptions.Timeout. That's handled like any other request error: logged, and the webhook gets a 500.cli.pyis unchanged. It's a local development tool and isn't in the Docker image._fetch_githubrejects any URL that isn't underhttps://api.github.com/, and builds the request on that base.#117 has since merged, and
mainis merged into this branch. The timeout and the login check are in_fetch_dsn, behind #117's DSN cache.Testing
test_every_request_has_a_timeoutdrives a full webhook throughWebAppHandlerin GitHub App mode: mint token, fetch config, fetch run, post envelope, revoke token. It asserts that each request was sent withREQUEST_TIMEOUT._fetch_githubrefuses another host,http, a lookalike host, a URL with userinfo, andgithub.com, without making a request.matchinstead offullmatch, or dropping theapi.github.comcheck makes its test fail too.pyteston the merged tree: 35 passed, 1 skipped (already skipped before this change).pre-commit runpasses on all changed files.CodeQL
The two
py/full-ssrfalerts are fixed by this PR. They're on theGETs whose URLs come from the webhook payload: the config fetch, and_fetch_github._fetch_githubbuilds the request onhttps://api.github.com, so the token can't be sent to another host.Running CodeQL 2.27.2's default Python suite locally, it reports
py/full-ssrfatsrc/github_sdk.py:60before this change and nothing after it. Both alerts already exist onmain, so merging this should also close #1 there.🤖 Generated with Claude Code