Skip to content

feat: add webhook-server package for receiving provider webhooks#9

Merged
khaliqgant merged 7 commits intomainfrom
feat/webhook-receiver
Mar 29, 2026
Merged

feat: add webhook-server package for receiving provider webhooks#9
khaliqgant merged 7 commits intomainfrom
feat/webhook-receiver

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

@khaliqgant khaliqgant commented Mar 29, 2026

Adds @relayfile/webhook-server package with signature verification, path sanitization, and event routing. Replaces #4.


Open with Devin

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 8 additional findings in Devin Review.

Open in Devin Review

Comment on lines +67 to +87
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";
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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.

Suggested change
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";
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +89 to +104
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`;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@khaliqgant khaliqgant force-pushed the feat/webhook-receiver branch from da4363f to a5c076c Compare March 29, 2026 20:30
@khaliqgant khaliqgant merged commit e8da711 into main Mar 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant