From 715a22ff71097300bdaadb53fdf237b600c161eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Far=C3=ADas=20Santana?= Date: Tue, 31 Dec 2024 11:25:10 +0100 Subject: [PATCH 1/3] fix(batch-exports): Remove zero unicode from error message --- posthog/temporal/batch_exports/batch_exports.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/posthog/temporal/batch_exports/batch_exports.py b/posthog/temporal/batch_exports/batch_exports.py index 1b8faf19e482e..8d85d1174fb74 100644 --- a/posthog/temporal/batch_exports/batch_exports.py +++ b/posthog/temporal/batch_exports/batch_exports.py @@ -902,6 +902,14 @@ async def finish_batch_export_run(inputs: FinishBatchExportRunInputs) -> None: for key, value in dataclasses.asdict(inputs).items() if key not in not_model_params and value is not None } + + latest_error = update_params.get("latest_error", None) + if latest_error is not None and isinstance(latest_error, str): + # NUL (\x00) bytes are not allowed in PostgreSQL, so we replace them from + # the free text field `latest_error`. + latest_error = latest_error.replace("\x00", "") + update_params["latest_error"] = latest_error + batch_export_run = await database_sync_to_async(update_batch_export_run)( run_id=uuid.UUID(inputs.id), finished_at=dt.datetime.now(dt.UTC), From 976a6ca56b8daa352ac760f9a3d73e306e3bf999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Far=C3=ADas=20Santana?= Date: Tue, 31 Dec 2024 11:32:28 +0100 Subject: [PATCH 2/3] test(batch-exports): Add test for nul bytes in finish_batch_export_run --- .../temporal/batch_exports/batch_exports.py | 2 +- .../tests/batch_exports/test_run_updates.py | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/posthog/temporal/batch_exports/batch_exports.py b/posthog/temporal/batch_exports/batch_exports.py index 8d85d1174fb74..e9f9288688dc2 100644 --- a/posthog/temporal/batch_exports/batch_exports.py +++ b/posthog/temporal/batch_exports/batch_exports.py @@ -905,7 +905,7 @@ async def finish_batch_export_run(inputs: FinishBatchExportRunInputs) -> None: latest_error = update_params.get("latest_error", None) if latest_error is not None and isinstance(latest_error, str): - # NUL (\x00) bytes are not allowed in PostgreSQL, so we replace them from + # NUL (\x00) bytes are not allowed in PostgreSQL, so we replace them in # the free text field `latest_error`. latest_error = latest_error.replace("\x00", "") update_params["latest_error"] = latest_error diff --git a/posthog/temporal/tests/batch_exports/test_run_updates.py b/posthog/temporal/tests/batch_exports/test_run_updates.py index 649585f52836b..b719ca455f7db 100644 --- a/posthog/temporal/tests/batch_exports/test_run_updates.py +++ b/posthog/temporal/tests/batch_exports/test_run_updates.py @@ -214,3 +214,38 @@ async def test_finish_batch_export_run_never_pauses_with_small_check_window(acti await sync_to_async(batch_export.refresh_from_db)() assert batch_export.paused is False + + +@pytest.mark.django_db(transaction=True) +@pytest.mark.asyncio +async def test_finish_batch_export_run_handles_nul_bytes(activity_environment, team, batch_export): + """Test if 'finish_batch_export_run' will not fail in the prescence of a NUL byte.""" + start = dt.datetime(2023, 4, 24, tzinfo=dt.UTC) + end = dt.datetime(2023, 4, 25, tzinfo=dt.UTC) + + inputs = StartBatchExportRunInputs( + team_id=team.id, + batch_export_id=str(batch_export.id), + data_interval_start=start.isoformat(), + data_interval_end=end.isoformat(), + ) + + batch_export_id = str(batch_export.id) + + run_id = await activity_environment.run(start_batch_export_run, inputs) + + finish_inputs = FinishBatchExportRunInputs( + id=str(run_id), + batch_export_id=batch_export_id, + status=BatchExportRun.Status.FAILED, + team_id=inputs.team_id, + latest_error="Oh No a NUL byte: \x00!", + ) + + await activity_environment.run(finish_batch_export_run, finish_inputs) + + runs = BatchExportRun.objects.filter(id=run_id) + run = await sync_to_async(runs.first)() # type:ignore + assert run is not None + assert run.status == "Failed" + assert run.latest_error == "Oh No a NUL byte: !" From e89663d1b72072f0dd2d7e1436fe1d921f6091ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Far=C3=ADas=20Santana?= Date: Tue, 31 Dec 2024 11:39:27 +0100 Subject: [PATCH 3/3] chore(typing): Remove unused comment --- posthog/temporal/tests/batch_exports/test_run_updates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posthog/temporal/tests/batch_exports/test_run_updates.py b/posthog/temporal/tests/batch_exports/test_run_updates.py index b719ca455f7db..904c79d6dd5cd 100644 --- a/posthog/temporal/tests/batch_exports/test_run_updates.py +++ b/posthog/temporal/tests/batch_exports/test_run_updates.py @@ -245,7 +245,7 @@ async def test_finish_batch_export_run_handles_nul_bytes(activity_environment, t await activity_environment.run(finish_batch_export_run, finish_inputs) runs = BatchExportRun.objects.filter(id=run_id) - run = await sync_to_async(runs.first)() # type:ignore + run = await sync_to_async(runs.first)() assert run is not None assert run.status == "Failed" assert run.latest_error == "Oh No a NUL byte: !"