Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions truss/base/truss_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,17 @@ class DockerServer(custom_types.ConfigModel):
default=None,
description="Skip the build step and deploy the base image as-is. Baseten copies the image to its container registry without running docker build or modifying the image in any way.",
)
max_payload_size: Optional[str] = pydantic.Field(
default=None,
description="The maximum inbound request body size for the container's reverse proxy. Accepts nginx size syntax, such as 64M, 128M, or 1G. Defaults to 64M.",
)

@pydantic.field_validator("max_payload_size")
@classmethod
def _validate_max_payload_size(cls, v: Optional[str]) -> Optional[str]:
if v is not None and not re.fullmatch(r"[0-9]+[kKmMgG]?", v):
raise ValueError(f"Invalid max_payload_size {v!r}.")
return v

@pydantic.field_validator("run_as_user_id")
@classmethod
Expand Down
13 changes: 13 additions & 0 deletions truss/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,19 @@
"default": null,
"description": "Skip the build step and deploy the base image as-is. Baseten copies the image to its container registry without running docker build or modifying the image in any way.",
"title": "No Build"
},
"max_payload_size": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The maximum inbound request body size for the container's reverse proxy. Accepts nginx size syntax, such as 64M, 128M, or 1G. Defaults to 64M.",
"title": "Max Payload Size"
}
},
"required": [
Expand Down
4 changes: 3 additions & 1 deletion truss/contexts/image_builder/serving_image_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,9 @@ def generate_docker_server_nginx_config(build_dir, config):
readiness_endpoint=config.docker_server.readiness_endpoint,
liveness_endpoint=config.docker_server.liveness_endpoint,
server_port=config.docker_server.server_port,
client_max_body_size=TRUSSLESS_MAX_PAYLOAD_SIZE,
client_max_body_size=config.docker_server.max_payload_size
if config.docker_server.max_payload_size is not None
else TRUSSLESS_MAX_PAYLOAD_SIZE,
transport_kind=config.runtime.transport.kind,
)
nginx_filepath = build_dir / "proxy.conf"
Expand Down
11 changes: 10 additions & 1 deletion truss/tests/contexts/image_builder/test_serving_image_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,14 +1033,22 @@ class MockConfig:
assert cfg.has_section("eventlistener:quit_on_failure")


def test_nginx_config_disables_disk_writes(tmp_path):
@pytest.mark.parametrize(
"max_payload_size,expected_max_payload_size", [(None, "64M"), ("128M", "128M")]
)
def test_nginx_config_disables_disk_writes(
tmp_path, max_payload_size, expected_max_payload_size
):
"""Test that nginx configuration disables all disk writes."""

class MockDockerServer:
predict_endpoint = "/predict"
readiness_endpoint = "/readiness"
liveness_endpoint = "/health"
server_port = 8090
max_payload_size = None

MockDockerServer.max_payload_size = max_payload_size

class MockTransport:
kind = "http"
Expand All @@ -1060,6 +1068,7 @@ class MockConfig:
# Verify logging is disabled
assert "access_log off;" in nginx_config
assert "error_log /dev/null;" in nginx_config
assert f"client_max_body_size {expected_max_payload_size};" in nginx_config

# Verify temp paths use /dev/shm (in-memory filesystem)
assert "client_body_temp_path /dev/shm/nginx_client_temp;" in nginx_config
Expand Down
14 changes: 14 additions & 0 deletions truss/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,20 @@ def test_docker_server_run_as_user_id(run_as_user_id, expected, raises):
assert docker_server.run_as_user_id == expected


def test_docker_server_invalid_max_payload_size():
with pytest.raises(
pydantic.ValidationError, match="Invalid max_payload_size '64MB'"
):
DockerServer(
start_command="python main.py",
server_port=8000,
predict_endpoint="/predict",
readiness_endpoint="/health",
liveness_endpoint="/health",
max_payload_size="64MB",
)


# =============================================================================
# Weights Configuration Tests
# =============================================================================
Expand Down
Loading