feat(github): governed internal merge-pr connection action (inert consumer)#253
feat(github): governed internal merge-pr connection action (inert consumer)#253chitcommit wants to merge 3 commits into
Conversation
Add POST /integrations/github/merge-pr — an internal-only, authenticated connection action that performs a GitHub PR merge with the App installation token. The token is minted/cached and used entirely within ChittyConnect; the calling executor (autoassist) holds no GitHub credential and decides maintainer policy itself. - Auth: X-Webhook-Secret (INTERNAL_WEBHOOK_SECRET), constant-time compare, fails closed if the secret is unset. Not public. - Resolves installation_id via GitHub's native repo->installation endpoint (new getInstallationIdForRepo in auth/github.js), so it does not depend on the local installations table. - TOCTOU guard: passes expected_head_sha as `sha` to the merge API; GitHub 409s if the head moved since the executor's decision. - Idempotent: on 405/409, confirms the PR's merged state via GET before reporting merged:true — never assumes 405 == already-merged (avoids the silent-failure of reporting an unmergeable PR as merged). - Fail-safe error JSON on every path. ChittyConnect does NOT decide maintainer policy here — it executes an authenticated GitHub merge on behalf of an internally-authenticated caller. 9 unit tests (real Hono pipeline + real RS256 JWT; only the GitHub HTTP boundary is stubbed, no live calls, no service mocks). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 23 minutes and 32 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
chittyconnect | 53b2f70 | Jun 16 2026, 05:13 PM |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
Adds a new internal-only GitHub PR merge “connection action” endpoint to ChittyConnect, using the GitHub App installation token minted/cached entirely inside the service (executor holds no GitHub credentials).
Changes:
- Adds
POST /integrations/github/merge-prroute with internal-secret authentication, merge execution, and idempotency handling for 405/409 responses. - Adds
getInstallationIdForRepo()helper to resolve GitHub App installation ID via GitHub’s/repos/{owner}/{repo}/installation. - Adds end-to-end route tests through the Hono pipeline with only the GitHub HTTP boundary stubbed.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/api/github-merge-routes.test.js | Adds Vitest coverage for auth, validation, TOCTOU guard forwarding, and 405/409 idempotency behavior. |
| src/index.js | Mounts the new /integrations/github route group and imports the route module. |
| src/auth/github.js | Adds repo→installation lookup helper for GitHub App installation resolution. |
| src/api/routes/github-merge.js | Implements the internal merge endpoint, including secret auth, merge execution, and failure surfacing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address Copilot review on PR #253: - repo must match exactly "owner/name" (was permissive includes("/"), letting owner/name/extra silently merge against the wrong repo) - expected_head_sha (TOCTOU guard) validated as 7-40 char hex sha; reject non-string/whitespace early instead of forwarding to GitHub - getInstallationIdForRepo trims + encodeURIComponent's owner/repo and rejects empty values to prevent malformed URLs / unintended paths Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ures The new expected_head_sha shape validation (7-40 hex) correctly rejected the placeholder fixtures "headsha123" and "stale". Replace with real-shaped 40-char hex git shas so tests exercise the guard with valid input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Adds
POST /integrations/github/merge-pr— an internal-only, authenticated connection action that performs a GitHub PR merge using the App installation token. The token is minted/cached and used entirely within ChittyConnect; the calling executor (autoassist, chittyentity PR) holds no GitHub credential and decides maintainer policy itself.This is the connection half of the operator-confirmed option (b): ChittyConnect performs the merge with its GitHub App token (token never leaves the connection layer); the executor decides policy and calls ChittyConnect to execute.
Endpoint
POST /integrations/github/merge-prX-Webhook-Secret: <INTERNAL_WEBHOOK_SECRET>— constant-time compare, fails closed if the secret is unset. Not public.{ repo: "owner/name", pr_number, merge_method?: "squash"|"merge"|"rebase" (default squash), expected_head_sha? }{ merged, sha?, message?, status }Behavior
installation_idvia GitHub's nativeGET /repos/{owner}/{repo}/installation(newgetInstallationIdForRepoinauth/github.js) — schema-independent, no dependency on the localinstallationstable.expected_head_shaasshato GitHub's merge API; GitHub 409s if the head moved since the executor's decision.GETs the PR and returnsmerged:trueonly if.merged === true; otherwise surfaces the failure JSON.ChittyConnect does not decide maintainer policy here — it executes an authenticated merge on behalf of an internally-authenticated caller (the App identity acting).
Tests
9 unit tests through the real Hono pipeline with a real RS256 App JWT; only the GitHub HTTP boundary is stubbed (no live calls, no service-module mocks). Covers: missing/wrong/unset secret, body validation, squash-default +
expected_head_shaforwarding, idempotent already-merged via PR re-check, 405-not-mergeable surfaced as failure, 409 head-moved surfaced.node --check+eslintclean.Inert / go-live
This endpoint is dormant until a caller invokes it. The caller (autoassist executor) is itself behind
MAINTAINER_EXECUTOR_ENABLED(default off). Do not deploy / do not merge as part of go-live — see the paired chittyentity PR for the wiring checklist.🤖 Generated with Claude Code