Skip to content

fix: list_changed_files uses live API SHAs instead of webhook payload SHAs #1096

@rnetser

Description

@rnetser

Problem

OwnersFileHandler.list_changed_files() fetches base.sha and head.sha via live PyGithub API calls (pull_request.base.sha, pull_request.head.sha). These return the current state of the PR from GitHub's API, which may differ from the state when the webhook was delivered.

This creates a race condition:

  1. Webhook fires, server clones the repository (captures state at time T)
  2. Base branch receives new commits (state moves to T+1)
  3. list_changed_files() calls the live API, gets SHAs from T+1
  4. git diff {base_sha}...{head_sha} fails with fatal: Invalid symmetric difference expression because the T+1 SHAs don't exist in the clone from time T

Expected Behavior

The git diff should use SHAs that are consistent with the cloned repository state.

Proposed Fix

Use the frozen SHAs from the webhook payload instead of live API calls:

# Current (live API — can drift)
base_sha = await github_api_call(lambda: pull_request.base.sha, ...)
head_sha = await github_api_call(lambda: pull_request.head.sha, ...)

# Proposed (frozen at webhook delivery time)
base_sha = self.github_webhook.hook_data["pull_request"]["base"]["sha"]
head_sha = self.github_webhook.hook_data["pull_request"]["head"]["sha"]

The webhook payload SHAs are snapshots from delivery time, matching what was cloned. The codebase already uses this pattern for other fields (e.g., hook_data["pull_request"]["base"]["ref"] in pull_request_handler.py).

Benefits

  • Eliminates the race condition between clone and API call
  • Saves 2 API calls per webhook event
  • Follows existing pattern used elsewhere in the codebase

Files to Modify

  • webhook_server/libs/handlers/owners_files_handler.pylist_changed_files() method

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions