From 88cbbbf12cc39eaeb8780cf9d6a78c27b2989bc5 Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Fri, 17 Jul 2026 03:59:18 +0000 Subject: [PATCH 1/2] CodeRabbit Generated Unit Tests: Generate Unit Tests for PR Changes --- tests/unit/test_cloud_routes.py | 113 +++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_cloud_routes.py b/tests/unit/test_cloud_routes.py index 4c3b29839..857d7749e 100644 --- a/tests/unit/test_cloud_routes.py +++ b/tests/unit/test_cloud_routes.py @@ -1316,7 +1316,11 @@ def test_generate_dashboard_url_service_error(self): } ) assert response.status_code == 500 - assert "Internal server error" in response.json()["detail"] + # The 500 body must be sanitized (CWE-209): a static message, never the + # caught exception text. See reporting_routes.generate_dashboard_url. + detail = response.json()["detail"] + assert detail == "Internal server error" + assert "Looker unavailable" not in detail def test_generate_dashboard_url_missing_fields(self): """Missing required fields return 422.""" @@ -1330,3 +1334,110 @@ def test_generate_dashboard_url_missing_fields(self): # missing tenant_id, user_id, user_email }) assert response.status_code == 422 + + # -------- CWE-209: additional coverage for sanitized 500 detail -------- + + @pytest.mark.parametrize( + "exc", + [ + Exception("Looker unavailable"), + ValueError("db_password=super-secret-123"), + KeyError("client_secret"), + RuntimeError("Traceback (most recent call last): connection to 10.0.0.5:5432 refused"), + Exception(""), + ], + ids=["generic", "value_error_with_secret", "key_error", "runtime_error_with_internals", "empty_message"], + ) + def test_generate_dashboard_url_error_detail_always_sanitized(self, exc): + """Regardless of exception type or message content, the 500 detail + returned to the client must always be the static generic string and + must never contain any fragment of the original exception text.""" + mock_service = MagicMock() + mock_service.get_tenant_dashboard_url = MagicMock(side_effect=exc) + + response = self._client_with_looker(mock_service).post( + "/api/v1/reporting/embed/dashboard", + json={ + "dashboard_id": "cost_usage", + "tenant_id": "tenant-xyz", + "user_id": "user-001", + "user_email": "bob@example.com", + } + ) + assert response.status_code == 500 + body = response.json() + assert body == {"detail": "Internal server error"} + exc_text = str(exc) + if exc_text: + assert exc_text not in body["detail"] + + def test_generate_dashboard_url_error_logs_original_exception(self): + """The original exception must still be logged server-side (with + traceback) even though it is withheld from the HTTP response, so + operators retain the ability to debug failures.""" + mock_service = MagicMock() + mock_service.get_tenant_dashboard_url = MagicMock( + side_effect=Exception("Looker unavailable") + ) + + import youtube_extension.backend.api.reporting_routes as _reporting_mod + + with patch.object(_reporting_mod, "logger") as mock_logger: + response = self._client_with_looker(mock_service).post( + "/api/v1/reporting/embed/dashboard", + json={ + "dashboard_id": "cost_usage", + "tenant_id": "tenant-xyz", + "user_id": "user-001", + "user_email": "bob@example.com", + } + ) + + assert response.status_code == 500 + assert response.json()["detail"] == "Internal server error" + mock_logger.error.assert_called_once() + args, kwargs = mock_logger.error.call_args + assert "Looker unavailable" in args[0] + assert kwargs.get("exc_info") is True + + def test_generate_dashboard_url_error_response_has_no_extra_keys(self): + """The sanitized error body must only expose the `detail` field and + must not leak `embed_url` or any other internal data on failure.""" + mock_service = MagicMock() + mock_service.get_tenant_dashboard_url = MagicMock( + side_effect=Exception("Looker unavailable") + ) + + response = self._client_with_looker(mock_service).post( + "/api/v1/reporting/embed/dashboard", + json={ + "dashboard_id": "cost_usage", + "tenant_id": "tenant-xyz", + "user_id": "user-001", + "user_email": "bob@example.com", + } + ) + assert response.status_code == 500 + assert set(response.json().keys()) == {"detail"} + + def test_generate_dashboard_url_success_after_prior_error(self): + """A subsequent successful call on a fresh client is unaffected by a + previous failure - the sanitized error path has no lingering state.""" + mock_service = MagicMock() + mock_service.get_tenant_dashboard_url = MagicMock( + return_value="https://looker.example.com/embed/dashboards/2?sig=def" + ) + + response = self._client_with_looker(mock_service).post( + "/api/v1/reporting/embed/dashboard", + json={ + "dashboard_id": "video_analytics", + "tenant_id": "tenant-xyz", + "user_id": "user-002", + "user_email": "carol@example.com", + } + ) + assert response.status_code == 200 + assert response.json() == { + "embed_url": "https://looker.example.com/embed/dashboards/2?sig=def" + } From b86050a7d8ab5a009307240a8e04129e48b946fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 04:27:08 +0000 Subject: [PATCH 2/2] fix: fix test_generate_dashboard_url_success_after_prior_error to issue failing then successful request through same client --- tests/unit/test_cloud_routes.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/tests/unit/test_cloud_routes.py b/tests/unit/test_cloud_routes.py index 857d7749e..5c37d096b 100644 --- a/tests/unit/test_cloud_routes.py +++ b/tests/unit/test_cloud_routes.py @@ -1421,14 +1421,34 @@ def test_generate_dashboard_url_error_response_has_no_extra_keys(self): assert set(response.json().keys()) == {"detail"} def test_generate_dashboard_url_success_after_prior_error(self): - """A subsequent successful call on a fresh client is unaffected by a - previous failure - the sanitized error path has no lingering state.""" + """A subsequent successful call through the same client is unaffected by + a prior failure - the sanitized error path leaves no lingering state.""" mock_service = MagicMock() mock_service.get_tenant_dashboard_url = MagicMock( - return_value="https://looker.example.com/embed/dashboards/2?sig=def" + side_effect=[ + Exception("Looker unavailable"), + "https://looker.example.com/embed/dashboards/2?sig=def", + ] ) - response = self._client_with_looker(mock_service).post( + client = self._client_with_looker(mock_service) + + # First request: the service raises, so we expect a sanitized 500. + error_response = client.post( + "/api/v1/reporting/embed/dashboard", + json={ + "dashboard_id": "cost_usage", + "tenant_id": "tenant-xyz", + "user_id": "user-001", + "user_email": "bob@example.com", + } + ) + assert error_response.status_code == 500 + assert error_response.json() == {"detail": "Internal server error"} + + # Second request: the service now returns a URL - success must not be + # blocked by any state left over from the previous failure. + ok_response = client.post( "/api/v1/reporting/embed/dashboard", json={ "dashboard_id": "video_analytics", @@ -1437,7 +1457,7 @@ def test_generate_dashboard_url_success_after_prior_error(self): "user_email": "carol@example.com", } ) - assert response.status_code == 200 - assert response.json() == { + assert ok_response.status_code == 200 + assert ok_response.json() == { "embed_url": "https://looker.example.com/embed/dashboards/2?sig=def" }