Skip to content

feat: PR change gating — pre-incident PR risk review (DEV-1252) - #506

Merged
damianloch merged 30 commits into
mainfrom
sms10221/dev-1252-alert-prediction-via-change-gate
Jun 18, 2026
Merged

feat: PR change gating — pre-incident PR risk review (DEV-1252)#506
damianloch merged 30 commits into
mainfrom
sms10221/dev-1252-alert-prediction-via-change-gate

Conversation

@isiddharthsingh

@isiddharthsingh isiddharthsingh commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Aurora now reviews pull requests on enrolled repos' default branches and posts a GitHub App review — APPROVE when the change looks safe, COMMENT with inline findings when it carries incident risk. Like CodeRabbit, but for incident prevention rather than code quality. Opt-in per repo via an "Incident Prevention" toggle; default off.

How it works

  • Trigger: PR opened / reopened / ready_for_review / synchronize against the default branch of an enrolled, App-installed repo. Drafts, non-default-branch, not-enrolled, and suspended-install PRs are skipped. Redis dedupe absorbs redeliveries.
  • Review: reuses the existing background agent (run_background_chat, mode=ask) with a read-only tool denylist (no write/exec/IaC tools). The agent investigates with the same read-only tools as RCA (logs, metrics, postmortems, etc.) and returns a SAFE/RISKY verdict with findings.
  • Posting: findings that anchor to diff hunks become inline review comments; all findings also appear in a top-level table. Each inline comment carries a hidden fingerprint marker.
  • Incremental re-review (CodeRabbit-style): on a later push the agent reviews only the new commits (three-dot compare, gated on a clean linear advance), never re-scans unchanged code, and never deletes prior comments — fixed findings collapse as GitHub "outdated" history.
  • State in the PR: prior findings + head SHA are stored base64 in a hidden HTML marker in the review body. No new tables — one connected_repos.change_gating_enabled boolean column only.

Scope

No Aurora UI tab, no Slack notifications, no REQUEST_CHANGES (advisory only — never blocks merge), no rate limiting. GitLab/Bitbucket left as a future adapter behind the same class boundary. A CHANGE_GATING_DRY_RUN flag logs the would-be review instead of posting (calibration before granting write perms).

Test plan

  • 132 unit tests: GitHub adapter (mocked requests), diff-hunk math, verdict parsing/rendering, webhook filter matrix, and the per-run tool denylist.
  • Live-verified end-to-end on a test repo: full review on open, incremental review on push (no duplicate inline comments, prior comments untouched), SAFE→APPROVE and RISKY→COMMENT paths.
  • CI pre-checks green.

Manual follow-up

  • Upgrade the GitHub App permission to Pull requests: write (existing installs must accept) before disabling dry-run mode.

Summary by CodeRabbit

  • New Features
    • Incident Prevention: automated pre-merge PR reviews with per-repository enablement, incremental re-reviews, and net-new inline comments.
  • Chores
    • Added calibration/dry-run mode to log would-be review results instead of posting (configurable).
  • Bug Fixes
    • Tool denylisting is now enforced consistently across nested and background chat runs.
    • OAuth mode behavior now separates “login onboarding” from whether existing OAuth tokens are honored.
  • Tests
    • Added/expanded coverage for diff/anchoring, verdict parsing/rendering, adapter behavior, webhook enqueueing, denylist enforcement, and GitHub flows.

@isiddharthsingh
isiddharthsingh requested a review from a team as a code owner June 12, 2026 19:03
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds repository-level change-gating: DB flag, API + frontend toggle, Celery investigate_pr workflow, GitHub PR adapter, diff/verdict utilities with hidden markers/fingerprints, tool denylist wiring across agent runtime, auth-mode refactoring, and comprehensive unit tests.

Changes

OAuth Auth-Mode Refactoring

Layer / File(s) Summary
Auth Mode Split
server/utils/auth/github_auth_mode.py, server/utils/auth/github_auth_router.py
Replaces is_oauth_enabled() with is_oauth_login_enabled() (oauth/hybrid only) and is_oauth_token_honored() (all modes); updates all call sites to gate OAuth login vs honoring existing tokens separately.

Agent Tool Denylist Infrastructure

Layer / File(s) Summary
Tool Denylist State & Filter
server/chat/backend/agent/utils/state.py
State gains tool_denylist: Optional[List[str]] and filter_denied_tools(tools, denylist) utility that fast-path-returns original list when denylist is falsy.
Agent & Sub-Agent Propagation
server/chat/backend/agent/agent.py, server/chat/backend/agent/orchestrator/dispatcher.py, server/chat/backend/agent/orchestrator/sub_agent.py
Agent agentic_tool_flow applies denylist after subset overrides; dispatcher includes parent_tool_denylist in sub-agent payloads; sub-agent initializes State from parent context.
Background Chat Threading
server/chat/background/task.py
run_background_chat, _execute_background_chat, _run_jira_action accept and forward tool_denylist into agent/Jira phases.
Tool Denylist Tests
server/tests/chat/test_tool_denylist.py
Tests for State field defaults/round-trip, filter behavior, and call-site enforcement.

GitHub PR Review Service Layer

Layer / File(s) Summary
GitHub PR Adapter
server/services/change_gating/github_adapter.py
GitHubPRAdapter for scoped (installation+repo) API interaction: lazy token minting, marker encode/decode/detection, paginated reads (PR/files/reviews/comments/diffs/compare), writes with 422-retry fallback, review dismissal/update, issue comment idempotency, and idempotent supersession logic for prior Aurora reviews.
Diff Utilities
server/services/change_gating/diff_utils.py
parse_diff_hunks maps files to right-side commentable lines; anchor_findings partitions findings by hunk coverage; format_changed_files and build_per_file_diff produce prompt-optimized summaries with character budgets, escaping, and fallback to whole-PR diff.
Verdict Pipeline
server/services/change_gating/verdict.py
build_review_prompt composes PR metadata/diffs/prior-context; parse_verdict resiliently extracts JSON; extract_verdict_with_llm is structured-output fallback; render_review_body formats SAFE/RISKY with hidden marker; render_inline_comment and fingerprint helpers enable incremental reconciliation.
Service Tests
server/tests/services/test_change_gating_adapter.py, test_change_gating_diff_utils.py, test_change_gating_verdict.py
Comprehensive mocked/unit tests for adapter HTTP routing, diff hunk parsing/anchoring, verdict parsing/rendering, fingerprinting, and hardening.

Change Gating Task & Webhook Orchestration

Layer / File(s) Summary
investigate_pr Celery Task
server/tasks/change_gating.py
Orchestrates PR review: Redis dedupe/locks, enrollment re-check, PR validation, prior-Aurora context, diff selection (compare-ahead/full), progress comment lifecycle, synchronous agent run with tool denylist, verdict normalization/caching, inline comment reconciliation, review rendering/posting/supersession, dry-run handling, and guaranteed cleanup.
Webhook Pull Request Handler
server/tasks/github_webhook_tasks.py
Adds _maybe_enqueue_change_gating filter chain (action/draft/base/installation presence/suspension/enrollment), Redis SET NX dedupe (24h TTL), owner resolution under RLS, and conditional enqueue with explicit dedupe-key release on skip/failure.
Task & Handler Tests
server/tests/tasks/test_change_gating_handler.py
Mocked end-to-end tests for webhook filter matrix, dedupe behavior, progress comments, live fingerprints, and background-mode blocking.

Repository Configuration & Frontend

Layer / File(s) Summary
Database Schema
server/utils/db/db_utils.py
Adds connected_repos.change_gating_enabled BOOLEAN DEFAULT FALSE migration with commit/rollback handling.
Repo Selection API
server/routes/github/github_repo_selection.py
get_repo_selections aggregates gating state via bool_or() window and returns per-repo change_gating_enabled. New PUT /repo-selections/<repo_full_name>/change-gating validates, verifies installation, updates row, and returns appropriate status codes.
Frontend Toggle UI
client/src/components/github-provider-integration.tsx
ConnectedRepo extends with change_gating_enabled/installation_id; GitHubIntegrationService.setChangeGating issues PUT; handleChangeGatingToggle uses optimistic updates/rollback; renders per-repo Switch conditionally on installation presence. Prevents skeleton re-flash on refetch via installationsLoaded flag.
GitHub App Auto-Import
server/routes/github/github_repo_metadata.py, server/routes/github/github_app.py
import_installation_repos task auto-discovers and UPSERTs repos with metadata_status='pending'; install callback enqueues auto-import best-effort. Tests validate insertion, idempotency, owner preservation, and edge cases.

Configuration & Wiring

Layer / File(s) Summary
Environment & Docker
.env.example, docker-compose.airtight.yml, docker-compose.prod-local.yml, docker-compose.yaml
Introduces CHANGE_GATING_DRY_RUN=false with calibration-mode comments.
Celery & Services
server/celery_config.py, server/services/change_gating/__init__.py
Registers tasks.change_gating module; adds service-layer package docstring.
CI & Dependencies
.github/workflows/linters.yml
Adds PyJWT==2.13.0 to pre-check pip install.
Icon Updates
client/src/components/connectors/ConnectorRegistry.ts
Switches GitHub connector from lucide icon to custom static asset with dark-mode inversion.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Arvo-AI/aurora#202: Overlaps on State model changes and agent-state schema augmentation.
  • Arvo-AI/aurora#371: Introduces OAuth auth-mode split (is_oauth_login_enabled() / is_oauth_token_honored()) used throughout this PR.
  • Arvo-AI/aurora#166: Both PRs modify connected_repos schema and repo-selection API/UI surfaces.

Suggested reviewers

  • beng360

🐰 I hop through diffs with careful cheer,
Hidden markers tucked where reviews appear,
I sniff denied tools and whisper "Nope",
Then nudge the PR with a gentle hope —
Safe hops, risky hops, I file them clear. ✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sms10221/dev-1252-alert-prediction-via-change-gate

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.

❤️ Share

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

Comment thread server/tests/services/test_change_gating_adapter.py Fixed
Comment thread server/tasks/change_gating.py Fixed

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/src/components/github-provider-integration.tsx`:
- Around line 1188-1200: The Switch for "Incident Prevention" is missing an
accessible name; update the Switch element in github-provider-integration.tsx to
include an aria-label or aria-labelledby that references the repository name
(use repo.repo_full_name) so each toggle is announced uniquely, e.g. build a
label like "Incident Prevention for {repo.repo_full_name}" and add it as
aria-label (or create a hidden id'd label and use aria-labelledby); keep
existing props (checked, disabled, onCheckedChange -> handleChangeGatingToggle,
data-testid, className) and ensure gatingUpdating.has(repo.repo_full_name) logic
remains unchanged.

In `@server/routes/github/github_repo_selection.py`:
- Around line 296-317: The LEFT JOIN allows connected_repos.r.installation_id to
be non-null while no matching github_installations row exists, so the code must
ensure the joined installation (alias i) actually exists and is not suspended
before treating it as active: either change the query to an INNER JOIN between
connected_repos r and github_installations i (or add "AND i.installation_id IS
NOT NULL" to the WHERE) so i is guaranteed present, or keep the LEFT JOIN but
return 409 when the joined installation columns are NULL; update the downstream
checks around row (currently using row[0] and row[1]) to explicitly verify i
exists (e.g., check the joined installation column is not NULL) before assuming
an active installation.

In `@server/services/change_gating/github_adapter.py`:
- Around line 91-112: The function find_aurora_reviews currently accepts any
review authored by an account with user.type == "Bot" if the body has an Aurora
marker; instead require the reviewer to match Aurora's configured bot identity
(e.g., compare user.get("login") or user.get("id") to the expected Aurora bot
login/id) before accepting the review. Update find_aurora_reviews (and the
related find_latest_aurora_review call sites/tests) to take an
expected_aurora_bot identifier parameter (login or id), check that value against
each review's user field in addition to has_aurora_marker(review.get("body")),
and propagate the new parameter through callers and unit tests so only reviews
from the configured Aurora bot are returned.

In `@server/services/change_gating/verdict.py`:
- Around line 179-187: The description string is interpolating
attacker-controlled PR fields (pr.get('title'), pr.get('body')) and the diff
block without escaping, so update the construction of description to pass title
and body through an escaping helper (call _escape_prompt_data on pr.get('title')
and pr.get('body')) and likewise sanitize the diff content before appending to
diff_block/diff_excerpt; ensure _escape_prompt_data exists and safely
neutralizes delimiter sequences like "</pr_description>" and triple backticks,
then use that helper wherever description, diff_block, or diff_excerpt are built
(e.g., in the description assignment and the diff_block/diff_excerpt population)
so all user-controlled strings are escaped before interpolation.

In `@server/tasks/change_gating.py`:
- Around line 142-160: The RLS session variables are only reset on the happy
path causing pooled connections to leak tenant context; update the three call
sites (_verify_enrollment, _read_final_assistant_message,
_resolve_change_gating_owner) to guarantee cleanup by either (preferred)
changing set_rls_context to use transaction-scoped SET LOCAL so settings
auto-reset at transaction end, or if retaining connection-scoped SET, wrap the
call and subsequent DB work in try/finally and always execute the RESET
statements ("RESET myapp.current_user_id; RESET myapp.current_org_id;") in the
finally block to ensure the pooled connection never returns with stale RLS
context. Ensure references to set_rls_context and the RESET statements are
preserved and applied consistently across all three functions.

In `@server/utils/db/db_utils.py`:
- Around line 1601-1616: The migration that adds the change_gating_enabled
column currently swallows errors in the except block (the try around
cursor.execute("ALTER TABLE connected_repos ADD COLUMN IF NOT EXISTS
change_gating_enabled ...")), which can let the service boot with a broken
schema; modify the except block to fail fast by logging the error (use
logging.error) and then re-raising the exception or exiting the process instead
of just calling conn.rollback(), so any failure to add change_gating_enabled
during startup halts boot and surfaces the DB migration error.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 4b73e655-9c8e-4832-896f-875d5683534c

📥 Commits

Reviewing files that changed from the base of the PR and between 2800df2 and c53f8ad.

📒 Files selected for processing (26)
  • .env.example
  • .github/workflows/linters.yml
  • client/src/components/github-provider-integration.tsx
  • docker-compose.airtight.yml
  • docker-compose.prod-local.yml
  • docker-compose.yaml
  • server/celery_config.py
  • server/chat/backend/agent/agent.py
  • server/chat/backend/agent/orchestrator/dispatcher.py
  • server/chat/backend/agent/orchestrator/sub_agent.py
  • server/chat/backend/agent/utils/state.py
  • server/chat/background/task.py
  • server/routes/github/github_repo_selection.py
  • server/services/change_gating/__init__.py
  • server/services/change_gating/diff_utils.py
  • server/services/change_gating/github_adapter.py
  • server/services/change_gating/verdict.py
  • server/tasks/change_gating.py
  • server/tasks/github_webhook_tasks.py
  • server/tests/chat/test_tool_denylist.py
  • server/tests/services/test_change_gating_adapter.py
  • server/tests/services/test_change_gating_diff_utils.py
  • server/tests/services/test_change_gating_verdict.py
  • server/tests/tasks/__init__.py
  • server/tests/tasks/test_change_gating_handler.py
  • server/utils/db/db_utils.py

Comment thread client/src/components/github-provider-integration.tsx Outdated
Comment thread server/routes/github/github_repo_selection.py Outdated
Comment thread server/services/change_gating/github_adapter.py
Comment thread server/services/change_gating/verdict.py
Comment thread server/tasks/change_gating.py
Comment thread server/utils/db/db_utils.py
…ity; prompt-injection escaping; orphan-install guard; a11y label; sonar cleanups)
…ict literal, RESET RLS constant, globalThis)

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/tasks/github_webhook_tasks.py`:
- Around line 697-700: The RLS reset (_RESET_RLS_SQL) can be skipped if an
exception occurs after set_rls_context succeeds in the probing loop; to fix,
wrap the loop body that calls set_rls_context and cur.execute in a try/finally
so cur.execute(_RESET_RLS_SQL) always runs in the finally block, or convert the
RLS change to a transaction-local setting (SET LOCAL) so cleanup is automatic;
update the probing loop around set_rls_context and the linked_users cur.execute
calls to ensure the RESET is executed regardless of exceptions.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: b0e78b7b-24f2-4a7a-85ca-196c9006b243

📥 Commits

Reviewing files that changed from the base of the PR and between 9919b9c and c84212b.

📒 Files selected for processing (3)
  • client/src/components/github-provider-integration.tsx
  • server/tasks/change_gating.py
  • server/tasks/github_webhook_tasks.py

Comment thread server/tasks/github_webhook_tasks.py
Comment thread server/routes/github/github_repo_metadata.py Fixed
Comment thread server/tests/tasks/test_github_repo_import.py Fixed

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/services/change_gating/diff_utils.py`:
- Around line 135-237: Extract the per-file block rendering logic from the
`build_per_file_diff` function into a separate nested helper function. Create a
new helper function (e.g., `_build_file_block`) that accepts the file dict, the
escape function, and the max_file_chars parameter, and returns the formatted
block string. Move the logic that constructs the header with filename and stats,
handles the missing patch case, applies truncation with the note, and builds the
complete block into this helper. Then replace the inline block construction in
the loop with a call to this new helper, passing the necessary parameters. This
refactoring will reduce the cognitive complexity of the main function by
extracting a self-contained concern into a separate, reusable helper.

In `@server/tests/auth/test_github_auth_mode.py`:
- Around line 13-18: The `_set_mode` function is missing an explicit return type
annotation, which causes Ruff ANN202 to flag it. Add a return type annotation of
`-> None` to the function signature to indicate that the function does not
return a value. This should be added to the function definition line between the
closing parenthesis of the parameters and the colon.

In `@server/tests/tasks/test_github_repo_import.py`:
- Around line 122-127: The variable conn is assigned from the _run function call
but never used in the test assertions that follow. Replace conn with an
underscore (_) in the tuple unpacking at the _run call to indicate the variable
is intentionally unused and satisfy the linter.
- Around line 51-65: The mocked `db_pool` is not being picked up because
`import_installation_repos` performs a deferred import of `from
utils.db.connection_pool import db_pool` inside its function body, which creates
a new local binding after the patch is applied. Instead of patching at the
source `utils.db.connection_pool.db_pool`, patch the attribute where it is
actually used by the task module. Change the patch target from
`patch("utils.db.connection_pool.db_pool", db_pool)` to
`patch("import_installation_repos.db_pool", db_pool)` (or the appropriate module
path where the task imports and uses db_pool), ensuring the mock is injected
into the task's namespace before the function executes and performs its import.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 4201a5b7-2a79-4c06-9f28-50f1baa7baf0

📥 Commits

Reviewing files that changed from the base of the PR and between c84212b and 4749f84.

📒 Files selected for processing (18)
  • client/src/components/connectors/ConnectorRegistry.ts
  • client/src/components/github-provider-integration.tsx
  • server/chat/backend/agent/tools/github_repos_tool.py
  • server/routes/connector_status.py
  • server/routes/github/github_app.py
  • server/routes/github/github_oauth.py
  • server/routes/github/github_repo_metadata.py
  • server/routes/github/github_repo_selection.py
  • server/routes/github/github_user_repos.py
  • server/services/change_gating/diff_utils.py
  • server/services/change_gating/verdict.py
  • server/tasks/change_gating.py
  • server/tests/auth/test_github_auth_mode.py
  • server/tests/services/test_change_gating_diff_utils.py
  • server/tests/services/test_change_gating_verdict.py
  • server/tests/tasks/test_github_repo_import.py
  • server/utils/auth/github_auth_mode.py
  • server/utils/auth/github_auth_router.py

Comment thread server/services/change_gating/diff_utils.py
Comment thread server/tests/auth/test_github_auth_mode.py
Comment thread server/tests/tasks/test_github_repo_import.py
Comment thread server/tests/tasks/test_github_repo_import.py Outdated

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
server/routes/github/github_repo_metadata.py (1)

260-296: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don’t derive repo ownership and “new row” side effects from a stale snapshot.

existing is loaded before the UPSERT, then reused to choose owner_id and enqueue metadata. Concurrent/retried imports for the same org can both see no row; because the conflict target is (user_id, provider, repo_full_name), different users can create duplicate same-org repo rows, and same-user races can still double-dispatch metadata. Serialize this section per org/repo or enforce an org-level uniqueness contract, then derive newly_added from the database-enforced insert outcome rather than the pre-UPSERT map.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/github/github_repo_metadata.py` around lines 260 - 296, The
existing map is loaded as a stale snapshot before the UPSERT operations, causing
race conditions where concurrent imports can both think they are the first to
insert a repo. Instead of deriving owner_id and newly_added from the pre-UPSERT
map, you need to either add row-level locking or check the actual insert outcome
from the database. Replace the logic that populates existing before the loop and
then uses it to determine owner_id and track newly_added with logic that either
locks rows per org/repo during the operation, or queries the database after each
UPSERT (via the cursor's rowcount or other insert-result mechanism) to determine
what was actually inserted versus updated, then populate newly_added based on
those verified insert outcomes rather than the stale pre-UPSERT snapshot.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/routes/github/github_repo_metadata.py`:
- Line 199: The _import_installation_repos method is missing a return type
annotation. Since the method only exits via bare return statements or
fallthrough that implicitly return None, add the `-> None` return type
annotation to the method signature after the closing parenthesis of the
parameters.

In `@server/tests/tasks/test_github_repo_import.py`:
- Around line 28-35: Add a return type annotation to the _task_self function to
satisfy Ruff's ANN202 check. The function currently returns a SimpleNamespace
object without a type hint; add the appropriate return type annotation
indicating that the function returns a SimpleNamespace instance.

---

Outside diff comments:
In `@server/routes/github/github_repo_metadata.py`:
- Around line 260-296: The existing map is loaded as a stale snapshot before the
UPSERT operations, causing race conditions where concurrent imports can both
think they are the first to insert a repo. Instead of deriving owner_id and
newly_added from the pre-UPSERT map, you need to either add row-level locking or
check the actual insert outcome from the database. Replace the logic that
populates existing before the loop and then uses it to determine owner_id and
track newly_added with logic that either locks rows per org/repo during the
operation, or queries the database after each UPSERT (via the cursor's rowcount
or other insert-result mechanism) to determine what was actually inserted versus
updated, then populate newly_added based on those verified insert outcomes
rather than the stale pre-UPSERT snapshot.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 3ca6f304-567c-474d-95da-bd50d471840a

📥 Commits

Reviewing files that changed from the base of the PR and between 4749f84 and 61234c4.

📒 Files selected for processing (2)
  • server/routes/github/github_repo_metadata.py
  • server/tests/tasks/test_github_repo_import.py

Comment thread server/routes/github/github_repo_metadata.py
Comment thread server/tests/tasks/test_github_repo_import.py
Comment thread server/chat/backend/agent/utils/state.py
Comment thread .env.example Outdated
Comment thread server/services/change_gating/github_adapter.py
Comment thread server/services/change_gating/github_adapter.py
Comment thread server/services/change_gating/verdict.py Outdated
Comment thread server/services/change_gating/verdict.py
Comment thread server/services/change_gating/verdict.py
Comment thread server/tasks/change_gating.py
Comment thread server/tasks/change_gating.py Outdated
Comment thread server/tasks/change_gating.py
Comment thread server/tasks/change_gating.py Fixed
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread docker-compose.airtight.yml
Comment thread website/docs/integrations/github-app.md Outdated
Comment thread website/docs/integrations/github-app.md Outdated
@damianloch
damianloch merged commit 699ddd5 into main Jun 18, 2026
15 checks passed
@damianloch
damianloch deleted the sms10221/dev-1252-alert-prediction-via-change-gate branch June 18, 2026 20:00
@sonarqubecloud

Copy link
Copy Markdown

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