From 2e19085875f2cb9c9bcbe678acaba76a2c623c45 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 6 Jul 2026 13:33:42 +0000 Subject: [PATCH] =?UTF-8?q?HubSpot=20failures=20surface=20without=20the=20?= =?UTF-8?q?response=20body=20that=20echoes=20tenant=20PII=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .../test_tenant_data_sync_orchestrator.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/orchestration/test_tenant_data_sync_orchestrator.py b/tests/orchestration/test_tenant_data_sync_orchestrator.py index 798b82d74..40b4c34da 100644 --- a/tests/orchestration/test_tenant_data_sync_orchestrator.py +++ b/tests/orchestration/test_tenant_data_sync_orchestrator.py @@ -1,3 +1,5 @@ +import json +import traceback import xml.etree.ElementTree as ET from pathlib import Path from unittest.mock import MagicMock, patch @@ -5,6 +7,7 @@ from unittest.mock import MagicMock, patch import pytest import requests from hubspot.crm.associations.v4 import AssociationSpec # type: ignore[reportMissingTypeStubs] +from hubspot.crm.contacts import ApiException as ContactsApiException # type: ignore[reportMissingTypeStubs] from hubspot.crm.contacts import SimplePublicObjectInputForCreate # type: ignore[reportMissingTypeStubs] from domain.abri.models import AbriRequestRejected, PlaceRef @@ -420,3 +423,47 @@ def test_run_raises_a_transport_error_when_the_relay_is_unreachable( with pytest.raises(AbriTransportError): orchestrator.run(PLACE_REF, deal_id=DEAL_ID) assert sdk_client.mock_calls == [] + + +# --- HubSpot failures: scrubbed of response bodies, which can echo PII --- + + +def _pii_echoing_api_error() -> ContactsApiException: + """A HubSpot validation error whose body echoes the submitted PII.""" + api_error = ContactsApiException(status=400, reason="Bad Request") + api_error.body = json.dumps( + { + "status": "error", + "message": 'Invalid value "09853460810" for mobilephone (Amanjeet Okello)', + "correlationId": "corr-abc-123", + "category": "VALIDATION_ERROR", + } + ) + api_error.headers = {} + return api_error + + +def test_run_raises_an_error_scrubbed_of_the_hubspot_response_body( + orchestrator: TenantDataSyncOrchestrator, + mock_session: MagicMock, + sdk_client: MagicMock, +) -> None: + # Arrange + mock_session.post.return_value.content = _tenancy_response( + '136847309853460810' + ) + sdk_client.crm.contacts.basic_api.create.side_effect = _pii_echoing_api_error() + + # Act + with pytest.raises(Exception) as exc_info: + orchestrator.run(PLACE_REF, deal_id=DEAL_ID) + + # Assert: non-PII diagnostics survive; the echoed body does not + rendered_traceback = "".join(traceback.format_exception(exc_info.value)) + assert "400" in str(exc_info.value) + assert "VALIDATION_ERROR" in str(exc_info.value) + assert "corr-abc-123" in str(exc_info.value) + assert "Amanjeet" not in rendered_traceback + assert "Okello" not in rendered_traceback + assert "09853460810" not in rendered_traceback