Skip to content

Fix/backend p0 audit - #6602

Open
shafeeq27edu-ai wants to merge 21 commits into
Agenta-AI:mainfrom
shafeeq27edu-ai:fix/backend-p0-audit
Open

Fix/backend p0 audit#6602
shafeeq27edu-ai wants to merge 21 commits into
Agenta-AI:mainfrom
shafeeq27edu-ai:fix/backend-p0-audit

Conversation

@shafeeq27edu-ai

Copy link
Copy Markdown
Contributor

Summary

What changed & Why it was needed:

  • Validation: Replaced assert statements in user_profile.py, permissions/service.py, and db_manager.py with explicit HTTPException, ValueError, and TypeError exceptions. assert statements are stripped out in optimized Python environments (-O), bypassing critical authorization and input validation checks.
  • Data Mutation: Updated the intercept_exceptions decorator in exceptions.py to use kwargs.get("request") instead of kwargs.pop("request"). The pop() method was destructively mutating the request dictionary, breaking downstream processes that relied on the request object.
  • Error Handling: Updated the delete_api_key endpoint in api_key_router.py to correctly catch sqlalchemy.exc.NoResultFound instead of KeyError. This ensures the endpoint returns a proper 404 Not Found instead of a 500 Internal Server Error when deleting non-existent keys.
  • Configuration: Replaced raw os.getenv("AGENTA_DEMOS") in commoners.py with the type-safe env.agenta.extras.demos object to align with repository standards and prevent runtime configuration issues.

Testing

Verified locally

  • Ran the api test suite locally using uv run --no-sync pytest to ensure these fixes did not break existing catalog or entrypoint logic.
  • Executed ruff check and ruff format to verify Python linting and code style compliance.

Added or updated tests

N/A

QA follow-up

N/A

Demo

image

AFTER FIX :

image

Checklist

  • Demo shows the real app running this branch (not a mock-up or recreated UI), or is marked N/A
  • Relevant tests pass locally
  • Relevant linting and formatting pass locally
  • I have signed the CLA, or I will sign it when the bot prompts me

Contributor Resources

Patches oss.src.services.user_service.create_reset_password_link
instead of supertokens_python... source module. The service imports
the function by name, so patching the source module does not
intercept the local binding.

All 4 IDOR tests pass. Full access test suite: 12/12 passing.
Keeps both:
- Main's new organization owner password-reset guard
- Our IDOR fix: PermissionError/NoResultFound handling
The merge added new DB calls (get_project_by_id, get_organization_owner)
to the router and changed the import structure. Updated mock patches:

- Fixed create_reset_password_link patch target to match post-merge import
- Added mocks for db_manager.get_project_by_id
- Added mocks for db_manager.get_organization_owner
- Verified all 4 IDOR tests pass without real network calls
… reset

Adds organization membership check in generate_user_password_reset_link
using db_manager.get_user_org_and_workspace_id BEFORE get_user_with_id.
Raises PermissionError when target user belongs to a different org,
which the router catches and returns 403.

Fixes test_cross_org_reset_returns_403 to mock org mismatch path.
Adds org membership check before get_user_with_id in generate_user_password_reset_link.
Updates tests to mock get_user_org_and_workspace_id for cross-org/same-org paths.
Ensures get_user_org_and_workspace_id is called before get_user_with_id.
Raises PermissionError on org mismatch. Updates tests to mock org check correctly.
…t tests

The router now reads request.state.organization_id for the cross-org check.
All test request mocks must include this attribute.
The test asserts 'permission' appears in the 403 detail text.
The PermissionError message and the router's hardcoded detail both
now include the word 'permission', matching the convention used by
every other permission-denied response in user_profile.py.

No logic, status-code, or exception-type changes — wording only.
get_user_org_and_workspace_id() returns a dict with an organization_ids list, not a 2-tuple. The previous tuple-unpacking silently bound target_org_id to the literal key name id, causing every same-organization password reset to be incorrectly rejected with 403. Fixed to check membership against organization_ids, and updated test mocks to match the real return shape.
@vercel

vercel Bot commented Sep 6, 2026

Copy link
Copy Markdown

@shafeeq27edu-ai is attempting to deploy a commit to the agenta projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Sep 6, 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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 0b413e26-8265-4bc4-8987-2e7921fbf131

📥 Commits

Reviewing files that changed from the base of the PR and between 92aafb1 and fe1ff42.

📒 Files selected for processing (1)
  • api/oss/tests/pytest/unit/access/test_reset_password_idor.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Bug Fixes

    • Improved authorization for password-reset requests by preventing cross-organization and unauthorized access.
    • Standardized responses for missing users and invalid API keys, including clearer 404 and 403 outcomes.
    • Prevented user and permission lookup errors from producing misleading responses.
    • Improved validation error handling for permission and role checks.
  • Configuration

    • Demo project listings now use centralized application configuration.
  • Tests

    • Added coverage for password-reset authorization, missing users, permission denial, and organization isolation.

Walkthrough

The changes add organization-based authorization to password-reset links, standardize missing-user responses, replace assertion validation with explicit exceptions, correct API key not-found handling, and load demo IDs from centralized configuration.

Changes

Password reset authorization

Layer / File(s) Summary
Password reset authorization flow
api/oss/src/routers/user_profile.py, api/oss/src/services/user_service.py, api/oss/tests/pytest/unit/access/test_reset_password_idor.py
The reset handler passes the caller organization to the service. The service checks target-user organization membership before generating a link. Tests cover allowed, denied, missing-user, missing-permission, and service-call signature cases.
User profile not-found handling
api/oss/src/routers/user_profile.py, api/oss/tests/pytest/unit/access/test_reset_password_idor.py
User profile lookup catches NoResultFound and returns a 404 response. The test verifies the response for a missing authenticated user.

Runtime error handling and configuration

Layer / File(s) Summary
Explicit permission validation
api/oss/src/core/access/permissions/service.py
Permission checks now raise explicit ValueError and TypeError exceptions instead of using assert.
API key deletion handling
api/oss/src/routers/api_key_router.py
API key deletion catches NoResultFound and preserves the 404 response for missing or unauthorized keys.
Centralized demo configuration
api/oss/src/services/commoners.py
list_all_demos reads demo project IDs from env.agenta.extras.demos instead of the AGENTA_DEMOS environment variable.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to fe1ff

Password resets now enforce organization boundaries and return consistent denial responses, while related validation and missing-resource handling are explicit. The covered behavior is ready to merge with no identified current-head risk.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant UserProfileRouter
  participant UserService
  participant DBManager
  Caller->>UserProfileRouter: request password-reset link
  UserProfileRouter->>UserService: pass target user and caller organization
  UserService->>DBManager: load target-user organization IDs
  DBManager-->>UserService: return organization IDs
  UserService-->>UserProfileRouter: return link or authorization error
  UserProfileRouter-->>Caller: return reset link or 403 response
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.78% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 8 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title identifies a backend audit but is too vague to communicate the primary changes, such as authorization fixes, explicit validation errors, and corrected exception handling. Replace the title with a specific summary of the main changes, such as "Fix backend authorization and validation issues".
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly covers backend validation, authorization, exception handling, configuration, and testing changes related to the pull request.
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 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 1f540dad-4451-4539-aaf1-5a431d097f27

📥 Commits

Reviewing files that changed from the base of the PR and between b7f21ec and d12b125.

📒 Files selected for processing (8)
  • api/oss/src/core/access/permissions/service.py
  • api/oss/src/routers/api_key_router.py
  • api/oss/src/routers/user_profile.py
  • api/oss/src/services/commoners.py
  • api/oss/src/services/db_manager.py
  • api/oss/src/services/user_service.py
  • api/oss/src/utils/exceptions.py
  • api/oss/tests/pytest/unit/access/test_reset_password_idor.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread api/oss/src/routers/user_profile.py Outdated

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks for the pr. i found one additional behavior gap that needs a change before qa. the existing exact-head security finding also remains open.

Comment thread api/oss/src/routers/user_profile.py Outdated
…umeration leak

- Resolve user_profile.py merge conflict: keep status_code=404 (fix/backend-p0-audit), discard 400 (main)
- Fix latent bug: get_user_with_id raises NoResultFound, never returns None. Wrap in try/except so a stale/deleted user_id returns 404 instead of crashing 500
- Fix user-enumeration leak: collapse PermissionError and NoResultFound handlers in reset_user_password to a single 403 response — callers can no longer distinguish 'user in another org' from 'user does not exist'
- Update test 3 to assert 403 (was 404) with permission-denied body
- Add test 5 for user_profile() missing-user → 404 via NoResultFound
@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

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

🧹 Nitpick comments (1)
api/oss/tests/pytest/unit/access/test_reset_password_idor.py (1)

18-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove redundant section comments.

Keep the module docstring that explains the security regression. Remove structural headings such as “Helpers”, “Fixtures”, and test-number banners. The declarations already show this structure.

Also applies to: 33-35, 65-67, 90-92, 138-140, 214-216, 261-263, 282-284

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: f2ff2d13-e253-498c-ad08-5532b609aa80

📥 Commits

Reviewing files that changed from the base of the PR and between b7f21ec and aa87c20.

📒 Files selected for processing (6)
  • api/oss/src/core/access/permissions/service.py
  • api/oss/src/routers/api_key_router.py
  • api/oss/src/routers/user_profile.py
  • api/oss/src/services/commoners.py
  • api/oss/src/services/user_service.py
  • api/oss/tests/pytest/unit/access/test_reset_password_idor.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • api/oss/src/services/commoners.py
  • api/oss/src/core/access/permissions/service.py
  • api/oss/src/services/user_service.py
  • api/oss/src/routers/api_key_router.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

@mmabrouk mmabrouk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks for the update. the two earlier findings are fixed, but this follow-up still has one runtime failure that needs a change before qa.

Comment thread api/oss/src/services/user_service.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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Team

Run ID: 9bbc5101-ed19-4056-b6d1-6fb917f52308

📥 Commits

Reviewing files that changed from the base of the PR and between f45b9f4 and 92aafb1.

📒 Files selected for processing (2)
  • api/oss/src/services/user_service.py
  • api/oss/tests/pytest/unit/access/test_reset_password_idor.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread api/oss/src/services/user_service.py
Comment thread api/oss/src/services/user_service.py
@shafeeq27edu-ai

Copy link
Copy Markdown
Contributor Author

@mmabrouk — CI's run-api-unit-tests check is failing on this PR, but the 5 failures are all in sessions/ (test_execution_watchdog.py, test_interaction_continuation_admission.py, test_records_mapping_upsert.py), none of which I've touched in this PR's commits.

Traced the root cause: a DAO change (.scalar_one_or_none() added to the sequenced-append path in dao.py, from a main merge) that the test fakes — specifically _FakeResult in test_records_mapping_upsert.py — weren't updated to implement. Same class of mock/signature drift as the user_uid issue you caught earlier, just in code outside this PR's scope.

I can write the fix (add scalar_one_or_none to the fake, matching the real DAO signature) if that's useful, but wanted to check first since it's unrelated to the P0 audit this PR is meant to cover — didn't want to expand scope into sessions/ code without your call. Let me know if you'd rather this land here or in a separate PR.

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