Skip to content

fix: enforce RLS by downgrading DB connection role to non-superuser#571

Open
OlivierTrudeau wants to merge 6 commits into
mainfrom
fix/rls-superuser-bypass
Open

fix: enforce RLS by downgrading DB connection role to non-superuser#571
OlivierTrudeau wants to merge 6 commits into
mainfrom
fix/rls-superuser-bypass

Conversation

@OlivierTrudeau

@OlivierTrudeau OlivierTrudeau commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • The aurora PostgreSQL role is a superuser which bypasses all RLS policies, even with FORCE ROW LEVEL SECURITY. This caused cross-org data leakage on tables that relied solely on RLS without an explicit WHERE org_id filter (specifically the actions table, which auto-seeds system actions per-org — new accounts would see other orgs' actions and run history).
  • Creates an aurora_app role (NOSUPERUSER NOBYPASSRLS NOLOGIN) during DB initialization and grants it full table/sequence access.
  • get_connection() now issues SET ROLE aurora_app so RLS policies are actually enforced for all request-handling queries.
  • get_admin_connection() is a real separate code path that retains superuser privileges — used only for DDL/migrations, auth registration, and cross-org background tasks that explicitly call set_rls_context() per-org.

Test plan

  • Verified locally: new user sees only their own org's actions (2), not all orgs' actions (4)
  • Admin connection still bypasses RLS for migrations and scheduled tasks
  • Celery scheduled actions continue to succeed
  • Server starts cleanly, role is created idempotently on each boot
  • Verify no regressions on routes that use get_connection() (incidents, connectors, chat, etc.)
  • Verify production Helm deployment picks up role creation on first restart

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added a dedicated aurora_app PostgreSQL role and initialized consistent permissions for public tables, sequences, and future objects.
  • Bug Fixes

    • Improved database session handling to enforce Row Level Security by switching to the correct role and clearing all RLS/session variables on connection release.
    • Ensures RLS context is set before retrieving postmortem action instructions.
  • Tests

    • Updated connection-pool and RLS/reset behavior tests to reflect the new cleanup and failure semantics.

The aurora PostgreSQL role is a superuser, which bypasses all RLS
policies regardless of FORCE ROW LEVEL SECURITY. This caused cross-org
data leakage on any table that relied solely on RLS without an explicit
WHERE org_id filter (e.g. the actions table).

- Create aurora_app role (NOSUPERUSER NOBYPASSRLS) during DB init
- get_connection() now issues SET ROLE aurora_app so RLS is enforced
- get_admin_connection() retains superuser for migrations/cross-org tasks
- Graceful fallback if role doesn't exist yet (first startup)

Co-authored-by: Cursor <cursoragent@cursor.com>
@OlivierTrudeau
OlivierTrudeau requested a review from a team as a code owner July 1, 2026 15:09
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds an aurora_app PostgreSQL role for RLS enforcement, downgrades pooled connections to that role on acquisition, resets role and session state on return, and sets RLS context before the postmortem instructions query.

Changes

RLS role enforcement

Layer / File(s) Summary
aurora_app role creation and privilege grants
server/utils/db/db_utils.py
initialize_tables() creates or normalizes the aurora_app role with restricted attributes, grants it access to existing and future public tables and sequences, grants schema usage, and grants the role to the current database user with commit and rollback handling.
Role downgrade helper and connection acquisition
server/utils/db/connection_pool.py
get_connection() disables autocommit, calls _downgrade_role() to apply SET ROLE aurora_app, and continues setting request-derived RLS session variables; _downgrade_role() rolls back and raises on role-switch failure, and the related cursor block change preserves the existing session-variable behavior.
Pool return cleanup and compatibility aliases
server/utils/db/connection_pool.py
get_connection() and get_admin_connection() now reset role, clear the myapp.* session variables including token-resolve values, commit the reset, and notify waiters; the backward-compatibility alias that redirected get_admin_connection() to get_connection() is removed while get_user_connection() remains.
Postmortem instructions RLS context
server/services/actions/postmortem_action.py
_get_action_instructions() sets the RLS context on the active cursor before querying the actions and users tables for generate_postmortem instructions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • Arvo-AI/aurora#259: Both PRs update PostgreSQL RLS behavior by managing the same myapp.current_user_id / myapp.current_org_id session variables and connection return/reset logic in server/utils/db/connection_pool.py.
  • Arvo-AI/aurora#339: Both PRs adjust server/utils/db/connection_pool.py tests around RLS session SET/RESET behavior and cleanup sequencing.
  • Arvo-AI/aurora#492: Both PRs ensure the generate_postmortem related database lookups run with proper RLS session context.

Suggested reviewers: beng360, damianloch

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the core change: enforcing RLS by switching DB connections to a non-superuser role.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rls-superuser-bypass

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.

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Aurora Risk Review

Verdict: RISKY

This PR fixes a real cross-org data leakage bug by enforcing RLS via SET ROLE aurora_app on every connection checkout. The core logic is sound, but _downgrade_role() silently swallows SET ROLE failures at DEBUG level and continues — meaning if a Celery worker pod starts before the server pod's initialize_app() has created and granted the aurora_app role, the RLS fix silently does not apply to that worker for its entire lifetime. Since this PR is specifically remediating an active data-leakage incident, a silent non-application of the fix on the Celery path is a meaningful deployment risk that should be surfaced as an error, not swallowed.

Findings

# Severity File Finding
1 HIGH server/utils/db/connection_pool.py:227 SET ROLE failure silently swallowed — RLS fix can be silently bypassed on Celery workers
2 MEDIUM server/utils/db/connection_pool.py:227 Celery workers have no guarantee aurora_app role exists before first connection checkout

Aurora reviews PRs for incident prevention. This is advisory only and does not block merge.

Comment thread server/utils/db/connection_pool.py
Comment thread server/utils/db/connection_pool.py
Comment thread server/utils/db/connection_pool.py Fixed
Comment thread server/utils/db/connection_pool.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/utils/db/connection_pool.py`:
- Around line 173-181: Reset logic in the connection pool is incomplete and can
leak session bypass state. Update the reset path in the connection return flow
inside the pool methods that handle connections, including get_connection() and
get_admin_connection(), so it clears the full RLS/bypass GUC set used by
initialize_tables(), specifically including myapp.mcp_token_resolve and
myapp.kubectl_token_resolve alongside the existing role/user/org resets. Also
change the failure handling in this reset block so a reset exception causes the
connection to be discarded/closed rather than returned to the pool, and keep the
cleanup behavior consistent in the _putconn_notify path.
- Line 155: The role-switch path in ConnectionPool must fail closed instead of
continuing with the original database role when SET ROLE aurora_app fails.
Update the logic around _downgrade_role and the connection acquisition flow it
feeds (including the same handling in the later 227-239 block) so that any
failure to switch roles raises an error, aborts the request, and prevents reuse
of the higher-privileged connection.

In `@server/utils/db/db_utils.py`:
- Around line 3075-3079: The privilege setup in the database grant block is too
broad for aurora_app because `GRANT ALL ON ALL TABLES` and the matching default
privileges include dangerous table-level rights like TRUNCATE. Update the grant
logic in the db utility code around the schema/public privilege setup to grant
only the minimal table permissions the app needs (for example, read/write DML),
and keep sequence/schema grants as needed. Make the same least-privilege
adjustment for the `ALTER DEFAULT PRIVILEGES` statements so future tables do not
inherit non-RLS-protected rights.
- Around line 3068-3074: The role setup block for aurora_app only creates the
role when missing, so existing roles with elevated privileges are left
unchanged. Update the DO $$ BEGIN block in the aurora_app role initialization
logic to explicitly enforce NOSUPERUSER and NOBYPASSRLS for both new and
pre-existing roles, using the same pg_roles/CREATE ROLE area so SET ROLE
aurora_app cannot bypass RLS.
🪄 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: fc8c8506-445c-499d-9cf5-c76fa56e12cb

📥 Commits

Reviewing files that changed from the base of the PR and between 259b4f7 and c9ee118.

📒 Files selected for processing (2)
  • server/utils/db/connection_pool.py
  • server/utils/db/db_utils.py

Comment thread server/utils/db/connection_pool.py
Comment thread server/utils/db/connection_pool.py Outdated
Comment thread server/utils/db/db_utils.py
Comment thread server/utils/db/db_utils.py Outdated
…GUC reset

- _downgrade_role() now raises RuntimeError on failure instead of
  silently continuing with superuser (fixes cross-org leakage on
  Celery workers that start before initialize_tables)
- Reset all RLS/bypass GUCs on pool return (mcp_token_resolve,
  kubectl_token_resolve) to prevent stale bypass state leaking
- Discard (close) connection on reset failure instead of returning
  dirty connection to pool
- ALTER ROLE aurora_app NOSUPERUSER NOBYPASSRLS on every startup to
  enforce attributes even if role was previously modified
- Use least-privilege grants (SELECT/INSERT/UPDATE/DELETE) instead of
  ALL to prevent TRUNCATE bypassing RLS
- Replace empty except:pass blocks with debug logging

Co-authored-by: Cursor <cursoragent@cursor.com>

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

Comment thread server/utils/db/connection_pool.py Fixed
Comment thread server/utils/db/connection_pool.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: 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/utils/db/connection_pool.py`:
- Around line 182-190: The cleanup path in connection_pool.get_connection
currently returns from the finally-like reset block, which can swallow any
exception already propagating from the caller or from _downgrade_role. Remove
the return from the failure handling in get_connection so cleanup only
closes/notifies the pool and then lets the original exception continue; apply
the same change in get_admin_connection as well. Keep the exception logging and
pool.putconn(..., close=True) behavior, but ensure no control flow in the reset
cleanup can suppress an in-flight 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: c39a375a-d723-4b7d-b350-12725b19f62f

📥 Commits

Reviewing files that changed from the base of the PR and between c9ee118 and d816d19.

📒 Files selected for processing (2)
  • server/utils/db/connection_pool.py
  • server/utils/db/db_utils.py

Comment thread server/utils/db/connection_pool.py Outdated

@damianloch damianloch 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.

Address bot comments they are valid

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.

when a postmortem gets generated automatically (from an incident rather than someone clicking the button), this path can't tell which org it belongs to anymore once RLS is enforced, so it quietly falls back to the default instructions and skips logging the run. Its not setup to error out so it will just silently ignore any custom postmortem instructions a team has set up

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.

Good catch — addressed. _get_action_instructions() now calls set_rls_context(cur, conn, user_id) before the query, so the org is resolved from the user_id even when there's no Flask request context (i.e. Celery-triggered postmortems). The function was already in the latest commit.

Comment thread server/utils/db/connection_pool.py

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.

mcp_server.py uses its own superuser pool and never downgrades, so RLS is still fully bypassed for all MCP requests. Nothing in the PR makes it worse but just wanted to make you aware

@OlivierTrudeau OlivierTrudeau Jul 6, 2026

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.

Looked into this — it's actually fine by design. The MCP server's only direct DB access is token resolution on mcp_tokens (which uses the mcp_token_resolve GUC bypass policy specifically for that) and a SELECT 1 health check. All actual data queries go through HTTP to aurora-server, which enforces RLS. So the superuser pool here is intentional — it's the authentication layer itself, not a data access path.

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@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.

Caution

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

⚠️ Outside diff range comments (1)
server/utils/db/db_utils.py (1)

3085-3088: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fail startup when aurora_app setup fails.

Line 3086 logs and continues, but get_connection() now raises when SET ROLE aurora_app fails. If role creation/grants fail here, the server reports DB initialization success and then request-handling queries fail at checkout.

Proposed fix
             except Exception as e:
-                logging.warning(f"Error creating aurora_app role: {e}")
+                logging.error(f"FATAL: Error creating aurora_app role: {e}")
                 conn.rollback()
+                raise
🤖 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/utils/db/db_utils.py` around lines 3085 - 3088, The aurora_app setup
failure is only being logged inside the get_connection()/role initialization
path, allowing startup to continue even though later SET ROLE aurora_app checks
will fail. Update the exception handling around the aurora_app role/grant setup
to re-raise after rollback (or otherwise propagate the failure) so
initialization aborts instead of reporting success; use the existing
get_connection and aurora_app role setup block to locate the change.
♻️ Duplicate comments (1)
server/utils/db/connection_pool.py (1)

182-190: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Remove return from cleanup finally blocks.

Line 190 and Line 243 can suppress an exception already propagating from the caller or _downgrade_role(). Keep closing dirty connections, but avoid returning from finally. This also replaces the remaining empty except at Lines 239-240.

Proposed fix
             if connection:
+                reset_failed = False
                 try:
                     connection.rollback()
                     with connection.cursor() as cur:
                         cur.execute(
                             "RESET ROLE; "
@@
                     connection.commit()
                 except Exception as e:
                     logger.warning("Failed to reset session vars on pool return: %s", e)
+                    reset_failed = True
                     try:
                         pool.putconn(connection, close=True)
                     except Exception as close_exc:
                         logger.debug("Failed to close broken connection during cleanup: %s", close_exc)
                     with self._pool_available:
                         self._pool_available.notify()
-                    return
-                try:
-                    self._putconn_notify(pool, connection)
-                except Exception as e:
-                    logger.error("Error returning connection to pool: %s", e)
+                if not reset_failed:
+                    try:
+                        self._putconn_notify(pool, connection)
+                    except Exception as e:
+                        logger.error("Error returning connection to pool: %s", e)
@@
             if connection:
+                reset_failed = False
                 try:
                     connection.rollback()
                     with connection.cursor() as cur:
                         cur.execute(
                             "RESET ROLE; "
@@
                     connection.commit()
                 except Exception as e:
                     logger.warning("Failed to reset session vars on pool return: %s", e)
+                    reset_failed = True
                     try:
                         pool.putconn(connection, close=True)
-                    except Exception:
-                        pass
+                    except Exception as close_exc:
+                        logger.debug("Failed to close broken admin connection during cleanup: %s", close_exc)
                     with self._pool_available:
                         self._pool_available.notify()
-                    return
-                try:
-                    self._putconn_notify(pool, connection)
-                except Exception as e:
-                    logger.error("Error returning connection to pool: %s", e)
+                if not reset_failed:
+                    try:
+                        self._putconn_notify(pool, connection)
+                    except Exception as e:
+                        logger.error("Error returning connection to pool: %s", e)

Also applies to: 235-243

🤖 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/utils/db/connection_pool.py` around lines 182 - 190, The cleanup path
in connection_pool handling is suppressing errors by returning from a finally
block and still has an empty except around the cleanup close path. Update the
pool-return cleanup near the session reset logic and the _downgrade_role-related
cleanup so they still attempt to close dirty/broken connections, but never use
return inside finally; instead let any caller exception continue propagating
after cleanup. Also replace the remaining empty except around the close/cleanup
block with explicit logging or targeted handling using the existing logger and
pool.putconn flow.

Source: Linters/SAST tools

🤖 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.

Outside diff comments:
In `@server/utils/db/db_utils.py`:
- Around line 3085-3088: The aurora_app setup failure is only being logged
inside the get_connection()/role initialization path, allowing startup to
continue even though later SET ROLE aurora_app checks will fail. Update the
exception handling around the aurora_app role/grant setup to re-raise after
rollback (or otherwise propagate the failure) so initialization aborts instead
of reporting success; use the existing get_connection and aurora_app role setup
block to locate the change.

---

Duplicate comments:
In `@server/utils/db/connection_pool.py`:
- Around line 182-190: The cleanup path in connection_pool handling is
suppressing errors by returning from a finally block and still has an empty
except around the cleanup close path. Update the pool-return cleanup near the
session reset logic and the _downgrade_role-related cleanup so they still
attempt to close dirty/broken connections, but never use return inside finally;
instead let any caller exception continue propagating after cleanup. Also
replace the remaining empty except around the close/cleanup block with explicit
logging or targeted handling using the existing logger and pool.putconn flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3208d996-e590-4cc2-b049-fbf7269f20db

📥 Commits

Reviewing files that changed from the base of the PR and between c9ee118 and af10e2d.

📒 Files selected for processing (2)
  • server/utils/db/connection_pool.py
  • server/utils/db/db_utils.py

- Remove `return` from `finally` blocks in get_connection() and
  get_admin_connection() that could swallow in-flight exceptions
  (SonarCloud/CodeRabbit). Uses reset_failed flag instead.
- Replace empty `except Exception: pass` in admin cleanup with
  logged debug message (github-code-quality).
- Fail startup on aurora_app role setup failure instead of logging
  a warning and continuing (CodeRabbit).
- Add set_rls_context to _get_action_instructions so auto-generated
  postmortems correctly resolve org-specific custom instructions
  when running from Celery workers (damianloch).

Co-authored-by: Cursor <cursoragent@cursor.com>

@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

Caution

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

⚠️ Outside diff range comments (1)
server/utils/db/db_utils.py (1)

3077-3081: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Revoke prior aurora_app grants before re-applying the hardened set.
These GRANTs are additive, so an existing deployment can keep older table/sequence privileges unless you explicitly REVOKE first; add matching ALTER DEFAULT PRIVILEGES ... REVOKE statements too.

🤖 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/utils/db/db_utils.py` around lines 3077 - 3081, The privilege setup in
the db utility is only granting the hardened permissions and does not remove any
older aurora_app privileges. Update the same grant block in db_utils to first
REVOKE the prior table, sequence, and schema privileges from aurora_app before
re-applying the desired set, and add matching ALTER DEFAULT PRIVILEGES ...
REVOKE statements alongside the existing ALTER DEFAULT PRIVILEGES grants. Keep
the changes grouped with the current GRANT/ALTER DEFAULT PRIVILEGES logic so the
privilege reset is applied consistently during setup.
🤖 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/utils/db/db_utils.py`:
- Around line 3086-3088: The fatal startup failure in the aurora_app role
creation path is using logging.error in the exception handler, which drops the
traceback and triggers Ruff warnings. Update the error handling in the db_utils
role-creation logic to use logging.exception in the same catch block that rolls
back and re-raises, so the failure is logged with full traceback while
preserving the existing rollback and raise behavior.

---

Outside diff comments:
In `@server/utils/db/db_utils.py`:
- Around line 3077-3081: The privilege setup in the db utility is only granting
the hardened permissions and does not remove any older aurora_app privileges.
Update the same grant block in db_utils to first REVOKE the prior table,
sequence, and schema privileges from aurora_app before re-applying the desired
set, and add matching ALTER DEFAULT PRIVILEGES ... REVOKE statements alongside
the existing ALTER DEFAULT PRIVILEGES grants. Keep the changes grouped with the
current GRANT/ALTER DEFAULT PRIVILEGES logic so the privilege reset is applied
consistently during setup.
🪄 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: 0277d4da-9403-4de5-9f7c-1445f2f7b66a

📥 Commits

Reviewing files that changed from the base of the PR and between af10e2d and 5099596.

📒 Files selected for processing (3)
  • server/services/actions/postmortem_action.py
  • server/utils/db/connection_pool.py
  • server/utils/db/db_utils.py

Comment thread server/utils/db/db_utils.py Outdated
OlivierTrudeau and others added 2 commits July 6, 2026 16:11
Existing deployments could retain broader privileges from earlier runs.
REVOKE ALL before GRANTing the hardened DML-only set ensures no stale
TRUNCATE/TRIGGER/REFERENCES rights persist. Also uses logging.exception
for full traceback on role creation failure.

Co-authored-by: Cursor <cursoragent@cursor.com>
Tests now account for SET ROLE aurora_app as the first execute call
and expect the full 5-GUC reset string. Also updates the failed-reset
test to verify connections are discarded (close=True) rather than
returned to pool.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

@arvo-ai-staging arvo-ai-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Aurora Risk Review — Latest changes

Verdict: SAFE

No new incident risk in the latest changes.


Aurora reviews PRs for incident prevention.

@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

Caution

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

⚠️ Outside diff range comments (1)
server/tests/db/test_connection_pool.py (1)

237-252: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale docstring after behavior change.

The docstring at Line 238 still says "the connection is still returned," but the test body (Lines 242-252) now verifies the opposite: a failed RESET causes the connection to be discarded via putconn(connection, close=True). Given this test specifically guards the security-relevant "don't return a tainted RLS-context connection to the pool" behavior, an accurate docstring matters for future maintainers.

📝 Proposed docstring fix
     def test_failed_reset_does_not_block_putconn(self, fresh_pool, flask_app):
-        """If the RESET execute raises, the connection is still returned."""
+        """If the RESET execute raises, the connection is discarded (close=True)
+        rather than returned to the pool with stale session state."""
🤖 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/tests/db/test_connection_pool.py` around lines 237 - 252, The test
docstring in test_failed_reset_does_not_block_putconn is stale and contradicts
the assertion now being made. Update the docstring to reflect that when RESET
fails, the connection is not returned to the pool and is discarded via
putconn(..., close=True). Keep the wording aligned with the behavior exercised
in pool.get_connection and the mocked cursor.execute failure so future readers
understand the intended RLS cleanup path.
🤖 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/tests/db/test_connection_pool.py`:
- Around line 245-248: The nested context managers in the test setup should be
combined to satisfy Ruff SIM117. Update the test around
flask_app.test_request_context and pool.get_connection so both are entered in a
single with statement, keeping the same request headers and connection
acquisition behavior while removing the extra nesting.

---

Outside diff comments:
In `@server/tests/db/test_connection_pool.py`:
- Around line 237-252: The test docstring in
test_failed_reset_does_not_block_putconn is stale and contradicts the assertion
now being made. Update the docstring to reflect that when RESET fails, the
connection is not returned to the pool and is discarded via putconn(...,
close=True). Keep the wording aligned with the behavior exercised in
pool.get_connection and the mocked cursor.execute failure so future readers
understand the intended RLS cleanup path.
🪄 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: dbfb5885-fb96-48b1-a00f-8eaa7763061a

📥 Commits

Reviewing files that changed from the base of the PR and between 5099596 and 8373abd.

📒 Files selected for processing (2)
  • server/tests/db/test_connection_pool.py
  • server/utils/db/db_utils.py

Comment on lines 245 to 248
with flask_app.test_request_context(
"/api/x", headers={"X-User-ID": "u-1", "X-Org-ID": "org-7"},
):
with pool.get_connection() as conn:

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Combine nested with statements.

Ruff SIM117 flags this nested with as combinable.

♻️ Proposed fix
-        with flask_app.test_request_context(
-            "/api/x", headers={"X-User-ID": "u-1", "X-Org-ID": "org-7"},
-        ):
-            with pool.get_connection() as conn:
-                assert conn is connection
+        with (
+            flask_app.test_request_context(
+                "/api/x", headers={"X-User-ID": "u-1", "X-Org-ID": "org-7"},
+            ),
+            pool.get_connection() as conn,
+        ):
+            assert conn is connection
📝 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
with flask_app.test_request_context(
"/api/x", headers={"X-User-ID": "u-1", "X-Org-ID": "org-7"},
):
with pool.get_connection() as conn:
with (
flask_app.test_request_context(
"/api/x", headers={"X-User-ID": "u-1", "X-Org-ID": "org-7"},
),
pool.get_connection() as conn,
):
assert conn is connection
🧰 Tools
🪛 Ruff (0.15.20)

[warning] 245-248: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

🤖 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/tests/db/test_connection_pool.py` around lines 245 - 248, The nested
context managers in the test setup should be combined to satisfy Ruff SIM117.
Update the test around flask_app.test_request_context and pool.get_connection so
both are entered in a single with statement, keeping the same request headers
and connection acquisition behavior while removing the extra nesting.

Source: Linters/SAST tools

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.

2 participants