QTZPOC-20
QTZPOC-20: Refactor ModelImport status engine for lazy initialization, add byte-counted size validation to bundle extraction, optimize MLflow run ID lookups, and ensure workflow cancellation propagates correctly.
This commit is contained in:
@@ -437,7 +437,7 @@ def test_gate_5_wraps_an_os_error_during_unpacking(work_dir, reader, monkeypatch
|
||||
def _raise_os_error(*_args, **_kwargs):
|
||||
raise OSError('disk full')
|
||||
|
||||
monkeypatch.setattr('laborious.utils.bundle.reader.shutil.copyfileobj', _raise_os_error)
|
||||
monkeypatch.setattr(zipfile.ZipExtFile, 'read', _raise_os_error)
|
||||
|
||||
with pytest.raises(BundleGateError, match='could not be unpacked') as error:
|
||||
_open(reader, work_dir, payload)
|
||||
@@ -463,6 +463,52 @@ def test_extract_member_rechecks_containment_on_the_resolved_path(work_dir, read
|
||||
assert error.value.gate == 5
|
||||
|
||||
|
||||
def test_extract_member_rejects_a_stream_larger_than_its_declared_size(work_dir, reader, monkeypatch):
|
||||
"""A decompressed stream longer than the entry's declared `file_size` is rejected mid-write,
|
||||
instead of trusting the central-directory metadata gate 4 already checked in aggregate.
|
||||
|
||||
A single crafted DEFLATE chunk can make `ZipExtFile.read()` return far more bytes than
|
||||
`file_size` declares before its own EOF/CRC bookkeeping catches up, so the stand-in here
|
||||
forces exactly that response shape rather than fighting zipfile's own CRC validation."""
|
||||
root = work_dir / 'root'
|
||||
root.mkdir()
|
||||
buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(buffer, 'w') as archive:
|
||||
archive.writestr('payload.bin', b'x' * 10)
|
||||
|
||||
call_count = {'n': 0}
|
||||
|
||||
def _oversized_read(self, *_args, **_kwargs):
|
||||
call_count['n'] += 1
|
||||
return b'x' * 1000 if call_count['n'] == 1 else b''
|
||||
|
||||
monkeypatch.setattr(zipfile.ZipExtFile, 'read', _oversized_read)
|
||||
|
||||
with zipfile.ZipFile(io.BytesIO(buffer.getvalue())) as archive:
|
||||
entry = archive.infolist()[0]
|
||||
with pytest.raises(BundleGateError, match='more than its declared') as error:
|
||||
reader._extract_member(archive, entry, root, root.resolve())
|
||||
|
||||
assert error.value.gate == 5
|
||||
|
||||
|
||||
def test_extract_member_writes_a_well_formed_member_in_full(work_dir, reader):
|
||||
"""A member whose decompressed size matches its declared `file_size` is extracted byte for
|
||||
byte, exactly as before the byte-counting check was added."""
|
||||
root = work_dir / 'root'
|
||||
root.mkdir()
|
||||
payload = b'y' * 100
|
||||
buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(buffer, 'w') as archive:
|
||||
archive.writestr('payload.bin', payload)
|
||||
|
||||
with zipfile.ZipFile(io.BytesIO(buffer.getvalue())) as archive:
|
||||
entry = archive.infolist()[0]
|
||||
reader._extract_member(archive, entry, root, root.resolve())
|
||||
|
||||
assert (root / 'payload.bin').read_bytes() == payload
|
||||
|
||||
|
||||
# ------------------------------------------------------------------- gate 6
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user