* fix: use original title from webhook payload instead of fetched title
- Add extractOriginalTitle() helper to extract title from webhook payload
- Add originalTitle parameter to fetchGitHubData()
- Update tag mode to pass original title from webhook context
- Add tests for extractOriginalTitle and originalTitle parameter
This ensures the title used in prompts is the one that existed when the
trigger event occurred, rather than a potentially modified title fetched
later via GraphQL.
* fix: add title sanitization and explicit TOCTOU test
- Apply sanitizeContent() to titles in formatContext() for defense-in-depth
- Add explicit test documenting TOCTOU prevention for title handling
Add trigger-time validation for issue/PR body content to prevent attackers
from exploiting a race condition where they edit the body between when an
authorized user triggers @claude and when Claude processes the request.
The existing filterCommentsToTriggerTime() already protected comments -
this extends the same pattern to the main issue/PR body via isBodySafeToUse().
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
Implement time-based filtering for GitHub comments and reviews to prevent
malicious actors from editing existing comments after Claude is triggered
to inject harmful content.
Changes:
- Add updatedAt and lastEditedAt fields to GraphQL queries
- Update GitHubComment and GitHubReview types with timestamp fields
- Implement filterCommentsToTriggerTime() and filterReviewsToTriggerTime()
- Add extractTriggerTimestamp() to extract trigger time from webhooks
- Update tag and review modes to pass trigger timestamp to data fetcher
Security benefits:
- Prevents comment injection attacks via post-trigger edits
- Maintains chronological integrity of conversation context
- Ensures only comments in their final state before trigger are processed
- Backward compatible with graceful degradation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: use GitHub display name in Co-authored-by trailers
- Add name field to GitHubAuthor type
- Update GraphQL queries to fetch user display names
- Add triggerDisplayName to CommonFields type
- Extract display name from fetched GitHub data in prepareContext
- Update Co-authored-by trailer generation to use display name when available
This ensures consistency with GitHub's web interface behavior where
Co-authored-by trailers use the user's display name rather than username.
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
* fix: update GraphQL queries to handle Actor type correctly
The name field is only available on the User subtype of Actor in GitHub's
GraphQL API. This commit updates the queries to use inline fragments
(... on User) to conditionally access the name field when the actor is
a User type.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: clarify Co-authored-by instructions in prompt
Replace interpolated values with clear references to XML tags and add
explicit formatting instructions. This makes it clearer how to use the
GitHub display name when available while maintaining the username for
the email portion.
Changes:
- Use explicit references to <trigger_display_name> and <trigger_username> tags
- Add clear formatting instructions and example
- Explain fallback behavior when display name is not available
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: fetch trigger user display name via dedicated GraphQL query
Instead of trying to extract the display name from existing data (which
was incomplete due to Actor type limitations), we now:
- Add a dedicated USER_QUERY to fetch user display names
- Pass the trigger username to fetchGitHubData
- Fetch the display name during data collection phase
- Simplify prepareContext to use the pre-fetched display name
This ensures we always get the correct display name for Co-authored-by
trailers, regardless of where the trigger came from.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>