feat(orb): maintainer OAuth self-enrollment (install-admin verified) - #1348
Merged
Conversation
Let a maintainer self-issue their brokered enrollment secret via the Orb App's OAuth callback — without the operator manually issuing it — while CLOSING the privilege-escalation hole that made the operator-issued path the only option. GitHub redirects to /v1/orb/oauth/callback with an OAuth code + installation_id; the handler now: exchanges the code (Orb App credentials) → identifies the user (GET /user) → VERIFIES the user is an admin of the installation's account → checks registered=1 → issues a one-time secret, recording the maintainer identity. The admin check is the gate: installation_id is an attacker-controllable query param, so a stolen code + a victim's installation_id must never enroll the victim's install. For an Org install the user must be an ACTIVE org ADMIN (their own /user/memberships/orgs role, requires the read:org scope); for a User install they must be the account owner. installation_id is bound server-side in the enrollment and read back (never from a request) at token-exchange time. No request input is echoed into the markup; the secret is shown once and never logged. issueOrbEnrollment now records the maintainer login + github id (the orb_enrollments columns already existed; no migration). The operator-issued path is unchanged (maintainer optional). Adversarially verified (6 properties). Advances #1255. (Configure the Orb App OAuth scopes to read:user + read:org for the org-admin check.)
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1348 +/- ##
=======================================
Coverage 95.27% 95.28%
=======================================
Files 188 188
Lines 20336 20371 +35
Branches 7327 7343 +16
=======================================
+ Hits 19375 19410 +35
Misses 378 378
Partials 583 583
🚀 New features to boost your workflow:
|
This was referenced Jun 25, 2026
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.
5 tasks
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.
Summary
Lets a maintainer self-issue their brokered enrollment secret via the Orb App's OAuth callback — without the operator manually issuing it — while closing the privilege-escalation hole that made the operator-issued path the only safe option. GitHub redirects to
/v1/orb/oauth/callbackwith an OAuthcode+installation_id; the handler now: exchanges the code (Orb App credentials) → identifies the user (GET /user) → verifies the user is an admin of the installation's account → checksregistered=1→ issues a one-time secret, recording the maintainer identity.The security gate (the whole point)
installation_idis an attacker-controllable query param, so a stolen code + a victim'sinstallation_idmust never enroll the victim's install.verifyInstallationAdmin:GET /user/memberships/orgs/{org}→role==="admin" && state==="active"; needs theread:orgscope).installation_idis bound server-side in the enrollment and read back (never from a request) at token-exchange. No request input is echoed into the markup; the secret is shown once and never logged. No migration —orb_enrollmentsalready had themaintainer_*columns; the operator-issued path is unchanged (maintainer optional).Validation
npm run test:cigreen; 100% branch coverage onoauth.ts+broker.tsdiff (every admin-verify arm: org-admin/member/pending/api-error, user-match/mismatch, no-account; the full callback flow incl. the non-admin 403 + no-enrollment gate, unregistered 403, unknown 404, exchange//userfailure 400).Safety
Advances #1255. Configure the Orb App OAuth scopes →
read:user+read:orgfor the org-admin check.