Skip to content

feat: add CodeRabbit integration for AI-powered code review#1315

Open
jeremyeder wants to merge 1 commit intoambient-code:mainfrom
jeremyeder:coderabbit-integration-clean
Open

feat: add CodeRabbit integration for AI-powered code review#1315
jeremyeder wants to merge 1 commit intoambient-code:mainfrom
jeremyeder:coderabbit-integration-clean

Conversation

@jeremyeder
Copy link
Copy Markdown
Contributor

@jeremyeder jeremyeder commented Apr 15, 2026

Summary

Backend (Go):

  • Auth handlers: connect, status, disconnect, test with K8s Secret storage
  • API key validation with error differentiation (401/403 = invalid, 5xx = upstream)
  • Runtime credential endpoint with RBAC for session pods
  • Unified integrations status includes CodeRabbit
  • 16 Ginkgo tests

Frontend (Next.js + React):

  • Informational-first connection card — public repos free via GitHub App, API key collapsed under "Private repository access" with billing warning
  • API client + React Query hooks, 4 proxy routes
  • Wired into IntegrationsClient and session integrations panel

Runner (Python):

  • CODERABBIT_API_KEY injected via asyncio.gather, cleared on turn completion

Pre-commit hook:

  • Runs coderabbit review --agent, supports API key env and cr auth login
  • Skips gracefully, never blocks commits

CI + Testing:

  • GHA smoke test (actions pinned to SHAs, permissions scoped)
  • Integration test script: ./scripts/test-coderabbit-integration.sh (9/9 against dev cluster)

Docs:

Test plan

  • Backend: go build, go vet, golangci-lint pass
  • Backend: 16 Ginkgo tests pass
  • Frontend: tsc --noEmit and npm run build pass (0 errors, 0 warnings)
  • Integration test: 9/9 passing against live dev cluster
  • Pre-commit + pre-push hooks all pass
  • Docs render in Starlight

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added CodeRabbit integration management: connect, disconnect, and view status of API key credentials through the Integrations page.
    • Added CodeRabbit credential injection into session environments for private repository access.
    • Added pre-commit hook to run CodeRabbit code reviews on staged changes during local development.
    • Integrated CodeRabbit status display in session settings and unified integrations panel.
  • Documentation

    • Added CodeRabbit integration guide covering setup, usage, and local workflows.
  • Tests

    • Added integration and unit test coverage for CodeRabbit backend APIs and workflows.

Full-stack integration following the Jira pattern and PR ambient-code#1307 conventions.
Implements infrastructure for ADR-0008 (automated inner-loop review).

Backend (Go):
- Auth handlers: connect, status, disconnect, test (K8s Secret storage)
- API key validation against CodeRabbit health API with error differentiation
  (401/403 = invalid key, 5xx = upstream error)
- Runtime credential endpoint with RBAC for session pods
- Unified integrations status includes CodeRabbit
- 16 Ginkgo tests

Frontend (Next.js + React):
- Informational-first connection card: public repos free via GitHub App,
  API key collapsed under "Private repository access" with billing warning
- API client layer + React Query hooks with dual cache invalidation
- 4 Next.js proxy routes
- Wired into IntegrationsClient grid and session integrations panel

Runner (Python):
- fetch_coderabbit_credentials via shared _fetch_credential helper
- CODERABBIT_API_KEY injected into session env via asyncio.gather
- Cleared on turn completion

Pre-commit hook:
- Runs coderabbit review --agent on staged changes
- Supports both CODERABBIT_API_KEY env and cr auth login session
- CLI reads env var directly (no --api-key in process listing)
- Skips gracefully when CLI/auth/changes unavailable

CI + Testing:
- GHA smoke test: validates config, runs live review, tests hook behavior
  (actions pinned to SHAs, permissions scoped)
- Integration test script: 9/9 passing against dev cluster

Docs:
- Starlight guide: public vs private repos, local dev, session flow
- ADR-0008: automated code reviews via inner-loop + Mergify
- PR ambient-code#1307 impact analysis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

📝 Walkthrough

Walkthrough

Adds CodeRabbit integration across the platform, enabling both organization-wide and per-user API key management. Includes backend credential persistence in Kubernetes, frontend UI for key management, session credential injection, pre-commit hook for local review automation, and comprehensive test coverage via GHA and shell scripts.

Changes

Cohort / File(s) Summary
Backend CodeRabbit Handlers
components/backend/handlers/coderabbit_auth.go, coderabbit_auth_test.go
Implements three primary endpoints (connect/status/disconnect) with Kubernetes Secret storage for per-user API keys; includes validation against CodeRabbit health endpoint and RBAC-aware credential retrieval.
Backend Integration Routes & Status
components/backend/routes.go, handlers/integrations_status.go, handlers/integration_validation.go, handlers/runtime_credentials.go
Registers CodeRabbit lifecycle endpoints, adds CodeRabbit field to unified integrations status, implements session-scoped credential exposure with 404 when missing, and adds test endpoint for key validation.
Frontend Next.js API Routes
components/frontend/src/app/api/auth/coderabbit/connect/route.ts, disconnect/route.ts, status/route.ts, test/route.ts
Proxy endpoints forwarding CodeRabbit auth requests to backend with preserved headers and response formatting.
Frontend React Components & Services
components/frontend/src/components/coderabbit-connection-card.tsx, src/services/api/coderabbit-auth.ts, src/services/queries/use-coderabbit.ts
UI card for API key management, typed service layer for backend communication, and React Query hooks with automatic cache invalidation.
Frontend Integration UI
components/frontend/src/app/integrations/IntegrationsClient.tsx, src/app/projects/.../integrations-panel.tsx, src/services/api/integrations.ts
Wires CodeRabbit status into integrations grid and session settings panel; updates integrations status type to include CodeRabbit field.
Credential & Environment Management
components/runners/ambient-runner/ambient_runner/platform/auth.py
Adds concurrent CodeRabbit credential fetch, sets CODERABBIT_API_KEY in session runtime, installs gh CLI wrapper for mid-run token refresh, includes error aggregation logic.
Pre-commit & Local Development
scripts/pre-commit/coderabbit-review.sh, .pre-commit-config.yaml
Hook for running CodeRabbit review on staged changes with graceful skip when CLI or auth missing; integrated into pre-commit pipeline.
Testing & Validation
.github/workflows/coderabbit-smoke-test.yml, scripts/test-coderabbit-integration.sh, components/backend/tests/constants/labels.go
GHA smoke test for CLI and .coderabbit.yaml validation; comprehensive bash test suite covering auth, credential CRUD, sessions, and frontend rendering; test label constant.
Documentation & Specifications
docs/src/content/docs/features/coderabbit.md, specs/001-coderabbit-integration/spec.md, specs/.../checklists/requirements.md, docs/pr-1307-impact-analysis.md, docs/internal/adr/0008-automate-code-reviews.md
Feature guide (public/private repo flows, local/session usage), formal spec with user stories and functional requirements, impact analysis referencing prior patterns, and ADR outlining automated code review confidence stack with Mergify integration.

Sequence Diagram(s)

sequenceDiagram
    participant User as User (Browser)
    participant Frontend as Frontend
    participant Backend as Backend API
    participant CodeRabbit as CodeRabbit API
    participant K8s as Kubernetes<br/>(Secret Storage)
    participant Runner as Session Runner
    
    User->>Frontend: 1. Navigate to Integrations
    Frontend->>Backend: 2. POST /api/auth/coderabbit/connect<br/>{ apiKey: "cr-..." }
    Backend->>CodeRabbit: 3. Validate key via /api/v1/health<br/>(Bearer token)
    CodeRabbit-->>Backend: 4. HTTP 200 (valid) or 401/403
    Backend->>K8s: 5. Store credentials in<br/>coderabbit-credentials Secret
    K8s-->>Backend: 6. Secret created/updated
    Backend-->>Frontend: 7. HTTP 200 { message: "connected" }
    Frontend-->>User: 8. Show "Connected" status
    
    Note over User,Backend: Later: User starts an agentic session
    
    User->>Frontend: 9. Create/join session
    Frontend->>Backend: 10. Start session (auth token)
    Backend->>K8s: 11. GET coderabbit-credentials<br/>for user
    K8s-->>Backend: 12. Return apiKey
    Backend->>Runner: 13. Inject CODERABBIT_API_KEY<br/>into session environment
    Runner-->>Backend: 14. Environment ready
    Backend-->>Frontend: 15. Session started
    Frontend-->>User: 16. Session active
    
    Note over Runner,CodeRabbit: During session execution
    Runner->>CodeRabbit: 17. Use $CODERABBIT_API_KEY<br/>for code review requests
    CodeRabbit-->>Runner: 18. Review results
    
    Note over User,Backend: Session cleanup
    Runner->>Runner: 19. Clear CODERABBIT_API_KEY<br/>from environment
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Security And Secret Handling ❌ Error PR contains five confirmed security violations: missing auth gates, credential leakage via CLI args, symlink hijacking vulnerability, missing error handling in proxy routes, and missing OwnerReferences in K8s Secrets. Add auth validation to TestCodeRabbitConnection, use env vars only for credentials, secure temp directories with 0o700 perms, wrap proxy routes in try/catch with proper Content-Type handling, and add OwnerReferences to Secrets.
Docstring Coverage ⚠️ Warning Docstring coverage is 57.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Kubernetes Resource Safety ⚠️ Warning coderabbit-credentials Secret lacks OwnerReferences, causing orphaned resources on deployment deletion. Pod security context missing hardening controls. Add OwnerReference to Secret pointing to backend Deployment. Define pod securityContext: runAsNonRoot: true, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title follows Conventional Commits format (feat: scope/description) and accurately describes the primary changeset—CodeRabbit integration with AI-powered code review.
Performance And Algorithmic Complexity ✅ Passed K8s Secret operations are O(1) with bounded retries, integrations status makes isolated lookups, and Python runner fetches main credentials concurrently via asyncio.gather(). MCP server loops are small and filtered (0-3 servers). Frontend uses React Query caching properly without unnecessary rerenders.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch coderabbit-integration-clean
✨ Simplify code
  • Create PR with simplified code

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/frontend/src/app/integrations/IntegrationsClient.tsx (1)

15-16: ⚠️ Potential issue | 🟠 Major

Handle query errors explicitly before rendering integration cards.

If useIntegrationsStatus() fails, this component drops into the non-loading branch and renders cards with undefined statuses, masking transport/auth failures as "disconnected." The hook returns error and isError fields (via React Query's useQuery), but you're not destructuring them. Add an isError branch with a clear failure UI before the grid render (lines 32–37).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/frontend/src/app/integrations/IntegrationsClient.tsx` around lines
15 - 16, The component currently only destructures { data: integrations,
isLoading, refetch } from useIntegrationsStatus() and will render integration
cards with undefined statuses when the query errors; update the destructuring to
also grab isError and error from useIntegrationsStatus(), add an early-return
branch that checks isError and renders a clear failure UI (e.g., a
message/button to retry using refetch) before the grid of cards is rendered, and
ensure any places referencing integrations handle the absence of data safely;
look for useIntegrationsStatus, integrations, isLoading, isError, error, refetch
and the grid render to implement this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/coderabbit-smoke-test.yml:
- Around line 86-90: The workflow currently passes the secret via the --api-key
flag in the coderabbit review invocation (the command that builds OUTPUT and
EXIT_CODE), which exposes it in process args; remove the --api-key
"$CODERABBIT_API_KEY" argument and rely on the CODERABBIT_API_KEY environment
variable being available to the CLI instead (ensure the step exports or sets
CODERABBIT_API_KEY in the environment or uses GitHub Actions secrets mapping so
coderabbit reads it from process.env rather than from a command-line flag).

In `@components/backend/handlers/integration_validation.go`:
- Around line 232-241: The TestCodeRabbitConnection handler currently begins
validation without establishing request-scoped auth; call
GetK8sClientsForRequest(c) at the start of TestCodeRabbitConnection, check its
returned error (and any nil client), and if it fails return the appropriate HTTP
error JSON and stop processing before binding/validating the API key—this
ensures the endpoint uses the request-scoped k8s client instead of the backend
service account and follows the same auth pattern as other user-facing
endpoints.

In `@components/frontend/src/app/api/auth/coderabbit/status/route.ts`:
- Around line 4-14: The GET handler currently throws on upstream fetch failures
and forces 'application/json'; wrap the fetch in try/catch, and when the fetch
succeeds read the upstream body (e.g., resp.text()) and return new
Response(body, { status: resp.status, headers: { 'Content-Type':
resp.headers.get('content-type') || 'text/plain' } }); if resp.ok is false still
forward the upstream status and content-type (fall back to 'text/plain' if
missing); in the catch block return a 502 Response with the error.message and
'text/plain' content-type. Apply the same pattern to the sibling handlers
(disconnect, test, connect and other integration routes) so they preserve
upstream content-type and handle network/fetch errors gracefully.

In `@scripts/test-coderabbit-integration.sh`:
- Around line 180-187: The health check is using a hardcoded port 9323 instead
of the discovered FRONTEND_PORT; update the curl invocation that sets
FRONTEND_STATUS to use the FRONTEND_PORT variable (e.g.
"http://localhost:${FRONTEND_PORT}/integrations") and keep the same error
fallback (|| echo "000"), preserving the surrounding conditional that checks
FRONTEND_PORT != "NONE" and the pass/skip calls (FRONTEND_STATUS, pass, skip).

---

Outside diff comments:
In `@components/frontend/src/app/integrations/IntegrationsClient.tsx`:
- Around line 15-16: The component currently only destructures { data:
integrations, isLoading, refetch } from useIntegrationsStatus() and will render
integration cards with undefined statuses when the query errors; update the
destructuring to also grab isError and error from useIntegrationsStatus(), add
an early-return branch that checks isError and renders a clear failure UI (e.g.,
a message/button to retry using refetch) before the grid of cards is rendered,
and ensure any places referencing integrations handle the absence of data
safely; look for useIntegrationsStatus, integrations, isLoading, isError, error,
refetch and the grid render to implement this change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 72b2e4da-a160-49a3-a5f6-cd8a48769aa9

📥 Commits

Reviewing files that changed from the base of the PR and between cec7993 and c0b7f62.

📒 Files selected for processing (27)
  • .github/workflows/coderabbit-smoke-test.yml
  • .pre-commit-config.yaml
  • components/backend/handlers/coderabbit_auth.go
  • components/backend/handlers/coderabbit_auth_test.go
  • components/backend/handlers/integration_validation.go
  • components/backend/handlers/integrations_status.go
  • components/backend/handlers/runtime_credentials.go
  • components/backend/routes.go
  • components/backend/tests/constants/labels.go
  • components/frontend/src/app/api/auth/coderabbit/connect/route.ts
  • components/frontend/src/app/api/auth/coderabbit/disconnect/route.ts
  • components/frontend/src/app/api/auth/coderabbit/status/route.ts
  • components/frontend/src/app/api/auth/coderabbit/test/route.ts
  • components/frontend/src/app/integrations/IntegrationsClient.tsx
  • components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/settings/integrations-panel.tsx
  • components/frontend/src/components/coderabbit-connection-card.tsx
  • components/frontend/src/services/api/coderabbit-auth.ts
  • components/frontend/src/services/api/integrations.ts
  • components/frontend/src/services/queries/use-coderabbit.ts
  • components/runners/ambient-runner/ambient_runner/platform/auth.py
  • docs/internal/adr/0008-automate-code-reviews.md
  • docs/pr-1307-impact-analysis.md
  • docs/src/content/docs/features/coderabbit.md
  • scripts/pre-commit/coderabbit-review.sh
  • scripts/test-coderabbit-integration.sh
  • specs/001-coderabbit-integration/checklists/requirements.md
  • specs/001-coderabbit-integration/spec.md

Comment on lines +86 to +90
OUTPUT=$(coderabbit review \
--agent \
--files .coderabbit.yaml \
--api-key "$CODERABBIT_API_KEY" \
2>&1) || EXIT_CODE=$?
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.

⚠️ Potential issue | 🟠 Major

Do not pass CODERABBIT_API_KEY as a command-line argument

Line 89 sends the key via --api-key, which can leak through process args. Keep it in environment only and let the CLI read CODERABBIT_API_KEY.

Safer command usage
           OUTPUT=$(coderabbit review \
             --agent \
             --files .coderabbit.yaml \
-            --api-key "$CODERABBIT_API_KEY" \
             2>&1) || EXIT_CODE=$?

As per coding guidelines, verify secrets are not exposed and permissions are scoped.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/coderabbit-smoke-test.yml around lines 86 - 90, The
workflow currently passes the secret via the --api-key flag in the coderabbit
review invocation (the command that builds OUTPUT and EXIT_CODE), which exposes
it in process args; remove the --api-key "$CODERABBIT_API_KEY" argument and rely
on the CODERABBIT_API_KEY environment variable being available to the CLI
instead (ensure the step exports or sets CODERABBIT_API_KEY in the environment
or uses GitHub Actions secrets mapping so coderabbit reads it from process.env
rather than from a command-line flag).

Comment on lines +232 to +241
// TestCodeRabbitConnection handles POST /api/auth/coderabbit/test
func TestCodeRabbitConnection(c *gin.Context) {
var req struct {
APIKey string `json:"apiKey" binding:"required"`
}

if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
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.

⚠️ Potential issue | 🟠 Major

Add the request-scoped auth gate before validating CodeRabbit keys.

Line 233 begins request processing without the GetK8sClientsForRequest(c) check used by other user-facing auth endpoints. This leaves the test endpoint outside the required request-auth pattern.

🔧 Proposed fix
 func TestCodeRabbitConnection(c *gin.Context) {
+	reqK8s, _ := GetK8sClientsForRequest(c)
+	if reqK8s == nil {
+		c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or missing token"})
+		return
+	}
+
+	userID := c.GetString("userID")
+	if userID == "" {
+		c.JSON(http.StatusUnauthorized, gin.H{"error": "User authentication required"})
+		return
+	}
+
 	var req struct {
 		APIKey string `json:"apiKey" binding:"required"`
 	}

As per coding guidelines, User-facing API ops MUST use GetK8sClientsForRequest(c), never the backend service account.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// TestCodeRabbitConnection handles POST /api/auth/coderabbit/test
func TestCodeRabbitConnection(c *gin.Context) {
var req struct {
APIKey string `json:"apiKey" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
func TestCodeRabbitConnection(c *gin.Context) {
reqK8s, _ := GetK8sClientsForRequest(c)
if reqK8s == nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or missing token"})
return
}
userID := c.GetString("userID")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User authentication required"})
return
}
var req struct {
APIKey string `json:"apiKey" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/backend/handlers/integration_validation.go` around lines 232 -
241, The TestCodeRabbitConnection handler currently begins validation without
establishing request-scoped auth; call GetK8sClientsForRequest(c) at the start
of TestCodeRabbitConnection, check its returned error (and any nil client), and
if it fails return the appropriate HTTP error JSON and stop processing before
binding/validating the API key—this ensures the endpoint uses the request-scoped
k8s client instead of the backend service account and follows the same auth
pattern as other user-facing endpoints.

Comment on lines +4 to +14
export async function GET(request: Request) {
const headers = await buildForwardHeadersAsync(request)

const resp = await fetch(`${BACKEND_URL}/auth/coderabbit/status`, {
method: 'GET',
headers,
})

const data = await resp.text()
return new Response(data, { status: resp.status, headers: { 'Content-Type': 'application/json' } })
}
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the same proxy pattern (uncaught fetch + forced JSON content-type) across CodeRabbit routes.
rg -n --type=ts -C2 'export async function (GET|POST|DELETE)\(request: Request\)|fetch\(|new Response\(data, \{ status: resp.status, headers: \{ '\''Content-Type'\'': '\''application/json'\'' \} \}\)' components/frontend/src/app/api/auth/coderabbit
rg -n --type=ts -C1 'try\s*\{' components/frontend/src/app/api/auth/coderabbit

Repository: ambient-code/platform

Length of output: 5123


🏁 Script executed:

#!/bin/bash
# Check buildForwardHeadersAsync implementation
rg -n "buildForwardHeadersAsync" components/frontend/src/lib/auth --type=ts -A 10

Repository: ambient-code/platform

Length of output: 137


🏁 Script executed:

#!/bin/bash
# Check if there are other proxy routes that handle errors correctly
find components/frontend/src/app/api -name "route.ts" -type f | head -20 | xargs grep -l "try\s*{" 2>/dev/null || echo "No routes with try/catch found"

Repository: ambient-code/platform

Length of output: 249


🏁 Script executed:

#!/bin/bash
# Check the structure of a few other API routes to see error handling patterns
fd "route.ts" components/frontend/src/app/api --max-results=5 | xargs head -20

Repository: ambient-code/platform

Length of output: 2796


🏁 Script executed:

#!/bin/bash
# Find buildForwardHeadersAsync implementation
rg -n "buildForwardHeadersAsync" components/frontend/src --type=ts -B2 -A8 | head -50

Repository: ambient-code/platform

Length of output: 4485


🏁 Script executed:

#!/bin/bash
# Get full Google status route to see correct error handling pattern
cat -n components/frontend/src/app/api/auth/google/status/route.ts

Repository: ambient-code/platform

Length of output: 1697


🏁 Script executed:

#!/bin/bash
# List all routes with the broken pattern (no try/catch)
rg -l "new Response\(data, \{ status: resp.status, headers: \{ 'Content-Type': 'application/json'" components/frontend/src/app/api --type=ts

Repository: ambient-code/platform

Length of output: 1894


Guard upstream fetch failures and preserve upstream content-type.

This proxy throws on upstream failure (no catch) and forces JSON content-type even when upstream returns non-JSON error bodies, breaking the API contract under outage conditions. Same pattern affects the sibling disconnect, test, and connect routes, plus 20+ other routes across Jira, GitLab, GitHub, and other integrations. The Google OAuth status route shows the correct pattern with try/catch and proper error handling.

Proposed fix (apply same pattern to disconnect/test/connect routes)
 export async function GET(request: Request) {
-  const headers = await buildForwardHeadersAsync(request)
-
-  const resp = await fetch(`${BACKEND_URL}/auth/coderabbit/status`, {
-    method: 'GET',
-    headers,
-  })
-
-  const data = await resp.text()
-  return new Response(data, { status: resp.status, headers: { 'Content-Type': 'application/json' } })
+  try {
+    const headers = await buildForwardHeadersAsync(request)
+    const resp = await fetch(`${BACKEND_URL}/auth/coderabbit/status`, {
+      method: 'GET',
+      headers,
+    })
+
+    const data = await resp.text()
+    return new Response(data, {
+      status: resp.status,
+      headers: {
+        'Content-Type': resp.headers.get('content-type') ?? 'application/json',
+      },
+    })
+  } catch {
+    return Response.json({ error: 'CodeRabbit upstream unavailable' }, { status: 502 })
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/frontend/src/app/api/auth/coderabbit/status/route.ts` around lines
4 - 14, The GET handler currently throws on upstream fetch failures and forces
'application/json'; wrap the fetch in try/catch, and when the fetch succeeds
read the upstream body (e.g., resp.text()) and return new Response(body, {
status: resp.status, headers: { 'Content-Type': resp.headers.get('content-type')
|| 'text/plain' } }); if resp.ok is false still forward the upstream status and
content-type (fall back to 'text/plain' if missing); in the catch block return a
502 Response with the error.message and 'text/plain' content-type. Apply the
same pattern to the sibling handlers (disconnect, test, connect and other
integration routes) so they preserve upstream content-type and handle
network/fetch errors gracefully.

Comment on lines +565 to +567
_GH_WRAPPER_DIR = "/tmp/bin"
_GH_WRAPPER_PATH = "/tmp/bin/gh"

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.

⚠️ Potential issue | 🟠 Major

Use a private, non-predictable wrapper path for gh

Line 565 and Line 566 place an executable shim in a fixed /tmp location. That is vulnerable to path/symlink hijack in shared runtime contexts and can compromise token-handling flow. Create a per-process private directory (0700) and write the wrapper there with restrictive permissions.

Proposed hardening patch
+import tempfile
@@
-_GH_WRAPPER_DIR = "/tmp/bin"
-_GH_WRAPPER_PATH = "/tmp/bin/gh"
+_GH_WRAPPER_DIR = tempfile.mkdtemp(prefix="ambient-gh-", dir="/tmp")
+os.chmod(_GH_WRAPPER_DIR, 0o700)
+_GH_WRAPPER_PATH = f"{_GH_WRAPPER_DIR}/gh"
@@
-        wrapper_path.chmod(
-            stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH
-        )  # 755
+        wrapper_path.chmod(stat.S_IRWXU)  # 700

Also applies to: 712-719

🧰 Tools
🪛 Ruff (0.15.10)

[error] 565-565: Probable insecure usage of temporary file or directory: "/tmp/bin"

(S108)


[error] 566-566: Probable insecure usage of temporary file or directory: "/tmp/bin/gh"

(S108)

Comment on lines +180 to +187
if [ "$FRONTEND_PORT" != "NONE" ]; then
# The frontend is behind the kind NodePort — check container port mapping
FRONTEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:9323/integrations" 2>/dev/null || echo "000")
if [ "$FRONTEND_STATUS" = "200" ]; then pass "Integrations page loads (HTTP 200)"
else skip "Integrations page returned $FRONTEND_STATUS (may need auth)"; fi
else
skip "Frontend NodePort not found"
fi
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.

⚠️ Potential issue | 🟡 Minor

Hardcoded port ignores discovered FRONTEND_PORT.

Line 182 uses hardcoded localhost:9323 instead of the FRONTEND_PORT discovered on lines 170-178. If the NodePort differs, this check will always hit the wrong endpoint.

Proposed fix
 if [ "$FRONTEND_PORT" != "NONE" ]; then
-  # The frontend is behind the kind NodePort — check container port mapping
-  FRONTEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:9323/integrations" 2>/dev/null || echo "000")
+  # Use discovered NodePort for frontend check
+  FRONTEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$FRONTEND_PORT/integrations" 2>/dev/null || echo "000")
   if [ "$FRONTEND_STATUS" = "200" ]; then pass "Integrations page loads (HTTP 200)"
   else skip "Integrations page returned $FRONTEND_STATUS (may need auth)"; fi
 else
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ "$FRONTEND_PORT" != "NONE" ]; then
# The frontend is behind the kind NodePort — check container port mapping
FRONTEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:9323/integrations" 2>/dev/null || echo "000")
if [ "$FRONTEND_STATUS" = "200" ]; then pass "Integrations page loads (HTTP 200)"
else skip "Integrations page returned $FRONTEND_STATUS (may need auth)"; fi
else
skip "Frontend NodePort not found"
fi
if [ "$FRONTEND_PORT" != "NONE" ]; then
# Use discovered NodePort for frontend check
FRONTEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$FRONTEND_PORT/integrations" 2>/dev/null || echo "000")
if [ "$FRONTEND_STATUS" = "200" ]; then pass "Integrations page loads (HTTP 200)"
else skip "Integrations page returned $FRONTEND_STATUS (may need auth)"; fi
else
skip "Frontend NodePort not found"
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/test-coderabbit-integration.sh` around lines 180 - 187, The health
check is using a hardcoded port 9323 instead of the discovered FRONTEND_PORT;
update the curl invocation that sets FRONTEND_STATUS to use the FRONTEND_PORT
variable (e.g. "http://localhost:${FRONTEND_PORT}/integrations") and keep the
same error fallback (|| echo "000"), preserving the surrounding conditional that
checks FRONTEND_PORT != "NONE" and the pass/skip calls (FRONTEND_STATUS, pass,
skip).

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