From e832014db26c98dd89ac7a02f93d30d5359fb062 Mon Sep 17 00:00:00 2001 From: Mohak Agrawal Date: Thu, 16 Jul 2026 16:25:06 +0530 Subject: [PATCH] fix: cap generated container name to GCP Cloud Run's service-id limit get_container_name() built "preswald-app-{slug}" with no length cap before handing it to `gcloud run deploy`/Cloud Run's CreateService API as the service name. Google Cloud Run rejects service_id values of 50 characters or more: 400 Violation in CreateServiceRequest.service_id: only lowercase, digits, and hyphens; must begin with letter, and cannot end with hyphen; must be less than 50 characters. Any project slug long enough to push the prefixed name past 49 characters triggered exactly this error, surfacing as an opaque 500 during deploy with no indication of the actual cause. Truncate the sanitized container name to 49 characters (stripping any trailing hyphen left by the cut) so it always satisfies Cloud Run's constraint, and add regression tests covering both a long slug (now capped) and a short slug (unaffected). Fixes #659 --- preswald/deploy.py | 7 +++++++ tests/test_deploy.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/test_deploy.py diff --git a/preswald/deploy.py b/preswald/deploy.py index 40ca2c95..cf1322a8 100644 --- a/preswald/deploy.py +++ b/preswald/deploy.py @@ -29,6 +29,12 @@ def get_deploy_dir(script_path: str) -> Path: return deploy_dir +# Google Cloud Run rejects service names of 50 characters or more +# (`CreateServiceRequest.service_id`), so the generated container name must +# stay under that limit even after the "preswald-app-" prefix is added. +GCP_SERVICE_NAME_MAX_LENGTH = 49 + + def get_container_name(script_path: str) -> str: """Generate a consistent container name for a given script""" script_dir = Path(script_path).parent @@ -39,6 +45,7 @@ def get_container_name(script_path: str) -> str: container_name = container_name.lower() container_name = re.sub(r"[^a-z0-9-]", "", container_name) container_name = container_name.strip("-") + container_name = container_name[:GCP_SERVICE_NAME_MAX_LENGTH].rstrip("-") return container_name diff --git a/tests/test_deploy.py b/tests/test_deploy.py new file mode 100644 index 00000000..aabe4b6e --- /dev/null +++ b/tests/test_deploy.py @@ -0,0 +1,41 @@ +import tempfile +from pathlib import Path + +import pytest + +from preswald.deploy import GCP_SERVICE_NAME_MAX_LENGTH, get_container_name + + +def _write_toml_project(tmp_path: Path, slug: str) -> Path: + script_path = tmp_path / "hello.py" + script_path.write_text("") + (tmp_path / "preswald.toml").write_text( + f'[project]\nslug = "{slug}"\nport = 8501\n' + ) + return script_path + + +def test_get_container_name_stays_under_gcp_limit(): + # A long-but-valid project slug used to produce a container name past + # Cloud Run's <50 char service_id limit once the "preswald-app-" prefix + # was added, causing `CreateServiceRequest.service_id` violations (#659). + long_slug = "a-very-descriptive-project-slug-for-an-org-1744321134" + with tempfile.TemporaryDirectory() as tmp: + script_path = _write_toml_project(Path(tmp), long_slug) + container_name = get_container_name(str(script_path)) + + assert len(container_name) <= GCP_SERVICE_NAME_MAX_LENGTH + assert not container_name.endswith("-") + assert container_name.startswith("preswald-app-") + + +def test_get_container_name_short_slug_unaffected(): + with tempfile.TemporaryDirectory() as tmp: + script_path = _write_toml_project(Path(tmp), "zwbq") + container_name = get_container_name(str(script_path)) + + assert container_name == "preswald-app-zwbq" + + +if __name__ == "__main__": + raise SystemExit(pytest.main([__file__, "-v"]))