Skip to content

Remove runtime realm owner escalation in webhook handler#4214

Merged
richardhjtan merged 3 commits intomainfrom
CS-10465-remove-runtime-realm-owner-escalation-in-webhook-handler
Mar 24, 2026
Merged

Remove runtime realm owner escalation in webhook handler#4214
richardhjtan merged 3 commits intomainfrom
CS-10465-remove-runtime-realm-owner-escalation-in-webhook-handler

Conversation

@richardhjtan
Copy link
Copy Markdown
Contributor

What is changing

  1. We had a privilege issue where webhook commands might run as the wrong user if they don't have write access to the submission realm. Instead of looking up the realm owner on every webhook event, we now register the webhook upfront as a user who already has the right permissions.
  2. Register webhook as submission_realm user instead

@richardhjtan richardhjtan requested review from a team March 19, 2026 13:38
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2d9ca8bfd0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

// Run as the realm owner so they have write permissions in the target realm
let runAs = webhook.username as string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve compatibility for webhooks registered before this change

This handler now always runs the command as webhook.username. On upgrade, existing incoming_webhooks rows keep the account that originally created them, while the new register-github-webhook.ts logic only affects future registrations. For any already-registered GitHub webhook owned by a user like @submissionbot or a human account, run-command will now reject the event once it targets /submissions/ because run-command.ts requires runAs to already have realm permissions. Without a migration/backfill or a compatibility fallback here, deploying this commit breaks existing webhook integrations until each webhook is manually recreated under submission_realm.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended, we will update the incoming webhook record to be the realm user who should have the write permission (@submission_realm:xxx ) in the github webhook use case

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 19, 2026

Host Test Results

    1 files  ±  0      1 suites  ±0   1h 54m 27s ⏱️ - 9m 32s
2 030 tests +184  2 015 ✅ +186  15 💤 ±0  0 ❌  - 1 
2 045 runs  +185  2 030 ✅ +188  15 💤 ±0  0 ❌  - 2 

Results for commit 068b0f4. ± Comparison against base commit 86cb8e6.

This pull request removes 1 and adds 185 tests. Note that renamed tests count towards both.
Chrome ‑ Global error: Uncaught TypeError: Failed to fetch at http://localhost:7357/assets/chunk.ba748e4cc236bfaae5b8.js, line 156670  While executing test: Acceptance | code-submode | field playground > single realm: can create new field instance (has preexisting Spec) 
Chrome ‑ Acceptance | code-submode | field playground > multiple realms: can autogenerate new Spec and field instance (no preexisting Spec)
Chrome ‑ Acceptance | code-submode | field playground > multiple realms: can autogenerate new field instance when spec exists but has no examples
Chrome ‑ Acceptance | code-submode | field playground > multiple realms: can create new field instance (has preexisting Spec)
Chrome ‑ Acceptance | code-submode | field playground > single realm: can autogenerate new field instance when spec exists but has no examples
Chrome ‑ Acceptance | code-submode | field playground > single realm: can create new field instance (has preexisting Spec)
Chrome ‑ Acceptance | code-submode | field playground > single realm: can request AI assistant to bulk generate samples
Chrome ‑ Acceptance | code-submode | field playground > single realm: can request AI assistant to fill in sample data
Chrome ‑ Acceptance | code-submode | field playground > single realm: does not persist the wrong card for field
Chrome ‑ Acceptance | code-submode | field playground > single realm: editing compound field instance live updates the preview
Chrome ‑ Acceptance | code-submode | field playground > single realm: has default templates when a format template is not provided
…

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes runtime “realm owner” privilege escalation when executing webhook-triggered commands by ensuring webhooks are registered under a user that already has the required permissions (intended to be submission_realm), and adds more explicit failure signaling when webhook command enqueueing fails.

Changes:

  • Stop looking up the target realm owner on each webhook and run commands as the webhook’s registered user instead.
  • Track “matched” vs “executed” webhook commands and return HTTP 500 if none of the matched commands were enqueued.
  • Update the GitHub webhook registration script to default to submission_realm credentials and register check_suite events.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
packages/realm-server/handlers/handle-webhook-receiver.ts Removes realm-owner escalation and adds a 500 response when all matched commands fail to enqueue.
packages/matrix/scripts/register-github-webhook.ts Attempts to default authentication to submission_realm (derived password) and adds check_suite event registration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@richardhjtan richardhjtan force-pushed the CS-10465-remove-runtime-realm-owner-escalation-in-webhook-handler branch from 2d9ca8b to 3c765b1 Compare March 24, 2026 02:49
@richardhjtan richardhjtan force-pushed the CS-10465-remove-runtime-realm-owner-escalation-in-webhook-handler branch from 3c765b1 to 24f2f4a Compare March 24, 2026 02:50
// Step 1: Authenticate
// Step 1: Authenticate as submission_realm user by default
if (!process.env.MATRIX_USERNAME) {
process.env.MATRIX_USERNAME = 'submission_realm';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this defaulting to 'submission_realm'?

if you want to register-github-webhook-for-submission-realm. Just write that script. You don't have to pollute this to fit your use-case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tintinthong last week we discussed that the submission_realm@xxx user should be the one registering incoming webhook commands, since it is the owner and has write access. That avoids any permission issues when the command writes cards into the submission realm.

Do you mean whether other users can use this base script to register webhooks under their own realm in their local environment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We called and verified the implementation is fine, but perhaps rename the script to register-github-webhook-for-submission-realm

@richardhjtan richardhjtan merged commit a203c93 into main Mar 24, 2026
109 of 110 checks passed
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.

3 participants