Skip to content

Conversation

@max-svistunov
Copy link
Contributor

@max-svistunov max-svistunov commented Jan 15, 2026

Description

Before storing feedback, validate that convo exists & belongs to user

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: Claude Opus 4.5
  • Generated by: Claude Opus 4.5

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.
  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

Summary by CodeRabbit

  • Bug Fixes

    • Feedback submission now validates conversation existence and ownership, returning 404 for missing conversations and 403 for conversations owned by other users.
  • Tests

    • End-to-end scenarios updated to cover non-existent and cross-user conversation cases.
    • Unit and e2e test steps added to simulate conversations owned by a different user.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

Walkthrough

Adds conversation existence and ownership validation to the feedback submission endpoint: the endpoint now retrieves the conversation by ID, returns 404 if missing, returns 403 if owned by a different user, and only stores feedback after these checks. Tests and E2E steps were updated to exercise these cases.

Changes

Cohort / File(s) Summary
Feedback endpoint
src/app/endpoints/feedback.py
Calls retrieve_conversation before storing feedback; returns 404 when not found and 403 when the conversation belongs to another user.
E2E feature scenarios
tests/e2e/features/feedback.feature
Updated nonexistent-conversation scenario to expect 404 and detailed error; added scenario for feedback against a conversation owned by a different user (expects 403).
E2E step implementations
tests/e2e/features/steps/feedback.py
Added initialize_conversation_different_user() step that creates a conversation under an alternate auth context to test ownership/permission checks.
Unit tests
tests/unit/app/endpoints/test_feedback.py
Mocked retrieve_conversation in multiple tests and aligned feedback_request.conversation_id to the mocked conversation to exercise ownership path in unit tests.

Sequence Diagram(s)

sequenceDiagram
  actor Client
  participant FeedbackAPI as Feedback Endpoint
  participant Retriever as Conversation Retriever
  participant Auth as Auth/User Context
  participant Store as Feedback Store

  Client->>FeedbackAPI: POST /feedback (conversation_id, feedback)
  FeedbackAPI->>Auth: determine request user_id
  FeedbackAPI->>Retriever: retrieve_conversation(conversation_id)
  alt conversation not found
    Retriever-->>FeedbackAPI: not found
    FeedbackAPI-->>Client: 404 Conversation not found
  else conversation found
    Retriever-->>FeedbackAPI: conversation (with owner_id)
    FeedbackAPI->>Auth: compare owner_id vs requester user_id
    alt owner mismatch
      FeedbackAPI-->>Client: 403 Forbidden (permission denied)
    else owner matches
      FeedbackAPI->>Store: persist feedback
      Store-->>FeedbackAPI: success
      FeedbackAPI-->>Client: 200/201 OK
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • tisnik
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: adding validation that conversations exist and belong to the user before storing feedback.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 719977e and 552bb04.

📒 Files selected for processing (2)
  • src/app/endpoints/feedback.py
  • tests/unit/app/endpoints/test_feedback.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/endpoints/feedback.py
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use absolute imports for internal modules: from authentication import get_auth_dependency
Use FastAPI dependencies: from fastapi import APIRouter, HTTPException, Request, status, Depends
Use Llama Stack imports: from llama_stack_client import AsyncLlamaStackClient
Check constants.py for shared constants before defining new ones
All modules start with descriptive docstrings explaining purpose
Use logger = logging.getLogger(__name__) pattern for module logging
Type aliases defined at module level for clarity
All functions require docstrings with brief descriptions
Complete type annotations for function parameters and return types, using typing_extensions.Self for model validators
Use union types with modern syntax: str | int instead of Union[str, int]
Use Optional[Type] for optional parameters
Use snake_case with descriptive, action-oriented function names (get_, validate_, check_)
Avoid in-place parameter modification anti-patterns; return new data structures instead
Use async def for I/O operations and external API calls
Handle APIConnectionError from Llama Stack in error handling
Use logger.debug() for detailed diagnostic information
Use logger.info() for general information about program execution
Use logger.warning() for unexpected events or potential problems
Use logger.error() for serious problems that prevented function execution
All classes require descriptive docstrings explaining purpose
Use PascalCase for class names with descriptive names and standard suffixes: Configuration, Error/Exception, Resolver, Interface
Use ABC for abstract base classes with @abstractmethod decorators
Complete type annotations for all class attributes
Follow Google Python docstring conventions (https://google.github.io/styleguide/pyguide.html) with sections: Args, Returns, Raises, Attributes
Run uv run make format to auto-format code with black and ruff before completion
Run uv run make verify to run all linters (black, pyl...

Files:

  • tests/unit/app/endpoints/test_feedback.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest for all unit and integration tests, not unittest
Use pytest-mock for AsyncMock objects in tests
Use MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token") pattern for authentication mocks in tests

Files:

  • tests/unit/app/endpoints/test_feedback.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/unit/**/*.py: Unit tests require 60% code coverage
Write unit tests covering new functionality before completion

Files:

  • tests/unit/app/endpoints/test_feedback.py
🧠 Learnings (1)
📚 Learning: 2026-01-11T16:30:41.784Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:30:41.784Z
Learning: Applies to tests/**/*.py : Use `MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token")` pattern for authentication mocks in tests

Applied to files:

  • tests/unit/app/endpoints/test_feedback.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: list_outdated_dependencies
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-on-pull-request
  • GitHub Check: E2E: server mode / ci
  • GitHub Check: E2E: library mode / ci
🔇 Additional comments (3)
tests/unit/app/endpoints/test_feedback.py (3)

105-115: LGTM!

The mock setup correctly aligns the conversation's user_id with the auth tuple's user ID ("test_user_id"), ensuring the ownership check passes. The conversation_id assignment on line 115 properly links the request to the mocked conversation.


137-143: LGTM!

The mock correctly sets up conversation ownership to pass validation, allowing the test to focus on verifying the OSError handling behavior.


319-325: LGTM!

The mock correctly uses "mock_user_id" which matches MOCK_AUTH[0], ensuring consistency with the auth tuple used at line 330. This follows the recommended MOCK_AUTH pattern from the coding guidelines.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

Copy link
Contributor

@tisnik tisnik left a comment

Choose a reason for hiding this comment

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

LGTM

Apply CodeRabbit suggestion to combine two DB queries into one by checking
conversation.user_id directly instead of calling validate_conversation_ownership.

Update unit tests to mock retrieve_conversation to avoid database initialization
errors during testing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
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: 0

Caution

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

⚠️ Outside diff range comments (1)
tests/unit/app/endpoints/test_feedback.py (1)

105-143: Missing test coverage for conversation validation error cases.

The PR adds validation that returns 404 when conversation doesn't exist and 403 when conversation belongs to a different user, but no tests cover these error paths. Per coding guidelines, unit tests should cover new functionality.

Consider adding tests for the new validation logic:

`@pytest.mark.asyncio`
async def test_feedback_endpoint_handler_conversation_not_found(
    mocker: MockerFixture,
) -> None:
    """Test that feedback_endpoint_handler returns 404 when conversation doesn't exist."""
    mock_authorization_resolvers(mocker)
    mocker.patch("app.endpoints.feedback.assert_feedback_enabled", return_value=None)
    mocker.patch("app.endpoints.feedback.retrieve_conversation", return_value=None)

    feedback_request = mocker.Mock()
    feedback_request.conversation_id = "12345678-abcd-0000-0123-456789abcdef"
    auth: AuthTuple = ("test_user_id", "test_user", True, "test_token")

    with pytest.raises(HTTPException) as exc_info:
        await feedback_endpoint_handler(
            feedback_request=feedback_request,
            _ensure_feedback_enabled=assert_feedback_enabled,
            auth=auth,
        )
    assert exc_info.value.status_code == status.HTTP_404_NOT_FOUND


`@pytest.mark.asyncio`
async def test_feedback_endpoint_handler_conversation_wrong_owner(
    mocker: MockerFixture,
) -> None:
    """Test that feedback_endpoint_handler returns 403 when conversation belongs to different user."""
    mock_authorization_resolvers(mocker)
    mocker.patch("app.endpoints.feedback.assert_feedback_enabled", return_value=None)

    mock_conversation = mocker.Mock()
    mock_conversation.user_id = "different_user_id"
    mocker.patch(
        "app.endpoints.feedback.retrieve_conversation", return_value=mock_conversation
    )

    feedback_request = mocker.Mock()
    feedback_request.conversation_id = "12345678-abcd-0000-0123-456789abcdef"
    auth: AuthTuple = ("test_user_id", "test_user", True, "test_token")

    with pytest.raises(HTTPException) as exc_info:
        await feedback_endpoint_handler(
            feedback_request=feedback_request,
            _ensure_feedback_enabled=assert_feedback_enabled,
            auth=auth,
        )
    assert exc_info.value.status_code == status.HTTP_403_FORBIDDEN
#!/bin/bash
# Verify the production code has 404 and 403 error handling that needs test coverage
rg -n "HTTP_404_NOT_FOUND|HTTP_403_FORBIDDEN" src/app/endpoints/feedback.py
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 719977e and 552bb04.

📒 Files selected for processing (2)
  • src/app/endpoints/feedback.py
  • tests/unit/app/endpoints/test_feedback.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/endpoints/feedback.py
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use absolute imports for internal modules: from authentication import get_auth_dependency
Use FastAPI dependencies: from fastapi import APIRouter, HTTPException, Request, status, Depends
Use Llama Stack imports: from llama_stack_client import AsyncLlamaStackClient
Check constants.py for shared constants before defining new ones
All modules start with descriptive docstrings explaining purpose
Use logger = logging.getLogger(__name__) pattern for module logging
Type aliases defined at module level for clarity
All functions require docstrings with brief descriptions
Complete type annotations for function parameters and return types, using typing_extensions.Self for model validators
Use union types with modern syntax: str | int instead of Union[str, int]
Use Optional[Type] for optional parameters
Use snake_case with descriptive, action-oriented function names (get_, validate_, check_)
Avoid in-place parameter modification anti-patterns; return new data structures instead
Use async def for I/O operations and external API calls
Handle APIConnectionError from Llama Stack in error handling
Use logger.debug() for detailed diagnostic information
Use logger.info() for general information about program execution
Use logger.warning() for unexpected events or potential problems
Use logger.error() for serious problems that prevented function execution
All classes require descriptive docstrings explaining purpose
Use PascalCase for class names with descriptive names and standard suffixes: Configuration, Error/Exception, Resolver, Interface
Use ABC for abstract base classes with @abstractmethod decorators
Complete type annotations for all class attributes
Follow Google Python docstring conventions (https://google.github.io/styleguide/pyguide.html) with sections: Args, Returns, Raises, Attributes
Run uv run make format to auto-format code with black and ruff before completion
Run uv run make verify to run all linters (black, pyl...

Files:

  • tests/unit/app/endpoints/test_feedback.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest for all unit and integration tests, not unittest
Use pytest-mock for AsyncMock objects in tests
Use MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token") pattern for authentication mocks in tests

Files:

  • tests/unit/app/endpoints/test_feedback.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/unit/**/*.py: Unit tests require 60% code coverage
Write unit tests covering new functionality before completion

Files:

  • tests/unit/app/endpoints/test_feedback.py
🧠 Learnings (1)
📚 Learning: 2026-01-11T16:30:41.784Z
Learnt from: CR
Repo: lightspeed-core/lightspeed-stack PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T16:30:41.784Z
Learning: Applies to tests/**/*.py : Use `MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token")` pattern for authentication mocks in tests

Applied to files:

  • tests/unit/app/endpoints/test_feedback.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: list_outdated_dependencies
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-on-pull-request
  • GitHub Check: E2E: server mode / ci
  • GitHub Check: E2E: library mode / ci
🔇 Additional comments (3)
tests/unit/app/endpoints/test_feedback.py (3)

105-115: LGTM!

The mock setup correctly aligns the conversation's user_id with the auth tuple's user ID ("test_user_id"), ensuring the ownership check passes. The conversation_id assignment on line 115 properly links the request to the mocked conversation.


137-143: LGTM!

The mock correctly sets up conversation ownership to pass validation, allowing the test to focus on verifying the OSError handling behavior.


319-325: LGTM!

The mock correctly uses "mock_user_id" which matches MOCK_AUTH[0], ensuring consistency with the auth tuple used at line 330. This follows the recommended MOCK_AUTH pattern from the coding guidelines.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.



@given("A conversation owned by a different user is initialized") # type: ignore
def initialize_conversation_different_user(context: Context) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

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

move this into test steps within the feature file, this test step should not be needed at all

user_id, _, _, _ = auth
check_configuration_loaded(configuration)

# Validate conversation exists and belongs to the user
Copy link
Contributor

Choose a reason for hiding this comment

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

this new logic should also be unit tested

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