From d533081a72a2a52bc4f9947724d6fa679e583345 Mon Sep 17 00:00:00 2001 From: Herman Snevajs Date: Mon, 15 Jun 2026 16:03:22 +0200 Subject: [PATCH] Fix upload size validation leaking versioned limit onto media files The versioned-size check was not gated on is_versioned_file, so media files (which never have a diff) were also capped at the smaller versioned limit. Branch on file type, and test both limits together. --- mergin/local_changes.py | 7 +++--- mergin/test/test_local_changes.py | 40 ++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/mergin/local_changes.py b/mergin/local_changes.py index 2b5ba8a..67b7715 100644 --- a/mergin/local_changes.py +++ b/mergin/local_changes.py @@ -88,9 +88,10 @@ def __post_init__(self): total_changes = len(upload_changes) oversize_changes = [] for change in upload_changes: - if not is_versioned_file(change.path) and change.size > MAX_UPLOAD_MEDIA_SIZE: - oversize_changes.append(change) - elif not change.diff and change.size > MAX_UPLOAD_VERSIONED_SIZE: + if is_versioned_file(change.path): + if not change.diff and change.size > MAX_UPLOAD_VERSIONED_SIZE: + oversize_changes.append(change) + elif change.size > MAX_UPLOAD_MEDIA_SIZE: oversize_changes.append(change) if oversize_changes: error = ChangesValidationError("Some files exceed the maximum upload size", oversize_changes) diff --git a/mergin/test/test_local_changes.py b/mergin/test/test_local_changes.py index 4366f5d..951dfda 100644 --- a/mergin/test/test_local_changes.py +++ b/mergin/test/test_local_changes.py @@ -151,7 +151,7 @@ def test_local_changes_post_init_validation_media(): assert err.value.invalid_changes[0].size == LARGE_FILE_SIZE -def test_local_changes_post_init_validation_gpgkg(): +def test_local_changes_post_init_validation_gpkg(): """Test the get_gpgk_upload_file method of LocalProjectChanges.""" # Define constants SIZE_LIMIT_MB = 10 @@ -186,6 +186,44 @@ def test_local_changes_post_init_validation_gpgkg(): assert err.value.invalid_changes[0].size == LARGE_FILE_SIZE +def test_local_changes_post_init_validation_both_limits(): + """ + Validate media and versioned size limits. + """ + VERSIONED_LIMIT = 5 * 1024 * 1024 # 5 MB + MEDIA_LIMIT = 10 * 1024 * 1024 # 10 MB + BETWEEN_SIZE = 7 * 1024 * 1024 + OVER_MEDIA_SIZE = 15 * 1024 * 1024 + OVER_VERSIONED_SIZE = 8 * 1024 * 1024 + + added = [ + # media file between the limits: valid, must NOT be flagged + FileChange(path="between.jpg", checksum="a1", size=BETWEEN_SIZE, mtime=datetime.now()), + # media file over the media limit: flagged + FileChange(path="big.jpg", checksum="a2", size=OVER_MEDIA_SIZE, mtime=datetime.now()), + ] + updated = [ + # versioned full upload over the versioned limit: flagged + FileChange(path="big.gpkg", checksum="b1", size=OVER_VERSIONED_SIZE, mtime=datetime.now(), diff=None), + # versioned upload over the versioned limit but sent as a diff: valid + FileChange( + path="diffed.gpkg", + checksum="b2", + size=OVER_VERSIONED_SIZE, + mtime=datetime.now(), + diff={"path": "diffed-diff.gpkg", "checksum": "d1", "size": 1024, "mtime": datetime.now()}, + ), + ] + + with patch("mergin.local_changes.MAX_UPLOAD_MEDIA_SIZE", MEDIA_LIMIT): + with patch("mergin.local_changes.MAX_UPLOAD_VERSIONED_SIZE", VERSIONED_LIMIT): + with pytest.raises(ChangesValidationError) as err: + LocalProjectChanges(added=added, updated=updated) + + flagged = {c.path for c in err.value.invalid_changes} + assert flagged == {"big.jpg", "big.gpkg"} + + def test_local_changes_post_init(): """Test the __post_init__ method of LocalProjectChanges.""" # Define constants