feat: add webhook-server package for receiving provider webhooks#9
feat: add webhook-server package for receiving provider webhooks#9khaliqgant merged 7 commits intomainfrom
Conversation
| function inferGitHubObjectType(eventName: string, payload: Record<string, unknown>): string { | ||
| if (eventName === "push" || Array.isArray(payload.commits)) { | ||
| return "commit"; | ||
| } | ||
| if (asRecord(payload.pull_request)) { | ||
| return "pull_request"; | ||
| } | ||
| if (asRecord(payload.review)) { | ||
| return "review"; | ||
| } | ||
| if (eventName === "pull_request_review_comment" || asRecord(payload.comment)) { | ||
| return "review_comment"; | ||
| } | ||
| if (asRecord(payload.issue)) { | ||
| return "issue"; | ||
| } | ||
| if (asRecord(payload.check_run)) { | ||
| return "check_run"; | ||
| } | ||
| return eventName || "event"; | ||
| } |
There was a problem hiding this comment.
🔴 inferGitHubObjectType misclassifies review events as pull_request due to check ordering
In normalizeGitHubWebhook, inferGitHubObjectType checks for payload.pull_request (line 71) before checking for payload.review (line 74). GitHub pull_request_review and pull_request_review_comment webhook payloads contain both a pull_request and a review (or comment) object. Because the pull_request check comes first, these events are always misclassified as "pull_request" instead of "review" or "review_comment". This causes downstream VFS path computation and object ID resolution to be wrong.
Since GitHubAdapter doesn't implement the RegisteredWebhookAdapter.normalizeWebhook method, the webhook server falls back to this built-in normalizer (routes.ts:309-310), making this the active code path when GitHubAdapter is registered with the server.
| function inferGitHubObjectType(eventName: string, payload: Record<string, unknown>): string { | |
| if (eventName === "push" || Array.isArray(payload.commits)) { | |
| return "commit"; | |
| } | |
| if (asRecord(payload.pull_request)) { | |
| return "pull_request"; | |
| } | |
| if (asRecord(payload.review)) { | |
| return "review"; | |
| } | |
| if (eventName === "pull_request_review_comment" || asRecord(payload.comment)) { | |
| return "review_comment"; | |
| } | |
| if (asRecord(payload.issue)) { | |
| return "issue"; | |
| } | |
| if (asRecord(payload.check_run)) { | |
| return "check_run"; | |
| } | |
| return eventName || "event"; | |
| } | |
| function inferGitHubObjectType(eventName: string, payload: Record<string, unknown>): string { | |
| if (eventName === "push" || Array.isArray(payload.commits)) { | |
| return "commit"; | |
| } | |
| if (eventName === "pull_request_review_comment" || asRecord(payload.comment)) { | |
| return "review_comment"; | |
| } | |
| if (asRecord(payload.review)) { | |
| return "review"; | |
| } | |
| if (asRecord(payload.pull_request)) { | |
| return "pull_request"; | |
| } | |
| if (asRecord(payload.issue)) { | |
| return "issue"; | |
| } | |
| if (asRecord(payload.check_run)) { | |
| return "check_run"; | |
| } | |
| return eventName || "event"; | |
| } |
Was this helpful? React with 👍 or 👎 to provide feedback.
| function inferGitHubObjectId(objectType: string, payload: Record<string, unknown>): string { | ||
| const candidates = [ | ||
| readString(payload.id), | ||
| readString(payload.number), | ||
| readNestedString(payload, "pull_request", "number"), | ||
| readNestedString(payload, "issue", "number"), | ||
| readNestedString(payload, "review", "id"), | ||
| readNestedString(payload, "comment", "id"), | ||
| readNestedString(payload, "check_run", "id"), | ||
| readNestedString(payload, "pull_request", "head", "sha"), | ||
| readString(payload.after), | ||
| ]; | ||
|
|
||
| const matched = candidates.find((value) => value !== undefined); | ||
| return matched ?? `${objectType}-unknown`; | ||
| } |
There was a problem hiding this comment.
🔴 inferGitHubObjectId ignores objectType, returning PR number instead of review/comment ID
The inferGitHubObjectId function accepts an objectType parameter but never uses it. Instead, it iterates a fixed candidate list where pull_request.number (index 2) appears before review.id (index 4) and comment.id (index 5). For pull_request_review payloads, readNestedString(payload, "pull_request", "number") matches first, so the PR number is returned as the object ID instead of the review's actual ID. This is wrong even if BUG-0001 is fixed — when objectType is correctly "review", the function still returns the PR number.
Prompt for agents
In packages/webhook-server/src/routes.ts, the function inferGitHubObjectId (lines 89-104) should use the objectType parameter to select the right candidate first, instead of using a fixed-order list. For example:
- If objectType is "review", prefer readNestedString(payload, "review", "id") first
- If objectType is "review_comment", prefer readNestedString(payload, "comment", "id") first
- If objectType is "pull_request", prefer readNestedString(payload, "pull_request", "number") or readString(payload.number) first
- If objectType is "issue", prefer readNestedString(payload, "issue", "number") first
- If objectType is "check_run", prefer readNestedString(payload, "check_run", "id") first
- If objectType is "commit", prefer readString(payload.after) or readNestedString(payload, "pull_request", "head", "sha") first
Fall back to the generic candidate list only after the type-specific lookup fails.
Was this helpful? React with 👍 or 👎 to provide feedback.
da4363f to
a5c076c
Compare
Adds @relayfile/webhook-server package with signature verification, path sanitization, and event routing. Replaces #4.