Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Add compressed image support for QEMU driver#789

Merged
bennyz merged 5 commits intojumpstarter-dev:mainfrom
evakhoni:qemu_image
Jan 6, 2026
Merged

Add compressed image support for QEMU driver#789
bennyz merged 5 commits intojumpstarter-dev:mainfrom
evakhoni:qemu_image

Conversation

@evakhoni
Copy link
Contributor

@evakhoni evakhoni commented Dec 29, 2025

Closes jumpstarter-dev/jumpstarter#116

Summary

Adds transparent decompression support for compressed disk images when flashing to the QEMU driver. Compressed images (.gz, .xz, .bz2, .zstd) are automatically detected and decompressed on the fly.

Changes

packages/jumpstarter/jumpstarter/streams/encoding.py

  • Added FileSignature dataclass to represent compression format signatures
  • Added COMPRESSION_SIGNATURES tuple with file signatures for gzip, xz, bz2, and zstd
  • Added detect_compression_from_signature() function for auto-detection
  • Added create_decompressor() helper function
  • Added AutoDecompressIterator async iterator that wraps a byte stream and transparently decompresses if needed

packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py

  • Modified QemuFlasher.flash() to wrap the source stream with AutoDecompressIterator

How it works

  1. When flash() is called, the first 8 bytes are buffered
  2. File signature detection matches against known compression formats
  3. If compressed: a decompressor is created and chunks are decompressed on the fly
  4. If uncompressed: data passes through unchanged

Summary by CodeRabbit

  • New Features

    • Flash operations now transparently accept and decompress images in gzip, xz, bz2, and zstd formats, allowing compressed files to be flashed without manual pre-processing.
    • Automatic on-the-fly compression detection for streamed inputs improves robustness with varied input chunking.
  • Documentation

    • Flash behavior and supported decompression formats are documented in the flash operation help text.
  • Tests

    • Added comprehensive tests covering compression detection and automatic decompression across formats, chunk sizes, large inputs, and error cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link

netlify bot commented Dec 29, 2025

Deploy Preview for jumpstarter-docs ready!

Name Link
🔨 Latest commit fc6933e
🔍 Latest deploy log https://app.netlify.com/projects/jumpstarter-docs/deploys/695bffc8e5d13000082aa1ca
😎 Deploy Preview https://deploy-preview-789--jumpstarter-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

Adds file-signature based compression detection and an async AutoDecompressIterator (gzip, xz, bz2, zstd), exposes detection/creator helpers, adds tests, and integrates AutoDecompressIterator into QemuFlasher.flash to transparently decompress input image streams before writing.

Changes

Cohort / File(s) Summary
Compression detection & decompression core
packages/jumpstarter/jumpstarter/streams/encoding.py
Added FileSignature dataclass, COMPRESSION_SIGNATURES, SIGNATURE_BUFFER_SIZE, detect_compression_from_signature(), create_decompressor(), and AutoDecompressIterator (async iterator that buffers initial bytes, detects gzip/xz/bz2/zstd, instantiates decompressor, and yields decompressed or passthrough bytes).
QEMU driver integration
packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
Wrapped the input AsyncIterator with AutoDecompressIterator in QemuFlasher.flash() and added a docstring describing decompression behavior; preserved existing write/chunking logic.
Tests
packages/jumpstarter/jumpstarter/streams/encoding_test.py
Added tests for signature detection and AutoDecompressIterator covering gzip, xz, bz2, zstd (conditional import), passthrough, small-chunk/empty/large inputs, and corrupted gzip handling.

Sequence Diagram(s)

sequenceDiagram
    participant Qemu as QemuFlasher.flash()
    participant Stream as Input AsyncIterator
    participant AutoDec as AutoDecompressIterator
    participant Factory as create_decompressor()
    participant Target as Target Stream/Writer

    Qemu->>AutoDec: wrap(Stream)
    Note right of AutoDec: buffer up to SIGNATURE_BUFFER_SIZE bytes
    AutoDec->>AutoDec: inspect buffered signature

    alt compression detected
        AutoDec->>Factory: create_decompressor(type)
        Factory-->>AutoDec: decompressor instance
        AutoDec->>AutoDec: decompress buffered + incoming chunks
        AutoDec-->>Target: yield decompressed chunks
    else no compression
        AutoDec-->>Target: yield original chunks (passthrough)
    end

    Target->>Qemu: writes/chunks to device
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • jumpstarter-dev/jumpstarter#772 — Adds Compression.ZSTD and zstd support in encoding, closely related to AutoDecompressIterator’s zstd handling and signature detection integration.

Suggested reviewers

  • mangelajo

Poem

🐇 I peeked at headers, tiny and bright,

I buffered whispers to learn their plight.
I unzip, unxz, untwist with delight—
I hop the stream so flashing goes right. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.06% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add compressed image support for QEMU driver' directly and clearly summarizes the main change: introducing support for compressed disk images in the QEMU driver.
Linked Issues check ✅ Passed The pull request implements compressed image support for gzip, xz, bzip2, and zstd formats requested in jumpstarter-dev/jumpstarter#116, with transparent decompression in the QEMU driver's flash method.
Out of Scope Changes check ✅ Passed All changes are directly related to adding compressed image support for the QEMU driver; no out-of-scope modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed90de4 and 0259828.

📒 Files selected for processing (3)
  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
  • packages/jumpstarter/jumpstarter/streams/encoding.py
  • packages/jumpstarter/jumpstarter/streams/encoding_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Ruff should be used for code formatting and linting, excluding jumpstarter-protocol package

Files:

  • packages/jumpstarter/jumpstarter/streams/encoding_test.py
  • packages/jumpstarter/jumpstarter/streams/encoding.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Redirect rules - jumpstarter-docs
  • GitHub Check: Header rules - jumpstarter-docs
  • GitHub Check: build
  • GitHub Check: pytest-matrix (macos-15, 3.13)
  • GitHub Check: pytest-matrix (macos-15, 3.12)
  • GitHub Check: pytest-matrix (macos-15, 3.11)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.12)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.13)
  • GitHub Check: e2e
  • GitHub Check: Pages changed - jumpstarter-docs
🔇 Additional comments (10)
packages/jumpstarter/jumpstarter/streams/encoding_test.py (4)

1-23: LGTM! Imports are well-organized.

The conditional zstd import logic correctly handles Python version differences, matching the pattern in encoding.py. All necessary test dependencies and symbols are properly imported.


49-54: LGTM! Clean test helper.

The helper function is straightforward and appropriate for test use.


57-98: Excellent test coverage for signature detection!

The test suite comprehensively covers:

  • All supported compression formats (gzip, xz, bz2, zstd)
  • Edge cases: uncompressed data, empty input, truncated signatures
  • Real-world validation using actual compression library outputs

This provides strong confidence in the signature detection logic.


100-176: Outstanding test coverage for AutoDecompressIterator!

The test suite is thorough and well-structured:

  • ✅ Passthrough for uncompressed data
  • ✅ Decompression for all four formats (gzip, xz, bz2, zstd)
  • ✅ Edge cases: tiny chunks (1 byte), empty input, large data (1MB)
  • ✅ Error handling for corrupted data

The helper methods (_async_iter_from_bytes, _decompress_and_check) are clean and promote test readability. This provides excellent confidence in the auto-decompression functionality.

packages/jumpstarter/jumpstarter/streams/encoding.py (6)

26-44: LGTM! Compression signatures are correct.

The magic bytes for all four compression formats are accurate:

  • GZIP: RFC 1952 compliant
  • XZ: Matches XZ Utils specification
  • BZ2: Correct "BZh" header
  • ZSTD: RFC 8478 compliant (little-endian)

The SIGNATURE_BUFFER_SIZE of 8 appropriately covers the longest signature. The frozen FileSignature dataclass is good practice for immutability.


47-59: LGTM! Clean and correct detection logic.

The function correctly uses startswith() to match compression signatures, allowing for buffers larger than the minimum signature size. The return type and documentation are clear.


62-73: LGTM! Decompressor creation is correct.

The decompressor instantiation for each format is appropriate:

  • wbits=47 for gzip enables auto-detection of gzip/zlib headers
  • All other decompressors use standard instantiation

170-183: Excellent error handling! This addresses past review feedback.

The _call_decompressor method provides robust error handling:

  • Catches all relevant decompression exceptions (zlib, lzma, OSError, zstd)
  • Generates user-friendly error messages with the compression format
  • Preserves original exception context with proper chaining

This directly addresses the past review comment requesting improved error handling for decompress() calls.


204-236: Excellent implementation! Past flush issue is properly resolved.

The __anext__ method correctly implements the async iterator protocol with proper decompressor handling:

Addresses past review feedback: The flush logic (lines 226-232) ensures no data loss by calling decompressor.flush() when the source stream is exhausted. This resolves the critical issue flagged in the previous review.

Key strengths:

  • Flush is correctly called before raising StopAsyncIteration
  • Error handling wraps the flush call via _call_decompressor
  • Decompressor is nullified after flush to prevent double-flush
  • Buffer is processed before fetching new chunks (no data loss)
  • Uncompressed data passes through unchanged

The implementation is robust and handles all edge cases properly.


238-239: LGTM! Correct async iterator protocol.

The __aiter__ method correctly returns self, following the standard async iterator pattern.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/jumpstarter/jumpstarter/streams/encoding.py (1)

62-72: Consider adding explicit handling for unmatched compression types.

The function relies on exhaustive pattern matching but lacks a default case. If a new Compression enum value is added without updating this function, it would silently return None.

🔎 Proposed improvement
 def create_decompressor(compression: Compression) -> Any:
     """Create a decompressor object for the given compression type."""
     match compression:
         case Compression.GZIP:
             return zlib.decompressobj(wbits=47)  # Auto-detect gzip/zlib
         case Compression.XZ:
             return lzma.LZMADecompressor()
         case Compression.BZ2:
             return bz2.BZ2Decompressor()
         case Compression.ZSTD:
             return zstd.ZstdDecompressor()
+        case _:
+            raise ValueError(f"Unsupported compression type: {compression}")
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b05be84 and fa7c213.

📒 Files selected for processing (2)
  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
  • packages/jumpstarter/jumpstarter/streams/encoding.py
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Ruff should be used for code formatting and linting, excluding jumpstarter-protocol package

Files:

  • packages/jumpstarter/jumpstarter/streams/encoding.py
  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
packages/jumpstarter-driver-*/jumpstarter_driver_*/driver.py

📄 CodeRabbit inference engine (.cursor/rules/creating-new-drivers.mdc)

Driver class names should be in CamelCase and be descriptive with appropriate suffixes based on functionality: Power drivers should end with *Power, Network drivers with *Network, Flasher drivers with *Flasher, Console drivers with *Console, Server drivers with *Server

Files:

  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
packages/jumpstarter-driver-**/jumpstarter_driver_**/*.py

📄 CodeRabbit inference engine (.cursor/rules/creating-new-drivers.mdc)

Driver implementations should follow existing code style validated with make lint (fix with make lint-fix), perform static type checking with make ty-pkg-${package_name}, add comprehensive tests, and verify all tests pass with make test-pkg-${package_name} or make test

Files:

  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
🧠 Learnings (1)
📚 Learning: 2025-11-27T09:58:41.875Z
Learnt from: CR
Repo: jumpstarter-dev/jumpstarter PR: 0
File: .cursor/rules/creating-new-drivers.mdc:0-0
Timestamp: 2025-11-27T09:58:41.875Z
Learning: Applies to packages/jumpstarter-driver-**/jumpstarter_driver_**/*.py : Driver implementations should follow existing code style validated with `make lint` (fix with `make lint-fix`), perform static type checking with `make ty-pkg-${package_name}`, add comprehensive tests, and verify all tests pass with `make test-pkg-${package_name}` or `make test`

Applied to files:

  • packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
🧬 Code graph analysis (2)
packages/jumpstarter/jumpstarter/streams/encoding.py (1)
packages/jumpstarter-driver-iscsi/jumpstarter_driver_iscsi/driver.py (1)
  • decompress (318-357)
packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py (1)
packages/jumpstarter/jumpstarter/streams/encoding.py (1)
  • AutoDecompressIterator (155-216)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Redirect rules - jumpstarter-docs
  • GitHub Check: Header rules - jumpstarter-docs
  • GitHub Check: Pages changed - jumpstarter-docs
  • GitHub Check: build
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.11)
  • GitHub Check: e2e
  • GitHub Check: pytest-matrix (macos-15, 3.13)
  • GitHub Check: pytest-matrix (macos-15, 3.12)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.13)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.12)
🔇 Additional comments (4)
packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py (1)

44-55: LGTM! Clean integration of auto-decompression.

The flash method correctly wraps the source stream with AutoDecompressIterator and the docstring accurately describes the new decompression capability. The implementation maintains the existing streaming behavior while adding transparent decompression support.

Minor style consideration: res.__aiter__() works but aiter(res) is the idiomatic built-in (Python 3.10+). Not required to change if you prefer explicitness here.

packages/jumpstarter/jumpstarter/streams/encoding.py (3)

26-44: LGTM! Well-structured signature definitions.

The FileSignature dataclass and COMPRESSION_SIGNATURES tuple are clean and correctly define the magic bytes for each compression format. The frozen dataclass is appropriate since signatures are immutable.


47-59: LGTM! Straightforward signature detection.

The function correctly iterates through signatures and uses startswith() for matching. Returning None for unknown formats is the right approach.


13-16: No changes needed. The backports-zstd>=1.1.0 dependency is correctly declared in pyproject.toml with the version constraint python_full_version < '3.14', matching the conditional import at lines 13-16.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/jumpstarter/jumpstarter/streams/encoding.py (1)

200-202: Missing flush when stream exhausted during detection phase.

The flush logic at lines 209-214 only runs when StopAsyncIteration is caught in the main read loop. However, if the source stream is exhausted during _detect_compression() (small compressed file < 8 bytes), the decompressor is never flushed here.

Scenario:

  1. Small gzip file fits entirely in buffer during detection
  2. _exhausted = True, decompressor created
  3. Buffer is decompressed and returned
  4. Next call: buffer empty, _exhausted is True → raises immediately without flushing

This could cause data loss for trailing decompressed bytes.

🔎 Proposed fix
         # Stream exhausted
         if self._exhausted:
+            # Flush any remaining data from decompressor
+            if self._decompressor is not None and hasattr(self._decompressor, "flush"):
+                remaining = self._decompressor.flush()
+                self._decompressor = None
+                if remaining:
+                    return remaining
             raise StopAsyncIteration
🧹 Nitpick comments (1)
packages/jumpstarter/jumpstarter/streams/encoding.py (1)

62-72: Consider adding a default case for defensive coding.

The match statement covers all current Compression enum values, but lacks a fallback. If the enum is ever extended without updating this function, it would silently return None.

🔎 Proposed fix
 def create_decompressor(compression: Compression) -> Any:
     """Create a decompressor object for the given compression type."""
     match compression:
         case Compression.GZIP:
             return zlib.decompressobj(wbits=47)  # Auto-detect gzip/zlib
         case Compression.XZ:
             return lzma.LZMADecompressor()
         case Compression.BZ2:
             return bz2.BZ2Decompressor()
         case Compression.ZSTD:
             return zstd.ZstdDecompressor()
+        case _:
+            raise ValueError(f"Unsupported compression type: {compression}")
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa7c213 and 3bda0f6.

📒 Files selected for processing (1)
  • packages/jumpstarter/jumpstarter/streams/encoding.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Ruff should be used for code formatting and linting, excluding jumpstarter-protocol package

Files:

  • packages/jumpstarter/jumpstarter/streams/encoding.py
🧬 Code graph analysis (1)
packages/jumpstarter/jumpstarter/streams/encoding.py (1)
packages/jumpstarter-driver-iscsi/jumpstarter_driver_iscsi/driver.py (1)
  • decompress (318-357)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Redirect rules - jumpstarter-docs
  • GitHub Check: Header rules - jumpstarter-docs
  • GitHub Check: Pages changed - jumpstarter-docs
  • GitHub Check: build
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.11)
  • GitHub Check: pytest-matrix (macos-15, 3.13)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.12)
  • GitHub Check: pytest-matrix (macos-15, 3.12)
  • GitHub Check: pytest-matrix (macos-15, 3.11)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.13)
  • GitHub Check: e2e
🔇 Additional comments (6)
packages/jumpstarter/jumpstarter/streams/encoding.py (6)

26-31: LGTM!

The FileSignature frozen dataclass is a clean, immutable value object for associating magic bytes with compression types.


34-44: LGTM!

Magic bytes are correct for all four compression formats, and SIGNATURE_BUFFER_SIZE = 8 adequately covers the longest signature (xz at 6 bytes).


47-59: LGTM!

The detection logic is clean and handles edge cases gracefully—startswith correctly handles buffers shorter than the signature.


154-185: LGTM!

The detection phase correctly buffers initial bytes and handles early stream exhaustion. The class design with clear internal state fields is well-structured.


207-219: Flush logic for main loop is correctly implemented.

The handling here properly flushes the decompressor, guards against double-flush by setting _decompressor = None, and returns remaining bytes before raising StopAsyncIteration. Good implementation.


71-72: The ZstdDecompressor() usage is compatible across both backports.zstd and Python 3.14's compression.zstd. The backports.zstd package is explicitly designed as a backport of compression.zstd (PEP 784) and exposes the same API, including the ZstdDecompressor class with identical decompress(data) method signature for incremental decompression. Both libraries support the same streaming decompression behavior used in this code and in CompressedStream.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/jumpstarter/jumpstarter/streams/encoding_test.py (2)

153-155: Consider a more idiomatic empty async generator.

The if False: yield pattern works but is unconventional. A clearer alternative would be:

async def empty_iter():
    return
    yield  # Make it a generator

Or simply:

async def empty_iter():
    pass
    yield

100-166: Consider adding tests for malformed compressed data.

The current test suite comprehensively covers happy paths and basic edge cases. Consider adding tests for error handling scenarios:

  • Malformed/corrupted compressed data (e.g., valid signature but invalid compression stream)
  • Truncated compressed data (stream ends mid-decompression)
  • Data with valid signature but incorrect compression format

These tests would verify that the AutoDecompressIterator handles decompression errors gracefully and fails with appropriate error messages.

Example test cases to add
async def test_malformed_gzip(self):
    """Malformed gzip data should raise an error."""
    # Valid gzip signature followed by random data
    malformed = b"\x1f\x8b\x08" + os.urandom(20)
    with pytest.raises(Exception):  # Adjust exception type as needed
        await self._decompress_and_check(malformed, b"", chunk_size=16)

async def test_truncated_compressed_data(self):
    """Truncated compressed stream should raise an error."""
    original = b"hello world" * 100
    compressed = gzip.compress(original)
    truncated = compressed[:len(compressed) // 2]  # Cut in half
    with pytest.raises(Exception):  # Adjust exception type as needed
        await self._decompress_and_check(truncated, original, chunk_size=16)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bda0f6 and ed90de4.

📒 Files selected for processing (1)
  • packages/jumpstarter/jumpstarter/streams/encoding_test.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Ruff should be used for code formatting and linting, excluding jumpstarter-protocol package

Files:

  • packages/jumpstarter/jumpstarter/streams/encoding_test.py
🧬 Code graph analysis (1)
packages/jumpstarter/jumpstarter/streams/encoding_test.py (1)
packages/jumpstarter/jumpstarter/streams/encoding.py (4)
  • AutoDecompressIterator (155-222)
  • Compression (19-23)
  • compress_stream (124-151)
  • detect_compression_from_signature (47-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Redirect rules - jumpstarter-docs
  • GitHub Check: Header rules - jumpstarter-docs
  • GitHub Check: Pages changed - jumpstarter-docs
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.12)
  • GitHub Check: pytest-matrix (macos-15, 3.12)
  • GitHub Check: pytest-matrix (macos-15, 3.13)
  • GitHub Check: pytest-matrix (macos-15, 3.11)
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.13)
  • GitHub Check: e2e
  • GitHub Check: pytest-matrix (ubuntu-24.04, 3.11)
  • GitHub Check: build
🔇 Additional comments (2)
packages/jumpstarter/jumpstarter/streams/encoding_test.py (2)

49-54: LGTM!

The helper function provides a clean abstraction for retrieving compression signatures in tests.


57-98: LGTM!

Comprehensive test coverage for signature detection including all compression formats and edge cases (empty input, truncated signatures, uncompressed data, and real compressed data).

@bkhizgiy bkhizgiy self-requested a review December 30, 2025 11:06
@evakhoni
Copy link
Contributor Author

cc @mangelajo @bennyz @bkhizgiy for review. thanks!

@evakhoni
Copy link
Contributor Author

evakhoni commented Jan 5, 2026

@bkhizgiy updated, tnx for the suggestions 👍

on a side note, pipeline error seems unrelated:

E       assert 'minikube is not installed' in 'Creating minikube cluster "test-cluster" and installing Jumpstarter...\n'
E        +  where 'Creating minikube cluster "test-cluster" and installing Jumpstarter...\n' = 
<Result JumpstarterKubernetesError(
"Failed to fetch controller versions: 502, message='Bad Gateway', 
url='https://quay.io/api/v1/repository/jumpstarter-dev/helm/jumpstarter/tag/'")>.output

Copy link
Member

@bennyz bennyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I feel like the signature checking is a bit of an overkill for this. Tools like unxz/gunzip/etc rely on the extensions, which can be good enough for our case as well, since flashing qemu has no risk of corruption

however I will not block on this

@evakhoni
Copy link
Contributor Author

evakhoni commented Jan 6, 2026

Personally I feel like the signature checking is a bit of an overkill for this. Tools like unxz/gunzip/etc rely on the extensions, which can be good enough for our case as well, since flashing qemu has no risk of corruption

however I will not block on this

yep that would work too i guess. ended up doing the sign check as the bot warned me that in some corner case with the URL we can lose the original filename. not sure how probable this thing is. but do you think it's worth reimplementing now?

@bennyz
Copy link
Member

bennyz commented Jan 6, 2026

Personally I feel like the signature checking is a bit of an overkill for this. Tools like unxz/gunzip/etc rely on the extensions, which can be good enough for our case as well, since flashing qemu has no risk of corruption
however I will not block on this

yep that would work too i guess. ended up doing the sign check as the bot warned me that in some corner case with the URL we can lose the original filename. not sure how probable this thing is. but do you think it's worth reimplementing now?

nope, merging

@bennyz bennyz merged commit 4b31a61 into jumpstarter-dev:main Jan 6, 2026
19 of 32 checks passed
@evakhoni evakhoni deleted the qemu_image branch January 6, 2026 13:26
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

qemu driver support for .gz .xz packed images

3 participants