Skip to content

Commit 49314f7

Browse files
Validate external payload storage policy types
1 parent 9670231 commit 49314f7

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

src/durable_workflow/external_storage.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,18 @@ def from_dict(cls, data: object) -> ExternalPayloadStoragePolicy:
5050
"""Parse a server namespace or Cloud organization storage policy."""
5151
policy = _extract_policy(data)
5252
driver = _optional_string(policy.get("driver"), "external payload storage driver")
53-
enabled = bool(policy.get("enabled", driver is not None))
53+
enabled = _optional_bool(policy.get("enabled"), "enabled", default=driver is not None)
5454
threshold_bytes = _optional_positive_int(policy.get("threshold_bytes"), "threshold_bytes")
5555
config = _optional_mapping(policy.get("config"), "config")
5656
prefix = _optional_string(policy.get("prefix"), "prefix") or _optional_string(
5757
config.get("prefix"),
5858
"config.prefix",
5959
)
60-
integrity_required = bool(policy.get("integrity_required", True))
60+
integrity_required = _optional_bool(
61+
policy.get("integrity_required"),
62+
"integrity_required",
63+
default=True,
64+
)
6165

6266
return cls(
6367
enabled=enabled,
@@ -520,10 +524,18 @@ def _optional_string(data: object, field_name: str) -> str | None:
520524
return data
521525

522526

527+
def _optional_bool(data: object, field_name: str, *, default: bool) -> bool:
528+
if data is None:
529+
return default
530+
if not isinstance(data, bool):
531+
raise ValueError(f"external payload storage policy {field_name} must be a boolean")
532+
return data
533+
534+
523535
def _optional_positive_int(data: object, field_name: str) -> int | None:
524536
if data is None:
525537
return None
526-
if not isinstance(data, int) or data < 1:
538+
if type(data) is not int or data < 1:
527539
raise ValueError(f"external payload storage policy {field_name} must be a positive integer")
528540
return data
529541

tests/test_external_storage.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,5 +515,23 @@ def test_external_storage_policy_validates_threshold_and_config_shape() -> None:
515515
with pytest.raises(ValueError, match="threshold_bytes"):
516516
ExternalPayloadStoragePolicy.from_dict({"driver": "local", "threshold_bytes": 0})
517517

518+
with pytest.raises(ValueError, match="threshold_bytes"):
519+
ExternalPayloadStoragePolicy.from_dict({"driver": "local", "threshold_bytes": True})
520+
518521
with pytest.raises(ValueError, match="config"):
519522
ExternalPayloadStoragePolicy.from_dict({"driver": "local", "config": "file:///tmp/payloads"})
523+
524+
525+
def test_external_storage_policy_validates_boolean_fields() -> None:
526+
with pytest.raises(ValueError, match="enabled"):
527+
ExternalPayloadStoragePolicy.from_dict({"driver": "local", "enabled": "false"})
528+
529+
with pytest.raises(ValueError, match="integrity_required"):
530+
ExternalPayloadStoragePolicy.from_dict({"driver": "local", "integrity_required": 1})
531+
532+
policy = ExternalPayloadStoragePolicy.from_dict(
533+
{"driver": "local", "enabled": False, "integrity_required": False}
534+
)
535+
536+
assert policy.enabled is False
537+
assert policy.integrity_required is False

0 commit comments

Comments
 (0)