Skip to content

Pull-request webhooks cannot resolve default-branch Git workspaces on their first delivery #126

Description

@dispatch-developer

Affected paths and symbols

  • src/connectors/github/api.ts, mountGitHubWebhookApi() lines 104–118: githubRevisionResolution() is only called when eventName === "issues".
  • src/runtime/postgres.ts, PostgresRuntimeStore.admitEvent() lines 562–568: a matching Git binding whose revision selector is /repository/defaultBranchRevision/commit requires a revision-resolution identity.
  • src/runtime/postgres.ts, recoverGitHubRevisionResolution() lines 840–860: the fallback can only recover an installation ID from an already persisted prior event for the repository.

Failure path

  1. Configure a github.app.webhook trigger with a binding for com.github.pull_request.opened (or another supported pull-request event).
  2. Give the binding a Git workspace using the documented default-branch selector:
    {
      "type":"git",
      "repository":{"url":{"path":"/repository/cloneUrl"}},
      "revision":{"commit":{"path":"/repository/defaultBranchRevision/commit"}}
    }
  3. Send the repository's first signed pull_request delivery. Normalization includes installationId, repository ID, full name, clone URL, and default branch in the event data.
  4. The webhook route does not pass those values as revisionResolution, because line 104 limits it to issues.
  5. admitEvent() identifies the matching default-branch binding as resolution-gated. Its fallback query runs before the current event is inserted and finds no prior event, so it returns no installation identity. admitEvent() throws WorkspaceResolutionError("Workspace revision resolution requires a GitHub installation identity").
  6. The webhook handler maps that error to HTTP 422. The delivery is not persisted, no resolution row is created, and no execution can later be created by retrying that same delivery.

Expected behavior

Any supported GitHub webhook whose normalized payload carries a valid installation and repository identity should provide revision-resolution metadata when a matching default-branch Git workspace needs it. The first pull-request delivery should be accepted, persisted with a pending resolution, and create the execution after the resolver returns the default-branch commit.

Actual behavior

Only issue deliveries supply revisionResolution directly. A first pull-request delivery using a default-branch workspace is rejected with 422 despite containing all required GitHub App identity fields.

Reproduction evidence / precise failing-test design

Extend test/e2e/github-webhook-persistence.test.ts using its existing signed pullRequestPayload() and webhook helper:

  1. Publish a second binding matching com.github.pull_request.synchronize, but replace the existing head-SHA workspace with the default-branch workspace shown above.
  2. Use a fresh webhook trigger/repository database so no prior event exists for repository ID 10.
  3. Submit the existing valid signed pull-request payload, which includes installation: { id: 44 }, repository acme/widgets, and default branch main.

Expected assertion:

expect((await webhook(app, "first-default-branch-pr", raw)).status).toBe(202);
expect(await store.claimRevisionResolution({
  leaseOwner: "resolver", leaseDurationMs: 60_000,
})).toMatchObject({ installationId: 44, repositoryId: 10, branch: "main" });

Current behavior is deterministic: the response is 422 from WorkspaceResolutionError, dispatch_events has no row for the delivery, and claimRevisionResolution() returns undefined. The issues path already demonstrates the required metadata construction in githubRevisionResolution(); removing the event-name gate (while retaining validation) makes the pending resolution reachable for pull-request deliveries.

Finding fingerprint

dispatch/github-webhook-pull-request-default-branch-revision-missing-resolution-metadata-v1

Metadata

Metadata

Assignees

No one assigned

    Labels

    mediumMedium Dispatch task

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions