feat(server): mount the Linear webhook ingress /webhooks/linear (RIG-2732 T7) - #744
Merged
Merged
Conversation
…2732 T7) Adds the shared Linear webhook ingress — `POST /webhooks/linear` (DL-302, Matt's RIG-2717 amendment) — as part of the forge agent-notification lane assembly. Mounted on the network TLS door, outside the bearer + admin-gate interceptors (Linear signs each delivery with the webhook secret, so the handler's own HMAC verify is its whole authentication), gated on the Linear webhook secret being declared — an **App-independent** gate: a deployment can run Linear notifications without a GitHub App and vice versa. ### What lands - `NewLinearWebhookHandler` + `buildLinearWebhookWiring`: one shared `http.Handler` that does a fail-closed raw-body HMAC verify then an inner `type`-switch — `AgentSessionEvent` → a local `SessionEventSink` seam (satisfied later by `*linearagent.Dispatcher`); `Issue`/`Comment` data-change events → a `ForgeEventSink` data arm. - Mount in `buildNetworkServer` guarded on `linearWebhookHandler != nil` (undeclared secret → nil handler → no route). - Flag `--forge-linear-webhook-secret` (env `COMPASS_FORGE_LINEAR_WEBHOOK_SECRET`) + `ForgeConfig.LinearWebhookSecretName` threading. - Status codes mirror the GitHub ingress: 405 / 413 (1 MiB cap) / 400 (bad sig) / 200-drop (stale 60s skew, unparseable, nil sink) / 500 (queue full / Enqueue error). ### Both sinks injected-and-nil-for-now (DL-302) The data-change arm's sink is nil for now by design: feeding the GitHub-coordinate notify+board fanout would mis-route Linear events (Linear subs looked up under a GitHub coordinate), so the data branch acks-and-drops until a Linear-provider-bound notify lane injects a real sink. The session arm is nil until the RIG-2717 responder assembly wires a real `*linearagent.Dispatcher`. Ten handler tests cover bad-sig, issue/comment create, session event, queue-full, stale-timestamp, nil-session-sink, ignored-type, issue-remove-drop, and nil-data-sink. Spec-impact: none. Refs RIG-2732, RIG-2717. Co-authored-by: Matt Wilkinson <matt@rigel.build>
|
Compass engineering docs preview: https://compass-forge-rig-2732-t7-li.compass-eng-docs.pages.dev Deployed from |
…e comments (RIG-2732 T7) Review follow-up for #744 (the /webhooks/linear mount slice). Close the test-adequacy gap the review flagged on this internet-facing, unauthenticated endpoint: four ServeHTTP branches had zero coverage, most critically the 1 MiB body-cap security control. Add table cases mirroring github_webhook_test.go: - non-POST -> 405 (method gate) - over-cap signed body -> 413 (MaxBytesReader memory-amplification guard) - secret-resolve fault -> 503 (fail-closed before parse) - verified-but-unparseable envelope -> 200-drop (no Linear retry on authentic malformed body) All assert zero enqueues. Also fix two stale doc-comment paths on linearWebhookHandler / NewLinearWebhookHandler (/webhooks -> /webhooks/linear), matching the linearWebhookPath constant the handler actually mounts at. Refs RIG-2732 Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ses (RIG-2732 T7) Round-2 review follow-up for #744. TestLinearWebhookHandler_BodyTooLarge and _SecretUnavailable each signed a body that the targeted branch never verifies — MaxBytesReader trips during io.ReadAll before the HMAC check in the former, and the secret resolver faults before it in the latter. The signature was inert plumbing a reader could mistake for a load-bearing part of the assertion. Pass "" with a one-line comment that the branch fires before verification, so each test is honest about what it exercises. Refs RIG-2732 Co-authored-by: Matt Wilkinson <matt@rigel.build>
mattwilkinsonn
marked this pull request as ready for review
August 30, 2026 18:55
mattwilkinsonn
approved these changes
Aug 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the shared Linear webhook ingress —
POST /webhooks/linear(DL-302, Matt's RIG-2717 amendment) — as part of the forge agent-notification lane assembly. Mounted on the network TLS door, outside the bearer + admin-gate interceptors (Linear signs each delivery with the webhook secret, so the handler's own HMAC verify is its whole authentication), gated on the Linear webhook secret being declared — an App-independent gate: a deployment can run Linear notifications without a GitHub App and vice versa.What lands
NewLinearWebhookHandler+buildLinearWebhookWiring: one sharedhttp.Handlerthat does a fail-closed raw-body HMAC verify then an innertype-switch —AgentSessionEvent→ a localSessionEventSinkseam (satisfied later by*linearagent.Dispatcher);Issue/Commentdata-change events → aForgeEventSinkdata arm.buildNetworkServerguarded onlinearWebhookHandler != nil(undeclared secret → nil handler → no route).--forge-linear-webhook-secret(envCOMPASS_FORGE_LINEAR_WEBHOOK_SECRET) +ForgeConfig.LinearWebhookSecretNamethreading.Both sinks injected-and-nil-for-now (DL-302)
The data-change arm's sink is nil for now by design: feeding the GitHub-coordinate notify+board fanout would mis-route Linear events (Linear subs looked up under a GitHub coordinate), so the data branch acks-and-drops until a Linear-provider-bound notify lane injects a real sink. The session arm is nil until the RIG-2717 responder assembly wires a real
*linearagent.Dispatcher. Ten handler tests cover bad-sig, issue/comment create, session event, queue-full, stale-timestamp, nil-session-sink, ignored-type, issue-remove-drop, and nil-data-sink.Spec-impact: none. Refs RIG-2732, RIG-2717.
Co-authored-by: Matt Wilkinson matt@rigel.build