feat: add dependency-free Go webhook receiver example with Standard Webhooks signature verification - #5268
Conversation
|
|
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (4): Last reviewed commit: "docs: add self-contained webhook receive..." | Re-trigger Greptile |
89461a9 to
9e6981f
Compare
88d9468 to
254c7eb
Compare
9e6981f to
9caf331
Compare
7cefd96 to
b32fc1a
Compare
9caf331 to
8290da0
Compare
b32fc1a to
7aaf2ad
Compare
8290da0 to
419f933
Compare
Merge activity
|
The base branch was changed.
7aaf2ad to
5039720
Compare
…ebhooks signature verification (#5268) ## Summary Adds a minimal, dependency-free Go example receiver for Bifrost async inference webhooks. The example demonstrates the critical requirement for any webhook receiver: verifying the Standard Webhooks HMAC-SHA256 signature before trusting a delivery. ## Changes - Added `examples/webhooks/main.go` implementing a webhook receiver with: - `verify` — validates the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers, enforces a 5-minute replay tolerance window, and accepts any matching signature from a space-separated list (supporting secret rotation) - `sign` — recomputes the `v1,<base64>` HMAC-SHA256 signature over `{id}.{timestamp}.{body}` using the `whsec_`-prefixed secret, mirroring Bifrost's own signer exactly - An HTTP handler that reads the body, verifies the signature, unmarshals the event envelope, and returns `204 No Content` on success - A `/healthz` endpoint alongside `POST /webhook` - Added `examples/webhooks/main_test.go` pinning the canonical Standard Webhooks reference vector (the same vector Bifrost's signer pins), plus table-driven rejection tests covering tampered bodies, wrong IDs, forged signatures, stale timestamps, and missing headers - Added `examples/webhooks/README.md` documenting the wire format, signature algorithm, deduplication requirement, and how to run and test the example ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test ```sh cd examples/webhooks go test ./... ``` To run the receiver against a live Bifrost instance: ```sh WEBHOOK_SECRET=whsec_your_secret_here go run . ``` The receiver listens on `:8080` by default (override with `ADDR`). Point a Bifrost webhook endpoint at `http://<host>:8080/webhook` and complete an async job to see verified deliveries logged. **Environment variables:** | Variable | Required | Default | Description | |------------------|----------|---------|--------------------------------------------------| | `WEBHOOK_SECRET` | Yes | — | Endpoint signing secret (`whsec_...`) | | `ADDR` | No | `:8080` | Address the receiver listens on | ## Screenshots/Recordings N/A ## Breaking changes - [x] No ## Related issues N/A ## Security considerations - Signatures are compared using `crypto/subtle.ConstantTimeCompare` to prevent timing-based secret leakage. - The timestamp tolerance window (5 minutes) blunts replay attacks. - The request body is capped at 1 MiB (`io.LimitReader`) to prevent memory exhaustion from malicious senders. - Verification failure reasons are logged server-side but not echoed in the HTTP response, avoiding attacker probing. - The `whsec_` signing secret is read from an environment variable; the README explicitly warns never to hard-code it. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
…ebhooks signature verification (#5268) ## Summary Adds a minimal, dependency-free Go example receiver for Bifrost async inference webhooks. The example demonstrates the critical requirement for any webhook receiver: verifying the Standard Webhooks HMAC-SHA256 signature before trusting a delivery. ## Changes - Added `examples/webhooks/main.go` implementing a webhook receiver with: - `verify` — validates the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers, enforces a 5-minute replay tolerance window, and accepts any matching signature from a space-separated list (supporting secret rotation) - `sign` — recomputes the `v1,<base64>` HMAC-SHA256 signature over `{id}.{timestamp}.{body}` using the `whsec_`-prefixed secret, mirroring Bifrost's own signer exactly - An HTTP handler that reads the body, verifies the signature, unmarshals the event envelope, and returns `204 No Content` on success - A `/healthz` endpoint alongside `POST /webhook` - Added `examples/webhooks/main_test.go` pinning the canonical Standard Webhooks reference vector (the same vector Bifrost's signer pins), plus table-driven rejection tests covering tampered bodies, wrong IDs, forged signatures, stale timestamps, and missing headers - Added `examples/webhooks/README.md` documenting the wire format, signature algorithm, deduplication requirement, and how to run and test the example ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test ```sh cd examples/webhooks go test ./... ``` To run the receiver against a live Bifrost instance: ```sh WEBHOOK_SECRET=whsec_your_secret_here go run . ``` The receiver listens on `:8080` by default (override with `ADDR`). Point a Bifrost webhook endpoint at `http://<host>:8080/webhook` and complete an async job to see verified deliveries logged. **Environment variables:** | Variable | Required | Default | Description | |------------------|----------|---------|--------------------------------------------------| | `WEBHOOK_SECRET` | Yes | — | Endpoint signing secret (`whsec_...`) | | `ADDR` | No | `:8080` | Address the receiver listens on | ## Screenshots/Recordings N/A ## Breaking changes - [x] No ## Related issues N/A ## Security considerations - Signatures are compared using `crypto/subtle.ConstantTimeCompare` to prevent timing-based secret leakage. - The timestamp tolerance window (5 minutes) blunts replay attacks. - The request body is capped at 1 MiB (`io.LimitReader`) to prevent memory exhaustion from malicious senders. - Verification failure reasons are logged server-side but not echoed in the HTTP response, avoiding attacker probing. - The `whsec_` signing secret is read from an environment variable; the README explicitly warns never to hard-code it. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
…ebhooks signature verification (maximhq#5268) ## Summary Adds a minimal, dependency-free Go example receiver for Bifrost async inference webhooks. The example demonstrates the critical requirement for any webhook receiver: verifying the Standard Webhooks HMAC-SHA256 signature before trusting a delivery. ## Changes - Added `examples/webhooks/main.go` implementing a webhook receiver with: - `verify` — validates the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers, enforces a 5-minute replay tolerance window, and accepts any matching signature from a space-separated list (supporting secret rotation) - `sign` — recomputes the `v1,<base64>` HMAC-SHA256 signature over `{id}.{timestamp}.{body}` using the `whsec_`-prefixed secret, mirroring Bifrost's own signer exactly - An HTTP handler that reads the body, verifies the signature, unmarshals the event envelope, and returns `204 No Content` on success - A `/healthz` endpoint alongside `POST /webhook` - Added `examples/webhooks/main_test.go` pinning the canonical Standard Webhooks reference vector (the same vector Bifrost's signer pins), plus table-driven rejection tests covering tampered bodies, wrong IDs, forged signatures, stale timestamps, and missing headers - Added `examples/webhooks/README.md` documenting the wire format, signature algorithm, deduplication requirement, and how to run and test the example ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test ```sh cd examples/webhooks go test ./... ``` To run the receiver against a live Bifrost instance: ```sh WEBHOOK_SECRET=whsec_your_secret_here go run . ``` The receiver listens on `:8080` by default (override with `ADDR`). Point a Bifrost webhook endpoint at `http://<host>:8080/webhook` and complete an async job to see verified deliveries logged. **Environment variables:** | Variable | Required | Default | Description | |------------------|----------|---------|--------------------------------------------------| | `WEBHOOK_SECRET` | Yes | — | Endpoint signing secret (`whsec_...`) | | `ADDR` | No | `:8080` | Address the receiver listens on | ## Screenshots/Recordings N/A ## Breaking changes - [x] No ## Related issues N/A ## Security considerations - Signatures are compared using `crypto/subtle.ConstantTimeCompare` to prevent timing-based secret leakage. - The timestamp tolerance window (5 minutes) blunts replay attacks. - The request body is capped at 1 MiB (`io.LimitReader`) to prevent memory exhaustion from malicious senders. - Verification failure reasons are logged server-side but not echoed in the HTTP response, avoiding attacker probing. - The `whsec_` signing secret is read from an environment variable; the README explicitly warns never to hard-code it. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable
…ebhooks signature verification (maximhq#5268) ## Summary Adds a minimal, dependency-free Go example receiver for Bifrost async inference webhooks. The example demonstrates the critical requirement for any webhook receiver: verifying the Standard Webhooks HMAC-SHA256 signature before trusting a delivery. ## Changes - Added `examples/webhooks/main.go` implementing a webhook receiver with: - `verify` — validates the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers, enforces a 5-minute replay tolerance window, and accepts any matching signature from a space-separated list (supporting secret rotation) - `sign` — recomputes the `v1,<base64>` HMAC-SHA256 signature over `{id}.{timestamp}.{body}` using the `whsec_`-prefixed secret, mirroring Bifrost's own signer exactly - An HTTP handler that reads the body, verifies the signature, unmarshals the event envelope, and returns `204 No Content` on success - A `/healthz` endpoint alongside `POST /webhook` - Added `examples/webhooks/main_test.go` pinning the canonical Standard Webhooks reference vector (the same vector Bifrost's signer pins), plus table-driven rejection tests covering tampered bodies, wrong IDs, forged signatures, stale timestamps, and missing headers - Added `examples/webhooks/README.md` documenting the wire format, signature algorithm, deduplication requirement, and how to run and test the example ## Type of change - [ ] Bug fix - [ ] Feature - [ ] Refactor - [x] Documentation - [ ] Chore/CI ## Affected areas - [ ] Core (Go) - [ ] Transports (HTTP) - [ ] Providers/Integrations - [ ] Plugins - [ ] UI (React) - [x] Docs ## How to test ```sh cd examples/webhooks go test ./... ``` To run the receiver against a live Bifrost instance: ```sh WEBHOOK_SECRET=whsec_your_secret_here go run . ``` The receiver listens on `:8080` by default (override with `ADDR`). Point a Bifrost webhook endpoint at `http://<host>:8080/webhook` and complete an async job to see verified deliveries logged. **Environment variables:** | Variable | Required | Default | Description | |------------------|----------|---------|--------------------------------------------------| | `WEBHOOK_SECRET` | Yes | — | Endpoint signing secret (`whsec_...`) | | `ADDR` | No | `:8080` | Address the receiver listens on | ## Screenshots/Recordings N/A ## Breaking changes - [x] No ## Related issues N/A ## Security considerations - Signatures are compared using `crypto/subtle.ConstantTimeCompare` to prevent timing-based secret leakage. - The timestamp tolerance window (5 minutes) blunts replay attacks. - The request body is capped at 1 MiB (`io.LimitReader`) to prevent memory exhaustion from malicious senders. - Verification failure reasons are logged server-side but not echoed in the HTTP response, avoiding attacker probing. - The `whsec_` signing secret is read from an environment variable; the README explicitly warns never to hard-code it. ## Checklist - [x] I read `docs/contributing/README.md` and followed the guidelines - [x] I added/updated tests where appropriate - [x] I updated documentation where needed - [x] I verified builds succeed (Go and UI) - [ ] I verified the CI pipeline passes locally if applicable

Summary
Adds a minimal, dependency-free Go example receiver for Bifrost async inference webhooks. The example demonstrates the critical requirement for any webhook receiver: verifying the Standard Webhooks HMAC-SHA256 signature before trusting a delivery.
Changes
examples/webhooks/main.goimplementing a webhook receiver with:verify— validates thewebhook-id,webhook-timestamp, andwebhook-signatureheaders, enforces a 5-minute replay tolerance window, and accepts any matching signature from a space-separated list (supporting secret rotation)sign— recomputes thev1,<base64>HMAC-SHA256 signature over{id}.{timestamp}.{body}using thewhsec_-prefixed secret, mirroring Bifrost's own signer exactly204 No Contenton success/healthzendpoint alongsidePOST /webhookexamples/webhooks/main_test.gopinning the canonical Standard Webhooks reference vector (the same vector Bifrost's signer pins), plus table-driven rejection tests covering tampered bodies, wrong IDs, forged signatures, stale timestamps, and missing headersexamples/webhooks/README.mddocumenting the wire format, signature algorithm, deduplication requirement, and how to run and test the exampleType of change
Affected areas
How to test
To run the receiver against a live Bifrost instance:
WEBHOOK_SECRET=whsec_your_secret_here go run .The receiver listens on
:8080by default (override withADDR). Point a Bifrost webhook endpoint athttp://<host>:8080/webhookand complete an async job to see verified deliveries logged.Environment variables:
WEBHOOK_SECRETwhsec_...)ADDR:8080Screenshots/Recordings
N/A
Breaking changes
Related issues
N/A
Security considerations
crypto/subtle.ConstantTimeCompareto prevent timing-based secret leakage.io.LimitReader) to prevent memory exhaustion from malicious senders.whsec_signing secret is read from an environment variable; the README explicitly warns never to hard-code it.Checklist
docs/contributing/README.mdand followed the guidelines