Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.
Merged
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: 9 additions & 2 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ permissions:
pull-requests: read
jobs:
pytest-matrix:
runs-on: ubuntu-latest
runs-on: ${{ matrix.runs-on }}
strategy:
matrix:
runs-on: [ubuntu-24.04, macos-15]
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
Expand All @@ -29,7 +30,8 @@ jobs:
- name: Install Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install Qemu
- name: Install Qemu (Linux)
if: runner.os == 'Linux'
Comment thread
NickCao marked this conversation as resolved.
run: |
echo <<EOF | sudo tee /etc/udev/rules.d/99-kvm.rules
KERNEL=="kvm", GROUP="kvm", MODE="0666"
Expand All @@ -46,6 +48,11 @@ jobs:
sudo apt-get update
sudo apt-get install -y qemu-system-arm qemu-system-x86

- name: Install Qemu (macOS)
if: runner.os == 'macOS'
run: |
brew install qemu

- name: Cache Fedora Cloud images
id: cache-fedora-cloud-images
uses: actions/cache@v4
Expand Down
13 changes: 11 additions & 2 deletions packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
from jumpstarter.driver import Driver, export


def _vsock_available():
return platform.system() == "Linux"


class QmpLogFilter(logging.Filter):
def filter(self, record):
return False
Expand Down Expand Up @@ -126,8 +130,11 @@ async def on(self) -> None: # noqa: C901
devices = [
"virtio-net-pci,netdev=eth0",
"virtio-gpu-pci",
"vhost-vsock-pci,guest-cid={}".format(self.parent._cid),
]

if _vsock_available():
devices.append("vhost-vsock-pci,guest-cid={}".format(self.parent._cid))

for device in devices:
cmdline += ["-device", device]

Expand Down Expand Up @@ -266,7 +273,9 @@ def __post_init__(self):
self.children["flasher"] = QemuFlasher(parent=self)
self.children["console"] = PySerial(url=self._pty, check_present=False)
self.children["vnc"] = UnixNetwork(path=self._vnc)
self.children["ssh"] = VsockNetwork(cid=self._cid, port=22)

if _vsock_available():
self.children["ssh"] = VsockNetwork(cid=self._cid, port=22)

Comment thread
NickCao marked this conversation as resolved.
for k, v in self.hostfwd.items():
match v.protocol:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ async def tftp_server():

async def create_test_client(server_port):
loop = asyncio.get_running_loop()
transport, protocol = await loop.create_datagram_endpoint(asyncio.DatagramProtocol, remote_addr=("127.0.0.1", 0))
transport, protocol = await loop.create_datagram_endpoint(
asyncio.DatagramProtocol, remote_addr=("127.0.0.1", server_port)
)
return transport, protocol


Expand Down Expand Up @@ -70,7 +72,7 @@ async def test_read_request_for_existing_file(tftp_server):
await server.ready_event.wait()

try:
transport, _ = await create_test_client(server.port)
transport, _ = await create_test_client(server_port)

rrq_packet = (
Opcode.RRQ.to_bytes(2, "big")
Expand All @@ -97,7 +99,7 @@ async def test_read_request_for_nonexistent_file(tftp_server):
server_task = asyncio.create_task(server.start())

try:
transport, protocol = await create_test_client(server.port)
transport, protocol = await create_test_client(server_port)

rrq_packet = Opcode.RRQ.to_bytes(2, "big") + b"nonexistent.txt\x00" + b"octet\x00"

Expand All @@ -117,7 +119,7 @@ async def test_write_request_rejection(tftp_server):
server_task = asyncio.create_task(server.start())

try:
transport, _ = await create_test_client(server.port)
transport, _ = await create_test_client(server_port)
wrq_packet = Opcode.WRQ.to_bytes(2, "big") + b"test.txt\x00" + b"octet\x00"

transport.sendto(wrq_packet)
Expand All @@ -137,7 +139,7 @@ async def test_invalid_packet_handling(tftp_server):
await server.ready_event.wait()

try:
transport, _ = await create_test_client(server.port)
transport, _ = await create_test_client(server_port)
transport.sendto(b"\x00\x01")

assert server.transport is not None
Expand All @@ -157,7 +159,7 @@ async def test_path_traversal_prevention(tftp_server):
await server.ready_event.wait()

try:
transport, _ = await create_test_client(server.port)
transport, _ = await create_test_client(server_port)

rrq_packet = Opcode.RRQ.to_bytes(2, "big") + b"../../../etc/passwd\x00" + b"octet\x00"

Expand All @@ -179,7 +181,7 @@ async def test_options_negotiation(tftp_server):
await server.ready_event.wait()

try:
transport, _ = await create_test_client(server.port)
transport, _ = await create_test_client(server_port)

# RRQ with options
rrq_packet = (
Expand Down Expand Up @@ -257,7 +259,7 @@ async def test_invalid_options_handling(tftp_server):
await server.ready_event.wait()

try:
transport, _ = await create_test_client(server.port)
transport, _ = await create_test_client(server_port)

rrq_packet = (
Opcode.RRQ.to_bytes(2, "big")
Expand Down
Loading