Skip to content

fix: use parameterized Popen[bytes] for QEMU handle type annotation in guest_vsock.py - #292

Closed
markg-github with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-code-review-suggestion-again
Closed

fix: use parameterized Popen[bytes] for QEMU handle type annotation in guest_vsock.py#292
markg-github with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-code-review-suggestion-again

Conversation

Copilot AI commented Aug 14, 2026

Copy link
Copy Markdown

The process parameter in wait_for_guest and check_guest_ready was annotated as subprocess.Popen | None, dropping the bytes type argument and diverging from the rest of the codebase (e.g. VMLaunchResult.process: subprocess.Popen[bytes] | None).

Change

  • sev_verify/guest_vsock.py — Updated both occurrences to subprocess.Popen[bytes] | None:
# Before
process: subprocess.Popen | None = None

# After
process: subprocess.Popen[bytes] | None = None

Applies to wait_for_guest (line 146) and check_guest_ready (line 184).

Copilot AI lite review requested due to automatic review settings August 14, 2026 18:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

markg-github and others added 6 commits August 14, 2026 18:39
execute_test assigned the loop's local `profile` onto `ctx.profile` at the
top of every iteration. A callable step that replaces the profile —
`dataclasses.replace` on a frozen VMProfile returns a new object, so
mutating it in place is not possible — had that replacement silently
overwritten before the next step ran.

Any handler that reconfigures the guest for subsequent steps was
therefore a no-op. Read the profile out of the context instead of
writing the stale local back over it.

Co-authored-by: markg-github <13836240+markg-github@users.noreply.github.com>
run_vm_launch_step reported "error" unconditionally when vm_launch
raised VMLaunchError, ignoring the step's expected_result. That made it
impossible to write a step that expects a launch to be refused: QEMU
exiting immediately raises rather than returning ok=False, so a step
declaring expected_result="exit_code:1" errored on exactly the outcome
it was asserting.

Evaluate expected_result against exit code 1 and the exception text, and
record exit_code=1 so the result is self-describing. Steps that do not
declare an expectation still default to "exit_code:0" and so still
report error, leaving existing behavior unchanged.

Co-authored-by: markg-github <13836240+markg-github@users.noreply.github.com>
execute_certification folded per-test results with

    if tr.result != "pass":
        overall = tr.result

which is last-writer-wins, not worst-wins. A run where the first test
errors and a later one merely fails reported the certification as
"fail", losing the error. The bug is latent today because both outcomes
are non-passing, but it silently downgrades severity in reports, and any
new non-passing state makes it worse.

Fold with an explicit severity ordering instead.

Co-authored-by: markg-github <13836240+markg-github@users.noreply.github.com>
vm_launch checks whether QEMU is still alive exactly once, at
wait_ready_seconds, and never again. wait_for_guest then polls vsock
until vsock_boot_timeout with no reference to the process at all. If
QEMU exits after that single check, the harness spends the rest of the
boot timeout pinging a VM that no longer exists.

Measured on an EPYC 9654 with a deliberately corrupted ID block
measurement, sampling the process at 1 Hz:

  +14.6s .. +17.2s   QEMU alive
  +17.2s ..          gone
  step ran +13.8s .. +195.9s

QEMU lived 2.6s; the step took 182.1s. ~179s was spent waiting on a
dead process. Policy violations are rejected at SNP_LAUNCH_START before
guest memory is loaded, so QEMU dies inside the initial check and those
launches already fail in ~2s — which is why only the measurement case
was slow.

Pass the process handle into wait_for_guest and abort as soon as it
exits. The step drops from 182.1s to ~3s and the id-block suite from
~200s to ~21s.

The diagnostics matter more than the speed. Firmware had already
reported the exact cause:

  SNP_LAUNCH_FINISH ret=-5 fw_error=11 'Bad measurement'

and the harness discarded it in favour of "Vsock agent on CID ... not
ready after 180.0s". A negative test asserting exit_code:1 is satisfied
by that timeout just as well as by a real rejection, so it would pass
identically if the guest merely hung or if the ID block were ignored
entirely. The failure message now carries QEMU's exit code and its
stderr tail, so a rejected launch states the firmware's reason.

process defaults to None, preserving the old behavior for any caller
that does not supply it.

Co-authored-by: markg-github <13836240+markg-github@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Co-authored-by: markg-github <13836240+markg-github@users.noreply.github.com>
Co-authored-by: markg-github <13836240+markg-github@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 14, 2026 18:40
Copilot AI changed the title [WIP] Fix code based on review comment fix: use parameterized Popen[bytes] for QEMU handle type annotation in guest_vsock.py Aug 14, 2026
Copilot AI requested a review from markg-github August 14, 2026 18:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (2)

sev_verify/vm_profile.py:234

  • The PR title/description state this is only a type-annotation fix in guest_vsock.py, but this hunk introduces functional behavior changes (passing the QEMU process into guest readiness checks and altering failure messaging/diagnostics). Please update the PR title/description to reflect the expanded scope (or split the behavioral changes into a separate PR) so reviewers and release notes aren’t misled.
            # Passing the process lets the wait abort as soon as QEMU dies,
            # instead of polling vsock until the boot timeout expires against
            # a VM that no longer exists.
            booted, boot_error = check_guest_ready(self, process=process)

sev_verify/vm_profile.py:244

  • Reading QEMU stderr via _read_guest_errors() loads the entire log file into memory (Path.read_bytes()) and only then truncates to max_bytes. If QEMU emits a large stderr log, this can cause avoidable memory spikes and slow failure handling. Consider changing _read_guest_errors() to read only the tail (seek from end) instead of reading the whole file.
                    stderr_tail = _read_guest_errors(self.guest_error_log).strip()
                    if stderr_tail:
                        message = f"{message}\nQEMU stderr:\n{stderr_tail}"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants