From 5b737fe97ee32da94c62ec3a018e171bd40fb271 Mon Sep 17 00:00:00 2001 From: Morgan Wowk Date: Fri, 22 May 2026 11:56:50 -0700 Subject: [PATCH] fix: 500 error when published component size is too large --- .../component_library_api_server.py | 11 +++++-- tests/test_component_library_api_server.py | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/cloud_pipelines_backend/component_library_api_server.py b/cloud_pipelines_backend/component_library_api_server.py index 450f2b5..6b046e7 100644 --- a/cloud_pipelines_backend/component_library_api_server.py +++ b/cloud_pipelines_backend/component_library_api_server.py @@ -20,14 +20,19 @@ def calculate_digest_for_component_text(text: str) -> str: return digest -MAX_COMPONENT_SIZE = 300_000 +# Baseline: MySQL TEXT column maximum (65,535 bytes). +MAX_COMPONENT_SIZE_BYTES = 65_535 def load_component_spec_from_text_and_validate( text: str, ) -> component_structures.ComponentSpec: - if len(text) > MAX_COMPONENT_SIZE: - raise ValueError(f"Component size {len(text)} > {MAX_COMPONENT_SIZE=}.") + text_bytes = len(text.encode("utf-8")) + if text_bytes > MAX_COMPONENT_SIZE_BYTES: + raise errors.ApiValidationError( + f"Component text is too large: {text_bytes} bytes" + f" (maximum allowed: {MAX_COMPONENT_SIZE_BYTES} bytes)." + ) component_dict = yaml.safe_load(text) return load_component_spec_from_dict_and_validate(component_dict) diff --git a/tests/test_component_library_api_server.py b/tests/test_component_library_api_server.py index e3a1636..31a6766 100644 --- a/tests/test_component_library_api_server.py +++ b/tests/test_component_library_api_server.py @@ -1,4 +1,5 @@ from sqlalchemy import orm +import pydantic import yaml import pytest @@ -314,5 +315,33 @@ def test_component_library_service(): assert pins_11b == pins_11 +def test_component_text_at_byte_limit_is_accepted(): + """Component text of exactly MAX_COMPONENT_SIZE_BYTES bytes does not raise ApiValidationError.""" + text = "a" * components_api.MAX_COMPONENT_SIZE_BYTES + assert len(text.encode("utf-8")) == components_api.MAX_COMPONENT_SIZE_BYTES + # Only assert that the size check does not reject the input; downstream + # yaml/pydantic parsing errors are expected because "a" * N is not a + # valid component spec. + try: + components_api.load_component_spec_from_text_and_validate(text) + except errors.ApiValidationError: + pytest.fail( + "ApiValidationError should not be raised for text at the byte limit" + ) + except (yaml.YAMLError, pydantic.ValidationError): + pass # Expected: synthetic text is not valid YAML / ComponentSpec + except Exception as exc: + pytest.fail(f"Unexpected exception raised: {type(exc).__name__}: {exc}") + + +def test_component_text_one_byte_over_limit_raises_api_validation_error(): + """Component text of MAX_COMPONENT_SIZE_BYTES + 1 bytes raises ApiValidationError.""" + text = "a" * (components_api.MAX_COMPONENT_SIZE_BYTES + 1) + assert len(text.encode("utf-8")) == components_api.MAX_COMPONENT_SIZE_BYTES + 1 + with pytest.raises(errors.ApiValidationError) as exc_info: + components_api.load_component_spec_from_text_and_validate(text) + assert str(components_api.MAX_COMPONENT_SIZE_BYTES) in str(exc_info.value) + + if __name__ == "__main__": pytest.main()