Problem
The webhook receiver at packages/server/src/routes/sourceWebhooks.ts is a leaky abstraction. The WebhookCapability port (packages/core/src/domain/plugin/SourceLoaderPlugin.ts) delegates only repoIdentity and shouldDispatch, while the server still hardcodes the GitHub-specific verification mechanics. This couples the kernel to a single provider. The port comment already admits it, "Provider this server's webhook receiver knows how to verify today."
Hardcoded github specifics in the server, should live in source-loader-github
PROVIDER = 'github' constant.
- HMAC scheme,
createHmac('sha256', ...), the sha256= prefix, and the X-Hub-Signature-256 header (verifySignature).
- The
X-GitHub-Event header.
- Payload shape,
extractFullName(payload) reads repository.full_name.
- The
/webhooks/github/ public-prefix bypass in middleware/auth.ts.
Already delegated, correct
WebhookCapability.repoIdentity(config).
WebhookCapability.shouldDispatch(config, delivery).
Proposed direction
Extend WebhookCapability so the plugin owns the full verify step, for example verifyDelivery(headers, rawBody, secret) returning { valid, event, repoFullName } or undefined, and move the HMAC, header, and payload logic into @braidhq/source-loader-github. The server keeps only generic plumbing, route /webhooks/:provider/:workspaceId/:sourceId, look up the source loader's webhook capability, delegate verification, and dispatch the background sync. The uniform anonymous 401 (anti-recon) and the secret storage stay in the server.
Forcing function
Do not do this speculatively. There is one webhook provider today (github), so the coupling costs nothing yet. The driver is a second provider such as gitlab or bitbucket, which the existing WebhookProvider type and the narrowly-listed /webhooks/github/ prefix already anticipate. Same "do not abstract on a sample size of one" tradeoff as the coding-preset extraction tracked in #50.
Problem
The webhook receiver at
packages/server/src/routes/sourceWebhooks.tsis a leaky abstraction. TheWebhookCapabilityport (packages/core/src/domain/plugin/SourceLoaderPlugin.ts) delegates onlyrepoIdentityandshouldDispatch, while the server still hardcodes the GitHub-specific verification mechanics. This couples the kernel to a single provider. The port comment already admits it, "Provider this server's webhook receiver knows how to verify today."Hardcoded github specifics in the server, should live in
source-loader-githubPROVIDER = 'github'constant.createHmac('sha256', ...), thesha256=prefix, and theX-Hub-Signature-256header (verifySignature).X-GitHub-Eventheader.extractFullName(payload)readsrepository.full_name./webhooks/github/public-prefix bypass inmiddleware/auth.ts.Already delegated, correct
WebhookCapability.repoIdentity(config).WebhookCapability.shouldDispatch(config, delivery).Proposed direction
Extend
WebhookCapabilityso the plugin owns the full verify step, for exampleverifyDelivery(headers, rawBody, secret)returning{ valid, event, repoFullName }or undefined, and move the HMAC, header, and payload logic into@braidhq/source-loader-github. The server keeps only generic plumbing, route/webhooks/:provider/:workspaceId/:sourceId, look up the source loader's webhook capability, delegate verification, and dispatch the background sync. The uniform anonymous 401 (anti-recon) and the secret storage stay in the server.Forcing function
Do not do this speculatively. There is one webhook provider today (github), so the coupling costs nothing yet. The driver is a second provider such as gitlab or bitbucket, which the existing
WebhookProvidertype and the narrowly-listed/webhooks/github/prefix already anticipate. Same "do not abstract on a sample size of one" tradeoff as the coding-preset extraction tracked in #50.