Skip to content

feat(orb): brokered self-host relay receiver — events flow end-to-end - #1354

Merged
JSONbored merged 1 commit into
mainfrom
feat/orb-relay-receiver
Jun 25, 2026
Merged

feat(orb): brokered self-host relay receiver — events flow end-to-end#1354
JSONbored merged 1 commit into
mainfrom
feat/orb-relay-receiver

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

The container side of the event relay — completing brokered self-host end-to-end (#1255). The central Orb now forwards a registered install's events (#1352); this is where the container receives them. POST /v1/orb/relay verifies the Orb's HMAC signature (x-orb-signature-256) against the container's own ORB_ENROLLMENT_SECRET — in constant time (crypto.subtle.verify) — then enqueues the event exactly like a GitHub webhook. So a brokered container (central Orb App + an enrollment secret, no own App key) now both receives its repos' events and acts on them via brokered tokens.

  • relayVerify (src/orb/relay.ts): constant-time HMAC verify of the sha256= signature; rejects wrong-secret, malformed/odd-length hex, missing secret/header.
  • handleOrbRelay (src/github/webhook.ts): 400 (no headers) / 404 (not a brokered self-host) / 413 (oversized) / 401 (bad signature) / 202 (verified → enqueued). The GitHub webhook receiver's post-verify path is extracted into the shared enqueueVerifiedWebhook (parse → dedup → record → WEBHOOKS lane → 202); both receivers reuse it.
  • Route + token-exemption (auth is the relay signature) + strict rate class.

The full brokered path is now live (all flag-gated, no users yet)

install central Orb App → self-enroll (#1348, admin-verified) → broker tokens (#1341) → register relay (#1349) → Orb forwards events (#1352) → this receiver verifies + enqueues → the container reviews + acts. Setup-wizard recognizes brokered mode (#1346).

Validation

  • npm run test:ci green; 100% branch coverage on relay.ts / github/webhook.ts / rate-limit.ts diff + the routes wiring — relayVerify (valid/wrong-secret/malformed/missing), and the receiver's 400/404/413/401/202 paths. The extraction left the existing GitHub-webhook tests green.

Safety

  • Constant-time signature verify; only the genuine Orb (holding the encrypted secret copy) can drive the container. Token-exempt by design (the signature is the auth); 404 for non-brokered instances.

Advances #1255. (Boot auto-registration of the relay URL is the remaining convenience follow-up.)

The container side of the event relay (#1255), completing brokered self-host end-to-end: the central Orb now
forwards a registered install's events (#1352), and this is where the container RECEIVES them. POST /v1/orb/relay
verifies the Orb's HMAC signature (x-orb-signature-256) against the container's own ORB_ENROLLMENT_SECRET — in
constant time (crypto.subtle.verify) — then enqueues the event exactly like a GitHub webhook. So a brokered
container (central Orb App + an enrollment secret, no own App key) now both RECEIVES its repos' events and ACTS
on them via brokered tokens.

- relayVerify (src/orb/relay.ts): constant-time HMAC verify of the sha256= signature; rejects wrong-secret,
  malformed/odd-length hex, and missing secret/header.
- handleOrbRelay (src/github/webhook.ts): 400 (no headers) / 404 (not a brokered self-host) / 413 (oversized) /
  401 (bad signature) / 202 (verified → enqueued). The GitHub webhook receiver's post-verify path is extracted
  into the shared enqueueVerifiedWebhook (parse → dedup → record → WEBHOOKS lane → 202); both receivers reuse it.
- Route + token-exemption (auth IS the relay signature) + strict rate class.

Auto-registering the container's relay URL on boot is the remaining convenience follow-up (the registration
endpoint #1349 already exists). Advances #1255.
@dosubot dosubot Bot added the size:M label Jun 25, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.30%. Comparing base (0ece080) to head (5d81e70).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1354   +/-   ##
=======================================
  Coverage   95.30%   95.30%           
=======================================
  Files         189      189           
  Lines       20447    20472   +25     
  Branches     7374     7387   +13     
=======================================
+ Hits        19486    19511   +25     
  Misses        378      378           
  Partials      583      583           
Files with missing lines Coverage Δ
src/api/routes.ts 94.59% <100.00%> (+<0.01%) ⬆️
src/auth/rate-limit.ts 98.82% <100.00%> (+0.01%) ⬆️
src/github/webhook.ts 100.00% <100.00%> (ø)
src/orb/relay.ts 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JSONbored
JSONbored merged commit 18881ba into main Jun 25, 2026
18 checks passed
@JSONbored
JSONbored deleted the feat/orb-relay-receiver branch June 25, 2026 10:31
JSONbored added a commit that referenced this pull request Jun 25, 2026
…1355)

Closes the brokered self-host loop (#1255): the container now self-registers its public relay URL with the
central Orb on startup, so the Orb forwards this install's events to it — no manual curl. The container computes
its relay URL from PUBLIC_API_ORIGIN + /v1/orb/relay and POSTs it to the broker with its enrollment secret.

registerOrbRelayTarget (src/orb/broker-client.ts) is BEST-EFFORT + fire-and-forget: skipped unless broker mode +
PUBLIC_API_ORIGIN are set, and any failure (Orb down, install not registered yet, non-public origin rejected by
the Orb's SSRF check) just means no relay until the next boot — it never throws or blocks startup. Wired into the
selfhost boot alongside the orb-export hook (server.ts, the codecov-ignored process entry).

End-to-end now: install Orb App → self-enroll (admin-verified, #1348) → broker tokens (#1341) → boot
auto-registers relay (this) → Orb forwards events (#1352) → relay receiver verifies + enqueues (#1354) → review +
act. Advances #1255.
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